mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-11-03 18:54:21 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d980d7a9ea | |||
| eab3b7aea4 | |||
| 3af177be19 | |||
| e4c7307c99 | |||
| f9c942c8ff | |||
| eeb977fc03 | |||
| 4b8a62122a | |||
| e44e947fc1 | |||
| 7588cfe1c5 | |||
| a9a643f222 | |||
| 77d6cb75be | |||
| 1942d221df | |||
| 041601ed65 | |||
| 5567281a85 | |||
| 4c3753046b | |||
| 89f8e16184 | |||
| a3e1125ced | |||
| 4dae8acfed | |||
| bc081c4344 | |||
| e4275b235d | |||
| 77397cac82 |
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Show sections tabs only if there is at least two sections
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/react-openapi": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix Python code example for JSON payload
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
'@gitbook/react-openapi': patch
|
||||||
|
'gitbook': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve OpenAPIResponses examples and schemas
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix dropdown menu not staying fixed
|
||||||
@@ -55,6 +55,7 @@ runs:
|
|||||||
GITBOOK_INTEGRATIONS_HOST: ${{ inputs.opItem }}/GITBOOK_INTEGRATIONS_HOST
|
GITBOOK_INTEGRATIONS_HOST: ${{ inputs.opItem }}/GITBOOK_INTEGRATIONS_HOST
|
||||||
GITBOOK_IMAGE_RESIZE_SIGNING_KEY: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_SIGNING_KEY
|
GITBOOK_IMAGE_RESIZE_SIGNING_KEY: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_SIGNING_KEY
|
||||||
GITBOOK_IMAGE_RESIZE_URL: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_URL
|
GITBOOK_IMAGE_RESIZE_URL: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_URL
|
||||||
|
GITBOOK_IMAGE_RESIZE_MODE: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_MODE
|
||||||
GITBOOK_ASSETS_PREFIX: ${{ inputs.opItem }}/GITBOOK_ASSETS_PREFIX
|
GITBOOK_ASSETS_PREFIX: ${{ inputs.opItem }}/GITBOOK_ASSETS_PREFIX
|
||||||
GITBOOK_FONTS_URL: ${{ inputs.opItem }}/GITBOOK_FONTS_URL
|
GITBOOK_FONTS_URL: ${{ inputs.opItem }}/GITBOOK_FONTS_URL
|
||||||
- name: Build worker
|
- name: Build worker
|
||||||
@@ -69,7 +70,7 @@ runs:
|
|||||||
apiToken: ${{ inputs.apiToken }}
|
apiToken: ${{ inputs.apiToken }}
|
||||||
accountId: ${{ inputs.accountId }}
|
accountId: ${{ inputs.accountId }}
|
||||||
workingDirectory: ./
|
workingDirectory: ./
|
||||||
wranglerVersion: '3.112.0'
|
wranglerVersion: '4.10.0'
|
||||||
environment: ${{ inputs.environment }}
|
environment: ${{ inputs.environment }}
|
||||||
command: ${{ inputs.deploy == 'true' && 'deploy' || format('versions upload --tag {0} --message "{1}"', inputs.commitTag, inputs.commitMessage) }} --config ./packages/gitbook-v2/wrangler.jsonc
|
command: ${{ inputs.deploy == 'true' && 'deploy' || format('versions upload --tag {0} --message "{1}"', inputs.commitTag, inputs.commitMessage) }} --config ./packages/gitbook-v2/wrangler.jsonc
|
||||||
- name: Outputs
|
- name: Outputs
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ runs:
|
|||||||
GITBOOK_INTEGRATIONS_HOST: ${{ inputs.opItem }}/GITBOOK_INTEGRATIONS_HOST
|
GITBOOK_INTEGRATIONS_HOST: ${{ inputs.opItem }}/GITBOOK_INTEGRATIONS_HOST
|
||||||
GITBOOK_IMAGE_RESIZE_SIGNING_KEY: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_SIGNING_KEY
|
GITBOOK_IMAGE_RESIZE_SIGNING_KEY: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_SIGNING_KEY
|
||||||
GITBOOK_IMAGE_RESIZE_URL: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_URL
|
GITBOOK_IMAGE_RESIZE_URL: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_URL
|
||||||
|
GITBOOK_IMAGE_RESIZE_MODE: ${{ inputs.opItem }}/GITBOOK_IMAGE_RESIZE_MODE
|
||||||
GITBOOK_ASSETS_PREFIX: ${{ inputs.opItem }}/GITBOOK_ASSETS_PREFIX
|
GITBOOK_ASSETS_PREFIX: ${{ inputs.opItem }}/GITBOOK_ASSETS_PREFIX
|
||||||
GITBOOK_FONTS_URL: ${{ inputs.opItem }}/GITBOOK_FONTS_URL
|
GITBOOK_FONTS_URL: ${{ inputs.opItem }}/GITBOOK_FONTS_URL
|
||||||
- name: Build Project Artifacts
|
- name: Build Project Artifacts
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ jobs:
|
|||||||
name: Visual Testing v2 (Cloudflare)
|
name: Visual Testing v2 (Cloudflare)
|
||||||
needs: deploy-v2-cloudflare
|
needs: deploy-v2-cloudflare
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
if: startsWith(github.ref_name, 'cloudflare/')
|
if: startsWith(github.head_ref || github.ref_name, 'cloudflare/') || github.ref == 'refs/heads/main'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -263,7 +263,7 @@ jobs:
|
|||||||
name: Visual Testing Customers v2 (Cloudflare)
|
name: Visual Testing Customers v2 (Cloudflare)
|
||||||
needs: deploy-v2-cloudflare
|
needs: deploy-v2-cloudflare
|
||||||
timeout-minutes: 8
|
timeout-minutes: 8
|
||||||
if: startsWith(github.ref_name, 'cloudflare/')
|
if: startsWith(github.head_ref || github.ref_name, 'cloudflare/') || github.ref == 'refs/heads/main'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -59,15 +59,15 @@ bun install
|
|||||||
4. Start your local development server.
|
4. Start your local development server.
|
||||||
|
|
||||||
```
|
```
|
||||||
bun dev
|
bun dev:v2
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Open a published GitBook space in your web browser, prefixing it with `http://localhost:3000/`.
|
5. Open a published GitBook space in your web browser, prefixing it with `http://localhost:3000/`.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
|
|
||||||
- http://localhost:3000/docs.gitbook.com
|
- http://localhost:3000/url/docs.gitbook.com
|
||||||
- http://localhost:3000/open-source.gitbook.io/midjourney
|
- http://localhost:3000/url/open-source.gitbook.io/midjourney
|
||||||
|
|
||||||
Any published GitBook site can be accessed through your local development instance, and any updates you make to the codebase will be reflected in your browser.
|
Any published GitBook site can be accessed through your local development instance, and any updates you make to the codebase will be reflected in your browser.
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,14 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
"wrangler": "^3.112.0",
|
"wrangler": "^4.10.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/cache-tags": {
|
"packages/cache-tags": {
|
||||||
"name": "@gitbook/cache-tags",
|
"name": "@gitbook/cache-tags",
|
||||||
"version": "0.2.0",
|
"version": "0.3.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "*",
|
"@gitbook/api": "^0.109.0",
|
||||||
"assert-never": "^1.2.1",
|
"assert-never": "^1.2.1",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
},
|
},
|
||||||
"packages/colors": {
|
"packages/colors": {
|
||||||
"name": "@gitbook/colors",
|
"name": "@gitbook/colors",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
},
|
},
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
},
|
},
|
||||||
"packages/gitbook": {
|
"packages/gitbook": {
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "0.9.2",
|
"version": "0.10.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "*",
|
"@gitbook/api": "*",
|
||||||
"@gitbook/cache-do": "workspace:*",
|
"@gitbook/cache-do": "workspace:*",
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
"zustand": "^5.0.3",
|
"zustand": "^5.0.3",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@argos-ci/playwright": "^4.3.0",
|
"@argos-ci/playwright": "^5.0.3",
|
||||||
"@cloudflare/next-on-pages": "1.13.7",
|
"@cloudflare/next-on-pages": "1.13.7",
|
||||||
"@cloudflare/workers-types": "^4.20241230.0",
|
"@cloudflare/workers-types": "^4.20241230.0",
|
||||||
"@playwright/test": "^1.51.1",
|
"@playwright/test": "^1.51.1",
|
||||||
@@ -140,11 +140,12 @@
|
|||||||
},
|
},
|
||||||
"packages/gitbook-v2": {
|
"packages/gitbook-v2": {
|
||||||
"name": "gitbook-v2",
|
"name": "gitbook-v2",
|
||||||
"version": "0.2.3",
|
"version": "0.2.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "*",
|
"@gitbook/api": "*",
|
||||||
"@gitbook/cache-tags": "workspace:*",
|
"@gitbook/cache-tags": "workspace:*",
|
||||||
"@sindresorhus/fnv1a": "^3.1.0",
|
"@sindresorhus/fnv1a": "^3.1.0",
|
||||||
|
"assert-never": "^1.2.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
@@ -154,7 +155,7 @@
|
|||||||
"warn-once": "^0.1.1",
|
"warn-once": "^0.1.1",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opennextjs/cloudflare": "https://pkg.pr.new/opennextjs/opennextjs-cloudflare/@opennextjs/cloudflare@7b3b305",
|
"@opennextjs/cloudflare": "^1.0.0-beta.3",
|
||||||
"@types/rison": "^0.0.9",
|
"@types/rison": "^0.0.9",
|
||||||
"gitbook": "*",
|
"gitbook": "*",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
@@ -183,7 +184,7 @@
|
|||||||
},
|
},
|
||||||
"packages/openapi-parser": {
|
"packages/openapi-parser": {
|
||||||
"name": "@gitbook/openapi-parser",
|
"name": "@gitbook/openapi-parser",
|
||||||
"version": "2.1.2",
|
"version": "2.1.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@scalar/openapi-parser": "^0.10.10",
|
"@scalar/openapi-parser": "^0.10.10",
|
||||||
"@scalar/openapi-types": "^0.1.9",
|
"@scalar/openapi-types": "^0.1.9",
|
||||||
@@ -230,7 +231,7 @@
|
|||||||
},
|
},
|
||||||
"packages/react-openapi": {
|
"packages/react-openapi": {
|
||||||
"name": "@gitbook/react-openapi",
|
"name": "@gitbook/react-openapi",
|
||||||
"version": "1.1.9",
|
"version": "1.1.10",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/openapi-parser": "workspace:*",
|
"@gitbook/openapi-parser": "workspace:*",
|
||||||
"@scalar/api-client-react": "^1.2.5",
|
"@scalar/api-client-react": "^1.2.5",
|
||||||
@@ -273,15 +274,15 @@
|
|||||||
|
|
||||||
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
|
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
|
||||||
|
|
||||||
"@argos-ci/api-client": ["@argos-ci/api-client@0.8.0", "", { "dependencies": { "debug": "^4.4.0", "openapi-fetch": "0.13.4" } }, "sha512-UHa1vAf8gwHVpkqM/RaSryrFe1juqWH6dHpPeMtT4e/ZMB9hNYwYFinaGq/KRWe88JEi2WeAu776YdoeUSZQkQ=="],
|
"@argos-ci/api-client": ["@argos-ci/api-client@0.8.1", "", { "dependencies": { "debug": "^4.4.0", "openapi-fetch": "0.13.5" } }, "sha512-3IHv7ANSPNO6OwWgwULlHbP9/tFV9kQDu6+nL9jysfPkGj0GgtrOsyBb+iU931c7wSMo1OD+XNujCnRzDD968w=="],
|
||||||
|
|
||||||
"@argos-ci/browser": ["@argos-ci/browser@3.2.0", "", {}, "sha512-mHLUamfywbdzrM6SRV4KB4kEQs2lrFxC1yS+QWB/9lME7FKzr7MJW/Q++iWcQli8IbmtLsZ+PqP2eqLaDiRsUw=="],
|
"@argos-ci/browser": ["@argos-ci/browser@4.1.1", "", {}, "sha512-UyKdnprGftUjWQkb0jqJ0zGHJmcWBzdko8zRy4y+4efukVX4jjC/Px2HvWW8aqwjoR4aplouMZuzhmOkq2SCsA=="],
|
||||||
|
|
||||||
"@argos-ci/core": ["@argos-ci/core@3.1.0", "", { "dependencies": { "@argos-ci/api-client": "0.8.0", "@argos-ci/util": "2.3.0", "axios": "^1.7.9", "convict": "^6.2.4", "debug": "^4.4.0", "fast-glob": "^3.3.3", "sharp": "^0.33.5", "tmp": "^0.2.3" } }, "sha512-bo/pNKk6P0pz4NRdymgU1letwQrRbMPTeFyMsUEW8fhKNdesSFnFIWZBFGsGkkh05uw75PBjl2ZN4PvQ2TxSog=="],
|
"@argos-ci/core": ["@argos-ci/core@3.1.1", "", { "dependencies": { "@argos-ci/api-client": "0.8.1", "@argos-ci/util": "2.3.1", "axios": "^1.8.4", "convict": "^6.2.4", "debug": "^4.4.0", "fast-glob": "^3.3.3", "sharp": "^0.33.5", "tmp": "^0.2.3" } }, "sha512-7iE3o1XGxlfHC5AF05pzT0OxuO387sryrZt3gKGj/e+6R20DXz7J49yI8++nQ2cuT+wLhcJp8+X0ox+SGMYHmw=="],
|
||||||
|
|
||||||
"@argos-ci/playwright": ["@argos-ci/playwright@4.3.0", "", { "dependencies": { "@argos-ci/browser": "3.2.0", "@argos-ci/core": "3.1.0", "@argos-ci/util": "2.3.0", "chalk": "^5.4.1", "debug": "^4.4.0" } }, "sha512-UQBC78zWg+bWXDaevWOL4m6zkrNeprMfdqjy6zagvU9kq7sPQC7nN/qZQ15hs/FT+JpTCa8CbbSAq13eQrmxKQ=="],
|
"@argos-ci/playwright": ["@argos-ci/playwright@5.0.3", "", { "dependencies": { "@argos-ci/browser": "4.1.1", "@argos-ci/core": "3.1.1", "@argos-ci/util": "2.3.1", "chalk": "^5.4.1", "debug": "^4.4.0" } }, "sha512-sqoARsgnDRrwKm1x10L3Z8+OQukk0F9OksVj9v9rvbzNI2WVCw5zbCUMY0qD4Q3Ba7vMFbl1ELUODRc2mfCbNw=="],
|
||||||
|
|
||||||
"@argos-ci/util": ["@argos-ci/util@2.3.0", "", {}, "sha512-tkxnCpaj7yN9nCFzo9MX0FJ5YjUepEOGYfdvF8COQqp+EdY1qubOPpc4Z0l1B60BlC8YtjQv/oRxHSh1XzxWFg=="],
|
"@argos-ci/util": ["@argos-ci/util@2.3.1", "", {}, "sha512-kE61HU2480fbAnimmA4x9HK45ZJvkoqLdW5GxT5uvwhkclQykVd2S6WfGFUr3JokTXfZ5LZEEfoWgtGA316KSQ=="],
|
||||||
|
|
||||||
"@ast-grep/napi": ["@ast-grep/napi@0.35.0", "", { "optionalDependencies": { "@ast-grep/napi-darwin-arm64": "0.35.0", "@ast-grep/napi-darwin-x64": "0.35.0", "@ast-grep/napi-linux-arm64-gnu": "0.35.0", "@ast-grep/napi-linux-arm64-musl": "0.35.0", "@ast-grep/napi-linux-x64-gnu": "0.35.0", "@ast-grep/napi-linux-x64-musl": "0.35.0", "@ast-grep/napi-win32-arm64-msvc": "0.35.0", "@ast-grep/napi-win32-ia32-msvc": "0.35.0", "@ast-grep/napi-win32-x64-msvc": "0.35.0" } }, "sha512-3ucaaSxV6fxXoqHrE/rxAvP1THnDdY5jNzGlnvx+JvnY9C/dSRKc0jlRMRz59N3El572+/yNRUUpAV1T9aBJug=="],
|
"@ast-grep/napi": ["@ast-grep/napi@0.35.0", "", { "optionalDependencies": { "@ast-grep/napi-darwin-arm64": "0.35.0", "@ast-grep/napi-darwin-x64": "0.35.0", "@ast-grep/napi-linux-arm64-gnu": "0.35.0", "@ast-grep/napi-linux-arm64-musl": "0.35.0", "@ast-grep/napi-linux-x64-gnu": "0.35.0", "@ast-grep/napi-linux-x64-musl": "0.35.0", "@ast-grep/napi-win32-arm64-msvc": "0.35.0", "@ast-grep/napi-win32-ia32-msvc": "0.35.0", "@ast-grep/napi-win32-x64-msvc": "0.35.0" } }, "sha512-3ucaaSxV6fxXoqHrE/rxAvP1THnDdY5jNzGlnvx+JvnY9C/dSRKc0jlRMRz59N3El572+/yNRUUpAV1T9aBJug=="],
|
||||||
|
|
||||||
@@ -469,19 +470,21 @@
|
|||||||
|
|
||||||
"@changesets/write": ["@changesets/write@0.3.2", "", { "dependencies": { "@changesets/types": "^6.0.0", "fs-extra": "^7.0.1", "human-id": "^1.0.2", "prettier": "^2.7.1" } }, "sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw=="],
|
"@changesets/write": ["@changesets/write@0.3.2", "", { "dependencies": { "@changesets/types": "^6.0.0", "fs-extra": "^7.0.1", "human-id": "^1.0.2", "prettier": "^2.7.1" } }, "sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw=="],
|
||||||
|
|
||||||
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.3.4", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q=="],
|
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
|
||||||
|
|
||||||
"@cloudflare/next-on-pages": ["@cloudflare/next-on-pages@1.13.7", "", { "dependencies": { "acorn": "^8.8.0", "ast-types": "^0.14.2", "chalk": "^5.2.0", "chokidar": "^3.5.3", "commander": "^11.1.0", "cookie": "^0.5.0", "esbuild": "^0.15.3", "js-yaml": "^4.1.0", "miniflare": "^3.20231218.1", "package-manager-manager": "^0.2.0", "pcre-to-regexp": "^1.1.0", "semver": "^7.5.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20240208.0", "vercel": ">=30.0.0", "wrangler": "^3.28.2" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "next-on-pages": "bin/index.js" } }, "sha512-TSMVy+1fmxzeyykOC9guMEj7G2FgENw1T8V1sIFnah6piaJNBmybdyikPdQSdikP5w6v9eQhBt/TrXDPMDw0dw=="],
|
"@cloudflare/next-on-pages": ["@cloudflare/next-on-pages@1.13.7", "", { "dependencies": { "acorn": "^8.8.0", "ast-types": "^0.14.2", "chalk": "^5.2.0", "chokidar": "^3.5.3", "commander": "^11.1.0", "cookie": "^0.5.0", "esbuild": "^0.15.3", "js-yaml": "^4.1.0", "miniflare": "^3.20231218.1", "package-manager-manager": "^0.2.0", "pcre-to-regexp": "^1.1.0", "semver": "^7.5.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20240208.0", "vercel": ">=30.0.0", "wrangler": "^3.28.2" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "next-on-pages": "bin/index.js" } }, "sha512-TSMVy+1fmxzeyykOC9guMEj7G2FgENw1T8V1sIFnah6piaJNBmybdyikPdQSdikP5w6v9eQhBt/TrXDPMDw0dw=="],
|
||||||
|
|
||||||
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250214.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cDvvedWDc5zrgDnuXe2qYcz/TwBvzmweO55C7XpPuAWJ9Oqxv81PkdekYxD8mH989aQ/GI5YD0Fe6fDYlM+T3Q=="],
|
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.3.1", "", { "peerDependencies": { "unenv": "2.0.0-rc.15", "workerd": "^1.20250320.0" }, "optionalPeers": ["workerd"] }, "sha512-Xq57Qd+ADpt6hibcVBO0uLG9zzRgyRhfCUgBT9s+g3+3Ivg5zDyVgLFy40ES1VdNcu8rPNSivm9A+kGP5IVaPg=="],
|
||||||
|
|
||||||
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250214.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-NytCvRveVzu0mRKo+tvZo3d/gCUway3B2ZVqSi/TS6NXDGBYIJo7g6s3BnTLS74kgyzeDOjhu9j/RBJBS809qw=="],
|
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250409.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-smA9yq77xsdQ1NMLhFz3JZxMHGd01lg0bE+X3dTFmIUs+hHskJ+HJ/IkMFInkCCeEFlUkoL4yO7ilaU/fin/xA=="],
|
||||||
|
|
||||||
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250214.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pQ7+aHNHj8SiYEs4d/6cNoimE5xGeCMfgU1yfDFtA9YGN9Aj2BITZgOWPec+HW7ZkOy9oWlNrO6EvVjGgB4tbQ=="],
|
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250409.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oLVcf+Y5Qun8JHcy1VcR/YnbA5U2ne0czh3XNhDqdHZFK8+vKeC7MnVPX+kEqQA3+uLcMM1/FsIDU1U4Na0h1g=="],
|
||||||
|
|
||||||
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250214.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Vhlfah6Yd9ny1npNQjNgElLIjR6OFdEbuR3LCfbLDCwzWEBFhIf7yC+Tpp/a0Hq7kLz3sLdktaP7xl3PJhyOjA=="],
|
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250409.0", "", { "os": "linux", "cpu": "x64" }, "sha512-D31B4kdC3a0RD5yfpdIa89//kGHbYsYihZmejm1k4S4NHOho3MUDHAEh4aHtafQNXbZdydGHlSyiVYjTdQ9ILQ=="],
|
||||||
|
|
||||||
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250214.0", "", { "os": "win32", "cpu": "x64" }, "sha512-GMwMyFbkjBKjYJoKDhGX8nuL4Gqe3IbVnVWf2Q6086CValyIknupk5J6uQWGw2EBU3RGO3x4trDXT5WphQJZDQ=="],
|
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250409.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Sr59P0TREayil5OQ7kcbjuIn6L6OTSRLI91LKu0D8vi1hss2q9FUwBcwxg0+Yd/x+ty/x7IISiAK5QBkAMeITQ=="],
|
||||||
|
|
||||||
|
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250409.0", "", { "os": "win32", "cpu": "x64" }, "sha512-dK9I8zBX5rR7MtaaP2AhICQTEw3PVzHcsltN8o46w7JsbYlMvFOj27FfYH5dhs3IahgmIfw2e572QXW2o/dbpg=="],
|
||||||
|
|
||||||
"@cloudflare/workers-types": ["@cloudflare/workers-types@4.20241230.0", "", {}, "sha512-dtLD4jY35Lb750cCVyO1i/eIfdZJg2Z0i+B1RYX6BVeRPlgaHx/H18ImKAkYmy0g09Ow8R2jZy3hIxMgXun0WQ=="],
|
"@cloudflare/workers-types": ["@cloudflare/workers-types@4.20241230.0", "", {}, "sha512-dtLD4jY35Lb750cCVyO1i/eIfdZJg2Z0i+B1RYX6BVeRPlgaHx/H18ImKAkYmy0g09Ow8R2jZy3hIxMgXun0WQ=="],
|
||||||
|
|
||||||
@@ -547,49 +550,55 @@
|
|||||||
|
|
||||||
"@esbuild-plugins/node-modules-polyfill": ["@esbuild-plugins/node-modules-polyfill@0.2.2", "", { "dependencies": { "escape-string-regexp": "^4.0.0", "rollup-plugin-node-polyfills": "^0.2.1" }, "peerDependencies": { "esbuild": "*" } }, "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA=="],
|
"@esbuild-plugins/node-modules-polyfill": ["@esbuild-plugins/node-modules-polyfill@0.2.2", "", { "dependencies": { "escape-string-regexp": "^4.0.0", "rollup-plugin-node-polyfills": "^0.2.1" }, "peerDependencies": { "esbuild": "*" } }, "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA=="],
|
||||||
|
|
||||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.17.19", "", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="],
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="],
|
||||||
|
|
||||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.17.19", "", { "os": "android", "cpu": "arm64" }, "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA=="],
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q=="],
|
||||||
|
|
||||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.17.19", "", { "os": "android", "cpu": "x64" }, "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww=="],
|
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg=="],
|
||||||
|
|
||||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg=="],
|
"@esbuild/android-x64": ["@esbuild/android-x64@0.24.2", "", { "os": "android", "cpu": "x64" }, "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw=="],
|
||||||
|
|
||||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw=="],
|
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA=="],
|
||||||
|
|
||||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.17.19", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ=="],
|
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA=="],
|
||||||
|
|
||||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.17.19", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ=="],
|
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.24.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg=="],
|
||||||
|
|
||||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.17.19", "", { "os": "linux", "cpu": "arm" }, "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA=="],
|
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q=="],
|
||||||
|
|
||||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg=="],
|
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA=="],
|
||||||
|
|
||||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.17.19", "", { "os": "linux", "cpu": "ia32" }, "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ=="],
|
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg=="],
|
||||||
|
|
||||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ=="],
|
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.24.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw=="],
|
||||||
|
|
||||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A=="],
|
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ=="],
|
||||||
|
|
||||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.17.19", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg=="],
|
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw=="],
|
||||||
|
|
||||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA=="],
|
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw=="],
|
||||||
|
|
||||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.17.19", "", { "os": "linux", "cpu": "s390x" }, "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q=="],
|
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q=="],
|
||||||
|
|
||||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw=="],
|
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw=="],
|
||||||
|
|
||||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.17.19", "", { "os": "none", "cpu": "x64" }, "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q=="],
|
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q=="],
|
||||||
|
|
||||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.17.19", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g=="],
|
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw=="],
|
||||||
|
|
||||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.17.19", "", { "os": "sunos", "cpu": "x64" }, "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg=="],
|
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.24.2", "", { "os": "none", "cpu": "x64" }, "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw=="],
|
||||||
|
|
||||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag=="],
|
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.24.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A=="],
|
||||||
|
|
||||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.17.19", "", { "os": "win32", "cpu": "ia32" }, "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw=="],
|
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.24.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA=="],
|
||||||
|
|
||||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA=="],
|
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.24.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.24.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="],
|
||||||
|
|
||||||
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
|
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
|
||||||
|
|
||||||
@@ -785,9 +794,9 @@
|
|||||||
|
|
||||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||||
|
|
||||||
"@opennextjs/aws": ["@opennextjs/aws@3.5.5", "", { "dependencies": { "@ast-grep/napi": "^0.35.0", "@aws-sdk/client-cloudfront": "3.398.0", "@aws-sdk/client-dynamodb": "^3.398.0", "@aws-sdk/client-lambda": "^3.398.0", "@aws-sdk/client-s3": "^3.398.0", "@aws-sdk/client-sqs": "^3.398.0", "@node-minify/core": "^8.0.6", "@node-minify/terser": "^8.0.6", "@tsconfig/node18": "^1.0.1", "aws4fetch": "^1.0.18", "chalk": "^5.3.0", "esbuild": "0.19.2", "express": "5.0.1", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.0.0", "yaml": "^2.7.0" }, "bin": { "open-next": "dist/index.js" } }, "sha512-vIqCcNxy7vPdC5HQQkCN+AXhxdNvagZ8EYw5XvuYIAP2T1Ci9ai/8m6UXtjgd3L9+aBA8pbWfr2Wr/BNLX5m2Q=="],
|
"@opennextjs/aws": ["@opennextjs/aws@3.5.7", "", { "dependencies": { "@ast-grep/napi": "^0.35.0", "@aws-sdk/client-cloudfront": "3.398.0", "@aws-sdk/client-dynamodb": "^3.398.0", "@aws-sdk/client-lambda": "^3.398.0", "@aws-sdk/client-s3": "^3.398.0", "@aws-sdk/client-sqs": "^3.398.0", "@node-minify/core": "^8.0.6", "@node-minify/terser": "^8.0.6", "@tsconfig/node18": "^1.0.1", "aws4fetch": "^1.0.18", "chalk": "^5.3.0", "esbuild": "0.19.2", "express": "5.0.1", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.0.0", "yaml": "^2.7.0" }, "bin": { "open-next": "dist/index.js" } }, "sha512-YjyHJrkIHI7YwQRCp8GjDOudu86oOc1RiwxvBBpPHrplsS18H4ZmkzGggAKhK6B4myGsJQ/q9kNP2TraoZiNzg=="],
|
||||||
|
|
||||||
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@https://pkg.pr.new/opennextjs/opennextjs-cloudflare/@opennextjs/cloudflare@7b3b305", { "dependencies": { "@dotenvx/dotenvx": "1.31.0", "@opennextjs/aws": "3.5.5", "enquirer": "^2.4.1", "glob": "^11.0.0", "ts-tqdm": "^0.8.6" }, "peerDependencies": { "wrangler": "^3.114.3 || ^4.7.0" }, "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }],
|
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.0.0-beta.3", "", { "dependencies": { "@dotenvx/dotenvx": "1.31.0", "@opennextjs/aws": "3.5.7", "enquirer": "^2.4.1", "glob": "^11.0.0", "ts-tqdm": "^0.8.6" }, "peerDependencies": { "wrangler": "^3.114.3 || ^4.7.0" }, "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-qKBXQZhUeQ+iGvfJeF7PO30g59LHnPOlRVZd77zxwn6Uc9C+c0LSwo8N28XRIWyQPkY007rKk9pSIxOrP4MHtQ=="],
|
||||||
|
|
||||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||||
|
|
||||||
@@ -1441,7 +1450,7 @@
|
|||||||
|
|
||||||
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
|
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
|
||||||
|
|
||||||
"axios": ["axios@1.7.9", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw=="],
|
"axios": ["axios@1.8.4", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw=="],
|
||||||
|
|
||||||
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
|
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
|
||||||
|
|
||||||
@@ -1699,7 +1708,7 @@
|
|||||||
|
|
||||||
"es6-weak-map": ["es6-weak-map@2.0.3", "", { "dependencies": { "d": "1", "es5-ext": "^0.10.46", "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.1" } }, "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA=="],
|
"es6-weak-map": ["es6-weak-map@2.0.3", "", { "dependencies": { "d": "1", "es5-ext": "^0.10.46", "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.1" } }, "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA=="],
|
||||||
|
|
||||||
"esbuild": ["esbuild@0.17.19", "", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="],
|
"esbuild": ["esbuild@0.24.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.24.2", "@esbuild/android-arm": "0.24.2", "@esbuild/android-arm64": "0.24.2", "@esbuild/android-x64": "0.24.2", "@esbuild/darwin-arm64": "0.24.2", "@esbuild/darwin-x64": "0.24.2", "@esbuild/freebsd-arm64": "0.24.2", "@esbuild/freebsd-x64": "0.24.2", "@esbuild/linux-arm": "0.24.2", "@esbuild/linux-arm64": "0.24.2", "@esbuild/linux-ia32": "0.24.2", "@esbuild/linux-loong64": "0.24.2", "@esbuild/linux-mips64el": "0.24.2", "@esbuild/linux-ppc64": "0.24.2", "@esbuild/linux-riscv64": "0.24.2", "@esbuild/linux-s390x": "0.24.2", "@esbuild/linux-x64": "0.24.2", "@esbuild/netbsd-arm64": "0.24.2", "@esbuild/netbsd-x64": "0.24.2", "@esbuild/openbsd-arm64": "0.24.2", "@esbuild/openbsd-x64": "0.24.2", "@esbuild/sunos-x64": "0.24.2", "@esbuild/win32-arm64": "0.24.2", "@esbuild/win32-ia32": "0.24.2", "@esbuild/win32-x64": "0.24.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA=="],
|
||||||
|
|
||||||
"esbuild-android-64": ["esbuild-android-64@0.15.18", "", { "os": "android", "cpu": "x64" }, "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA=="],
|
"esbuild-android-64": ["esbuild-android-64@0.15.18", "", { "os": "android", "cpu": "x64" }, "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA=="],
|
||||||
|
|
||||||
@@ -1773,6 +1782,8 @@
|
|||||||
|
|
||||||
"express": ["express@5.0.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.0.1", "content-disposition": "^1.0.0", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "^1.2.1", "debug": "4.3.6", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "^2.0.0", "fresh": "2.0.0", "http-errors": "2.0.0", "merge-descriptors": "^2.0.0", "methods": "~1.1.2", "mime-types": "^3.0.0", "on-finished": "2.4.1", "once": "1.4.0", "parseurl": "~1.3.3", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "router": "^2.0.0", "safe-buffer": "5.2.1", "send": "^1.1.0", "serve-static": "^2.1.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "^2.0.0", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ=="],
|
"express": ["express@5.0.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.0.1", "content-disposition": "^1.0.0", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "^1.2.1", "debug": "4.3.6", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "^2.0.0", "fresh": "2.0.0", "http-errors": "2.0.0", "merge-descriptors": "^2.0.0", "methods": "~1.1.2", "mime-types": "^3.0.0", "on-finished": "2.4.1", "once": "1.4.0", "parseurl": "~1.3.3", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "router": "^2.0.0", "safe-buffer": "5.2.1", "send": "^1.1.0", "serve-static": "^2.1.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "^2.0.0", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ=="],
|
||||||
|
|
||||||
|
"exsolve": ["exsolve@1.0.4", "", {}, "sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw=="],
|
||||||
|
|
||||||
"ext": ["ext@1.7.0", "", { "dependencies": { "type": "^2.7.2" } }, "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw=="],
|
"ext": ["ext@1.7.0", "", { "dependencies": { "type": "^2.7.2" } }, "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw=="],
|
||||||
|
|
||||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||||
@@ -2281,7 +2292,7 @@
|
|||||||
|
|
||||||
"min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],
|
"min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],
|
||||||
|
|
||||||
"miniflare": ["miniflare@3.20250214.2", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250214.0", "ws": "8.18.0", "youch": "3.2.3", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-t+lT4p2lbOcKv4PS3sx1F/wcDAlbEYZCO2VooLp4H7JErWWYIi9yjD3UillC3CGOpiBahVg5nrPCoFltZf6UlA=="],
|
"miniflare": ["miniflare@4.20250409.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250409.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-Hu02dYZvFR+MyrI57O6rSrOUTofcO9EIvcodgq2SAHzAeWSJw2E0oq9lylOrcckFwPMcwxUAb/cQN1LIoCyySw=="],
|
||||||
|
|
||||||
"minimatch": ["minimatch@10.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ=="],
|
"minimatch": ["minimatch@10.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ=="],
|
||||||
|
|
||||||
@@ -2351,7 +2362,7 @@
|
|||||||
|
|
||||||
"obliterator": ["obliterator@1.6.1", "", {}, "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig=="],
|
"obliterator": ["obliterator@1.6.1", "", {}, "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig=="],
|
||||||
|
|
||||||
"ohash": ["ohash@1.1.4", "", {}, "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g=="],
|
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
|
||||||
|
|
||||||
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||||
|
|
||||||
@@ -2363,7 +2374,7 @@
|
|||||||
|
|
||||||
"oniguruma-to-es": ["oniguruma-to-es@4.1.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "oniguruma-parser": "^0.5.4", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-SNwG909cSLo4vPyyPbU/VJkEc9WOXqu2ycBlfd1UCXLqk1IijcQktSBb2yRQ2UFPsDhpkaf+C1dtT3PkLK/yWA=="],
|
"oniguruma-to-es": ["oniguruma-to-es@4.1.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "oniguruma-parser": "^0.5.4", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-SNwG909cSLo4vPyyPbU/VJkEc9WOXqu2ycBlfd1UCXLqk1IijcQktSBb2yRQ2UFPsDhpkaf+C1dtT3PkLK/yWA=="],
|
||||||
|
|
||||||
"openapi-fetch": ["openapi-fetch@0.13.4", "", { "dependencies": { "openapi-typescript-helpers": "^0.0.15" } }, "sha512-JHX7UYjLEiHuQGCPxa3CCCIqe/nc4bTIF9c4UYVC8BegAbWoS3g4gJxKX5XcG7UtYQs2060kY6DH64KkvNZahg=="],
|
"openapi-fetch": ["openapi-fetch@0.13.5", "", { "dependencies": { "openapi-typescript-helpers": "^0.0.15" } }, "sha512-AQK8T9GSKFREFlN1DBXTYsLjs7YV2tZcJ7zUWxbjMoQmj8dDSFRrzhLCbHPZWA1TMV3vACqfCxLEZcwf2wxV6Q=="],
|
||||||
|
|
||||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||||
|
|
||||||
@@ -2429,7 +2440,7 @@
|
|||||||
|
|
||||||
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
||||||
|
|
||||||
"pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
|
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||||
|
|
||||||
"pcre-to-regexp": ["pcre-to-regexp@1.1.0", "", {}, "sha512-KF9XxmUQJ2DIlMj3TqNqY1AWvyvTuIuq11CuuekxyaYMiFuMKGgQrePYMX5bXKLhLG3sDI4CsGAYHPaT7VV7+g=="],
|
"pcre-to-regexp": ["pcre-to-regexp@1.1.0", "", {}, "sha512-KF9XxmUQJ2DIlMj3TqNqY1AWvyvTuIuq11CuuekxyaYMiFuMKGgQrePYMX5bXKLhLG3sDI4CsGAYHPaT7VV7+g=="],
|
||||||
|
|
||||||
@@ -2817,7 +2828,7 @@
|
|||||||
|
|
||||||
"undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
|
"undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
|
||||||
|
|
||||||
"unenv": ["unenv@2.0.0-rc.1", "", { "dependencies": { "defu": "^6.1.4", "mlly": "^1.7.4", "ohash": "^1.1.4", "pathe": "^1.1.2", "ufo": "^1.5.4" } }, "sha512-PU5fb40H8X149s117aB4ytbORcCvlASdtF97tfls4BPIyj4PeVxvpSuy1jAptqYHqB0vb2w2sHvzM0XWcp2OKg=="],
|
"unenv": ["unenv@2.0.0-rc.15", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.5.4" } }, "sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA=="],
|
||||||
|
|
||||||
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
|
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
|
||||||
|
|
||||||
@@ -2907,9 +2918,9 @@
|
|||||||
|
|
||||||
"widest-line": ["widest-line@3.1.0", "", { "dependencies": { "string-width": "^4.0.0" } }, "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg=="],
|
"widest-line": ["widest-line@3.1.0", "", { "dependencies": { "string-width": "^4.0.0" } }, "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg=="],
|
||||||
|
|
||||||
"workerd": ["workerd@1.20250214.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250214.0", "@cloudflare/workerd-darwin-arm64": "1.20250214.0", "@cloudflare/workerd-linux-64": "1.20250214.0", "@cloudflare/workerd-linux-arm64": "1.20250214.0", "@cloudflare/workerd-windows-64": "1.20250214.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-QWcqXZLiMpV12wiaVnb3nLmfs/g4ZsFQq2mX85z546r3AX4CTIkXl0VP50W3CwqLADej3PGYiRDOTelDOwVG1g=="],
|
"workerd": ["workerd@1.20250409.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250409.0", "@cloudflare/workerd-darwin-arm64": "1.20250409.0", "@cloudflare/workerd-linux-64": "1.20250409.0", "@cloudflare/workerd-linux-arm64": "1.20250409.0", "@cloudflare/workerd-windows-64": "1.20250409.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-hqjX9swiHvrkOI3jlH9lrZsZRRv9lddUwcMe8Ua76jnyQz+brybWznNjHu8U5oswwcrFwvky1A4CcLjcLY31gQ=="],
|
||||||
|
|
||||||
"wrangler": ["wrangler@3.112.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-modules-polyfill": "0.2.2", "blake3-wasm": "2.1.5", "esbuild": "0.17.19", "miniflare": "3.20250214.2", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.1", "workerd": "1.20250214.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250214.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-PNQWGze3ODlWwG33LPr8kNhbht3eB3L9fogv+fapk2fjaqj0kNweRapkwmvtz46ojcqWzsxmTe4nOC0hIVUfPA=="],
|
"wrangler": ["wrangler@4.10.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.1", "blake3-wasm": "2.1.5", "esbuild": "0.24.2", "miniflare": "4.20250409.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.15", "workerd": "1.20250409.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250409.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-fTE4hZ79msEUt8+HEjl/8Q72haCyzPLu4PgrU3L81ysmjrMEdiYfUPqnvCkBUVtJvrDNdctTEimkufT1Y0ipNg=="],
|
||||||
|
|
||||||
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||||
|
|
||||||
@@ -2941,7 +2952,7 @@
|
|||||||
|
|
||||||
"yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="],
|
"yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="],
|
||||||
|
|
||||||
"youch": ["youch@3.2.3", "", { "dependencies": { "cookie": "^0.5.0", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-ZBcWz/uzZaQVdCvfV4uk616Bbpf2ee+F/AvuKDR5EwX/Y4v06xWdtMluqTD7+KlZdM93lLm9gMZYo0sKBS0pgw=="],
|
"youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="],
|
||||||
|
|
||||||
"zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="],
|
"zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="],
|
||||||
|
|
||||||
@@ -3555,6 +3566,8 @@
|
|||||||
|
|
||||||
"@cloudflare/next-on-pages/miniflare": ["miniflare@3.20241018.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "^8.8.0", "acorn-walk": "^8.2.0", "capnp-ts": "^0.7.0", "exit-hook": "^2.2.1", "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.4", "workerd": "1.20241018.1", "ws": "^8.17.1", "youch": "^3.2.2", "zod": "^3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-g7i5oGAoJOk8+hJp77A5/wAdu7PEvi5hQc+0wzwzjhUNM2I5DHd2Cc29ACPhAe1kIXvCCVkxs3+REF52qnX0aw=="],
|
"@cloudflare/next-on-pages/miniflare": ["miniflare@3.20241018.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "^8.8.0", "acorn-walk": "^8.2.0", "capnp-ts": "^0.7.0", "exit-hook": "^2.2.1", "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.4", "workerd": "1.20241018.1", "ws": "^8.17.1", "youch": "^3.2.2", "zod": "^3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-g7i5oGAoJOk8+hJp77A5/wAdu7PEvi5hQc+0wzwzjhUNM2I5DHd2Cc29ACPhAe1kIXvCCVkxs3+REF52qnX0aw=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler": ["wrangler@3.112.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-modules-polyfill": "0.2.2", "blake3-wasm": "2.1.5", "esbuild": "0.17.19", "miniflare": "3.20250214.2", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.1", "workerd": "1.20250214.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250214.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-PNQWGze3ODlWwG33LPr8kNhbht3eB3L9fogv+fapk2fjaqj0kNweRapkwmvtz46ojcqWzsxmTe4nOC0hIVUfPA=="],
|
||||||
|
|
||||||
"@codemirror/lang-html/@codemirror/autocomplete": ["@codemirror/autocomplete@6.18.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA=="],
|
"@codemirror/lang-html/@codemirror/autocomplete": ["@codemirror/autocomplete@6.18.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA=="],
|
||||||
|
|
||||||
"@codemirror/lang-html/@codemirror/lang-css": ["@codemirror/lang-css@6.3.0", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.2", "@lezer/css": "^1.1.7" } }, "sha512-CyR4rUNG9OYcXDZwMPvJdtb6PHbBDKUc/6Na2BIwZ6dKab1JQqKa4di+RNRY9Myn7JB81vayKwJeQ7jEdmNVDA=="],
|
"@codemirror/lang-html/@codemirror/lang-css": ["@codemirror/lang-css@6.3.0", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.2", "@lezer/css": "^1.1.7" } }, "sha512-CyR4rUNG9OYcXDZwMPvJdtb6PHbBDKUc/6Na2BIwZ6dKab1JQqKa4di+RNRY9Myn7JB81vayKwJeQ7jEdmNVDA=="],
|
||||||
@@ -4017,7 +4030,7 @@
|
|||||||
|
|
||||||
"gaxios/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
"gaxios/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||||
|
|
||||||
"gitbook-v2/next": ["next@15.3.0-canary.43", "", { "dependencies": { "@next/env": "15.3.0-canary.43", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.0-canary.43", "@next/swc-darwin-x64": "15.3.0-canary.43", "@next/swc-linux-arm64-gnu": "15.3.0-canary.43", "@next/swc-linux-arm64-musl": "15.3.0-canary.43", "@next/swc-linux-x64-gnu": "15.3.0-canary.43", "@next/swc-linux-x64-musl": "15.3.0-canary.43", "@next/swc-win32-arm64-msvc": "15.3.0-canary.43", "@next/swc-win32-x64-msvc": "15.3.0-canary.43", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-am6xpZIx2P0VJ26N7K2CImmznYUP65XS0e0nkYtypWf/RiMsScwmCqrA4qrEK9u/tiPlA+583IcQPos9yKLg1Q=="],
|
"gitbook-v2/next": ["next@15.3.1-canary.7", "", { "dependencies": { "@next/env": "15.3.1-canary.7", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.1-canary.7", "@next/swc-darwin-x64": "15.3.1-canary.7", "@next/swc-linux-arm64-gnu": "15.3.1-canary.7", "@next/swc-linux-arm64-musl": "15.3.1-canary.7", "@next/swc-linux-x64-gnu": "15.3.1-canary.7", "@next/swc-linux-x64-musl": "15.3.1-canary.7", "@next/swc-win32-arm64-msvc": "15.3.1-canary.7", "@next/swc-win32-x64-msvc": "15.3.1-canary.7", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-RblvC7A7k8cKpSa6JSCbaatb6JAncv2niUSH7TqXt6xHUoItnxa3Fu7xkducFJQdcW2Hv2h0+NBu6kaKf0S4zw=="],
|
||||||
|
|
||||||
"global-dirs/ini": ["ini@1.3.7", "", {}, "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ=="],
|
"global-dirs/ini": ["ini@1.3.7", "", {}, "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ=="],
|
||||||
|
|
||||||
@@ -4087,8 +4100,6 @@
|
|||||||
|
|
||||||
"mlly/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
"mlly/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
||||||
|
|
||||||
"mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
|
||||||
|
|
||||||
"next/@swc/helpers": ["@swc/helpers@0.5.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A=="],
|
"next/@swc/helpers": ["@swc/helpers@0.5.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A=="],
|
||||||
|
|
||||||
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
||||||
@@ -4103,8 +4114,6 @@
|
|||||||
|
|
||||||
"path-scurry/lru-cache": ["lru-cache@11.0.2", "", {}, "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA=="],
|
"path-scurry/lru-cache": ["lru-cache@11.0.2", "", {}, "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA=="],
|
||||||
|
|
||||||
"pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
|
||||||
|
|
||||||
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||||
|
|
||||||
"postcss/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
|
"postcss/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
|
||||||
@@ -4205,6 +4214,8 @@
|
|||||||
|
|
||||||
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
|
"youch/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||||
|
|
||||||
"@aws-crypto/crc32/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
"@aws-crypto/crc32/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
||||||
|
|
||||||
"@aws-crypto/crc32c/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
"@aws-crypto/crc32c/@aws-sdk/types/@smithy/types": ["@smithy/types@4.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw=="],
|
||||||
@@ -4639,10 +4650,18 @@
|
|||||||
|
|
||||||
"@cloudflare/next-on-pages/miniflare/workerd": ["workerd@1.20241018.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20241018.1", "@cloudflare/workerd-darwin-arm64": "1.20241018.1", "@cloudflare/workerd-linux-64": "1.20241018.1", "@cloudflare/workerd-linux-arm64": "1.20241018.1", "@cloudflare/workerd-windows-64": "1.20241018.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-JPW2oAbYOnJj1c5boyDOdjl/Yvur45jhVE8lf+I9oxR6myyAvuH2tdXO62kye68jRluJOMUeyssLes+JRwLmaA=="],
|
"@cloudflare/next-on-pages/miniflare/workerd": ["workerd@1.20241018.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20241018.1", "@cloudflare/workerd-darwin-arm64": "1.20241018.1", "@cloudflare/workerd-linux-64": "1.20241018.1", "@cloudflare/workerd-linux-arm64": "1.20241018.1", "@cloudflare/workerd-windows-64": "1.20241018.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-JPW2oAbYOnJj1c5boyDOdjl/Yvur45jhVE8lf+I9oxR6myyAvuH2tdXO62kye68jRluJOMUeyssLes+JRwLmaA=="],
|
||||||
|
|
||||||
"@cloudflare/next-on-pages/miniflare/youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="],
|
|
||||||
|
|
||||||
"@cloudflare/next-on-pages/miniflare/zod": ["zod@3.23.8", "", {}, "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g=="],
|
"@cloudflare/next-on-pages/miniflare/zod": ["zod@3.23.8", "", {}, "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.3.4", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild": ["esbuild@0.17.19", "", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/miniflare": ["miniflare@3.20250214.2", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250214.0", "ws": "8.18.0", "youch": "3.2.3", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-t+lT4p2lbOcKv4PS3sx1F/wcDAlbEYZCO2VooLp4H7JErWWYIi9yjD3UillC3CGOpiBahVg5nrPCoFltZf6UlA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/unenv": ["unenv@2.0.0-rc.1", "", { "dependencies": { "defu": "^6.1.4", "mlly": "^1.7.4", "ohash": "^1.1.4", "pathe": "^1.1.2", "ufo": "^1.5.4" } }, "sha512-PU5fb40H8X149s117aB4ytbORcCvlASdtF97tfls4BPIyj4PeVxvpSuy1jAptqYHqB0vb2w2sHvzM0XWcp2OKg=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/workerd": ["workerd@1.20250214.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250214.0", "@cloudflare/workerd-darwin-arm64": "1.20250214.0", "@cloudflare/workerd-linux-64": "1.20250214.0", "@cloudflare/workerd-linux-arm64": "1.20250214.0", "@cloudflare/workerd-windows-64": "1.20250214.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-QWcqXZLiMpV12wiaVnb3nLmfs/g4ZsFQq2mX85z546r3AX4CTIkXl0VP50W3CwqLADej3PGYiRDOTelDOwVG1g=="],
|
||||||
|
|
||||||
"@codemirror/lang-json/@codemirror/language/@codemirror/view": ["@codemirror/view@6.34.1", "", { "dependencies": { "@codemirror/state": "^6.4.0", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ=="],
|
"@codemirror/lang-json/@codemirror/language/@codemirror/view": ["@codemirror/view@6.34.1", "", { "dependencies": { "@codemirror/state": "^6.4.0", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ=="],
|
||||||
|
|
||||||
"@codemirror/lang-json/@codemirror/language/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
"@codemirror/lang-json/@codemirror/language/@lezer/common": ["@lezer/common@1.2.2", "", {}, "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw=="],
|
||||||
@@ -4885,23 +4904,23 @@
|
|||||||
|
|
||||||
"gaxios/https-proxy-agent/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
"gaxios/https-proxy-agent/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/env": ["@next/env@15.3.0-canary.43", "", {}, "sha512-ogryUGufxhtidxr/42NY6+ADlvxt9Hq6Q/DOMS/20vGuePZ70wO6Z5m1RP3Q397RGgpe1gSWyYdlg+Mt7H4KeQ=="],
|
"gitbook-v2/next/@next/env": ["@next/env@15.3.1-canary.7", "", {}, "sha512-QSzAlzxaGrQYj3Nzgxd35WM6pmxmNk9lOCn0nsNLPidvc3H6wj/fV3Pl8/tVCYQP61luGuA0Ib0VwZc8ja119w=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.0-canary.43", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eXrs8CyIBgdnMTNjku+h/xm61gmRCcKAT+tM2CjpEXbEqXBux5hRIakOk5kJJDu2fA2P3pzQGt5PRD1hg4srXA=="],
|
"gitbook-v2/next/@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.1-canary.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fs7JYU0MKtpgsDBIvbT/wn1MwKP8C+bqcb6IjWnDtVcciFKzYDs/tPCBW6CtYg1wpHqm9horZDA1ytb/sAghxA=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.3.0-canary.43", "", { "os": "darwin", "cpu": "x64" }, "sha512-iRGvblEh/b2grxkkp9pT+yea9EzGNM4tLyUZoCzkejkU2jMLsn2DH6h3bQwCfEYZL3YFGsYmVISrVCOVi8LeMw=="],
|
"gitbook-v2/next/@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.3.1-canary.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-Efl6es/IEXJf5groF78fc1PrTEwK9bOyi6fRjp1bsa/AWOHp8rTc3l0T6EeY5T0SWeYilisZZa9rax7nTgw4bw=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.3.0-canary.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-IqknHGNxpL03uIutIuv7FPjGHuD/AnJVC5exi5g+C7P3f6JVvOjFLS264eqi91tVCXhN2LpcKNGwTlK81bJVVg=="],
|
"gitbook-v2/next/@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.3.1-canary.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-IS71I8z2wlecRZRHXqWTtxVozZt1h9IH/2MX1P/WkCjQH98acFmCkw0jo/y70mrZ4lw6tRGTNkSBMun+5P5P+w=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.3.0-canary.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-FbO0dnFsNe3f1LWTn4vyXTWTSrZdwNRnURYExSQ+0AINHphNfwKQNrPqVLrapQ9CAOCOz8R5p9Kf1++IsH3JJQ=="],
|
"gitbook-v2/next/@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.3.1-canary.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-uJ4env9fZxIFM+aRBCjNeG91HHZ2cRXiF25xJqGmCC1Y5jT5oYAB/tIBCFRSj6NRzdt4pZAamCMRS41WzzVVUQ=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.3.0-canary.43", "", { "os": "linux", "cpu": "x64" }, "sha512-MAaLEm8eO6Xir3YC3xLYDHDjLGogAAGRrxhuflvaqAtGQZ6NIMG4YjvAyramYTq/SwrUIDobggKxdQLtu8/pPQ=="],
|
"gitbook-v2/next/@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.3.1-canary.7", "", { "os": "linux", "cpu": "x64" }, "sha512-/+efTL2TxoSAYCxdf+g6WvDKIJDoaETvF3I+lxpixhctfrIwpr2qnG0e6u2M55k1iYiiyFIOA63fpIsGnIMJZA=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.3.0-canary.43", "", { "os": "linux", "cpu": "x64" }, "sha512-gdwF79/EQjY3zgcolO0jlDe0yfII9tXyXQeqL+uvzA8gZT5FpH0KkwSWzxj8EUswWzZcprbDa87sq8H0Eo+whw=="],
|
"gitbook-v2/next/@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.3.1-canary.7", "", { "os": "linux", "cpu": "x64" }, "sha512-Hb+agfULOjEhJAmq/r9OTVAo8KxFlnuCT7BEUbSuVP/Gxn883al6juSG7ZZfk7P4a+ZU6iVYyHKIFAKCarZmUA=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.3.0-canary.43", "", { "os": "win32", "cpu": "arm64" }, "sha512-5WYne3jvo1478kUfe901wFxvPMdC8tRKundKIgU5Upe1HafMMS7ymm1hQ7CUpp3/1vY/R1TV1oKHHJfqDubiNg=="],
|
"gitbook-v2/next/@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.3.1-canary.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-gNd5Vq7k9xIEQj85JoavHGRsyvu1zKOjVoPUYtsZRxXw6kcBg84x2g8NeT/3SmwH1PiFU/sjQXtRzr2Kuc2j3A=="],
|
||||||
|
|
||||||
"gitbook-v2/next/@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.3.0-canary.43", "", { "os": "win32", "cpu": "x64" }, "sha512-xE3WZhwjb91eezecVsmXn/OtdISfMsIfS3t0ZXsS/+bMvO/LZLdcVBtl0Zy5yR+XJyKfXXmwpdYbL6WH4dGuQg=="],
|
"gitbook-v2/next/@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.3.1-canary.7", "", { "os": "win32", "cpu": "x64" }, "sha512-D5i+KinvNNmspXfgIvEZ1RFOKVhOgdtoSC7/xEUm55hEkcWFVHOtVVPvgV7WUeo1elNxbgxytzmyKbLaifP03g=="],
|
||||||
|
|
||||||
"gitbook-v2/next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
"gitbook-v2/next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
||||||
|
|
||||||
@@ -5101,7 +5120,71 @@
|
|||||||
|
|
||||||
"@cloudflare/next-on-pages/miniflare/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20241018.1", "", { "os": "win32", "cpu": "x64" }, "sha512-qwDVh/KrwEPY82h6tZ1O4BXBAKeGy30BeTr9wvTUVeY9eX/KT73GuEG+ttwiashRfqjOa0Gcqjsfpd913ITFyg=="],
|
"@cloudflare/next-on-pages/miniflare/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20241018.1", "", { "os": "win32", "cpu": "x64" }, "sha512-qwDVh/KrwEPY82h6tZ1O4BXBAKeGy30BeTr9wvTUVeY9eX/KT73GuEG+ttwiashRfqjOa0Gcqjsfpd913ITFyg=="],
|
||||||
|
|
||||||
"@cloudflare/next-on-pages/miniflare/youch/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.17.19", "", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.17.19", "", { "os": "android", "cpu": "arm64" }, "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.17.19", "", { "os": "android", "cpu": "x64" }, "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.17.19", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.17.19", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.17.19", "", { "os": "linux", "cpu": "arm" }, "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.17.19", "", { "os": "linux", "cpu": "ia32" }, "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.17.19", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.17.19", "", { "os": "linux", "cpu": "s390x" }, "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.17.19", "", { "os": "none", "cpu": "x64" }, "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.17.19", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.17.19", "", { "os": "sunos", "cpu": "x64" }, "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.17.19", "", { "os": "win32", "cpu": "ia32" }, "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/miniflare/undici": ["undici@5.28.5", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/miniflare/youch": ["youch@3.2.3", "", { "dependencies": { "cookie": "^0.5.0", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-ZBcWz/uzZaQVdCvfV4uk616Bbpf2ee+F/AvuKDR5EwX/Y4v06xWdtMluqTD7+KlZdM93lLm9gMZYo0sKBS0pgw=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/unenv/ohash": ["ohash@1.1.4", "", {}, "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/unenv/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250214.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cDvvedWDc5zrgDnuXe2qYcz/TwBvzmweO55C7XpPuAWJ9Oqxv81PkdekYxD8mH989aQ/GI5YD0Fe6fDYlM+T3Q=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250214.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-NytCvRveVzu0mRKo+tvZo3d/gCUway3B2ZVqSi/TS6NXDGBYIJo7g6s3BnTLS74kgyzeDOjhu9j/RBJBS809qw=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250214.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pQ7+aHNHj8SiYEs4d/6cNoimE5xGeCMfgU1yfDFtA9YGN9Aj2BITZgOWPec+HW7ZkOy9oWlNrO6EvVjGgB4tbQ=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250214.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Vhlfah6Yd9ny1npNQjNgElLIjR6OFdEbuR3LCfbLDCwzWEBFhIf7yC+Tpp/a0Hq7kLz3sLdktaP7xl3PJhyOjA=="],
|
||||||
|
|
||||||
|
"@cloudflare/next-on-pages/wrangler/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250214.0", "", { "os": "win32", "cpu": "x64" }, "sha512-GMwMyFbkjBKjYJoKDhGX8nuL4Gqe3IbVnVWf2Q6086CValyIknupk5J6uQWGw2EBU3RGO3x4trDXT5WphQJZDQ=="],
|
||||||
|
|
||||||
"@node-minify/core/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
"@node-minify/core/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
"wrangler": "^3.112.0"
|
"wrangler": "^4.10.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"generate": "wrangler types --experimental-include-runtime",
|
"generate": "wrangler types",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"dev": "tsc -w",
|
"dev": "tsc -w",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"types": ["./.wrangler/types/runtime.d.ts"]
|
"types": ["./worker-configuration.d.ts"]
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts"],
|
"include": ["src/**/*.ts"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @gitbook/cache-tags
|
# @gitbook/cache-tags
|
||||||
|
|
||||||
|
## 0.3.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 77397ca: Fix version of @gitbook/api referenced in package.json
|
||||||
|
|
||||||
## 0.3.0
|
## 0.3.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
"default": "./dist/index.js"
|
"default": "./dist/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version": "0.3.0",
|
"version": "0.3.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "*",
|
"@gitbook/api": "^0.109.0",
|
||||||
"assert-never": "^1.2.1"
|
"assert-never": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# gitbook-v2
|
# gitbook-v2
|
||||||
|
|
||||||
|
## 0.2.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [77397ca]
|
||||||
|
- @gitbook/cache-tags@0.3.1
|
||||||
|
|
||||||
## 0.2.4
|
## 0.2.4
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ const nextConfig = {
|
|||||||
experimental: {
|
experimental: {
|
||||||
// This is needed to throw "forbidden" when the api token expired during revalidation
|
// This is needed to throw "forbidden" when the api token expired during revalidation
|
||||||
authInterrupts: true,
|
authInterrupts: true,
|
||||||
|
useCache: true,
|
||||||
// We don't use 'use cache' as it's not supported in OpenNext yet
|
|
||||||
// and instead we scope `unstable_cache` to the parameters of the function
|
|
||||||
useCache: false,
|
|
||||||
|
|
||||||
// Content is fully static, we can cache it in the session memory cache for a long time
|
// Content is fully static, we can cache it in the session memory cache for a long time
|
||||||
staleTimes: {
|
staleTimes: {
|
||||||
@@ -34,6 +31,7 @@ const nextConfig = {
|
|||||||
GITBOOK_ASSETS_PREFIX: process.env.GITBOOK_ASSETS_PREFIX,
|
GITBOOK_ASSETS_PREFIX: process.env.GITBOOK_ASSETS_PREFIX,
|
||||||
GITBOOK_SECRET: process.env.GITBOOK_SECRET,
|
GITBOOK_SECRET: process.env.GITBOOK_SECRET,
|
||||||
GITBOOK_IMAGE_RESIZE_SIGNING_KEY: process.env.GITBOOK_IMAGE_RESIZE_SIGNING_KEY,
|
GITBOOK_IMAGE_RESIZE_SIGNING_KEY: process.env.GITBOOK_IMAGE_RESIZE_SIGNING_KEY,
|
||||||
|
GITBOOK_IMAGE_RESIZE_MODE: process.env.GITBOOK_IMAGE_RESIZE_MODE,
|
||||||
GITBOOK_FONTS_URL: process.env.GITBOOK_FONTS_URL,
|
GITBOOK_FONTS_URL: process.env.GITBOOK_FONTS_URL,
|
||||||
GITBOOK_RUNTIME: process.env.GITBOOK_RUNTIME,
|
GITBOOK_RUNTIME: process.env.GITBOOK_RUNTIME,
|
||||||
|
|
||||||
@@ -55,6 +53,24 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async headers() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/~gitbook/static/:path*',
|
||||||
|
headers: [
|
||||||
|
{
|
||||||
|
key: 'Cache-Control',
|
||||||
|
value: 'public, max-age=31536000, immutable',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'Access-Control-Allow-Origin',
|
||||||
|
value: '*',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook-v2",
|
"name": "gitbook-v2",
|
||||||
"version": "0.2.4",
|
"version": "0.2.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
@@ -12,11 +12,12 @@
|
|||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"warn-once": "^0.1.1",
|
"warn-once": "^0.1.1",
|
||||||
"rison": "^0.1.1",
|
"rison": "^0.1.1",
|
||||||
"jwt-decode": "^4.0.0"
|
"jwt-decode": "^4.0.0",
|
||||||
|
"assert-never": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"gitbook": "*",
|
"gitbook": "*",
|
||||||
"@opennextjs/cloudflare": "https://pkg.pr.new/opennextjs/opennextjs-cloudflare/@opennextjs/cloudflare@7b3b305",
|
"@opennextjs/cloudflare": "^1.0.0-beta.3",
|
||||||
"@types/rison": "^0.0.9",
|
"@types/rison": "^0.0.9",
|
||||||
"tailwindcss": "^3.4.0",
|
"tailwindcss": "^3.4.0",
|
||||||
"postcss": "^8"
|
"postcss": "^8"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -98,6 +98,10 @@ export async function wrapDataFetcherError<T>(
|
|||||||
*/
|
*/
|
||||||
export function getExposableError(error: Error): DataFetcherErrorData {
|
export function getExposableError(error: Error): DataFetcherErrorData {
|
||||||
if (error instanceof GitBookAPIError) {
|
if (error instanceof GitBookAPIError) {
|
||||||
|
if (error.code >= 500) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: error.code,
|
code: error.code,
|
||||||
message: error.errorMessage,
|
message: error.errorMessage,
|
||||||
@@ -105,6 +109,10 @@ export function getExposableError(error: Error): DataFetcherErrorData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error instanceof DataFetcherError) {
|
if (error instanceof DataFetcherError) {
|
||||||
|
if (error.code >= 500) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: error.code,
|
code: error.code,
|
||||||
message: error.message,
|
message: error.message,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { withCacheKey, withoutConcurrentExecution } from './memoize';
|
|||||||
|
|
||||||
describe('withoutConcurrentExecution', () => {
|
describe('withoutConcurrentExecution', () => {
|
||||||
it('should memoize the function based on the cache key', async () => {
|
it('should memoize the function based on the cache key', async () => {
|
||||||
const fn = mock(async (a: number, b: number) => a + b);
|
const fn = mock(async (_cacheKey: string, a: number, b: number) => a + b);
|
||||||
const memoized = withoutConcurrentExecution(() => null, fn);
|
const memoized = withoutConcurrentExecution(() => null, fn);
|
||||||
|
|
||||||
const p1 = memoized('c1', 1, 2);
|
const p1 = memoized('c1', 1, 2);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
export function withoutConcurrentExecution<ArgsType extends any[], ReturnType>(
|
export function withoutConcurrentExecution<ArgsType extends any[], ReturnType>(
|
||||||
getGlobalContext: () => object | null | undefined,
|
getGlobalContext: () => object | null | undefined,
|
||||||
wrapped: (...args: ArgsType) => Promise<ReturnType>
|
wrapped: (key: string, ...args: ArgsType) => Promise<ReturnType>
|
||||||
): (cacheKey: string, ...args: ArgsType) => Promise<ReturnType> {
|
): (cacheKey: string, ...args: ArgsType) => Promise<ReturnType> {
|
||||||
const globalPromiseCache = new WeakMap<object, Map<string, Promise<ReturnType>>>();
|
const globalPromiseCache = new WeakMap<object, Map<string, Promise<ReturnType>>>();
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ export function withoutConcurrentExecution<ArgsType extends any[], ReturnType>(
|
|||||||
|
|
||||||
const promise = (async () => {
|
const promise = (async () => {
|
||||||
try {
|
try {
|
||||||
const result = await wrapped(...args);
|
const result = await wrapped(key, ...args);
|
||||||
return result;
|
return result;
|
||||||
} finally {
|
} finally {
|
||||||
promiseCache.delete(key);
|
promiseCache.delete(key);
|
||||||
|
|||||||
+18
@@ -85,6 +85,15 @@ export const GITBOOK_IMAGE_RESIZE_URL = process.env.GITBOOK_IMAGE_RESIZE_URL ??
|
|||||||
export const GITBOOK_IMAGE_RESIZE_SIGNING_KEY =
|
export const GITBOOK_IMAGE_RESIZE_SIGNING_KEY =
|
||||||
process.env.GITBOOK_IMAGE_RESIZE_SIGNING_KEY ?? null;
|
process.env.GITBOOK_IMAGE_RESIZE_SIGNING_KEY ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode used for resizing images.
|
||||||
|
*/
|
||||||
|
export const GITBOOK_IMAGE_RESIZE_MODE = enforceEnum(
|
||||||
|
'GITBOOK_IMAGE_RESIZE_MODE',
|
||||||
|
process.env.GITBOOK_IMAGE_RESIZE_MODE || 'cdn-cgi',
|
||||||
|
['cdn-cgi', 'cf-fetch']
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endpoint where icons are served.
|
* Endpoint where icons are served.
|
||||||
*/
|
*/
|
||||||
@@ -100,3 +109,12 @@ export const GITBOOK_ICONS_TOKEN = process.env.GITBOOK_ICONS_TOKEN;
|
|||||||
* Secret used to validate requests from the GitBook app.
|
* Secret used to validate requests from the GitBook app.
|
||||||
*/
|
*/
|
||||||
export const GITBOOK_SECRET = process.env.GITBOOK_SECRET ?? null;
|
export const GITBOOK_SECRET = process.env.GITBOOK_SECRET ?? null;
|
||||||
|
|
||||||
|
function enforceEnum<T extends string>(key: string, value: string, enumValues: T[]): T {
|
||||||
|
if (!enumValues.includes(value as T)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid value for ${key}: "${value}", expected one of: ${enumValues.join(', ')}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return value as T;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { checkIsHttpURL } from '@/lib/urls';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an image URL is resizable.
|
||||||
|
* Skip it for non-http(s) URLs (data, etc).
|
||||||
|
* Skip it for SVGs.
|
||||||
|
* Skip it for GitBook images (to avoid recursion).
|
||||||
|
*/
|
||||||
|
export function checkIsSizableImageURL(input: string): boolean {
|
||||||
|
if (!URL.canParse(input)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.includes('/~gitbook/image')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = new URL(input);
|
||||||
|
if (parsed.pathname.endsWith('.svg') || parsed.pathname.endsWith('.avif')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!checkIsHttpURL(parsed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -1,34 +1,11 @@
|
|||||||
import 'server-only';
|
import 'server-only';
|
||||||
|
|
||||||
import { GITBOOK_IMAGE_RESIZE_SIGNING_KEY, GITBOOK_IMAGE_RESIZE_URL } from '../env';
|
import { GITBOOK_IMAGE_RESIZE_SIGNING_KEY, GITBOOK_IMAGE_RESIZE_URL } from '../env';
|
||||||
import type { GitBookLinker } from '../links';
|
import type { GitBookLinker } from '../links';
|
||||||
|
import { checkIsSizableImageURL } from './checkIsSizableImageURL';
|
||||||
|
import { getImageSize } from './resizer';
|
||||||
import { type SignatureVersion, generateImageSignature } from './signatures';
|
import { type SignatureVersion, generateImageSignature } from './signatures';
|
||||||
import type { ImageResizer } from './types';
|
import type { ImageResizer } from './types';
|
||||||
|
|
||||||
interface CloudflareImageJsonFormat {
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
original: {
|
|
||||||
file_size: number;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
format: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://developers.cloudflare.com/images/image-resizing/resize-with-workers/
|
|
||||||
*/
|
|
||||||
export interface CloudflareImageOptions {
|
|
||||||
format?: 'webp' | 'avif' | 'json' | 'jpeg';
|
|
||||||
fit?: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
dpr?: number;
|
|
||||||
anim?: boolean;
|
|
||||||
quality?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an image resizer for a rendering context.
|
* Create an image resizer for a rendering context.
|
||||||
*/
|
*/
|
||||||
@@ -106,124 +83,6 @@ export function createNoopImageResizer(): ImageResizer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a URL is an HTTP URL.
|
|
||||||
*/
|
|
||||||
export function checkIsHttpURL(input: string | URL): boolean {
|
|
||||||
if (!URL.canParse(input)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const parsed = new URL(input);
|
|
||||||
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an image URL is resizable.
|
|
||||||
* Skip it for non-http(s) URLs (data, etc).
|
|
||||||
* Skip it for SVGs.
|
|
||||||
* Skip it for GitBook images (to avoid recursion).
|
|
||||||
*/
|
|
||||||
export function checkIsSizableImageURL(input: string): boolean {
|
|
||||||
if (!URL.canParse(input)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.includes('/~gitbook/image')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsed = new URL(input);
|
|
||||||
if (parsed.pathname.endsWith('.svg') || parsed.pathname.endsWith('.avif')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!checkIsHttpURL(parsed)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of an image.
|
|
||||||
*/
|
|
||||||
export async function getImageSize(
|
|
||||||
input: string,
|
|
||||||
defaultSize: Partial<CloudflareImageOptions> = {}
|
|
||||||
): Promise<{ width: number; height: number } | null> {
|
|
||||||
if (!checkIsSizableImageURL(input)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await resizeImage(input, {
|
|
||||||
// Abort the request after 2 seconds to avoid blocking rendering for too long
|
|
||||||
signal: AbortSignal.timeout(2000),
|
|
||||||
// Measure size and resize it to the most common size
|
|
||||||
// to optimize caching
|
|
||||||
...defaultSize,
|
|
||||||
format: 'json',
|
|
||||||
anim: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const json = (await response.json()) as CloudflareImageJsonFormat;
|
|
||||||
return {
|
|
||||||
width: json.original.width,
|
|
||||||
height: json.original.height,
|
|
||||||
};
|
|
||||||
} catch (_error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a Cloudflare Image Resize operation on an image.
|
|
||||||
*/
|
|
||||||
export async function resizeImage(
|
|
||||||
input: string,
|
|
||||||
options: CloudflareImageOptions & {
|
|
||||||
signal?: AbortSignal;
|
|
||||||
}
|
|
||||||
): Promise<Response> {
|
|
||||||
const { signal, ...resizeOptions } = options;
|
|
||||||
|
|
||||||
const parsed = new URL(input);
|
|
||||||
if (parsed.protocol === 'data:') {
|
|
||||||
throw new Error('Cannot resize data: URLs');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsed.hostname === 'localhost') {
|
|
||||||
throw new Error('Cannot resize localhost URLs');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since Cloudflare Images options on fetch are not supported on Cloudflare Pages,
|
|
||||||
// we need to use the Cloudflare Image Resize API directly.
|
|
||||||
if (!GITBOOK_IMAGE_RESIZE_URL) {
|
|
||||||
throw new Error('GITBOOK_IMAGE_RESIZE_URL is not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
return await fetch(
|
|
||||||
`${GITBOOK_IMAGE_RESIZE_URL}${stringifyOptions(
|
|
||||||
resizeOptions
|
|
||||||
)}/${encodeURIComponent(input)}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
// Pass the `Accept` header, as Cloudflare uses this to validate the format.
|
|
||||||
Accept:
|
|
||||||
resizeOptions.format === 'json'
|
|
||||||
? 'application/json'
|
|
||||||
: `image/${resizeOptions.format || 'jpeg'}`,
|
|
||||||
},
|
|
||||||
signal,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringifyOptions(options: CloudflareImageOptions): string {
|
|
||||||
return Object.entries({ ...options }).reduce((rest, [key, value]) => {
|
|
||||||
return `${rest}${rest ? ',' : ''}${key}=${value}`;
|
|
||||||
}, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because of a bug in Cloudflare, 127.0.0.1 is replaced by localhost.
|
* Because of a bug in Cloudflare, 127.0.0.1 is replaced by localhost.
|
||||||
* We protect against it by converting to a special token, and then parsing
|
* We protect against it by converting to a special token, and then parsing
|
||||||
|
|||||||
@@ -3,3 +3,5 @@ export * from './createImageResizer';
|
|||||||
export * from './signatures';
|
export * from './signatures';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './getImageResizingContextId';
|
export * from './getImageResizingContextId';
|
||||||
|
export * from './resizer';
|
||||||
|
export * from './checkIsSizableImageURL';
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { GITBOOK_IMAGE_RESIZE_URL } from '@v2/lib/env';
|
||||||
|
import type { CloudflareImageOptions } from './types';
|
||||||
|
import { copyImageResponse } from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize an image by doing a request to a /cdn/cgi/ endpoint.
|
||||||
|
* https://developers.cloudflare.com/images/transform-images/transform-via-url/
|
||||||
|
*/
|
||||||
|
export async function resizeImageWithCDNCgi(
|
||||||
|
input: string,
|
||||||
|
options: CloudflareImageOptions & {
|
||||||
|
signal?: AbortSignal;
|
||||||
|
}
|
||||||
|
): Promise<Response> {
|
||||||
|
const { signal, ...resizeOptions } = options;
|
||||||
|
|
||||||
|
// Since Cloudflare Images options on fetch are not supported on Cloudflare Pages,
|
||||||
|
// we need to use the Cloudflare Image Resize API directly.
|
||||||
|
if (!GITBOOK_IMAGE_RESIZE_URL) {
|
||||||
|
throw new Error('GITBOOK_IMAGE_RESIZE_URL is not set for cdn-cgi image resize mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
const resizeURL = `${GITBOOK_IMAGE_RESIZE_URL}${stringifyOptions(
|
||||||
|
resizeOptions
|
||||||
|
)}/${encodeURIComponent(input)}`;
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsole: this log is useful for debugging
|
||||||
|
console.log(`resize image using cdn-cgi: ${resizeURL}`);
|
||||||
|
|
||||||
|
return copyImageResponse(
|
||||||
|
await fetch(resizeURL, {
|
||||||
|
headers: {
|
||||||
|
// Pass the `Accept` header, as Cloudflare uses this to validate the format.
|
||||||
|
Accept:
|
||||||
|
resizeOptions.format === 'json'
|
||||||
|
? 'application/json'
|
||||||
|
: `image/${resizeOptions.format || 'jpeg'}`,
|
||||||
|
},
|
||||||
|
signal,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyOptions(options: CloudflareImageOptions): string {
|
||||||
|
return Object.entries({ ...options }).reduce((rest, [key, value]) => {
|
||||||
|
return `${rest}${rest ? ',' : ''}${key}=${value}`;
|
||||||
|
}, '');
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import type { CloudflareImageOptions } from './types';
|
||||||
|
import { copyImageResponse } from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize an image by doing a request to the image itself using the Cloudflare fetch.
|
||||||
|
* https://developers.cloudflare.com/images/transform-images/transform-via-workers/
|
||||||
|
*
|
||||||
|
* This method doesn't work in Cloudflare Pages and is only supported in workers.
|
||||||
|
*/
|
||||||
|
export async function resizeImageWithCFFetch(
|
||||||
|
input: string,
|
||||||
|
options: CloudflareImageOptions & {
|
||||||
|
signal?: AbortSignal;
|
||||||
|
}
|
||||||
|
): Promise<Response> {
|
||||||
|
const { signal, ...resizeOptions } = options;
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsole: this log is useful for debugging
|
||||||
|
console.log(`resize image using cf-fetch: ${input}`);
|
||||||
|
|
||||||
|
return copyImageResponse(
|
||||||
|
await fetch(input, {
|
||||||
|
headers: {
|
||||||
|
// Pass the `Accept` header, as Cloudflare uses this to validate the format.
|
||||||
|
Accept:
|
||||||
|
resizeOptions.format === 'json'
|
||||||
|
? 'application/json'
|
||||||
|
: `image/${resizeOptions.format || 'jpeg'}`,
|
||||||
|
},
|
||||||
|
signal,
|
||||||
|
cf: { image: resizeOptions },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './types';
|
||||||
|
export * from './resizeImage';
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import 'server-only';
|
||||||
|
import assertNever from 'assert-never';
|
||||||
|
import { GITBOOK_IMAGE_RESIZE_MODE } from '../../env';
|
||||||
|
import { checkIsSizableImageURL } from '../checkIsSizableImageURL';
|
||||||
|
import { resizeImageWithCDNCgi } from './cdn-cgi';
|
||||||
|
import { resizeImageWithCFFetch } from './cf-fetch';
|
||||||
|
import type { CloudflareImageJsonFormat, CloudflareImageOptions } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of an image.
|
||||||
|
*/
|
||||||
|
export async function getImageSize(
|
||||||
|
input: string,
|
||||||
|
defaultSize: Partial<CloudflareImageOptions> = {}
|
||||||
|
): Promise<{ width: number; height: number } | null> {
|
||||||
|
if (!checkIsSizableImageURL(input)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await resizeImage(input, {
|
||||||
|
// Abort the request after 2 seconds to avoid blocking rendering for too long
|
||||||
|
signal: AbortSignal.timeout(2000),
|
||||||
|
// Measure size and resize it to the most common size
|
||||||
|
// to optimize caching
|
||||||
|
...defaultSize,
|
||||||
|
format: 'json',
|
||||||
|
anim: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = (await response.json()) as CloudflareImageJsonFormat;
|
||||||
|
return {
|
||||||
|
width: json.original.width,
|
||||||
|
height: json.original.height,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Error getting image size for ${input}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a Cloudflare Image Resize operation on an image.
|
||||||
|
*/
|
||||||
|
export async function resizeImage(
|
||||||
|
input: string,
|
||||||
|
options: CloudflareImageOptions & {
|
||||||
|
signal?: AbortSignal;
|
||||||
|
}
|
||||||
|
): Promise<Response> {
|
||||||
|
const parsed = new URL(input);
|
||||||
|
if (parsed.protocol === 'data:') {
|
||||||
|
throw new Error('Cannot resize data: URLs');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed.hostname === 'localhost') {
|
||||||
|
throw new Error('Cannot resize localhost URLs');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (GITBOOK_IMAGE_RESIZE_MODE) {
|
||||||
|
case 'cdn-cgi':
|
||||||
|
return resizeImageWithCDNCgi(input, options);
|
||||||
|
case 'cf-fetch':
|
||||||
|
return resizeImageWithCFFetch(input, options);
|
||||||
|
default:
|
||||||
|
assertNever(GITBOOK_IMAGE_RESIZE_MODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
export interface CloudflareImageJsonFormat {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
original: {
|
||||||
|
file_size: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
format: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://developers.cloudflare.com/images/image-resizing/resize-with-workers/
|
||||||
|
*/
|
||||||
|
export interface CloudflareImageOptions {
|
||||||
|
format?: 'webp' | 'avif' | 'json' | 'jpeg';
|
||||||
|
fit?: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
dpr?: number;
|
||||||
|
anim?: boolean;
|
||||||
|
quality?: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Copy a response to make sure it can be mutated by the rest of the middleware.
|
||||||
|
* To avoid errors "Can't modify immutable headers".
|
||||||
|
*/
|
||||||
|
export function copyImageResponse(response: Response) {
|
||||||
|
return new Response(response.body, response);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"main": ".open-next/worker.js",
|
"main": ".open-next/worker.js",
|
||||||
"name": "gitbook-open-v2",
|
"name": "gitbook-open-v2",
|
||||||
"compatibility_date": "2025-03-11",
|
"compatibility_date": "2025-04-14",
|
||||||
"compatibility_flags": ["nodejs_compat", "allow_importable_env"],
|
"compatibility_flags": ["nodejs_compat", "allow_importable_env"],
|
||||||
"assets": {
|
"assets": {
|
||||||
"directory": ".open-next/assets",
|
"directory": ".open-next/assets",
|
||||||
@@ -12,13 +12,6 @@
|
|||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"preview": {
|
"preview": {
|
||||||
"d1_databases": [
|
|
||||||
{
|
|
||||||
"binding": "NEXT_CACHE_D1",
|
|
||||||
"database_id": "f59ddb40-ad72-4312-9395-0ac6a129af8e",
|
|
||||||
"database_name": "gitbook-open-v2-tags-preview"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"r2_buckets": [
|
"r2_buckets": [
|
||||||
{
|
{
|
||||||
"binding": "NEXT_INC_CACHE_R2_BUCKET",
|
"binding": "NEXT_INC_CACHE_R2_BUCKET",
|
||||||
@@ -55,13 +48,6 @@
|
|||||||
"bucket_name": "gitbook-open-v2-cache-staging"
|
"bucket_name": "gitbook-open-v2-cache-staging"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"d1_databases": [
|
|
||||||
{
|
|
||||||
"binding": "NEXT_CACHE_D1",
|
|
||||||
"database_id": "9df62e39-1f35-4066-83aa-e9b8ed3ac8d5",
|
|
||||||
"database_name": "gitbook-open-v2-tags-staging"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"binding": "WORKER_SELF_REFERENCE",
|
"binding": "WORKER_SELF_REFERENCE",
|
||||||
@@ -113,13 +99,6 @@
|
|||||||
"bucket_name": "gitbook-open-v2-cache-production"
|
"bucket_name": "gitbook-open-v2-cache-production"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"d1_databases": [
|
|
||||||
{
|
|
||||||
"binding": "NEXT_CACHE_D1",
|
|
||||||
"database_id": "a6f16fce-5f45-43a9-89a4-7b83ddf25b77",
|
|
||||||
"database_name": "gitbook-open-v2-tags-production"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"binding": "WORKER_SELF_REFERENCE",
|
"binding": "WORKER_SELF_REFERENCE",
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# gitbook
|
# gitbook
|
||||||
|
|
||||||
|
## 0.10.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [77397ca]
|
||||||
|
- @gitbook/cache-tags@0.3.1
|
||||||
|
|
||||||
## 0.10.0
|
## 0.10.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -219,10 +219,10 @@ export function runTestCases(testCases: TestsCase[]) {
|
|||||||
fullPage: testEntry.fullPage ?? false,
|
fullPage: testEntry.fullPage ?? false,
|
||||||
beforeScreenshot: async ({ runStabilization }) => {
|
beforeScreenshot: async ({ runStabilization }) => {
|
||||||
await runStabilization();
|
await runStabilization();
|
||||||
await waitForIcons(page);
|
|
||||||
if (screenshotOptions?.waitForTOCScrolling !== false) {
|
if (screenshotOptions?.waitForTOCScrolling !== false) {
|
||||||
await waitForTOCScrolling(page);
|
await waitForTOCScrolling(page);
|
||||||
}
|
}
|
||||||
|
await waitForIcons(page);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -345,61 +345,74 @@ export function getCustomizationURL(partial: DeepPartial<SiteCustomizationSettin
|
|||||||
*/
|
*/
|
||||||
async function waitForIcons(page: Page) {
|
async function waitForIcons(page: Page) {
|
||||||
await page.waitForFunction(() => {
|
await page.waitForFunction(() => {
|
||||||
const urls = new Set<string>();
|
const urlStates: Record<string, 'pending' | 'loaded'> =
|
||||||
|
(window as any).__ICONS_STATES__ || {};
|
||||||
|
(window as any).__ICONS_STATES__ = urlStates;
|
||||||
|
|
||||||
|
const loadUrl = (url: string) => {
|
||||||
|
// Mark the URL as pending.
|
||||||
|
urlStates[url] = 'pending';
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
urlStates[url] = 'loaded';
|
||||||
|
};
|
||||||
|
img.src = url;
|
||||||
|
};
|
||||||
|
|
||||||
const icons = Array.from(document.querySelectorAll('svg.gb-icon'));
|
const icons = Array.from(document.querySelectorAll('svg.gb-icon'));
|
||||||
const results = icons.map((icon) => {
|
const results = icons.map((icon) => {
|
||||||
if (!(icon instanceof SVGElement)) {
|
if (!(icon instanceof SVGElement)) {
|
||||||
throw new Error('Icon is not an SVGElement');
|
throw new Error('Icon is not an SVGElement');
|
||||||
}
|
}
|
||||||
|
|
||||||
// If loaded, good it passes the test.
|
|
||||||
if (icon.dataset.loadingState === 'loaded') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not loaded yet, we need to load it.
|
|
||||||
if (icon.dataset.loadingState === 'pending') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore icons that are not visible.
|
// Ignore icons that are not visible.
|
||||||
if (!icon.checkVisibility()) {
|
if (!icon.checkVisibility()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const state = icon.getAttribute('data-argos-state');
|
||||||
|
|
||||||
|
if (state === 'pending') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'loaded') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// url("https://ka-p.fontawesome.com/releases/v6.6.0/svgs/light/moon.svg?v=2&token=a463935e93")
|
// url("https://ka-p.fontawesome.com/releases/v6.6.0/svgs/light/moon.svg?v=2&token=a463935e93")
|
||||||
const maskImage = window.getComputedStyle(icon).getPropertyValue('mask-image');
|
const maskImage = window.getComputedStyle(icon).getPropertyValue('mask-image');
|
||||||
const urlMatch = maskImage.match(/url\("([^"]+)"\)/);
|
const urlMatch = maskImage.match(/url\("([^"]+)"\)/);
|
||||||
const url = urlMatch ? urlMatch[1] : null;
|
const url = urlMatch?.[1];
|
||||||
|
|
||||||
// If URL is invalid we throw an error.
|
// If URL is invalid we throw an error.
|
||||||
if (!url) {
|
if (!url) {
|
||||||
throw new Error('No mask-image');
|
throw new Error('No mask-image');
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the URL is already loaded, we just mark it as loaded.
|
// If the URL is already queued for loading, we return the state.
|
||||||
if (urls.has(url)) {
|
if (urlStates[url]) {
|
||||||
icon.dataset.loadingState = 'loaded';
|
if (urlStates[url] === 'loaded') {
|
||||||
return true;
|
icon.setAttribute('data-argos-state', 'pending');
|
||||||
|
const bckMaskImage = icon.style.maskImage;
|
||||||
|
const bckDisplay = icon.style.display;
|
||||||
|
icon.style.maskImage = '';
|
||||||
|
icon.style.display = 'none';
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
icon.style.maskImage = bckMaskImage;
|
||||||
|
icon.style.display = bckDisplay;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
icon.setAttribute('data-argos-state', 'loaded');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the icon as pending and load the image.
|
return false;
|
||||||
icon.dataset.loadingState = 'pending';
|
}
|
||||||
|
|
||||||
// Mark the URL as seen.
|
|
||||||
urls.add(url);
|
|
||||||
|
|
||||||
const img = new Image();
|
|
||||||
img.src = url;
|
|
||||||
img.decode().then(() => {
|
|
||||||
// Wait two frames to let the time to the icon to repaint.
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
icon.dataset.loadingState = 'loaded';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
loadUrl(url);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "0.10.0",
|
"version": "0.10.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "env-cmd --silent -f ../../.env.local next dev",
|
"dev": "env-cmd --silent -f ../../.env.local next dev",
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@argos-ci/playwright": "^4.3.0",
|
"@argos-ci/playwright": "^5.0.3",
|
||||||
"@cloudflare/next-on-pages": "1.13.7",
|
"@cloudflare/next-on-pages": "1.13.7",
|
||||||
"@cloudflare/workers-types": "^4.20241230.0",
|
"@cloudflare/workers-types": "^4.20241230.0",
|
||||||
"@playwright/test": "^1.51.1",
|
"@playwright/test": "^1.51.1",
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
# GitBook immutable static assets
|
# GitBook immutable static assets
|
||||||
|
# Duplicated from next.config.mjs until OpenNext supports generating static headers
|
||||||
/~gitbook/static/*
|
/~gitbook/static/*
|
||||||
cache-control: public,max-age=31536000,immutable
|
cache-control: public,max-age=31536000,immutable
|
||||||
|
Access-Control-Allow-Origin: *
|
||||||
|
/_next/static/*
|
||||||
|
Access-Control-Allow-Origin: *
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export function ClientCodeBlock(props: ClientBlockProps) {
|
|||||||
const [isInViewport, setIsInViewport] = useState(false);
|
const [isInViewport, setIsInViewport] = useState(false);
|
||||||
const plainLines = useMemo(() => plainHighlight(block, []), [block]);
|
const plainLines = useMemo(() => plainHighlight(block, []), [block]);
|
||||||
const [lines, setLines] = useState<null | HighlightLine[]>(null);
|
const [lines, setLines] = useState<null | HighlightLine[]>(null);
|
||||||
|
const [highlighting, setHighlighting] = useState(false);
|
||||||
|
|
||||||
// Preload the highlighter when the block is mounted.
|
// Preload the highlighter when the block is mounted.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -77,6 +78,7 @@ export function ClientCodeBlock(props: ClientBlockProps) {
|
|||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
|
setHighlighting(true);
|
||||||
import('./highlight').then(({ highlight }) => {
|
import('./highlight').then(({ highlight }) => {
|
||||||
highlight(block, inlines).then((lines) => {
|
highlight(block, inlines).then((lines) => {
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
@@ -84,6 +86,7 @@ export function ClientCodeBlock(props: ClientBlockProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setLines(lines);
|
setLines(lines);
|
||||||
|
setHighlighting(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -98,6 +101,12 @@ export function ClientCodeBlock(props: ClientBlockProps) {
|
|||||||
}, [isInViewport, block, inlines]);
|
}, [isInViewport, block, inlines]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CodeBlockRenderer ref={blockRef} block={block} style={style} lines={lines ?? plainLines} />
|
<CodeBlockRenderer
|
||||||
|
ref={blockRef}
|
||||||
|
aria-busy={highlighting}
|
||||||
|
block={block}
|
||||||
|
style={style}
|
||||||
|
lines={lines ?? plainLines}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import './CodeBlockRenderer.css';
|
|||||||
|
|
||||||
type CodeBlockRendererProps = Pick<BlockProps<DocumentBlockCode>, 'block' | 'style'> & {
|
type CodeBlockRendererProps = Pick<BlockProps<DocumentBlockCode>, 'block' | 'style'> & {
|
||||||
lines: HighlightLine[];
|
lines: HighlightLine[];
|
||||||
|
'aria-busy'?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,7 +24,7 @@ export const CodeBlockRenderer = forwardRef(function CodeBlockRenderer(
|
|||||||
props: CodeBlockRendererProps,
|
props: CodeBlockRendererProps,
|
||||||
ref: React.ForwardedRef<HTMLDivElement>
|
ref: React.ForwardedRef<HTMLDivElement>
|
||||||
) {
|
) {
|
||||||
const { block, style, lines } = props;
|
const { block, style, lines, 'aria-busy': ariaBusy } = props;
|
||||||
|
|
||||||
const id = useId();
|
const id = useId();
|
||||||
const withLineNumbers = Boolean(block.data.lineNumbers) && block.nodes.length > 1;
|
const withLineNumbers = Boolean(block.data.lineNumbers) && block.nodes.length > 1;
|
||||||
@@ -31,7 +32,11 @@ export const CodeBlockRenderer = forwardRef(function CodeBlockRenderer(
|
|||||||
const title = block.data.title;
|
const title = block.data.title;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className={tcls('group/codeblock grid grid-flow-col', style)}>
|
<div
|
||||||
|
ref={ref}
|
||||||
|
aria-busy={ariaBusy}
|
||||||
|
className={tcls('group/codeblock grid grid-flow-col', style)}
|
||||||
|
>
|
||||||
<div className="flex items-center justify-start gap-2 text-sm [grid-area:1/1]">
|
<div className="flex items-center justify-start gap-2 text-sm [grid-area:1/1]">
|
||||||
{title ? (
|
{title ? (
|
||||||
<div className="inline-flex items-center justify-center rounded-t straight-corners:rounded-t-s bg-tint px-3 py-2 text-tint text-xs leading-none tracking-wide">
|
<div className="inline-flex items-center justify-center rounded-t straight-corners:rounded-t-s bg-tint px-3 py-2 text-tint text-xs leading-none tracking-wide">
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
@apply flex flex-col mb-14 flex-1;
|
@apply flex flex-col mb-14 flex-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-schemas-title {
|
||||||
|
@apply tabular-nums text-[0.813rem] leading-4 font-mono shrink-0 font-medium text-tint-strong;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-columns {
|
.openapi-columns {
|
||||||
@apply grid grid-cols-1 lg:grid-cols-2 gap-6 print-mode:grid-cols-1 justify-stretch;
|
@apply grid grid-cols-1 lg:grid-cols-2 gap-6 print-mode:grid-cols-1 justify-stretch;
|
||||||
}
|
}
|
||||||
@@ -46,10 +50,7 @@
|
|||||||
@apply font-semibold font-mono truncate;
|
@apply font-semibold font-mono truncate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-description.openapi-markdown {
|
.openapi-description.openapi-markdown,
|
||||||
@apply prose-sm text-[0.938rem];
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-description.openapi-markdown code {
|
.openapi-description.openapi-markdown code {
|
||||||
@apply prose-sm;
|
@apply prose-sm;
|
||||||
}
|
}
|
||||||
@@ -89,21 +90,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Method Tags */
|
/* Method Tags */
|
||||||
.openapi-method {
|
.openapi-method,
|
||||||
@apply rounded uppercase font-mono shrink-0 font-bold text-xs px-1 py-0.5 mr-2 text-tint-12/8 leading-tight align-middle inline-flex ring-1 ring-inset ring-tint-12/1 dark:ring-tint-1/1 whitespace-nowrap;
|
.openapi-statuscode {
|
||||||
|
@apply rounded uppercase font-mono items-center shrink-0 font-semibold text-[0.813rem] px-1 py-0.5 mr-2 text-tint-12/8 leading-tight align-middle inline-flex ring-1 ring-inset ring-tint-12/1 dark:ring-tint-1/1 whitespace-nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-method-get {
|
.openapi-method-get,
|
||||||
/* @apply bg-[hsl(215,54%,86%)] dark:bg-[hsla(215,54%,45%,0.24)] dark:text-[hsl(215,54%,86%)]; */
|
.openapi-statuscode-success {
|
||||||
@apply bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100;
|
@apply bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-method-post {
|
.openapi-method-post,
|
||||||
/* @apply bg-[hsl(120,25%,80%)] dark:bg-[hsla(120,54%,32%,0.24)] dark:text-[hsl(120,25%,80%)]; */
|
.openapi-statuscode-redirection {
|
||||||
@apply bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-100;
|
@apply bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-method-put {
|
.openapi-method-put,
|
||||||
|
.openapi-statuscode-informational {
|
||||||
@apply bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-100;
|
@apply bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,8 +114,9 @@
|
|||||||
@apply bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-100;
|
@apply bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-method-delete {
|
.openapi-method-delete,
|
||||||
@apply bg-pomegranate-100 text-pomegranate-800 dark:bg-pomegranate-900 dark:text-pomegranate-100;
|
.openapi-statuscode-error {
|
||||||
|
@apply bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-method-head,
|
.openapi-method-head,
|
||||||
@@ -140,7 +144,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-column-preview-body {
|
.openapi-column-preview-body {
|
||||||
@apply flex flex-col gap-4 sticky top-4 site-header:top-20 site-header-sections:page-has-toc:top-32 page-api-block:xl:max-2xl:top-32 print-mode:static;
|
@apply flex flex-col gap-4 sticky top-4 site-header:top-20 site-header-sections:top-32 page-api-block:xl:max-2xl:top-32 print-mode:static;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-column-preview pre {
|
.openapi-column-preview pre {
|
||||||
@@ -157,7 +161,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-section-schemas > .openapi-section-body > .openapi-schema-root-description {
|
.openapi-section-schemas > .openapi-section-body > .openapi-schema-root-description {
|
||||||
@apply px-2.5 pt-1 !text-sm;
|
@apply px-2.5 pt-2.5 mt-0 !text-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-properties {
|
.openapi-schema-properties {
|
||||||
@@ -360,7 +364,7 @@
|
|||||||
|
|
||||||
/* Responses */
|
/* Responses */
|
||||||
.openapi-responses-header {
|
.openapi-responses-header {
|
||||||
@apply py-2 border-b border-tint-subtle max-w-full flex-1;
|
@apply py-2 max-w-full flex-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-responses-header-content {
|
.openapi-responses-header-content {
|
||||||
@@ -368,7 +372,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-tab-content {
|
.openapi-response-tab-content {
|
||||||
@apply overflow-hidden max-w-full flex items-baseline gap-2;
|
@apply overflow-hidden max-w-full flex items-baseline;
|
||||||
|
@apply text-left text-pretty relative leading-[1.125rem] text-tint !font-normal truncate select-text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-description.openapi-markdown {
|
.openapi-response-description.openapi-markdown {
|
||||||
@@ -383,10 +388,6 @@
|
|||||||
@apply truncate max-w-full inline pr-1;
|
@apply truncate max-w-full inline pr-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-statuscode {
|
|
||||||
@apply tabular-nums text-sm font-normal font-mono shrink-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-response-content-type {
|
.openapi-response-content-type {
|
||||||
@apply text-xs text-tint-8 ml-auto shrink-0;
|
@apply text-xs text-tint-8 ml-auto shrink-0;
|
||||||
}
|
}
|
||||||
@@ -416,15 +417,23 @@
|
|||||||
|
|
||||||
/* Code Sample */
|
/* Code Sample */
|
||||||
.openapi-codesample {
|
.openapi-codesample {
|
||||||
@apply border rounded bg-tint border-tint-subtle;
|
@apply border rounded-md straight-corners:rounded-none bg-tint border-tint-subtle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-codesample-header {
|
.openapi-codesample-header {
|
||||||
@apply flex flex-row items-center;
|
@apply flex flex-row items-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-codesample-header .openapi-select > button {
|
.openapi-response-media-types-examples-footer-content {
|
||||||
@apply border-none;
|
@apply flex flex-row items-center gap-2.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-header .openapi-select > button {
|
||||||
|
@apply max-w-full overflow-hidden shrink pl-0.5 py-0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-header .openapi-select > button .openapi-statuscode {
|
||||||
|
@apply h-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-codesample-header-content {
|
.openapi-codesample-header-content {
|
||||||
@@ -432,7 +441,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-codesample-header-content .openapi-path {
|
.openapi-codesample-header-content .openapi-path {
|
||||||
@apply flex items-center font-mono *:text-[0.813rem] gap-2 h-fit *:truncate overflow-x-auto min-w-0 max-w-full font-normal text-tint-strong;
|
@apply flex items-center font-mono text-[0.813rem] gap-1 h-fit *:truncate overflow-x-auto min-w-0 max-w-full font-normal text-tint-strong;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-codesample-header-content .openapi-path .openapi-path-variable {
|
.openapi-codesample-header-content .openapi-path .openapi-path-variable {
|
||||||
@@ -463,7 +472,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-path .openapi-method {
|
.openapi-path .openapi-method {
|
||||||
@apply text-[0.813rem] m-0 mt-0.5 items-center flex px-1;
|
@apply m-0 mt-0.5 items-center flex px-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-path-title {
|
.openapi-path-title {
|
||||||
@@ -494,7 +503,7 @@
|
|||||||
|
|
||||||
/* Panel */
|
/* Panel */
|
||||||
.openapi-panel {
|
.openapi-panel {
|
||||||
@apply border rounded bg-tint border-tint-subtle;
|
@apply border rounded-md straight-corners:rounded-none bg-tint border-tint-subtle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-panel-heading {
|
.openapi-panel-heading {
|
||||||
@@ -516,13 +525,41 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Example */
|
/* Example */
|
||||||
|
.openapi-response-examples {
|
||||||
|
@apply border rounded-md straight-corners:rounded-none bg-tint border-tint-subtle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-header {
|
||||||
|
@apply flex flex-row items-center p-2.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-header-content {
|
||||||
|
@apply max-w-full overflow-hidden truncate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-statuscode-title {
|
||||||
|
@apply flex items-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-header .openapi-select > button,
|
||||||
|
.openapi-response-examples-header .openapi-markdown,
|
||||||
|
.openapi-response-examples-statuscode-title {
|
||||||
|
@apply text-[0.813rem] truncate text-tint font-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-response-examples-panel,
|
||||||
|
.openapi-codesample-panel {
|
||||||
|
@apply flex-1 text-sm relative focus-visible:outline-none;
|
||||||
|
@apply before:w-full before:h-px before:absolute before:bg-tint-6 before:-top-px before:z-10;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-example-empty {
|
.openapi-example-empty {
|
||||||
@apply relative text-tint bg-tint min-h-20 flex flex-col justify-center items-center;
|
@apply relative text-tint bg-tint min-h-20 flex flex-col justify-center items-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common Elements */
|
/* Common Elements */
|
||||||
.openapi-select {
|
.openapi-select {
|
||||||
/* unstyled */
|
@apply w-auto max-w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prevent react-aria popover from setting overflow:auto on body */
|
/* Prevent react-aria popover from setting overflow:auto on body */
|
||||||
@@ -531,24 +568,32 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select > button {
|
.openapi-select > button {
|
||||||
@apply flex items-center cursor-pointer gap-1.5 text-tint-strong max-w-60 rounded text-xs leading-6 px-1.5 truncate border border-tint-subtle bg-tint;
|
@apply flex items-center font-normal cursor-pointer *:truncate gap-1.5 text-tint-strong max-w-32 rounded text-xs p-1.5 leading-none border border-tint-subtle bg-tint;
|
||||||
@apply hover:bg-tint-hover transition-all;
|
@apply hover:bg-tint-hover transition-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-select > button[data-focused="true"] {
|
||||||
|
@apply outline-primary -outline-offset-1 outline outline-1;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-select > button > span.react-aria-SelectValue {
|
.openapi-select > button > span.react-aria-SelectValue {
|
||||||
@apply shrink truncate;
|
@apply shrink truncate flex items-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select > button > .gb-icon {
|
.openapi-select > button > span.react-aria-SelectValue span:not(.openapi-statuscode) {
|
||||||
@apply shrink-0;
|
@apply truncate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select > button svg {
|
.openapi-select > button .openapi-markdown {
|
||||||
@apply size-2.5;
|
@apply *:leading-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-select > button .gb-icon {
|
||||||
|
@apply size-2.5 shrink-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select-popover {
|
.openapi-select-popover {
|
||||||
@apply min-w-32 max-w-fit w-auto max-h-52 overflow-y-auto p-1.5 border border-tint-subtle bg-tint-base backdrop-blur-xl rounded-md;
|
@apply min-w-32 z-10 max-w-[max(20rem,var(--trigger-width))] overflow-x-hidden max-h-52 overflow-y-auto p-1.5 border border-tint-subtle bg-tint-base backdrop-blur-xl rounded-md straight-corners:rounded-none;
|
||||||
@apply shadow-md shadow-tint-12/1 dark:shadow-tint-1/1;
|
@apply shadow-md shadow-tint-12/1 dark:shadow-tint-1/1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,11 +606,17 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select-item {
|
.openapi-select-item {
|
||||||
@apply text-sm cursor-pointer px-1.5 py-0.5 truncate text-tint ring-0 border-none rounded !outline-none;
|
@apply text-sm flex items-center cursor-pointer px-1.5 overflow-hidden py-1 *:truncate text-tint ring-0 border-none rounded !outline-none;
|
||||||
@apply hover:bg-tint-hover theme-gradient:hover:bg-tint-12/1 hover:text-tint-strong contrast-more:hover:ring-1 contrast-more:hover:ring-inset contrast-more:hover:ring-current;
|
@apply hover:bg-tint-hover theme-gradient:hover:bg-tint-12/1 hover:text-tint-strong contrast-more:hover:ring-1 contrast-more:hover:ring-inset contrast-more:hover:ring-current;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-select-item-selected {
|
.openapi-select button .openapi-markdown,
|
||||||
|
.openapi-select-item .openapi-markdown {
|
||||||
|
@apply text-[0.813rem] *:truncate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-select-item-selected,
|
||||||
|
.openapi-select-item-selected .openapi-markdown {
|
||||||
@apply text-primary-subtle hover:text-primary hover:bg-primary-hover;
|
@apply text-primary-subtle hover:text-primary hover:bg-primary-hover;
|
||||||
@apply theme-muted:hover:bg-primary-active theme-gradient:hover:bg-primary-active tint:font-semibold;
|
@apply theme-muted:hover:bg-primary-active theme-gradient:hover:bg-primary-active tint:font-semibold;
|
||||||
@apply contrast-more:text-primary contrast-more:hover:text-primary-strong contrast-more:font-semibold;
|
@apply contrast-more:text-primary contrast-more:hover:text-primary-strong contrast-more:font-semibold;
|
||||||
@@ -600,6 +651,14 @@ body:has(.openapi-select-popover) {
|
|||||||
@apply text-tint;
|
@apply text-tint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-section-footer {
|
||||||
|
@apply flex flex-row items-center p-2.5 gap-2.5 text-sm text-tint-strong border-t border-tint-subtle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-section-footer-content {
|
||||||
|
@apply text-sm text-tint-strong;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-section-toggle {
|
.openapi-section-toggle {
|
||||||
@apply text-tint-subtle contrast-more:text-tint-strong;
|
@apply text-tint-subtle contrast-more:text-tint-strong;
|
||||||
}
|
}
|
||||||
@@ -621,6 +680,7 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Tabs */
|
/* Tabs */
|
||||||
|
.openapi-panel-header,
|
||||||
.openapi-tabs-list {
|
.openapi-tabs-list {
|
||||||
@apply flex flex-row gap-1.5 py-1.5 px-2.5 w-full overflow-x-scroll;
|
@apply flex flex-row gap-1.5 py-1.5 px-2.5 w-full overflow-x-scroll;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
@@ -632,18 +692,17 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-tabs-tab[aria-selected="true"] {
|
.openapi-tabs-tab[aria-selected="true"] {
|
||||||
@apply text-primary after:absolute after:-bottom-[calc(0.375rem_+_1px)] after:z-20 after:left-0 after:w-full after:h-px after:bg-primary-solid after:transition-all;
|
@apply !text-primary-subtle after:absolute after:-bottom-[calc(0.375rem_+_1px)] after:z-20 after:left-0 after:w-full after:h-px after:bg-primary-solid after:transition-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-tabs-panel,
|
.openapi-tabs-panel {
|
||||||
.openapi-codesample-panel {
|
|
||||||
@apply flex-1 text-sm relative focus-visible:outline-none;
|
@apply flex-1 text-sm relative focus-visible:outline-none;
|
||||||
@apply before:w-full before:h-px before:absolute before:bg-tint-6 before:-top-px before:z-10;
|
@apply before:w-full before:h-px before:absolute before:bg-tint-6 before:-top-px before:z-10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disclosure group */
|
/* Disclosure group */
|
||||||
.openapi-disclosure-group {
|
.openapi-disclosure-group {
|
||||||
@apply border-b border-tint-subtle relative;
|
@apply border-tint-subtle border-b border-x overflow-auto last:rounded-b-md straight-corners:last:rounded-none first:rounded-t-md straight-corners:first:rounded-none first:border-t relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-header {
|
.openapi-disclosure-group-header {
|
||||||
@@ -651,16 +710,11 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger {
|
.openapi-disclosure-group-trigger {
|
||||||
@apply flex items-baseline relative flex-1 gap-2.5 py-2 truncate -outline-offset-1;
|
@apply flex items-baseline transition-all hover:bg-tint-subtle relative flex-1 gap-2.5 p-3 truncate -outline-offset-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger:disabled {
|
.openapi-disclosure-group-trigger:disabled {
|
||||||
@apply cursor-default;
|
@apply cursor-default hover:bg-inherit;
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-group:only-child,
|
|
||||||
.openapi-disclosure-group:last-child {
|
|
||||||
@apply border-b-0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger:disabled .openapi-disclosure-group-icon {
|
.openapi-disclosure-group-trigger:disabled .openapi-disclosure-group-icon {
|
||||||
@@ -680,28 +734,42 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-panel {
|
.openapi-disclosure-group-panel {
|
||||||
@apply pb-2.5;
|
@apply p-3 pt-1 transition-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger[aria-expanded="true"] > .openapi-disclosure-group-icon > svg {
|
.openapi-disclosure-group-trigger[aria-expanded="true"] > .openapi-disclosure-group-icon > svg {
|
||||||
@apply rotate-90;
|
@apply rotate-90;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group:hover .openapi-disclosure-group-mediatype {
|
.openapi-disclosure-group:hover .openapi-disclosure-group-mediatype,
|
||||||
@apply opacity-11 flex;
|
.openapi-disclosure-group-mediatype:has(> .openapi-select[data-open="true"]) {
|
||||||
|
@apply opacity-11 visible flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-mediatype {
|
.openapi-disclosure-group-mediatype {
|
||||||
@apply opacity-0 hidden text-xs transition-all duration-200 shrink-0 absolute right-0 top-2.5;
|
@apply opacity-0 invisible text-xs transition-opacity duration-300 shrink-0 absolute right-2.5 top-2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-mediatype > span {
|
.openapi-disclosure-group-mediatype > span {
|
||||||
@apply px-1 bg-tint-6 text-tint-12 rounded-full;
|
@apply px-1 bg-tint-6 text-tint-12 rounded-full straight-corners:rounded-md;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disclosure */
|
/* Disclosure */
|
||||||
|
.openapi-schemas-disclosure > .openapi-disclosure-trigger {
|
||||||
|
@apply flex items-center font-mono !w-full transition-all text-tint-strong !text-sm hover:bg-tint-subtle relative flex-1 gap-2.5 p-3 truncate -outline-offset-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-schemas-disclosure > .openapi-disclosure-trigger,
|
||||||
|
.openapi-schemas-disclosure .openapi-disclosure-panel {
|
||||||
|
@apply straight-corners:!rounded-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-schemas-disclosure > .openapi-disclosure-trigger[aria-expanded="true"] > svg {
|
||||||
|
@apply rotate-90;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger {
|
.openapi-disclosure-trigger {
|
||||||
@apply transition-all truncate duration-300 max-w-full hover:text-tint-strong rounded-2xl border border-tint-subtle px-2.5 py-1 text-[0.813rem] text-tint flex flex-row items-center gap-1.5 -outline-offset-1;
|
@apply transition-all truncate duration-300 max-w-full hover:text-tint-strong rounded-2xl straight-corners:rounded border border-tint-subtle px-2.5 py-1 text-[0.813rem] text-tint flex flex-row items-center gap-1.5 -outline-offset-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger span {
|
.openapi-disclosure-trigger span {
|
||||||
@@ -717,7 +785,7 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger[aria-expanded="true"] {
|
.openapi-disclosure-trigger[aria-expanded="true"] {
|
||||||
@apply w-full rounded-lg border-b rounded-b-none;
|
@apply w-full rounded-lg border-b rounded-b-none straight-corners:rounded-b-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger[aria-expanded="false"] {
|
.openapi-disclosure-trigger[aria-expanded="false"] {
|
||||||
@@ -725,7 +793,7 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-panel[aria-hidden="false"] {
|
.openapi-disclosure-panel[aria-hidden="false"] {
|
||||||
@apply border-b border-x border-tint-subtle rounded-b-lg;
|
@apply border-b border-x border-tint-subtle rounded-b-lg straight-corners:rounded-b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-panel .openapi-schema {
|
.openapi-disclosure-panel .openapi-schema {
|
||||||
@@ -745,17 +813,13 @@ body:has(.openapi-select-popover) {
|
|||||||
@apply space-y-2.5;
|
@apply space-y-2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-section-schemas {
|
|
||||||
@apply border border-tint-subtle rounded-lg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-section-schemas > .openapi-section-body > .openapi-schema-properties > .openapi-schema,
|
.openapi-section-schemas > .openapi-section-body > .openapi-schema-properties > .openapi-schema,
|
||||||
.openapi-section-schemas > .openapi-section-body > .openapi-schema-root {
|
.openapi-section-schemas > .openapi-section-body > .openapi-schema-root {
|
||||||
@apply p-2.5;
|
@apply p-2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-tooltip {
|
.openapi-tooltip {
|
||||||
@apply flex items-center gap-1 bg-tint-base border border-tint-subtle text-tint-strong rounded-md font-medium px-1.5 py-0.5 shadow-sm text-[13px];
|
@apply flex items-center gap-1 bg-tint-base border border-tint-subtle text-tint-strong rounded-md straight-corners:rounded-none font-medium px-1.5 py-0.5 shadow-sm text-[13px];
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-tooltip svg {
|
.openapi-tooltip svg {
|
||||||
|
|||||||
@@ -10,18 +10,22 @@ export type DropdownButtonProps<E extends HTMLElement = HTMLElement> = Omit<
|
|||||||
'ref'
|
'ref'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
export type DropdownProps<E extends HTMLElement = HTMLElement> = {
|
||||||
* Button with a dropdown.
|
|
||||||
*/
|
|
||||||
export function Dropdown<E extends HTMLElement>(props: {
|
|
||||||
/** Content of the button */
|
/** Content of the button */
|
||||||
button: (buttonProps: DropdownButtonProps<E>) => React.ReactNode;
|
button: (buttonProps: DropdownButtonProps<E>) => React.ReactNode;
|
||||||
/** Content of the dropdown */
|
/** Content of the dropdown */
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
/** Custom styles */
|
/** Custom styles */
|
||||||
className?: ClassValue;
|
className?: ClassValue;
|
||||||
}) {
|
/** Whether to use fixed positioning (for fixed navbars) */
|
||||||
const { button, children, className } = props;
|
useFixedPosition?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Button with a dropdown.
|
||||||
|
*/
|
||||||
|
export function Dropdown<E extends HTMLElement = HTMLElement>(props: DropdownProps<E>) {
|
||||||
|
const { button, children, className, useFixedPosition = false } = props;
|
||||||
const dropdownId = useId();
|
const dropdownId = useId();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -53,7 +57,7 @@ export function Dropdown<E extends HTMLElement>(props: {
|
|||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="fixed z-50 w-52">
|
<div className={tcls(useFixedPosition ? 'fixed' : 'absolute', 'z-50 w-52')}>
|
||||||
<div
|
<div
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'mt-2',
|
'mt-2',
|
||||||
@@ -92,6 +96,7 @@ export function DropdownChevron() {
|
|||||||
'ms-1',
|
'ms-1',
|
||||||
'transition-all',
|
'transition-all',
|
||||||
'group-hover/dropdown:opacity-11',
|
'group-hover/dropdown:opacity-11',
|
||||||
|
'group-hover/dropdown:rotate-180',
|
||||||
'group-focus-within/dropdown:rotate-180'
|
'group-focus-within/dropdown:rotate-180'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -212,10 +212,11 @@ export function Header(props: { context: GitBookSiteContext; withTopHeader?: boo
|
|||||||
siteSpace={siteSpace}
|
siteSpace={siteSpace}
|
||||||
siteSpaces={siteSpaces}
|
siteSpaces={siteSpaces}
|
||||||
className="w-full grow py-1"
|
className="w-full grow py-1"
|
||||||
|
useFixedPosition={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{sections && (
|
{sections && sections.list.length > 1 && (
|
||||||
<SiteSectionTabs
|
<SiteSectionTabs
|
||||||
sections={encodeClientSiteSections(context, sections)}
|
sections={encodeClientSiteSections(context, sections)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,15 +3,17 @@ import type { SiteSpace } from '@gitbook/api';
|
|||||||
import { tcls } from '@/lib/tailwind';
|
import { tcls } from '@/lib/tailwind';
|
||||||
|
|
||||||
import type { GitBookSiteContext } from '@v2/lib/context';
|
import type { GitBookSiteContext } from '@v2/lib/context';
|
||||||
import { Dropdown, DropdownChevron, DropdownMenu } from './Dropdown';
|
import { Dropdown, DropdownChevron, DropdownMenu, type DropdownProps } from './Dropdown';
|
||||||
import { SpacesDropdownMenuItem } from './SpacesDropdownMenuItem';
|
import { SpacesDropdownMenuItem } from './SpacesDropdownMenuItem';
|
||||||
|
|
||||||
export function SpacesDropdown(props: {
|
export function SpacesDropdown(
|
||||||
|
props: {
|
||||||
context: GitBookSiteContext;
|
context: GitBookSiteContext;
|
||||||
siteSpace: SiteSpace;
|
siteSpace: SiteSpace;
|
||||||
siteSpaces: SiteSpace[];
|
siteSpaces: SiteSpace[];
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
} & Partial<DropdownProps>
|
||||||
|
) {
|
||||||
const { context, siteSpace, siteSpaces, className } = props;
|
const { context, siteSpace, siteSpaces, className } = props;
|
||||||
const { linker } = context;
|
const { linker } = context;
|
||||||
|
|
||||||
@@ -67,6 +69,7 @@ export function SpacesDropdown(props: {
|
|||||||
<DropdownChevron />
|
<DropdownChevron />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
{siteSpaces.map((otherSiteSpace, index) => (
|
{siteSpaces.map((otherSiteSpace, index) => (
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export function ScrollSectionsList(props: { sections: DocumentSection[] }) {
|
|||||||
>
|
>
|
||||||
{section.tag ? (
|
{section.tag ? (
|
||||||
<span
|
<span
|
||||||
className={`-mt-0.5 openapi-method openapi-method-${section.tag.toLowerCase()}`}
|
className={`-mt-0.5 openapi-method !text-xs openapi-method-${section.tag.toLowerCase()}`}
|
||||||
>
|
>
|
||||||
{section.tag}
|
{section.tag}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { type ImageResizer, checkIsHttpURL } from '@v2/lib/images';
|
import type { ImageResizer } from '@v2/lib/images';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
import { type ClassValue, tcls } from '@/lib/tailwind';
|
import { type ClassValue, tcls } from '@/lib/tailwind';
|
||||||
|
|
||||||
|
import { checkIsHttpURL } from '@/lib/urls';
|
||||||
import { ZoomImage } from './ZoomImage';
|
import { ZoomImage } from './ZoomImage';
|
||||||
import type { PolymorphicComponentProp } from './types';
|
import type { PolymorphicComponentProp } from './types';
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export const en = {
|
|||||||
table_of_contents_button_label: 'Open table of contents',
|
table_of_contents_button_label: 'Open table of contents',
|
||||||
cookies_title: 'Cookies',
|
cookies_title: 'Cookies',
|
||||||
cookies_prompt:
|
cookies_prompt:
|
||||||
'This site uses cookies to deliver its service and to analyse traffic. By browsing this site, you accept the ${1}.',
|
'This site uses cookies to deliver its service and to analyze traffic. By browsing this site, you accept the ${1}.',
|
||||||
cookies_prompt_privacy: 'privacy policy',
|
cookies_prompt_privacy: 'privacy policy',
|
||||||
cookies_accept: 'Accept',
|
cookies_accept: 'Accept',
|
||||||
cookies_reject: 'Reject',
|
cookies_reject: 'Reject',
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ export const getLatestOpenAPISpecVersionContent = cache({
|
|||||||
* Resolve a URL to the content to render.
|
* Resolve a URL to the content to render.
|
||||||
*/
|
*/
|
||||||
export const getPublishedContentByUrl = cache({
|
export const getPublishedContentByUrl = cache({
|
||||||
name: 'api.getPublishedContentByUrl.v4',
|
name: 'api.getPublishedContentByUrl.v7',
|
||||||
tag: (url) => getCacheTagForURL(url),
|
tag: (url) => getCacheTagForURL(url),
|
||||||
get: async (
|
get: async (
|
||||||
url: string,
|
url: string,
|
||||||
@@ -267,6 +267,10 @@ export const getPublishedContentByUrl = cache({
|
|||||||
|
|
||||||
const parsed = parseCacheResponse(response);
|
const parsed = parseCacheResponse(response);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Parsed ttl: ${parsed.ttl} at ${Date.now()}, for ${'apiToken' in response.data ? response.data.apiToken : '<no-token>'}`
|
||||||
|
);
|
||||||
|
|
||||||
const data: PublishedContentWithCache = {
|
const data: PublishedContentWithCache = {
|
||||||
...response.data,
|
...response.data,
|
||||||
cacheMaxAge: parsed.ttl,
|
cacheMaxAge: parsed.ttl,
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import { GITBOOK_ASSETS_URL, GITBOOK_URL } from '@v2/lib/env';
|
import { GITBOOK_ASSETS_URL, GITBOOK_URL } from '@v2/lib/env';
|
||||||
|
import { joinPath, joinPathWithBaseURL } from './paths';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a public URL for an asset.
|
* Create a public URL for an asset.
|
||||||
*/
|
*/
|
||||||
export function getAssetURL(path: string): string {
|
export function getAssetURL(path: string): string {
|
||||||
return `${GITBOOK_ASSETS_URL || GITBOOK_URL}/~gitbook/static/${path}`;
|
return joinPathWithBaseURL(
|
||||||
|
GITBOOK_ASSETS_URL || GITBOOK_URL,
|
||||||
|
joinPath('~gitbook/static', path)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type {
|
|||||||
} from '@/lib/openapi/types';
|
} from '@/lib/openapi/types';
|
||||||
import { getCloudflareRequestGlobal } from '@v2/lib/data/cloudflare';
|
import { getCloudflareRequestGlobal } from '@v2/lib/data/cloudflare';
|
||||||
import { withCacheKey, withoutConcurrentExecution } from '@v2/lib/data/memoize';
|
import { withCacheKey, withoutConcurrentExecution } from '@v2/lib/data/memoize';
|
||||||
|
import { GITBOOK_RUNTIME } from '@v2/lib/env';
|
||||||
import { assert } from 'ts-essentials';
|
import { assert } from 'ts-essentials';
|
||||||
import { resolveContentRef } from '../references';
|
import { resolveContentRef } from '../references';
|
||||||
import { isV2 } from '../v2';
|
import { isV2 } from '../v2';
|
||||||
@@ -68,26 +69,27 @@ const fetchFilesystemV1 = cache({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchFilesystemV2 = withCacheKey(async (cacheKey, url: string) => {
|
const fetchFilesystemV2 = withCacheKey(
|
||||||
const uncached = unstable_cache(
|
withoutConcurrentExecution(getCloudflareRequestGlobal, async (cacheKey, url: string) => {
|
||||||
async () => fetchFilesystemV2Uncached(cacheKey, url),
|
if (GITBOOK_RUNTIME !== 'cloudflare') {
|
||||||
[cacheKey],
|
return fetchFilesystemUseCache(url);
|
||||||
{
|
|
||||||
revalidate: 60 * 60 * 24,
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
// FIXME: OpenNext doesn't support 'use cache' yet
|
||||||
|
const uncached = unstable_cache(async () => fetchFilesystemUncached(url), [cacheKey], {
|
||||||
|
revalidate: 60 * 60 * 24,
|
||||||
|
});
|
||||||
|
|
||||||
const response = await uncached();
|
const response = await uncached();
|
||||||
return response;
|
return response;
|
||||||
});
|
})
|
||||||
const fetchFilesystemV2Uncached = withoutConcurrentExecution(
|
|
||||||
getCloudflareRequestGlobal,
|
|
||||||
async function fetchFilesystemV2(url: string) {
|
|
||||||
const response = await fetchFilesystemUncached(url);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fetchFilesystemUseCache = async (url: string) => {
|
||||||
|
'use cache';
|
||||||
|
return fetchFilesystemUncached(url);
|
||||||
|
};
|
||||||
|
|
||||||
async function fetchFilesystemUncached(
|
async function fetchFilesystemUncached(
|
||||||
url: string,
|
url: string,
|
||||||
options?: {
|
options?: {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Check if a URL is an HTTP URL.
|
||||||
|
*/
|
||||||
|
export function checkIsHttpURL(input: string | URL): boolean {
|
||||||
|
if (!URL.canParse(input)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const parsed = new URL(input);
|
||||||
|
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
||||||
|
}
|
||||||
@@ -107,12 +107,13 @@ export async function serveResizedImage(
|
|||||||
try {
|
try {
|
||||||
const response = await resizeImage(url, options);
|
const response = await resizeImage(url, options);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to resize image');
|
throw new Error(`Failed to resize image, received status code ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (_error) {
|
} catch (error) {
|
||||||
// Redirect to the original image if resizing fails
|
// Redirect to the original image if resizing fails
|
||||||
|
console.warn('Error while resizing image, redirecting to original', error);
|
||||||
return NextResponse.redirect(url, 302);
|
return NextResponse.redirect(url, 302);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ async function main() {
|
|||||||
writeDataFile('styles-map', JSON.stringify(onlyStyles, null, 2)),
|
writeDataFile('styles-map', JSON.stringify(onlyStyles, null, 2)),
|
||||||
writeDataFile('icons', JSON.stringify(result, null, 2)),
|
writeDataFile('icons', JSON.stringify(result, null, 2)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsole: We want the CLI to log
|
||||||
|
console.log(`Generated ${result.length} icons`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function writeDataFile(name, content) {
|
async function writeDataFile(name, content) {
|
||||||
@@ -74,6 +77,7 @@ async function writeDataFile(name, content) {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((_error) => {
|
main().catch((error) => {
|
||||||
|
console.error(`Error generating icons list: ${error}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ async function main() {
|
|||||||
// Create the output folder if it doesn't exist
|
// Create the output folder if it doesn't exist
|
||||||
await fs.mkdir(outputFolder, { recursive: true });
|
await fs.mkdir(outputFolder, { recursive: true });
|
||||||
|
|
||||||
const _printOutputFolder = path.relative(process.cwd(), outputFolder);
|
|
||||||
|
|
||||||
// Copy the assets from
|
// Copy the assets from
|
||||||
// source/sprites to outputFolder/sprites
|
// source/sprites to outputFolder/sprites
|
||||||
// source/svgs to outputFolder/svgs
|
// source/svgs to outputFolder/svgs
|
||||||
@@ -45,8 +43,12 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsole: We want the CLI to log
|
||||||
|
console.log(`Copied ${stylesToCopy.length} styles to ${outputFolder}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((_error) => {
|
main().catch((error) => {
|
||||||
|
console.error(`Error copying icons: ${error}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"extends": ["//"],
|
"extends": ["//"],
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"generate": {
|
"generate": {
|
||||||
|
"inputs": ["bin/**/*", "package.json"],
|
||||||
"outputs": ["src/data/*.json", "dist/data/*.json"]
|
"outputs": ["src/data/*.json", "dist/data/*.json"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useRef, useState } from 'react';
|
import { useRef } from 'react';
|
||||||
import { mergeProps, useButton, useDisclosure, useFocusRing } from 'react-aria';
|
import { mergeProps, useButton, useDisclosure, useFocusRing } from 'react-aria';
|
||||||
import { useDisclosureState } from 'react-stately';
|
import { useDisclosureState } from 'react-stately';
|
||||||
import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
||||||
import { Section, SectionBody, SectionHeader, SectionHeaderContent } from './StaticSection';
|
import { Section, SectionBody, SectionHeader, SectionHeaderContent } from './StaticSection';
|
||||||
|
|
||||||
interface InteractiveSectionTab {
|
interface InteractiveSectionTab {
|
||||||
@@ -35,6 +35,10 @@ export function InteractiveSection(props: {
|
|||||||
header?: React.ReactNode;
|
header?: React.ReactNode;
|
||||||
/** Children to display within the container */
|
/** Children to display within the container */
|
||||||
overlay?: React.ReactNode;
|
overlay?: React.ReactNode;
|
||||||
|
/** State key to use with a store */
|
||||||
|
stateKey?: string;
|
||||||
|
/** Icon for the tabs select */
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
@@ -46,12 +50,9 @@ export function InteractiveSection(props: {
|
|||||||
header,
|
header,
|
||||||
overlay,
|
overlay,
|
||||||
toggleIcon = '▶',
|
toggleIcon = '▶',
|
||||||
|
selectIcon,
|
||||||
|
stateKey = 'interactive-section',
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [selectedTabKey, setSelectedTab] = useState(defaultTab);
|
|
||||||
const selectedTab: InteractiveSectionTab | undefined =
|
|
||||||
tabs.find((tab) => tab.key === selectedTabKey) ?? tabs[0];
|
|
||||||
|
|
||||||
const state = useDisclosureState({
|
const state = useDisclosureState({
|
||||||
defaultExpanded: defaultOpened,
|
defaultExpanded: defaultOpened,
|
||||||
});
|
});
|
||||||
@@ -60,6 +61,10 @@ export function InteractiveSection(props: {
|
|||||||
const { buttonProps: triggerProps, panelProps } = useDisclosure({}, state, panelRef);
|
const { buttonProps: triggerProps, panelProps } = useDisclosure({}, state, panelRef);
|
||||||
const { buttonProps } = useButton(triggerProps, triggerRef);
|
const { buttonProps } = useButton(triggerProps, triggerRef);
|
||||||
const { isFocusVisible, focusProps } = useFocusRing();
|
const { isFocusVisible, focusProps } = useFocusRing();
|
||||||
|
const store = useSelectState(stateKey, defaultTab);
|
||||||
|
|
||||||
|
const selectedTab: InteractiveSectionTab | undefined =
|
||||||
|
tabs.find((tab) => tab.key === store.key) ?? tabs[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section
|
<Section
|
||||||
@@ -108,16 +113,12 @@ export function InteractiveSection(props: {
|
|||||||
>
|
>
|
||||||
{tabs.length > 1 ? (
|
{tabs.length > 1 ? (
|
||||||
<OpenAPISelect
|
<OpenAPISelect
|
||||||
className={clsx(
|
stateKey={stateKey}
|
||||||
'openapi-section-select',
|
|
||||||
`${className}-tabs-select`
|
|
||||||
)}
|
|
||||||
items={tabs}
|
items={tabs}
|
||||||
selectedKey={selectedTab?.key ?? ''}
|
onSelectionChange={() => {
|
||||||
onSelectionChange={(key) => {
|
|
||||||
setSelectedTab(String(key));
|
|
||||||
state.expand();
|
state.expand();
|
||||||
}}
|
}}
|
||||||
|
icon={selectIcon}
|
||||||
placement="bottom end"
|
placement="bottom end"
|
||||||
>
|
>
|
||||||
{tabs.map((tab) => (
|
{tabs.map((tab) => (
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ function OpenAPICodeSampleFooter(props: {
|
|||||||
method={data.method}
|
method={data.method}
|
||||||
path={data.path}
|
path={data.path}
|
||||||
renderers={renderers}
|
renderers={renderers}
|
||||||
|
selectIcon={context.icons.chevronDown}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|||||||
@@ -1,70 +1,41 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { useStore } from 'zustand';
|
|
||||||
import type { MediaTypeRenderer } from './OpenAPICodeSample';
|
import type { MediaTypeRenderer } from './OpenAPICodeSample';
|
||||||
import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
||||||
import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
|
|
||||||
|
|
||||||
type MediaTypeState = {
|
|
||||||
mediaType: string;
|
|
||||||
setMediaType: (mediaType: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
function useMediaTypeState(
|
|
||||||
data: { method: string; path: string },
|
|
||||||
defaultKey: string
|
|
||||||
): MediaTypeState {
|
|
||||||
const { method, path } = data;
|
|
||||||
const store = useStore(getOrCreateStoreByKey(`media-type-${method}-${path}`, defaultKey));
|
|
||||||
if (typeof store.key !== 'string') {
|
|
||||||
throw new Error('Media type key is not a string');
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
mediaType: store.key,
|
|
||||||
setMediaType: useCallback((index: string) => store.setKey(index), [store.setKey]),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function useMediaTypeSampleIndexState(data: { method: string; path: string }, mediaType: string) {
|
|
||||||
const { method, path } = data;
|
|
||||||
const store = useStore(
|
|
||||||
getOrCreateStoreByKey(`media-type-sample-${mediaType}-${method}-${path}`, 0)
|
|
||||||
);
|
|
||||||
if (typeof store.key !== 'number') {
|
|
||||||
throw new Error('Example key is not a number');
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
index: store.key,
|
|
||||||
setIndex: useCallback((index: number) => store.setKey(index), [store.setKey]),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OpenAPIMediaTypeExamplesSelector(props: {
|
export function OpenAPIMediaTypeExamplesSelector(props: {
|
||||||
method: string;
|
method: string;
|
||||||
path: string;
|
path: string;
|
||||||
renderers: MediaTypeRenderer[];
|
renderers: MediaTypeRenderer[];
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { method, path, renderers } = props;
|
const { method, path, renderers, selectIcon } = props;
|
||||||
if (!renderers[0]) {
|
if (!renderers[0]) {
|
||||||
throw new Error('No renderers provided');
|
throw new Error('No renderers provided');
|
||||||
}
|
}
|
||||||
const state = useMediaTypeState({ method, path }, renderers[0].mediaType);
|
const stateKey = `media-type-${method}-${path}`;
|
||||||
const selected = renderers.find((r) => r.mediaType === state.mediaType) || renderers[0];
|
const state = useSelectState(stateKey, renderers[0].mediaType);
|
||||||
|
const selected = renderers.find((r) => r.mediaType === state.key) || renderers[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="openapi-codesample-selectors">
|
<div className="openapi-codesample-selectors">
|
||||||
<MediaTypeSelector state={state} renderers={renderers} />
|
<MediaTypeSelector selectIcon={selectIcon} stateKey={stateKey} renderers={renderers} />
|
||||||
<ExamplesSelector method={method} path={path} renderer={selected} />
|
<ExamplesSelector
|
||||||
|
selectIcon={selectIcon}
|
||||||
|
method={method}
|
||||||
|
path={path}
|
||||||
|
renderer={selected}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MediaTypeSelector(props: {
|
function MediaTypeSelector(props: {
|
||||||
state: MediaTypeState;
|
stateKey: string;
|
||||||
renderers: MediaTypeRenderer[];
|
renderers: MediaTypeRenderer[];
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { renderers, state } = props;
|
const { renderers, stateKey, selectIcon } = props;
|
||||||
|
|
||||||
if (renderers.length < 2) {
|
if (renderers.length < 2) {
|
||||||
return null;
|
return null;
|
||||||
@@ -78,12 +49,12 @@ function MediaTypeSelector(props: {
|
|||||||
return (
|
return (
|
||||||
<OpenAPISelect
|
<OpenAPISelect
|
||||||
className={clsx('openapi-select')}
|
className={clsx('openapi-select')}
|
||||||
selectedKey={state.mediaType}
|
|
||||||
items={renderers.map((renderer) => ({
|
items={renderers.map((renderer) => ({
|
||||||
key: renderer.mediaType,
|
key: renderer.mediaType,
|
||||||
label: renderer.mediaType,
|
label: renderer.mediaType,
|
||||||
}))}
|
}))}
|
||||||
onSelectionChange={(e) => state.setMediaType(String(e))}
|
icon={selectIcon}
|
||||||
|
stateKey={stateKey}
|
||||||
placement="bottom start"
|
placement="bottom start"
|
||||||
>
|
>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
@@ -99,9 +70,9 @@ function ExamplesSelector(props: {
|
|||||||
method: string;
|
method: string;
|
||||||
path: string;
|
path: string;
|
||||||
renderer: MediaTypeRenderer;
|
renderer: MediaTypeRenderer;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { method, path, renderer } = props;
|
const { method, path, renderer, selectIcon } = props;
|
||||||
const state = useMediaTypeSampleIndexState({ method, path }, renderer.mediaType);
|
|
||||||
if (renderer.examples.length < 2) {
|
if (renderer.examples.length < 2) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -114,8 +85,8 @@ function ExamplesSelector(props: {
|
|||||||
return (
|
return (
|
||||||
<OpenAPISelect
|
<OpenAPISelect
|
||||||
items={items}
|
items={items}
|
||||||
selectedKey={state.index}
|
icon={selectIcon}
|
||||||
onSelectionChange={(e) => state.setIndex(Number(e))}
|
stateKey={`media-type-sample-${renderer.mediaType}-${method}-${path}`}
|
||||||
placement="bottom start"
|
placement="bottom start"
|
||||||
>
|
>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
@@ -136,9 +107,9 @@ export function OpenAPIMediaTypeExamplesBody(props: {
|
|||||||
if (!renderers[0]) {
|
if (!renderers[0]) {
|
||||||
throw new Error('No renderers provided');
|
throw new Error('No renderers provided');
|
||||||
}
|
}
|
||||||
const mediaTypeState = useMediaTypeState({ method, path }, renderers[0].mediaType);
|
|
||||||
const selected =
|
const mediaTypeState = useSelectState(`media-type-${method}-${path}`, renderers[0].mediaType);
|
||||||
renderers.find((r) => r.mediaType === mediaTypeState.mediaType) ?? renderers[0];
|
const selected = renderers.find((r) => r.mediaType === mediaTypeState.key) ?? renderers[0];
|
||||||
if (selected.examples.length === 0) {
|
if (selected.examples.length === 0) {
|
||||||
return selected.element;
|
return selected.element;
|
||||||
}
|
}
|
||||||
@@ -147,10 +118,13 @@ export function OpenAPIMediaTypeExamplesBody(props: {
|
|||||||
|
|
||||||
function ExamplesBody(props: { method: string; path: string; renderer: MediaTypeRenderer }) {
|
function ExamplesBody(props: { method: string; path: string; renderer: MediaTypeRenderer }) {
|
||||||
const { method, path, renderer } = props;
|
const { method, path, renderer } = props;
|
||||||
const exampleState = useMediaTypeSampleIndexState({ method, path }, renderer.mediaType);
|
const exampleState = useSelectState(
|
||||||
const example = renderer.examples[exampleState.index] ?? renderer.examples[0];
|
`media-type-sample-${renderer.mediaType}-${method}-${path}`,
|
||||||
|
renderer.mediaType
|
||||||
|
);
|
||||||
|
const example = renderer.examples[Number(exampleState.key)] ?? renderer.examples[0];
|
||||||
if (!example) {
|
if (!example) {
|
||||||
throw new Error(`No example found for index ${exampleState.index}`);
|
throw new Error(`No example found for key ${exampleState.key}`);
|
||||||
}
|
}
|
||||||
return example.element;
|
return example.element;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,25 +22,21 @@ type CodeSampleItem = OpenAPISelectItem & {
|
|||||||
footer?: React.ReactNode;
|
footer?: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function OpenAPICodeSampleHeader(props: {
|
function OpenAPICodeSampleHeader(props: {
|
||||||
items: CodeSampleItem[];
|
items: CodeSampleItem[];
|
||||||
data: OpenAPIOperationData;
|
data: OpenAPIOperationData;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { data, items } = props;
|
const { data, items, selectIcon } = props;
|
||||||
|
|
||||||
const state = useCodeSampleState(items[0]?.key ?? '');
|
|
||||||
const selected = items.find((item) => item.key === state.key) || items[0];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<OpenAPIPath canCopy={false} withServer={false} data={data} />
|
<OpenAPIPath canCopy={false} withServer={false} data={data} />
|
||||||
{items.length > 1 ? (
|
{items.length > 1 ? (
|
||||||
<OpenAPISelect
|
<OpenAPISelect
|
||||||
selectedKey={selected?.key}
|
icon={selectIcon}
|
||||||
onSelectionChange={(key) => {
|
|
||||||
state.setKey(key);
|
|
||||||
}}
|
|
||||||
items={items}
|
items={items}
|
||||||
|
stateKey="codesample"
|
||||||
placement="bottom end"
|
placement="bottom end"
|
||||||
>
|
>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
@@ -59,8 +55,9 @@ export function OpenAPICodeSampleHeader(props: {
|
|||||||
export function OpenAPICodeSampleBody(props: {
|
export function OpenAPICodeSampleBody(props: {
|
||||||
items: CodeSampleItem[];
|
items: CodeSampleItem[];
|
||||||
data: OpenAPIOperationData;
|
data: OpenAPIOperationData;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { items, data } = props;
|
const { items, data, selectIcon } = props;
|
||||||
if (!items[0]) {
|
if (!items[0]) {
|
||||||
throw new Error('No items provided');
|
throw new Error('No items provided');
|
||||||
}
|
}
|
||||||
@@ -75,7 +72,7 @@ export function OpenAPICodeSampleBody(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StaticSection
|
<StaticSection
|
||||||
header={<OpenAPICodeSampleHeader data={data} items={items} />}
|
header={<OpenAPICodeSampleHeader selectIcon={selectIcon} data={data} items={items} />}
|
||||||
className="openapi-codesample"
|
className="openapi-codesample"
|
||||||
>
|
>
|
||||||
<div id={selected.key as string} className="openapi-codesample-panel">
|
<div id={selected.key as string} className="openapi-codesample-panel">
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import type React from 'react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button, Disclosure, DisclosurePanel, Heading } from 'react-aria-components';
|
import { Button, Disclosure, DisclosurePanel } from 'react-aria-components';
|
||||||
import type { OpenAPIClientContext } from './types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an interactive OpenAPI disclosure.
|
* Display an interactive OpenAPI disclosure.
|
||||||
*/
|
*/
|
||||||
export function OpenAPIDisclosure(props: {
|
export function OpenAPIDisclosure(props: {
|
||||||
context: OpenAPIClientContext;
|
icon: React.ReactNode;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
label: string;
|
label: string | ((isExpanded: boolean) => string);
|
||||||
|
className?: string;
|
||||||
}): React.JSX.Element {
|
}): React.JSX.Element {
|
||||||
const { context, children, label } = props;
|
const { icon, children, label, className } = props;
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Disclosure
|
<Disclosure
|
||||||
className="openapi-disclosure"
|
className={clsx('openapi-disclosure', className)}
|
||||||
isExpanded={isExpanded}
|
isExpanded={isExpanded}
|
||||||
onExpandedChange={setIsExpanded}
|
onExpandedChange={setIsExpanded}
|
||||||
>
|
>
|
||||||
<Heading>
|
|
||||||
<Button
|
<Button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
className="openapi-disclosure-trigger"
|
className="openapi-disclosure-trigger"
|
||||||
@@ -30,12 +31,9 @@ export function OpenAPIDisclosure(props: {
|
|||||||
: 'none',
|
: 'none',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{context.icons.plus}
|
{icon}
|
||||||
<span>
|
<span>{typeof label === 'function' ? label(isExpanded) : label}</span>
|
||||||
{isExpanded ? 'Hide' : 'Show'} {label}
|
|
||||||
</span>
|
|
||||||
</Button>
|
</Button>
|
||||||
</Heading>
|
|
||||||
<DisclosurePanel className="openapi-disclosure-panel">
|
<DisclosurePanel className="openapi-disclosure-panel">
|
||||||
{isExpanded ? children : null}
|
{isExpanded ? children : null}
|
||||||
</DisclosurePanel>
|
</DisclosurePanel>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { createContext, useContext, useRef, useState } from 'react';
|
import { createContext, useContext, useRef } from 'react';
|
||||||
import { mergeProps, useButton, useDisclosure, useFocusRing, useId } from 'react-aria';
|
import { mergeProps, useButton, useDisclosure, useFocusRing, useId } from 'react-aria';
|
||||||
import {
|
import {
|
||||||
type DisclosureGroupProps,
|
type DisclosureGroupProps,
|
||||||
@@ -8,18 +8,23 @@ import {
|
|||||||
useDisclosureGroupState,
|
useDisclosureGroupState,
|
||||||
useDisclosureState,
|
useDisclosureState,
|
||||||
} from 'react-stately';
|
} from 'react-stately';
|
||||||
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
groups: TDisclosureGroup[];
|
groups: TDisclosureGroup[];
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
/** State key to use with a store */
|
||||||
|
selectStateKey?: string;
|
||||||
|
/** Icon to display for the select */
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TDisclosureGroup = {
|
type TDisclosureGroup = {
|
||||||
id: string;
|
key: string;
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
tabs?: {
|
tabs?: {
|
||||||
id: string;
|
key: string;
|
||||||
label?: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
body?: React.ReactNode;
|
body?: React.ReactNode;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
@@ -30,24 +35,35 @@ const DisclosureGroupStateContext = createContext<DisclosureGroupState | null>(n
|
|||||||
* Display an interactive OpenAPI disclosure group.
|
* Display an interactive OpenAPI disclosure group.
|
||||||
*/
|
*/
|
||||||
export function OpenAPIDisclosureGroup(props: DisclosureGroupProps & Props) {
|
export function OpenAPIDisclosureGroup(props: DisclosureGroupProps & Props) {
|
||||||
const { icon, groups } = props;
|
const { icon, groups, selectStateKey, selectIcon } = props;
|
||||||
|
|
||||||
const state = useDisclosureGroupState(props);
|
const state = useDisclosureGroupState(props);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DisclosureGroupStateContext.Provider value={state}>
|
<DisclosureGroupStateContext.Provider value={state}>
|
||||||
{groups.map((group) => (
|
{groups.map((group) => (
|
||||||
<DisclosureItem icon={icon} key={group.id} group={group} />
|
<DisclosureItem
|
||||||
|
selectStateKey={selectStateKey}
|
||||||
|
selectIcon={selectIcon}
|
||||||
|
icon={icon}
|
||||||
|
key={group.key}
|
||||||
|
group={group}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</DisclosureGroupStateContext.Provider>
|
</DisclosureGroupStateContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode }) {
|
function DisclosureItem(props: {
|
||||||
const { icon, group } = props;
|
group: TDisclosureGroup;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
selectStateKey?: string;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
const { icon, group, selectStateKey, selectIcon } = props;
|
||||||
|
|
||||||
const defaultId = useId();
|
const defaultId = useId();
|
||||||
const id = group.id || defaultId;
|
const id = group.key || defaultId;
|
||||||
const groupState = useContext(DisclosureGroupStateContext);
|
const groupState = useContext(DisclosureGroupStateContext);
|
||||||
const isExpanded = groupState?.expandedKeys.has(id) || false;
|
const isExpanded = groupState?.expandedKeys.has(id) || false;
|
||||||
const state = useDisclosureState({
|
const state = useDisclosureState({
|
||||||
@@ -74,9 +90,9 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
|
|||||||
const { buttonProps } = useButton(triggerProps, triggerRef);
|
const { buttonProps } = useButton(triggerProps, triggerRef);
|
||||||
const { isFocusVisible, focusProps } = useFocusRing();
|
const { isFocusVisible, focusProps } = useFocusRing();
|
||||||
|
|
||||||
const defaultTab = group.tabs?.[0]?.id || '';
|
const defaultTab = group.tabs?.[0]?.key || '';
|
||||||
const [selectedTabKey, setSelectedTabKey] = useState(defaultTab);
|
const store = useSelectState(selectStateKey, defaultTab);
|
||||||
const selectedTab = group.tabs?.find((tab) => tab.id === selectedTabKey);
|
const selectedTab = group.tabs?.find((tab) => tab.key === store.key) || group.tabs?.[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
|
<div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
|
||||||
@@ -104,23 +120,25 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
|
|||||||
{group.label}
|
{group.label}
|
||||||
</button>
|
</button>
|
||||||
{group.tabs ? (
|
{group.tabs ? (
|
||||||
<div className="openapi-disclosure-group-mediatype">
|
<div
|
||||||
|
className="openapi-disclosure-group-mediatype"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
{group.tabs?.length > 1 ? (
|
{group.tabs?.length > 1 ? (
|
||||||
<select
|
<OpenAPISelect
|
||||||
className="openapi-section-select openapi-select openapi-disclosure-group-tabs-select"
|
icon={selectIcon}
|
||||||
onClick={(event) => event.stopPropagation()}
|
stateKey={selectStateKey}
|
||||||
value={selectedTab?.id}
|
onSelectionChange={() => {
|
||||||
onChange={(event) => {
|
|
||||||
setSelectedTabKey(event.target.value);
|
|
||||||
state.expand();
|
state.expand();
|
||||||
}}
|
}}
|
||||||
|
items={group.tabs}
|
||||||
>
|
>
|
||||||
{group.tabs.map((tab) => (
|
{group.tabs.map((tab) => (
|
||||||
<option key={tab.id} value={tab.id}>
|
<OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
|
||||||
{tab.label}
|
{tab.label}
|
||||||
</option>
|
</OpenAPISelectItem>
|
||||||
))}
|
))}
|
||||||
</select>
|
</OpenAPISelect>
|
||||||
) : group.tabs[0]?.label ? (
|
) : group.tabs[0]?.label ? (
|
||||||
<span>{group.tabs[0].label}</span>
|
<span>{group.tabs[0].label}</span>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { InteractiveSection } from './InteractiveSection';
|
import { InteractiveSection } from './InteractiveSection';
|
||||||
import { OpenAPIRootSchema } from './OpenAPISchemaServer';
|
import { OpenAPIRootSchema } from './OpenAPISchemaServer';
|
||||||
import type { OpenAPIClientContext } from './types';
|
import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
|
||||||
import { checkIsReference } from './utils';
|
import { checkIsReference } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,8 +10,10 @@ import { checkIsReference } from './utils';
|
|||||||
export function OpenAPIRequestBody(props: {
|
export function OpenAPIRequestBody(props: {
|
||||||
requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject;
|
requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject;
|
||||||
context: OpenAPIClientContext;
|
context: OpenAPIClientContext;
|
||||||
|
data: OpenAPIOperationData;
|
||||||
}) {
|
}) {
|
||||||
const { requestBody, context } = props;
|
const { requestBody, context, data } = props;
|
||||||
|
const { method, path } = data;
|
||||||
|
|
||||||
if (checkIsReference(requestBody)) {
|
if (checkIsReference(requestBody)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -21,6 +23,8 @@ export function OpenAPIRequestBody(props: {
|
|||||||
<InteractiveSection
|
<InteractiveSection
|
||||||
header="Body"
|
header="Body"
|
||||||
className="openapi-requestbody"
|
className="openapi-requestbody"
|
||||||
|
stateKey={`media-type-${method}-${path}`}
|
||||||
|
selectIcon={context.icons.chevronDown}
|
||||||
tabs={Object.entries(requestBody.content ?? {}).map(
|
tabs={Object.entries(requestBody.content ?? {}).map(
|
||||||
([contentType, mediaTypeObject]) => {
|
([contentType, mediaTypeObject]) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function OpenAPIResponse(props: {
|
|||||||
return (
|
return (
|
||||||
<div className="openapi-response-body">
|
<div className="openapi-response-body">
|
||||||
{headers.length > 0 ? (
|
{headers.length > 0 ? (
|
||||||
<OpenAPIDisclosure context={context} label="Headers">
|
<OpenAPIDisclosure icon={context.icons.plus} label="Headers">
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
properties={headers.map(([name, header]) =>
|
properties={headers.map(([name, header]) =>
|
||||||
parameterToProperty({ name, ...header })
|
parameterToProperty({ name, ...header })
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import {
|
|||||||
getExampleFromReference,
|
getExampleFromReference,
|
||||||
getExamplesFromMediaTypeObject,
|
getExamplesFromMediaTypeObject,
|
||||||
} from './OpenAPIExample';
|
} from './OpenAPIExample';
|
||||||
import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
|
import { OpenAPIResponseExampleContent } from './OpenAPIResponseExampleContent';
|
||||||
import { StaticSection } from './StaticSection';
|
import { OpenAPIResponseMediaTypeContent } from './OpenAPIResponseMediaType';
|
||||||
import type { OpenAPIContext, OpenAPIOperationData } from './types';
|
import type { OpenAPIContext, OpenAPIOperationData } from './types';
|
||||||
import { checkIsReference, createStateKey, resolveDescription } from './utils';
|
import { getStatusCodeDefaultLabel } from './utils';
|
||||||
|
import { checkIsReference, resolveDescription } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an example of the response content.
|
* Display an example of the response content.
|
||||||
@@ -45,11 +46,17 @@ export function OpenAPIResponseExample(props: {
|
|||||||
|
|
||||||
const tabs = responses.map(([key, responseObject]) => {
|
const tabs = responses.map(([key, responseObject]) => {
|
||||||
const description = resolveDescription(responseObject);
|
const description = resolveDescription(responseObject);
|
||||||
|
const label = description ? (
|
||||||
|
<Markdown source={description} />
|
||||||
|
) : (
|
||||||
|
getStatusCodeDefaultLabel(key)
|
||||||
|
);
|
||||||
|
|
||||||
if (checkIsReference(responseObject)) {
|
if (checkIsReference(responseObject)) {
|
||||||
return {
|
return {
|
||||||
key: key,
|
key: key,
|
||||||
label: key,
|
label,
|
||||||
|
statusCode: key,
|
||||||
body: (
|
body: (
|
||||||
<OpenAPIExample
|
<OpenAPIExample
|
||||||
example={getExampleFromReference(responseObject)}
|
example={getExampleFromReference(responseObject)}
|
||||||
@@ -57,24 +64,23 @@ export function OpenAPIResponseExample(props: {
|
|||||||
syntax="json"
|
syntax="json"
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
footer: description ? <Markdown source={description} /> : undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
|
if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
|
||||||
return {
|
return {
|
||||||
key: key,
|
key: key,
|
||||||
label: key,
|
label,
|
||||||
|
statusCode: key,
|
||||||
body: <OpenAPIEmptyExample />,
|
body: <OpenAPIEmptyExample />,
|
||||||
footer: description ? <Markdown source={description} /> : undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: key,
|
key: key,
|
||||||
label: key,
|
label,
|
||||||
|
statusCode: key,
|
||||||
body: <OpenAPIResponse context={context} content={responseObject.content} />,
|
body: <OpenAPIResponse context={context} content={responseObject.content} />,
|
||||||
footer: description ? <Markdown source={description} /> : undefined,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,11 +89,11 @@ export function OpenAPIResponseExample(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OpenAPITabs stateKey={createStateKey('response-example')} items={tabs}>
|
<OpenAPIResponseExampleContent
|
||||||
<StaticSection header={<OpenAPITabsList />} className="openapi-panel">
|
selectIcon={context.icons.chevronDown}
|
||||||
<OpenAPITabsPanels />
|
blockKey={context.blockKey}
|
||||||
</StaticSection>
|
items={tabs}
|
||||||
</OpenAPITabs>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,42 +112,30 @@ function OpenAPIResponse(props: {
|
|||||||
throw new Error('One media type is required');
|
throw new Error('One media type is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entries.length === 1) {
|
|
||||||
const [mediaType, mediaTypeObject] = firstEntry;
|
|
||||||
return (
|
|
||||||
<OpenAPIResponseMediaType
|
|
||||||
context={context}
|
|
||||||
mediaType={mediaType}
|
|
||||||
mediaTypeObject={mediaTypeObject}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tabs = entries.map((entry) => {
|
const tabs = entries.map((entry) => {
|
||||||
const [mediaType, mediaTypeObject] = entry;
|
const [mediaType, mediaTypeObject] = entry;
|
||||||
return {
|
return {
|
||||||
key: mediaType,
|
key: mediaType,
|
||||||
label: mediaType,
|
label: mediaType,
|
||||||
body: (
|
body: <></>,
|
||||||
<OpenAPIResponseMediaType
|
examples: getExamples({
|
||||||
context={context}
|
mediaTypeObject,
|
||||||
mediaType={mediaType}
|
mediaType,
|
||||||
mediaTypeObject={mediaTypeObject}
|
context,
|
||||||
/>
|
}),
|
||||||
),
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OpenAPITabs stateKey={createStateKey('response-media-types')} items={tabs}>
|
<OpenAPIResponseMediaTypeContent
|
||||||
<StaticSection header={<OpenAPITabsList />} className="openapi-response-media-types">
|
selectIcon={context.icons.chevronDown}
|
||||||
<OpenAPITabsPanels />
|
blockKey={context.blockKey}
|
||||||
</StaticSection>
|
items={tabs}
|
||||||
</OpenAPITabs>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function OpenAPIResponseMediaType(props: {
|
function getExamples(props: {
|
||||||
mediaTypeObject: OpenAPIV3.MediaTypeObject;
|
mediaTypeObject: OpenAPIV3.MediaTypeObject;
|
||||||
mediaType: string;
|
mediaType: string;
|
||||||
context: OpenAPIContext;
|
context: OpenAPIContext;
|
||||||
@@ -149,23 +143,8 @@ function OpenAPIResponseMediaType(props: {
|
|||||||
const { mediaTypeObject, mediaType } = props;
|
const { mediaTypeObject, mediaType } = props;
|
||||||
const examples = getExamplesFromMediaTypeObject({ mediaTypeObject, mediaType });
|
const examples = getExamplesFromMediaTypeObject({ mediaTypeObject, mediaType });
|
||||||
const syntax = getSyntaxFromMediaType(mediaType);
|
const syntax = getSyntaxFromMediaType(mediaType);
|
||||||
const firstExample = examples[0];
|
|
||||||
|
|
||||||
if (!firstExample) {
|
return examples.map((example) => {
|
||||||
return <OpenAPIEmptyExample />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (examples.length === 1) {
|
|
||||||
return (
|
|
||||||
<OpenAPIExample
|
|
||||||
example={firstExample.example}
|
|
||||||
context={props.context}
|
|
||||||
syntax={syntax}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tabs = examples.map((example) => {
|
|
||||||
return {
|
return {
|
||||||
key: example.key,
|
key: example.key,
|
||||||
label: example.example.summary || example.key,
|
label: example.example.summary || example.key,
|
||||||
@@ -174,17 +153,6 @@ function OpenAPIResponseMediaType(props: {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
|
||||||
<OpenAPITabs stateKey={createStateKey('response-media-type-examples')} items={tabs}>
|
|
||||||
<StaticSection
|
|
||||||
header={<OpenAPITabsList />}
|
|
||||||
className="openapi-response-media-type-examples"
|
|
||||||
>
|
|
||||||
<OpenAPITabsPanels />
|
|
||||||
</StaticSection>
|
|
||||||
</OpenAPITabs>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import type { Key } from 'react-aria';
|
||||||
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
||||||
|
import { StaticSection } from './StaticSection';
|
||||||
|
import { createStateKey, getStatusCodeClassName } from './utils';
|
||||||
|
|
||||||
|
type OpenAPIResponseExampleItem = OpenAPISelectItem & {
|
||||||
|
statusCode: string;
|
||||||
|
body: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the state of the response examples select.
|
||||||
|
*/
|
||||||
|
export function useResponseExamplesState(
|
||||||
|
blockKey: string | undefined,
|
||||||
|
initialKey: Key = 'default'
|
||||||
|
) {
|
||||||
|
return useSelectState(getResponseExampleStateKey(blockKey), initialKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OpenAPIResponseExampleContent(props: {
|
||||||
|
items: OpenAPIResponseExampleItem[];
|
||||||
|
blockKey?: string;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
const { blockKey, items, selectIcon } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StaticSection
|
||||||
|
header={
|
||||||
|
<OpenAPIResponseExampleHeader
|
||||||
|
selectIcon={selectIcon}
|
||||||
|
blockKey={blockKey}
|
||||||
|
items={items}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
className="openapi-response-examples"
|
||||||
|
>
|
||||||
|
<OpenAPIResponseExampleBody blockKey={blockKey} items={items} />
|
||||||
|
</StaticSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function OpenAPIResponseExampleHeader(props: {
|
||||||
|
items: OpenAPIResponseExampleItem[];
|
||||||
|
blockKey?: string;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
const { items, blockKey, selectIcon } = props;
|
||||||
|
|
||||||
|
if (items.length === 1) {
|
||||||
|
const item = items[0];
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="openapi-response-examples-statuscode-title">
|
||||||
|
<span
|
||||||
|
className={clsx(
|
||||||
|
'openapi-statuscode',
|
||||||
|
`openapi-statuscode-${getStatusCodeClassName(item.statusCode)}`,
|
||||||
|
'openapi-response-examples-statuscode'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{item.statusCode}
|
||||||
|
</span>
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OpenAPISelect
|
||||||
|
items={items}
|
||||||
|
icon={selectIcon}
|
||||||
|
stateKey={getResponseExampleStateKey(blockKey)}
|
||||||
|
placement="bottom start"
|
||||||
|
>
|
||||||
|
{items.map((item) => (
|
||||||
|
<OpenAPISelectItem key={item.key} id={item.key} value={item}>
|
||||||
|
<span
|
||||||
|
className={clsx(
|
||||||
|
'openapi-statuscode',
|
||||||
|
`openapi-statuscode-${getStatusCodeClassName(item.statusCode)}`,
|
||||||
|
'openapi-response-examples-statuscode'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{item.statusCode}
|
||||||
|
</span>
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</OpenAPISelectItem>
|
||||||
|
))}
|
||||||
|
</OpenAPISelect>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function OpenAPIResponseExampleBody(props: {
|
||||||
|
items: OpenAPIResponseExampleItem[];
|
||||||
|
blockKey?: string;
|
||||||
|
}) {
|
||||||
|
const { blockKey, items } = props;
|
||||||
|
const state = useResponseExamplesState(blockKey, items[0]?.key);
|
||||||
|
|
||||||
|
const selectedItem = items.find((item) => item.key === state.key) ?? items[0];
|
||||||
|
|
||||||
|
if (!selectedItem) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className="openapi-response-examples-panel">{selectedItem.body}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the state key for the response examples.
|
||||||
|
*/
|
||||||
|
function getResponseExampleStateKey(blockKey: string | undefined) {
|
||||||
|
return createStateKey('openapi-responses', blockKey);
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
'use client';
|
||||||
|
import type { Key } from 'react-aria';
|
||||||
|
import { OpenAPIEmptyExample } from './OpenAPIExample';
|
||||||
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
||||||
|
import { StaticSection } from './StaticSection';
|
||||||
|
import { createStateKey } from './utils';
|
||||||
|
|
||||||
|
type OpenAPIResponseMediaTypeItem = OpenAPISelectItem & {
|
||||||
|
body: React.ReactNode;
|
||||||
|
examples?: OpenAPIResponseMediaTypeItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the state of the response examples select.
|
||||||
|
*/
|
||||||
|
export function useResponseMediaTypesState(
|
||||||
|
blockKey: string | undefined,
|
||||||
|
initialKey: Key = 'default'
|
||||||
|
) {
|
||||||
|
return useSelectState(getResponseMediaTypeStateKey(blockKey), initialKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useResponseMediaTypeExamplesState(
|
||||||
|
blockKey: string | undefined,
|
||||||
|
initialKey: Key = 'default'
|
||||||
|
) {
|
||||||
|
return useSelectState(getResponseMediaTypeExamplesStateKey(blockKey), initialKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OpenAPIResponseMediaTypeContent(props: {
|
||||||
|
items: OpenAPIResponseMediaTypeItem[];
|
||||||
|
blockKey?: string;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
const { blockKey, items, selectIcon } = props;
|
||||||
|
const state = useResponseMediaTypesState(blockKey, items[0]?.key);
|
||||||
|
|
||||||
|
const examples = items.find((item) => item.key === state.key)?.examples ?? [];
|
||||||
|
|
||||||
|
if (!items.length && !examples.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StaticSection
|
||||||
|
footer={
|
||||||
|
items.length > 1 || examples.length > 1 ? (
|
||||||
|
<OpenAPIResponseMediaTypeFooter
|
||||||
|
blockKey={blockKey}
|
||||||
|
items={items}
|
||||||
|
examples={examples}
|
||||||
|
selectIcon={selectIcon}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
className="openapi-response-media-types-examples"
|
||||||
|
>
|
||||||
|
<OpenAPIResponseMediaTypeBody blockKey={blockKey} items={items} examples={examples} />
|
||||||
|
</StaticSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function OpenAPIResponseMediaTypeFooter(props: {
|
||||||
|
items: OpenAPIResponseMediaTypeItem[];
|
||||||
|
examples?: OpenAPIResponseMediaTypeItem[];
|
||||||
|
blockKey?: string;
|
||||||
|
selectIcon?: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
const { items, examples, blockKey, selectIcon } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{items.length > 1 && (
|
||||||
|
<OpenAPISelect
|
||||||
|
icon={selectIcon}
|
||||||
|
items={items}
|
||||||
|
stateKey={getResponseMediaTypeStateKey(blockKey)}
|
||||||
|
placement="bottom start"
|
||||||
|
>
|
||||||
|
{items.map((item) => (
|
||||||
|
<OpenAPISelectItem key={item.key} id={item.key} value={item}>
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</OpenAPISelectItem>
|
||||||
|
))}
|
||||||
|
</OpenAPISelect>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{examples && examples.length > 1 ? (
|
||||||
|
<OpenAPISelect
|
||||||
|
icon={selectIcon}
|
||||||
|
items={examples}
|
||||||
|
stateKey={getResponseMediaTypeExamplesStateKey(blockKey)}
|
||||||
|
placement="bottom start"
|
||||||
|
>
|
||||||
|
{examples.map((example) => (
|
||||||
|
<OpenAPISelectItem key={example.key} id={example.key} value={example}>
|
||||||
|
<span>{example.label}</span>
|
||||||
|
</OpenAPISelectItem>
|
||||||
|
))}
|
||||||
|
</OpenAPISelect>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function OpenAPIResponseMediaTypeBody(props: {
|
||||||
|
items: OpenAPIResponseMediaTypeItem[];
|
||||||
|
examples?: OpenAPIResponseMediaTypeItem[];
|
||||||
|
blockKey?: string;
|
||||||
|
}) {
|
||||||
|
const { blockKey, items, examples } = props;
|
||||||
|
const state = useResponseMediaTypesState(blockKey, items[0]?.key);
|
||||||
|
|
||||||
|
const selectedItem = items.find((item) => item.key === state.key) ?? items[0];
|
||||||
|
|
||||||
|
const exampleState = useResponseMediaTypeExamplesState(
|
||||||
|
blockKey,
|
||||||
|
selectedItem?.examples?.[0]?.key
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!selectedItem) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (examples) {
|
||||||
|
const selectedExample =
|
||||||
|
examples.find((example) => example.key === exampleState.key) ?? examples[0];
|
||||||
|
|
||||||
|
if (!selectedExample) {
|
||||||
|
return <OpenAPIEmptyExample />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedExample.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedItem.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the state key for the response media types.
|
||||||
|
*/
|
||||||
|
function getResponseMediaTypeStateKey(blockKey: string | undefined) {
|
||||||
|
return createStateKey('response-media-types', blockKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResponseMediaTypeExamplesStateKey(blockKey: string | undefined) {
|
||||||
|
return createStateKey('response-media-types-examples', blockKey);
|
||||||
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import type { OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
||||||
|
import clsx from 'clsx';
|
||||||
import { Markdown } from './Markdown';
|
import { Markdown } from './Markdown';
|
||||||
import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
|
import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
|
||||||
import { OpenAPIResponse } from './OpenAPIResponse';
|
import { OpenAPIResponse } from './OpenAPIResponse';
|
||||||
|
import { useResponseExamplesState } from './OpenAPIResponseExampleContent';
|
||||||
import { StaticSection } from './StaticSection';
|
import { StaticSection } from './StaticSection';
|
||||||
import type { OpenAPIClientContext } from './types';
|
import type { OpenAPIClientContext } from './types';
|
||||||
|
import { createStateKey, getStatusCodeClassName, getStatusCodeDefaultLabel } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an interactive response body.
|
* Display an interactive response body.
|
||||||
@@ -14,12 +19,7 @@ export function OpenAPIResponses(props: {
|
|||||||
}) {
|
}) {
|
||||||
const { responses, context } = props;
|
const { responses, context } = props;
|
||||||
|
|
||||||
return (
|
const groups = Object.entries(responses).map(
|
||||||
<StaticSection header="Responses" className="openapi-responses">
|
|
||||||
<OpenAPIDisclosureGroup
|
|
||||||
allowsMultipleExpanded
|
|
||||||
icon={context.icons.chevronRight}
|
|
||||||
groups={Object.entries(responses).map(
|
|
||||||
([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
|
([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
|
||||||
const tabs = (() => {
|
const tabs = (() => {
|
||||||
// If there is no content, but there are headers, we need to show the headers
|
// If there is no content, but there are headers, we need to show the headers
|
||||||
@@ -30,7 +30,8 @@ export function OpenAPIResponses(props: {
|
|||||||
) {
|
) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 'default',
|
key: 'default',
|
||||||
|
label: '',
|
||||||
body: (
|
body: (
|
||||||
<OpenAPIResponse
|
<OpenAPIResponse
|
||||||
response={response}
|
response={response}
|
||||||
@@ -42,9 +43,8 @@ export function OpenAPIResponses(props: {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.entries(response.content ?? {}).map(
|
return Object.entries(response.content ?? {}).map(([contentType, mediaType]) => ({
|
||||||
([contentType, mediaType]) => ({
|
key: contentType,
|
||||||
id: contentType,
|
|
||||||
label: contentType,
|
label: contentType,
|
||||||
body: (
|
body: (
|
||||||
<OpenAPIResponse
|
<OpenAPIResponse
|
||||||
@@ -53,17 +53,21 @@ export function OpenAPIResponses(props: {
|
|||||||
context={context}
|
context={context}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const description = response.description;
|
const description = response.description;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: statusCode,
|
key: statusCode,
|
||||||
label: (
|
label: (
|
||||||
<div className="openapi-response-tab-content">
|
<div className="openapi-response-tab-content">
|
||||||
<span className="openapi-response-statuscode">
|
<span
|
||||||
|
className={clsx(
|
||||||
|
'openapi-statuscode',
|
||||||
|
`openapi-statuscode-${getStatusCodeClassName(statusCode)}`
|
||||||
|
)}
|
||||||
|
>
|
||||||
{statusCode}
|
{statusCode}
|
||||||
</span>
|
</span>
|
||||||
{description ? (
|
{description ? (
|
||||||
@@ -71,13 +75,29 @@ export function OpenAPIResponses(props: {
|
|||||||
source={description}
|
source={description}
|
||||||
className="openapi-response-description"
|
className="openapi-response-description"
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : (
|
||||||
|
getStatusCodeDefaultLabel(statusCode)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
tabs,
|
tabs,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)}
|
);
|
||||||
|
|
||||||
|
const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StaticSection header="Responses" className="openapi-responses">
|
||||||
|
<OpenAPIDisclosureGroup
|
||||||
|
icon={context.icons.chevronRight}
|
||||||
|
expandedKeys={state.key ? new Set([state.key]) : new Set()}
|
||||||
|
onExpandedChange={(keys) => {
|
||||||
|
const key = keys.values().next().value ?? null;
|
||||||
|
state.setKey(key);
|
||||||
|
}}
|
||||||
|
groups={groups}
|
||||||
|
selectStateKey={createStateKey('response-media-types', context.blockKey)}
|
||||||
/>
|
/>
|
||||||
</StaticSection>
|
</StaticSection>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ function OpenAPISchemaProperty(props: {
|
|||||||
const properties = getSchemaProperties(schema);
|
const properties = getSchemaProperties(schema);
|
||||||
if (properties?.length) {
|
if (properties?.length) {
|
||||||
return (
|
return (
|
||||||
<OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
|
<OpenAPIDisclosure
|
||||||
|
icon={context.icons.plus}
|
||||||
|
label={(isExpanded) => getDisclosureLabel(schema, isExpanded)}
|
||||||
|
>
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
properties={properties}
|
properties={properties}
|
||||||
circularRefs={circularRefs}
|
circularRefs={circularRefs}
|
||||||
@@ -208,7 +211,10 @@ function OpenAPISchemaAlternative(props: {
|
|||||||
{description ? (
|
{description ? (
|
||||||
<Markdown source={description} className="openapi-schema-description" />
|
<Markdown source={description} className="openapi-schema-description" />
|
||||||
) : null}
|
) : null}
|
||||||
<OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
|
<OpenAPIDisclosure
|
||||||
|
icon={context.icons.plus}
|
||||||
|
label={(isExpanded) => getDisclosureLabel(schema, isExpanded)}
|
||||||
|
>
|
||||||
{properties?.length ? (
|
{properties?.length ? (
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
properties={properties}
|
properties={properties}
|
||||||
@@ -502,19 +508,21 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisclosureLabel(schema: OpenAPIV3.SchemaObject): string {
|
function getDisclosureLabel(schema: OpenAPIV3.SchemaObject, isExpanded: boolean) {
|
||||||
|
let label: string;
|
||||||
if (schema.type === 'array' && !!schema.items) {
|
if (schema.type === 'array' && !!schema.items) {
|
||||||
if (schema.items.oneOf) {
|
if (schema.items.oneOf) {
|
||||||
return 'available items';
|
label = 'available items';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to "child attributes" for enums and objects
|
// Fallback to "child attributes" for enums and objects
|
||||||
if (schema.items.enum || schema.items.type === 'object') {
|
else if (schema.items.enum || schema.items.type === 'object') {
|
||||||
return 'child attributes';
|
label = 'child attributes';
|
||||||
|
} else {
|
||||||
|
label = schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label = schema.title || 'child attributes';
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
return `${isExpanded ? 'Hide' : 'Show'} ${label}`;
|
||||||
}
|
|
||||||
|
|
||||||
return schema.title || 'child attributes';
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type {
|
|||||||
OpenAPIOperationData,
|
OpenAPIOperationData,
|
||||||
OpenAPISecurityWithRequired,
|
OpenAPISecurityWithRequired,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { resolveDescription } from './utils';
|
import { createStateKey, resolveDescription } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Present securities authorization that can be used for this operation.
|
* Present securities authorization that can be used for this operation.
|
||||||
@@ -24,9 +24,11 @@ export function OpenAPISecurities(props: {
|
|||||||
return (
|
return (
|
||||||
<InteractiveSection
|
<InteractiveSection
|
||||||
header="Authorizations"
|
header="Authorizations"
|
||||||
|
stateKey={createStateKey('securities', context.blockKey)}
|
||||||
toggeable
|
toggeable
|
||||||
defaultOpened={false}
|
defaultOpened={false}
|
||||||
toggleIcon={context.icons.chevronRight}
|
toggleIcon={context.icons.chevronRight}
|
||||||
|
selectIcon={context.icons.chevronDown}
|
||||||
className="openapi-securities"
|
className="openapi-securities"
|
||||||
tabs={securities.map(([key, security]) => {
|
tabs={securities.map(([key, security]) => {
|
||||||
const description = resolveDescription(security);
|
const description = resolveDescription(security);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
type Key,
|
type Key,
|
||||||
@@ -13,38 +14,63 @@ import {
|
|||||||
type SelectProps,
|
type SelectProps,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from 'react-aria-components';
|
} from 'react-aria-components';
|
||||||
|
import { useStore } from 'zustand';
|
||||||
|
import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
|
||||||
|
|
||||||
export type OpenAPISelectItem = {
|
export type OpenAPISelectItem = {
|
||||||
key: Key;
|
key: Key;
|
||||||
label: string;
|
label: string | React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OpenAPISelectProps<T extends OpenAPISelectItem> extends Omit<SelectProps<T>, 'children'> {
|
interface OpenAPISelectProps<T extends OpenAPISelectItem> extends Omit<SelectProps<T>, 'children'> {
|
||||||
items: T[];
|
items: T[];
|
||||||
children: React.ReactNode | ((item: T) => React.ReactNode);
|
children: React.ReactNode | ((item: T) => React.ReactNode);
|
||||||
selectedKey?: Key;
|
|
||||||
onChange?: (key: string | number) => void;
|
|
||||||
placement?: PopoverProps['placement'];
|
placement?: PopoverProps['placement'];
|
||||||
|
stateKey?: string;
|
||||||
|
/**
|
||||||
|
* Icon to display in the select button.
|
||||||
|
*/
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSelectState(stateKey = 'select-state', initialKey?: Key) {
|
||||||
|
const store = useStore(getOrCreateStoreByKey(stateKey, initialKey));
|
||||||
|
return {
|
||||||
|
key: store.key,
|
||||||
|
setKey: useCallback((key: Key | null) => store.setKey(key), [store.setKey]),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenAPISelect<T extends OpenAPISelectItem>(props: OpenAPISelectProps<T>) {
|
export function OpenAPISelect<T extends OpenAPISelectItem>(props: OpenAPISelectProps<T>) {
|
||||||
const { items, children, className, placement } = props;
|
const {
|
||||||
|
icon = '▼',
|
||||||
|
items,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
placement,
|
||||||
|
stateKey,
|
||||||
|
selectedKey,
|
||||||
|
onSelectionChange,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const state = useSelectState(stateKey, items[0]?.key);
|
||||||
|
|
||||||
|
const selected = items.find((item) => item.key === state.key) || items[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select {...props} className={clsx('openapi-select', className)}>
|
<Select
|
||||||
|
aria-label="OpenAPI Select"
|
||||||
|
{...props}
|
||||||
|
selectedKey={selectedKey || selected?.key}
|
||||||
|
onSelectionChange={(key) => {
|
||||||
|
onSelectionChange?.(key);
|
||||||
|
state.setKey(key);
|
||||||
|
}}
|
||||||
|
className={clsx('openapi-select', className)}
|
||||||
|
>
|
||||||
<Button>
|
<Button>
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
<span aria-hidden="true">
|
{icon}
|
||||||
<svg
|
|
||||||
className="gb-icon"
|
|
||||||
style={{
|
|
||||||
maskImage:
|
|
||||||
"url('https://ka-p.fontawesome.com/releases/v6.6.0/svgs/regular/chevron-down.svg?v=2&token=a463935e93')",
|
|
||||||
maskRepeat: 'no-repeat',
|
|
||||||
maskPosition: 'center center',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</Button>
|
</Button>
|
||||||
<Popover placement={placement} className="openapi-select-popover">
|
<Popover placement={placement} className="openapi-select-popover">
|
||||||
<ListBox className="openapi-select-listbox" items={items}>
|
<ListBox className="openapi-select-listbox" items={items}>
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
|
|||||||
key="body"
|
key="body"
|
||||||
requestBody={operation.requestBody}
|
requestBody={operation.requestBody}
|
||||||
context={context}
|
context={context}
|
||||||
|
data={data}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{operation.responses ? (
|
{operation.responses ? (
|
||||||
|
|||||||
@@ -42,18 +42,50 @@ export const SectionBody = forwardRef(function SectionBody(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function SectionFooter(props: ComponentPropsWithoutRef<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
className={clsx(
|
||||||
|
'openapi-section-footer',
|
||||||
|
props.className && `${props.className}-footer`
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SectionFooterContent(props: ComponentPropsWithoutRef<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
className={clsx(
|
||||||
|
'openapi-section-footer-content',
|
||||||
|
props.className && `${props.className}-footer-content`
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function StaticSection(props: {
|
export function StaticSection(props: {
|
||||||
className: string;
|
className: string;
|
||||||
header: React.ReactNode;
|
header?: React.ReactNode;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
footer?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { className, header, children } = props;
|
const { className, header, children, footer } = props;
|
||||||
return (
|
return (
|
||||||
<Section className={className}>
|
<Section className={className}>
|
||||||
|
{header ? (
|
||||||
<SectionHeader className={className}>
|
<SectionHeader className={className}>
|
||||||
<SectionHeaderContent className={className}>{header}</SectionHeaderContent>
|
<SectionHeaderContent className={className}>{header}</SectionHeaderContent>
|
||||||
</SectionHeader>
|
</SectionHeader>
|
||||||
|
) : null}
|
||||||
<SectionBody className={className}>{children}</SectionBody>
|
<SectionBody className={className}>{children}</SectionBody>
|
||||||
|
{footer ? (
|
||||||
|
<SectionFooter className={className}>
|
||||||
|
<SectionFooterContent className={className}>{footer}</SectionFooterContent>
|
||||||
|
</SectionFooter>
|
||||||
|
) : null}
|
||||||
</Section>
|
</Section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -413,13 +413,15 @@ describe('python code sample generator', () => {
|
|||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
key: 'value',
|
key: 'value',
|
||||||
|
truethy: true,
|
||||||
|
falsey: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const output = generator?.generate(input);
|
const output = generator?.generate(input);
|
||||||
|
|
||||||
expect(output).toBe(
|
expect(output).toBe(
|
||||||
'import requests\n\nresponse = requests.get(\n "https://example.com/path",\n headers={"Content-Type":"application/json"},\n data={"key":"value"}\n)\n\ndata = response.json()'
|
'import requests\n\nresponse = requests.get(\n "https://example.com/path",\n headers={"Content-Type":"application/json"},\n data=json.dumps({"key":"value","truethy":True,"falsey":False})\n)\n\ndata = response.json()'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
isFormData,
|
isFormData,
|
||||||
isFormUrlEncoded,
|
isFormUrlEncoded,
|
||||||
isGraphQL,
|
isGraphQL,
|
||||||
|
isJSON,
|
||||||
isPDF,
|
isPDF,
|
||||||
isPlainObject,
|
isPlainObject,
|
||||||
isText,
|
isText,
|
||||||
@@ -26,6 +27,52 @@ export interface CodeSampleGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const codeSampleGenerators: CodeSampleGenerator[] = [
|
export const codeSampleGenerators: CodeSampleGenerator[] = [
|
||||||
|
{
|
||||||
|
id: 'http',
|
||||||
|
label: 'HTTP',
|
||||||
|
syntax: 'bash',
|
||||||
|
generate: ({ method, url, headers = {}, body }: CodeSampleInput) => {
|
||||||
|
const { host, path } = parseHostAndPath(url);
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
// if we had a body add a content length header
|
||||||
|
const bodyContent = body ? stringifyOpenAPI(body) : '';
|
||||||
|
// handle unicode chars with a text encoder
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
const bodyString = BodyGenerators.getHTTPBody(body, headers);
|
||||||
|
|
||||||
|
if (bodyString) {
|
||||||
|
body = bodyString;
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
...headers,
|
||||||
|
'Content-Length': encoder.encode(bodyContent).length.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!headers.hasOwnProperty('Accept')) {
|
||||||
|
headers.Accept = '*/*';
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerString = headers
|
||||||
|
? `${Object.entries(headers)
|
||||||
|
.map(([key, value]) =>
|
||||||
|
key.toLowerCase() !== 'host' ? `${key}: ${value}` : ''
|
||||||
|
)
|
||||||
|
.join('\n')}\n`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const bodyString = body ? `\n${body}` : '';
|
||||||
|
|
||||||
|
const httpRequest = `${method.toUpperCase()} ${decodeURI(path)} HTTP/1.1
|
||||||
|
Host: ${host}
|
||||||
|
${headerString}${bodyString}`;
|
||||||
|
|
||||||
|
return httpRequest;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'curl',
|
id: 'curl',
|
||||||
label: 'cURL',
|
label: 'cURL',
|
||||||
@@ -127,11 +174,14 @@ export const codeSampleGenerators: CodeSampleGenerator[] = [
|
|||||||
code += indent(`headers=${stringifyOpenAPI(headers)},\n`, 4);
|
code += indent(`headers=${stringifyOpenAPI(headers)},\n`, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contentType = headers?.['Content-Type'];
|
||||||
if (body) {
|
if (body) {
|
||||||
if (body === 'files') {
|
if (body === 'files') {
|
||||||
code += indent(`files=${body}\n`, 4);
|
code += indent(`files=${body}\n`, 4);
|
||||||
|
} else if (isJSON(contentType)) {
|
||||||
|
code += indent(`data=json.dumps(${body})\n`, 4);
|
||||||
} else {
|
} else {
|
||||||
code += indent(`data=${stringifyOpenAPI(body)}\n`, 4);
|
code += indent(`data=${body}\n`, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,52 +190,6 @@ export const codeSampleGenerators: CodeSampleGenerator[] = [
|
|||||||
return code;
|
return code;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'http',
|
|
||||||
label: 'HTTP',
|
|
||||||
syntax: 'bash',
|
|
||||||
generate: ({ method, url, headers = {}, body }: CodeSampleInput) => {
|
|
||||||
const { host, path } = parseHostAndPath(url);
|
|
||||||
|
|
||||||
if (body) {
|
|
||||||
// if we had a body add a content length header
|
|
||||||
const bodyContent = body ? stringifyOpenAPI(body) : '';
|
|
||||||
// handle unicode chars with a text encoder
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
|
|
||||||
const bodyString = BodyGenerators.getHTTPBody(body, headers);
|
|
||||||
|
|
||||||
if (bodyString) {
|
|
||||||
body = bodyString;
|
|
||||||
}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
...headers,
|
|
||||||
'Content-Length': encoder.encode(bodyContent).length.toString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!headers.hasOwnProperty('Accept')) {
|
|
||||||
headers.Accept = '*/*';
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerString = headers
|
|
||||||
? `${Object.entries(headers)
|
|
||||||
.map(([key, value]) =>
|
|
||||||
key.toLowerCase() !== 'host' ? `${key}: ${value}` : ''
|
|
||||||
)
|
|
||||||
.join('\n')}\n`
|
|
||||||
: '';
|
|
||||||
|
|
||||||
const bodyString = body ? `\n${body}` : '';
|
|
||||||
|
|
||||||
const httpRequest = `${method.toUpperCase()} ${decodeURI(path)} HTTP/1.1
|
|
||||||
Host: ${host}
|
|
||||||
${headerString}${bodyString}`;
|
|
||||||
|
|
||||||
return httpRequest;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function indent(code: string, spaces: number) {
|
function indent(code: string, spaces: number) {
|
||||||
@@ -343,18 +347,27 @@ const BodyGenerators = {
|
|||||||
}
|
}
|
||||||
code += '}\n\n';
|
code += '}\n\n';
|
||||||
body = 'files';
|
body = 'files';
|
||||||
}
|
} else if (isPDF(contentType)) {
|
||||||
|
|
||||||
if (isPDF(contentType)) {
|
|
||||||
code += 'files = {\n';
|
code += 'files = {\n';
|
||||||
code += `${indent(`"file": "${body}",`, 4)}\n`;
|
code += `${indent(`"file": "${body}",`, 4)}\n`;
|
||||||
code += '}\n\n';
|
code += '}\n\n';
|
||||||
body = 'files';
|
body = 'files';
|
||||||
}
|
} else if (isXML(contentType)) {
|
||||||
|
|
||||||
if (isXML(contentType)) {
|
|
||||||
// Convert JSON to XML if needed
|
// Convert JSON to XML if needed
|
||||||
body = convertBodyToXML(body);
|
body = JSON.stringify(convertBodyToXML(body));
|
||||||
|
} else {
|
||||||
|
body = stringifyOpenAPI(body, (_key, value) => {
|
||||||
|
switch (value) {
|
||||||
|
case true:
|
||||||
|
return '$$__TRUE__$$';
|
||||||
|
case false:
|
||||||
|
return '$$__FALSE__$$';
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.replaceAll('"$$__TRUE__$$"', 'True')
|
||||||
|
.replaceAll('"$$__FALSE__$$"', 'False');
|
||||||
}
|
}
|
||||||
|
|
||||||
return { body, code, headers };
|
return { body, code, headers };
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { createStore } from 'zustand';
|
import { createStore } from 'zustand';
|
||||||
|
|
||||||
type Key = string | number;
|
type Key = string | number;
|
||||||
@@ -10,7 +8,7 @@ type State = {
|
|||||||
|
|
||||||
type Actions = { setKey: (key: Key | null) => void };
|
type Actions = { setKey: (key: Key | null) => void };
|
||||||
|
|
||||||
type Store = State & Actions;
|
export type Store = State & Actions;
|
||||||
|
|
||||||
const createStateStore = (initial?: Key) => {
|
const createStateStore = (initial?: Key) => {
|
||||||
return createStore<Store>()((set) => ({
|
return createStore<Store>()((set) => ({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { OpenAPISchema } from '@gitbook/openapi-parser';
|
import type { OpenAPISchema } from '@gitbook/openapi-parser';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { OpenAPIDisclosureGroup } from '../OpenAPIDisclosureGroup';
|
import { OpenAPIDisclosure } from '../OpenAPIDisclosure';
|
||||||
import { OpenAPIExample, getExampleFromSchema } from '../OpenAPIExample';
|
import { OpenAPIExample, getExampleFromSchema } from '../OpenAPIExample';
|
||||||
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
||||||
import { Section, SectionBody, StaticSection } from '../StaticSection';
|
import { Section, SectionBody, StaticSection } from '../StaticSection';
|
||||||
@@ -72,33 +72,22 @@ export function OpenAPISchemas(props: {
|
|||||||
// If there are multiple schemas, we use a disclosure group to show them all.
|
// If there are multiple schemas, we use a disclosure group to show them all.
|
||||||
return (
|
return (
|
||||||
<div className={clsx('openapi-schemas', className)}>
|
<div className={clsx('openapi-schemas', className)}>
|
||||||
<OpenAPIDisclosureGroup
|
{schemas.map(({ name, schema }) => {
|
||||||
allowsMultipleExpanded
|
return (
|
||||||
|
<OpenAPIDisclosure
|
||||||
|
className="openapi-schemas-disclosure"
|
||||||
|
key={name}
|
||||||
icon={context.icons.chevronRight}
|
icon={context.icons.chevronRight}
|
||||||
groups={schemas.map(({ name, schema }) => ({
|
label={name}
|
||||||
id: name,
|
>
|
||||||
label: (
|
|
||||||
<div className="openapi-response-tab-content" key={`model-${name}`}>
|
|
||||||
<span className="openapi-response-statuscode">{name}</span>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
id: 'model',
|
|
||||||
body: (
|
|
||||||
<Section className="openapi-section-schemas">
|
<Section className="openapi-section-schemas">
|
||||||
<SectionBody>
|
<SectionBody>
|
||||||
<OpenAPIRootSchema
|
<OpenAPIRootSchema schema={schema} context={clientContext} />
|
||||||
schema={schema}
|
|
||||||
context={clientContext}
|
|
||||||
/>
|
|
||||||
</SectionBody>
|
</SectionBody>
|
||||||
</Section>
|
</Section>
|
||||||
),
|
</OpenAPIDisclosure>
|
||||||
},
|
);
|
||||||
],
|
})}
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,25 @@
|
|||||||
/**
|
/**
|
||||||
* Stringify an OpenAPI object. Same API as JSON.stringify.
|
* Stringify an OpenAPI object. Same API as JSON.stringify.
|
||||||
*/
|
*/
|
||||||
export function stringifyOpenAPI(body: unknown, _?: null, indent?: number): string {
|
export function stringifyOpenAPI(
|
||||||
|
value: any,
|
||||||
|
replacer?: ((this: any, key: string, value: any) => any) | null,
|
||||||
|
space?: string | number
|
||||||
|
): string {
|
||||||
return JSON.stringify(
|
return JSON.stringify(
|
||||||
body,
|
value,
|
||||||
(key, value) => {
|
(key, value) => {
|
||||||
// Ignore internal keys
|
// Ignore internal keys
|
||||||
if (key.startsWith('x-gitbook-')) {
|
if (key.startsWith('x-gitbook-')) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (replacer) {
|
||||||
|
return replacer(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
indent
|
space
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,3 +149,65 @@ function shouldDisplayExample(schema: OpenAPIV3.SchemaObject): boolean {
|
|||||||
Object.keys(schema.example).length > 0)
|
Object.keys(schema.example).length > 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the class name for a status code.
|
||||||
|
* 1xx: informational
|
||||||
|
* 2xx: success
|
||||||
|
* 3xx: redirect
|
||||||
|
* 4xx, 5xx: error
|
||||||
|
*/
|
||||||
|
export function getStatusCodeClassName(statusCode: number | string): string {
|
||||||
|
const category = getStatusCodeCategory(statusCode);
|
||||||
|
switch (category) {
|
||||||
|
case 1:
|
||||||
|
return 'informational';
|
||||||
|
case 2:
|
||||||
|
return 'success';
|
||||||
|
case 3:
|
||||||
|
return 'redirect';
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
return 'error';
|
||||||
|
default:
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a default label for a status code.
|
||||||
|
* This is used when there is no label provided in the OpenAPI spec.
|
||||||
|
* 1xx: Information
|
||||||
|
* 2xx: Success
|
||||||
|
* 3xx: Redirect
|
||||||
|
* 4xx, 5xx: Error
|
||||||
|
*/
|
||||||
|
export function getStatusCodeDefaultLabel(statusCode: number | string): string {
|
||||||
|
const category = getStatusCodeCategory(statusCode);
|
||||||
|
switch (category) {
|
||||||
|
case 1:
|
||||||
|
return 'Information';
|
||||||
|
case 2:
|
||||||
|
return 'Success';
|
||||||
|
case 3:
|
||||||
|
return 'Redirect';
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
return 'Error';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusCodeCategory(statusCode: number | string): number | string {
|
||||||
|
const code = typeof statusCode === 'string' ? Number.parseInt(statusCode, 10) : statusCode;
|
||||||
|
|
||||||
|
if (Number.isNaN(code) || code < 100 || code >= 600) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the category of the status code based on the first digit
|
||||||
|
const category = Math.floor(code / 100);
|
||||||
|
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user