mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-11-13 07:31:14 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2dca38796d |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Bump Next.js to 16.4.3, keeping the dev-mode OOM patch.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Preconnect each asset origin once, skip same-origin icon URLs, and open the fonts preconnect in CORS mode so font requests can reuse it.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Stop caching failed searches, so a rate-limited or failing search is retried on the next query instead of being served from cache for 15 minutes.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Declare the Tailwind layer order in each component stylesheet, so a route whose first stylesheet is one of them still puts `base` before `components` and preflight does not strip their padding and borders.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Forward the visitor's user agent on ask and Assistant calls so questions are classified by who asked.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Load the inline expression runtime only on pages whose code blocks or text use expressions, so other pages ship less JavaScript.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/react-contentkit": patch
|
||||
---
|
||||
|
||||
Load a webframe only once it is near the viewport. A page can hold hundreds of them inside collapsed expandables, and loading every one on mount held up the first paint.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Pack the class lists that every block, heading anchor and table cell repeats into shared CSS classes, and carry a table cell's width once as a custom property instead of spelling it out as both width and min-width, so a large page carries far less markup.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Split llms-full.txt into parts by size so large sites no longer fail with "content too large"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Follow site and space redirects when the MCP getPage tool resolves a page URL.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix the MCP `getPage` tool returning "Page not found" for the Markdown URL of a page (`<page>.md`).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Add a search input to filter models by name on OpenAPI models pages.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Let analytics tools like GA4 track outbound link clicks by using native link navigation.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Set `Partitioned` on visitor cookies set inside an iframe so authenticated embeds work cross-site.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix encoded or non-normalized links on proxied sites redirecting to the internal proxy path instead of the public URL.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Support a secondary brand colour for secondary buttons and `$secondary` text, background, icon and tag colours. Sites without one render as before.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Remove the ChatGPT-specific plain text response for Markdown and llms.txt routes; these now always serve `text/markdown`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Resolve the published content with the full URL in a single lookup and always send the visitor country.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Resolve dark-mode image URLs in published Markdown.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Keep lists, paragraphs and code blocks as HTML in Updates RSS feeds, instead of running all the text together
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/openapi-parser": patch
|
||||
---
|
||||
|
||||
Bump @scalar/openapi-parser to 0.29 so valid OpenAPI 3.2 documents no longer report false validation errors.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Only apply a site preview customization override to the section or variant it was made for.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Render soft line breaks in paragraphs that contain buttons.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix visitors being logged out right after signing in on sites with a logout link in the header.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Truncate long tab titles one by one and show the selected tab's full title, instead of hiding tabs behind a "…" menu
|
||||
@@ -87,5 +87,3 @@ The site must be [published publicly](https://gitbook.com/docs/published-documen
|
||||
## License
|
||||
|
||||
The renderer is distributed under the [GNU GPLv3 License](https://github.com/GitbookIO/gitbook/blob/main/LICENSE). If you distribute the code, you must keep the source code public. To use it in a private repository, you need a [commercial license](https://www.gitbook.com/pricing).
|
||||
|
||||
The [`@gitbook/embed`](https://github.com/GitbookIO/gitbook/blob/main/packages/embed) package is distributed under the [Apache License 2.0](https://github.com/GitbookIO/gitbook/blob/main/packages/embed/LICENSE). Contributions to it are made under the same license.
|
||||
|
||||
@@ -25,8 +25,6 @@ jobs:
|
||||
with:
|
||||
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
||||
fetch-depth: 0
|
||||
# Otherwise git pushes with GITHUB_TOKEN instead of the PAT, and the release PR never triggers Preview
|
||||
persist-credentials: false
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
@@ -124,8 +124,6 @@ If you plan to distribute the code, you must make the source code public to comp
|
||||
|
||||
See `LICENSE` for more information.
|
||||
|
||||
The [`@gitbook/embed`](packages/embed) package is an exception: it is distributed under the [Apache License 2.0](packages/embed/LICENSE), so it can be used in proprietary applications.
|
||||
|
||||
## Badges
|
||||
|
||||
<p align="left">
|
||||
@@ -163,4 +161,4 @@ GitBook wouldn't be possible without these projects:
|
||||
|
||||
## Legacy GitBook (Deprecated)
|
||||
|
||||
Our previous version of GitBook and it's CLI tool are now deprecated. You can still view the old repository and it's commits on this [branch](https://github.com/GitbookIO/gitbook/tree/legacy).
|
||||
Our previous version of GitBook and it's CLI tool are now deprecated. You can still view the old repository and it's commits on this [branch](https://github.com/GitbookIO/gitbook/tree/legacy).
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.31.1",
|
||||
"oxfmt": "^0.62.0",
|
||||
"oxlint": "^1.93.0",
|
||||
"oxlint": "^1.90.0",
|
||||
"turbo": "^2.11.10",
|
||||
"vercel": "50.37.3",
|
||||
},
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"packages/colors": {
|
||||
"name": "@gitbook/colors",
|
||||
"version": "0.4.5",
|
||||
"version": "0.4.4",
|
||||
"devDependencies": {
|
||||
"bun-types": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
@@ -49,9 +49,10 @@
|
||||
},
|
||||
"packages/embed": {
|
||||
"name": "@gitbook/embed",
|
||||
"version": "0.7.0",
|
||||
"version": "0.6.0",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "catalog:",
|
||||
"@gitbook/icons": "workspace:",
|
||||
"bidc": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -109,7 +110,7 @@
|
||||
},
|
||||
"packages/gitbook": {
|
||||
"name": "gitbook",
|
||||
"version": "0.28.2",
|
||||
"version": "0.28.0",
|
||||
"dependencies": {
|
||||
"@base-ui/react": "catalog:",
|
||||
"@cloudflare/workers-types": "^4.20251011.0",
|
||||
@@ -128,8 +129,8 @@
|
||||
"@gitbook/react-openapi": "workspace:*",
|
||||
"@mermaid-js/mermaid-zenuml": "^0.2.2",
|
||||
"@modelcontextprotocol/sdk": "1.17.5",
|
||||
"@opennextjs/aws": "4.1.15",
|
||||
"@opennextjs/cloudflare": "1.20.16",
|
||||
"@opennextjs/aws": "4.1.11",
|
||||
"@opennextjs/cloudflare": "1.20.12",
|
||||
"@panzoom/panzoom": "^4.6.1",
|
||||
"@sindresorhus/fnv1a": "^3.1.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
@@ -159,7 +160,7 @@
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"motion": "^12.23.24",
|
||||
"negotiator": "^1.0.0",
|
||||
"next": "^16.4.5",
|
||||
"next": "^16.4.3",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.2.3",
|
||||
"object-hash": "^3.0.0",
|
||||
@@ -248,7 +249,7 @@
|
||||
},
|
||||
"packages/openapi-parser": {
|
||||
"name": "@gitbook/openapi-parser",
|
||||
"version": "3.1.0",
|
||||
"version": "3.0.13",
|
||||
"dependencies": {
|
||||
"@scalar/json-magic": "^0.17.0",
|
||||
"@scalar/openapi-parser": "^0.29.19",
|
||||
@@ -265,7 +266,7 @@
|
||||
},
|
||||
"packages/react-contentkit": {
|
||||
"name": "@gitbook/react-contentkit",
|
||||
"version": "0.7.18",
|
||||
"version": "0.7.17",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "catalog:",
|
||||
"@gitbook/icons": "workspace:*",
|
||||
@@ -308,7 +309,7 @@
|
||||
},
|
||||
"packages/react-openapi": {
|
||||
"name": "@gitbook/react-openapi",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"@base-ui/react": "catalog:",
|
||||
"@gitbook/expr": "workspace:*",
|
||||
@@ -341,9 +342,8 @@
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"decode-named-character-reference@1.0.2": "patches/decode-named-character-reference@1.0.2.patch",
|
||||
"next@16.4.5": "patches/next@16.4.5.patch",
|
||||
"@shikijs/langs@3.21.0": "patches/@shikijs%2Flangs@3.21.0.patch",
|
||||
"mermaid@11.16.1": "patches/mermaid@11.16.1.patch",
|
||||
"next@16.4.3": "patches/next@16.4.3.patch",
|
||||
},
|
||||
"overrides": {
|
||||
"@codemirror/state": "6.4.1",
|
||||
@@ -888,23 +888,23 @@
|
||||
|
||||
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.6", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-DXj75ewm11LIWUk198QSKUTxjyRjsBwk09MuMk5DGK+GDUtyPhhEHOGP/Xwwj3DjQXXkivoBirmOnKrLfc0+9g=="],
|
||||
|
||||
"@next/env": ["@next/env@16.4.5", "", {}, "sha512-JwSPwpdkZL5VMl2jA/q+JI8MZdweAL3xmw5/tb9y/TLtmS0YXZnmYDzSihwk8xTj1OL+WM53gTqaj96yuLp6Xw=="],
|
||||
"@next/env": ["@next/env@16.4.3", "", {}, "sha512-a7tz1QCcWWkwC/rPJcPMJk/UNRu9CFhDd3OHYE5hddbJrs8BqRTalxI6GlKCWEGzRLHN+S/B7a4PAHCtm25aBQ=="],
|
||||
|
||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.4.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W5TniBzWKASbNNwHZ/S/f1MxQUXU/LdjklVMWA0Ujbfl7SZnUzFls45hO0i/sF7Bx1jJBWp7WWmoQajXtX/O8A=="],
|
||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.4.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4yq5EXBt+VDtAZwTyfijaFp5D2C5oz3Ikw5a2kiX2K9nw72vrZX2q5UuAlkPtUMO1tQz6JTKpaKWjS7OOefTDQ=="],
|
||||
|
||||
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.4.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-uWq4qkHapBDS1oFltWS4YxTb9pLHAtLNcpbuK6SmRsebLYZqpBML/j/C0op+50JYGTpZgVL/DWNt/6oWlamrrw=="],
|
||||
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.4.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-1Rvkn/LUhnEF8WxnRkOrqGhbwXui1bkWFxONKIbN+r7C+9KHDSZ+iUoj4CzymVMWUyZIyx9szcb9+kbKhD500A=="],
|
||||
|
||||
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-FdRcyOx5u5P51mlAqLB9EXdd8jZO5fsdHtk4BAQSkqOywCsbTNN/rmw+jO7pnmjNdAtu2AG46NzbCL2FPDrrgw=="],
|
||||
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.4.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-dCKpXErGg3abUM6t5JTJV/ottVBTStJB5lRJTbgdUdQaQ+jNHiK56Hsc0YAEg/rinSh42hYG3HWiYmEMdilnxg=="],
|
||||
|
||||
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-cyvmmgtRXR8aGVT86wi9Py53IlfyCx7P2fZxuAXAoTummDnhKtUyjrMeXfapqp4qgD+gT5RqyGD/VfA16jEK7Q=="],
|
||||
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.4.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-WwYbhWkhYBvBtib1K4W0kL8MW2snBD2A5b3SN4vPpqalZbZs5+bQ1yzAdepVoOqrFfEW3dmREy4Zs1MrWcrFbw=="],
|
||||
|
||||
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-hPc+Fl+N22DAvqZHq559NmamXboOX5Lu8I5Wl0DezfrhTk1Zz21NQeYoZDmNI/NjTcrdsVxM72Fzn2lI+Q+vAw=="],
|
||||
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.4.3", "", { "os": "linux", "cpu": "x64" }, "sha512-QymWvfUwDEC5/lpJOsxX5VAbyoR2D13+2Jsjz4be7gT4LPqEgdpkeLIR/HFfCLgKzoMhpJbp6I/JnogyNZHcaA=="],
|
||||
|
||||
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-gbACYE8IP/jlprNTpiWXHb8N9CofOzpnEwH2SrIz1dUbiJf1FbDssDupCAPeP1Taxe8mgG20sGZamJI7KFOdZw=="],
|
||||
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.4.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Vmjd9D7DpA4Vv3cUlr82QWgJD/BQZmns801vtC5VWHg6jCIA4a5vMKpQnfrM2pyCrp2eV0ENdUg4PlN3bAc2Yw=="],
|
||||
|
||||
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.4.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-+8gj++ZMo8H20Xh2ijjNqyFk5LPLw0AC4Fs4Tq/G94rjjQXhOjN4jgSWsWKPFsyY26hfIeemJIwKtMxOsp5GBA=="],
|
||||
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.4.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-lG1pPdPLk7gTyGb00n5JIMLdBJgjb+UEhSdZvFbhUMg0DyC6z4B7RnpSKF9VCd4imkLObVbXOFA0kFCpw7yFow=="],
|
||||
|
||||
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.4.5", "", { "os": "win32", "cpu": "x64" }, "sha512-qNZj66pYXnaWLiF9R9GUbfBdrCv7kC6TaZfIwB2KH5WPc/8pEM3nVOj8hpQhWJU8S94rlH5MPDcX15+RrgUhiw=="],
|
||||
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.4.3", "", { "os": "win32", "cpu": "x64" }, "sha512-NmQC9RkJdnPXRaMxtkCzobB3teVjqF33oSOnwDfi+XYGWWYpt+xlGK3mtktSKLbdjwaWbJu2OkkMiRFGUUncKg=="],
|
||||
|
||||
"@node-minify/core": ["@node-minify/core@9.0.2", "", { "dependencies": { "@node-minify/utils": "9.0.1", "glob": "10.3.3", "mkdirp": "3.0.1" } }, "sha512-FNhv29Wom6wKrrFKaeAfmZqz7TX5A1E6P+bpd0VIc+DYWMLUIhAViS8riaZg3A1oD0s06s+5BG2Fg7RqMKiKHw=="],
|
||||
|
||||
@@ -934,9 +934,9 @@
|
||||
|
||||
"@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
|
||||
"@opennextjs/aws": ["@opennextjs/aws@4.1.15", "", { "dependencies": { "@ast-grep/napi": "^0.45.3", "@aws-sdk/client-cloudfront": "3.984.0", "@aws-sdk/client-dynamodb": "3.984.0", "@aws-sdk/client-lambda": "3.984.0", "@aws-sdk/client-s3": "3.984.0", "@aws-sdk/client-sqs": "3.984.0", "@node-minify/core": "^9.0.2", "@node-minify/terser": "^9.0.1", "@tsconfig/node18": "^18.2.7", "aws4fetch": "^1.0.20", "chalk": "^5.6.2", "cookie": "^1.1.1", "esbuild": "0.28.2", "express": "^5.2.1", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.1.0", "yaml": "^2.9.1" }, "peerDependencies": { "diff": "^9.0.0", "next": ">=15.5.29 <16 || >=16.4.5" }, "optionalPeers": ["diff"], "bin": { "open-next": "dist/index.js" } }, "sha512-ulv7rFEAeieD0d/zDMnw4IFPU+zY/atVUhn7ezgFqIurLB5oBYeHCUGlcGk3Pg7uMPeI03SNRjHW1+xL9EwMPw=="],
|
||||
"@opennextjs/aws": ["@opennextjs/aws@4.1.11", "", { "dependencies": { "@ast-grep/napi": "^0.45.3", "@aws-sdk/client-cloudfront": "3.984.0", "@aws-sdk/client-dynamodb": "3.984.0", "@aws-sdk/client-lambda": "3.984.0", "@aws-sdk/client-s3": "3.984.0", "@aws-sdk/client-sqs": "3.984.0", "@node-minify/core": "^9.0.2", "@node-minify/terser": "^9.0.1", "@tsconfig/node18": "^18.2.7", "aws4fetch": "^1.0.20", "chalk": "^5.6.2", "cookie": "^1.1.1", "esbuild": "0.28.2", "express": "^5.2.1", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.1.0", "yaml": "^2.9.1" }, "peerDependencies": { "next": ">=15.5.28 <16 || >=16.4.1" }, "bin": { "open-next": "dist/index.js" } }, "sha512-cew0cUgGZF/Kr/C+Z1qvmAdKj4Va5cRho+aB6Ci/5ILd+QDdrR2LVaC/6Qm12KVF37vSLDK7lPDd/KdvvCoNEw=="],
|
||||
|
||||
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.20.16", "", { "dependencies": { "@ast-grep/napi": "^0.45.3", "@dotenvx/dotenvx": "^2.33.0", "@opennextjs/aws": "4.1.15", "ci-info": "^4.2.0", "cloudflare": "^4.4.1", "comment-json": "^4.5.1", "enquirer": "^2.4.1", "glob": "^13.0.6", "ts-tqdm": "^0.8.6", "yargs": "^18.2.0" }, "peerDependencies": { "next": ">=15.5.29 <16 || >=16.4.5", "rclone.js": "^0.6.6", "wrangler": "^4.148.0" }, "optionalPeers": ["rclone.js"], "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-3c1Cwex5e2jXy4o4RZAusy8o9Uz4eowuPCjdVLYEZ/MnkAzN2jh9dOgsRjgu3wjigXuNe8rmPECmOTo+xKQHsw=="],
|
||||
"@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.20.12", "", { "dependencies": { "@ast-grep/napi": "^0.45.3", "@dotenvx/dotenvx": "^2.33.0", "@opennextjs/aws": "4.1.11", "ci-info": "^4.2.0", "cloudflare": "^4.4.1", "comment-json": "^4.5.1", "enquirer": "^2.4.1", "glob": "^13.0.6", "ts-tqdm": "^0.8.6", "yargs": "^18.2.0" }, "peerDependencies": { "next": ">=15.5.28 <16 || >=16.4.1", "rclone.js": "^0.6.6", "wrangler": "^4.148.0" }, "optionalPeers": ["rclone.js"], "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-ZU1j7hMuOFaa0RHT/wrPXQKEEqzkkoc3fHaHy0Xrx4K0zZdSXGQbwbSHCnbjPRGXblCuWo+ur6UUkl0o9kVhrg=="],
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
@@ -1020,43 +1020,43 @@
|
||||
|
||||
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.62.0", "", { "os": "win32", "cpu": "x64" }, "sha512-dlI5SY7XYQCiCBafntWagCR6HcAJB/NpsLtdlPx8x08+Osz8Ok1HHz1GZuusegCe/VoJ6pAnF5a4pd5OZAq7qQ=="],
|
||||
|
||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.93.0", "", { "os": "android", "cpu": "arm" }, "sha512-KKw70pbD5Pvq3G2lJ+WQ71XPMjCmg37rkSe2+mDqCRP3PoTSdDMuEi4UOnE8JBtyNM7bek61EC2s0Jt7S7u+Sg=="],
|
||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.90.0", "", { "os": "android", "cpu": "arm" }, "sha512-sgfalb1HuxYjiAa4wESZ626z1FGusqNcXYHyB5oIOEprS2sbPg0UYEfo83uF1GNG70DIfZxHkXuE6KFrlSdn8Q=="],
|
||||
|
||||
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.93.0", "", { "os": "android", "cpu": "arm64" }, "sha512-fvr1fTUZGelwRxKDt64pf28aL1WaWgviwz3X+E/FcRYvrlEahH0NECRz/c1SY+K+KWmZk5uAf6h1kQnyBkp/2A=="],
|
||||
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.90.0", "", { "os": "android", "cpu": "arm64" }, "sha512-RcKhz1ETMq+fazE9TKS2+5NIRGwigm/nW8egqF0LI+A8Yw2iW5r0E/C3XAPRiwIm/vcPiutIRIa6IQCIKhZsTQ=="],
|
||||
|
||||
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.93.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VdvSN9JRf4Es6ZzoAdvEeh8tgKdw8L4H82WmA8MMPVfPdZGCwE/nI27Z1HrRHYQhPxOh4kmnxQEioSUFrOvDaw=="],
|
||||
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.90.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PSrxMvP6mx+p1karZcUxLdy9lpaP+JWQPti4al9FgTaPhxE+pT/BjhGExloVVSWgZgIfOlLOjVyyq8BXlodhLQ=="],
|
||||
|
||||
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.93.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-QR1V890Ml0YGRG0F/iV0K9igG+pOhe+VWd+aZnxY849rRHZf3F2gEoQks5+GVHf105X9Mh/6HdShTP5juekG2g=="],
|
||||
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.90.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-OLbU9qsrV2Q8QxT2OEzOPdO8zCCpyI8qB+hDI8yr6RsYELtkf0FAZhJdfjM/RnLHKzt44HWwAPnk92vBtKofvw=="],
|
||||
|
||||
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.93.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jDfIbi30zZaKi+rTvig3sge+Xhi8pFFSgHxb0jzovc4qh8ETm/irKV9c7N/JsuwnYc5sbvf4IC8w1vQQ0IL+BA=="],
|
||||
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.90.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fBA4pWyVDARmNucQqpyFuPC49xYf1r+sX7dxPL5fNPQrSMLum39Sn56tZ9JPleWC7FzLPwSQ7plYYfirYBHF8A=="],
|
||||
|
||||
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.93.0", "", { "os": "linux", "cpu": "arm" }, "sha512-qtxZ714ND/koFgVH00QgxlzZiIbRPmguaPhnHRU5DFFtrtEdOrSnZD4U/H2AzXrXkZ59eQbMBnJwbum5XohrIQ=="],
|
||||
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.90.0", "", { "os": "linux", "cpu": "arm" }, "sha512-zhxH78eP2nR6/pGdhBc7MIfjhhcgATeu8fkmkFJbuzfk6Cj0FzBxyEhL85yDqrCybjx+G2YDzZGsxIO9kvO4Iw=="],
|
||||
|
||||
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.93.0", "", { "os": "linux", "cpu": "arm" }, "sha512-5pJ9NjMvH7WMUqXB6bTTOSemBm39w2cod27Hu3+Yom/GhbTeNXlYcpDx1o4CgBP6fhp0YHG66TNdVaUm6sHjsA=="],
|
||||
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.90.0", "", { "os": "linux", "cpu": "arm" }, "sha512-MvYmpHyJqUJjEvkZbJHdwfdL45cGn8EVBkYmoXFiaYFW9suoD3dbJl5mBdpy0DVgdjlyddmldbRtk3cCgETadQ=="],
|
||||
|
||||
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.93.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-pRf+7jtbt2fHE23SX7qBxRgnBZicUgsoCK1PVIjnOk+t3a6UBkpt/GrKI99WlxsKUxftz/5nv/kfKvScmYywkw=="],
|
||||
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.90.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-L13Sy+Kg0nZhwTsToniqjUFPA2TuM6962qCZ5Wp5KeB517Tw7ApdLTTtlb+bF86fcZZa2EtvCVvAJxk4Dya/MQ=="],
|
||||
|
||||
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.93.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-zM8Fd/K8sqGvsBcJBZ3oVZ3ctGWbszA08IaGt5gFFF5RcunppAI/ZnAXbouABvnWeJ//S44KKlfPZnDDbeiphg=="],
|
||||
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.90.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-wFDdZWGpzIPFdJFjSLWnKB0TGzFriTKUIrl04iMqMyM9BBIJTuerfCHYa0WpDSjr5x3lcW/CHLyacSt886WpGg=="],
|
||||
|
||||
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.93.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-7qKCnvhZKDXJG2pdbLazd2hw4FxjJHbZOFrrbzyy5PdHfPLH9vnNUa1le01A8uItZuYKPBPncH+HCoEiFT4SgA=="],
|
||||
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.90.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FRywfn+MoKn8xpBSzgNwNVliSKRI2QXkxi/iF7o6FEQs8Bh8z2RpVTaFAcO3pchXjvB2eGNFIoLLQABIQ+u7VA=="],
|
||||
|
||||
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.93.0", "", { "os": "linux", "cpu": "none" }, "sha512-2pgulxC6G8V5wE750NJE/fRkf9aO6i6yoj10wyaR2EdiNtan4OemsOtsQ0ZTXGdY8Q3IoTmlND3GYvjJsvikYg=="],
|
||||
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.90.0", "", { "os": "linux", "cpu": "none" }, "sha512-IS2PaUgpc/qeLADTyhUNmdx3x4ijs9pjJdPKBYHaT+mAE7k3FsjnHPTjhpsak1b++h6CIPhv6WX9Z+y7Pw0voQ=="],
|
||||
|
||||
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.93.0", "", { "os": "linux", "cpu": "none" }, "sha512-yWsn6Gg2PnGG5jlyDz5+pHGiMTMiy4adaa4WRMzDgzB8efaShk1JMmTHIBSVLQMh0tYXRs4CN5uJCO79r4Mi4g=="],
|
||||
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.90.0", "", { "os": "linux", "cpu": "none" }, "sha512-s7JFKRkGS8O7i2ZVODfuO++NC7sH6HDqpMn8lYxw91w0SXJOxnAVjQ8utvmDwLMMT0jaSkuOKuUYJDGDtu4sHQ=="],
|
||||
|
||||
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.93.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-WCn5plwp/ezS2RDPQKp0/EXEVRr9/dDexUdRKmsMFqzNM5xBSZ1wbsi3PuMk1VfkMRnI5BuazCsziCWMXRDOlw=="],
|
||||
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.90.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-b0GxrOQr5VONCkd7KLSqmP6b6nqZuTpuS8QPQHzltmqdXP5bY0Jl0CZ0QmlCTrS3ExaLYbioFYOARzNbYvcApQ=="],
|
||||
|
||||
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.93.0", "", { "os": "linux", "cpu": "x64" }, "sha512-F2CGjb9LAkzH+IYTZSzd1klQ1vk5z6Utjax64WeLByCkYXbVDbsun+Oy2hLfW2MDSKCvW+jwy/9ld0EPgdeu+A=="],
|
||||
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.90.0", "", { "os": "linux", "cpu": "x64" }, "sha512-iaJeShJtgUp8rZbt9YUdTAGOpmX5KogCLba17Jp1tWdJ3F4M3D2g2TKUyI1FMTHxKH9NNHuQcuC2kZRg6IV7yQ=="],
|
||||
|
||||
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.93.0", "", { "os": "linux", "cpu": "x64" }, "sha512-plf5DE2objcG8Tf7mXRuRa8tT8rzDkpjqXQtKoGsKHWkpgsialbON1+cCtoSEUTVbQUjXvuAm8vV9+3rR0yCBw=="],
|
||||
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.90.0", "", { "os": "linux", "cpu": "x64" }, "sha512-/aZoXnL5WBLCXuzfHqvEFXcm4iwYmr/cYByHDTXzLFzJdE5DC7bm6phpWqHv6BeqpVgY9IpBAxGDv2WEkl5JCg=="],
|
||||
|
||||
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.93.0", "", { "os": "none", "cpu": "arm64" }, "sha512-Kp2yJrKvoTe9FfKdO/xwLNUbs2bYTMKx0+aoQD1s0h/Tx0kSgtHSdGmrk8tTKdluosjFbo88qYRIaNIX43AfFw=="],
|
||||
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.90.0", "", { "os": "none", "cpu": "arm64" }, "sha512-SMhk7ozwoxYDKfYqGZCQEfULOKDneF9uhaoIf2neoDLWvNtjY9yVeL7YHmE5L9WdKvMpWNwwZxhenxBu6AgfOg=="],
|
||||
|
||||
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.93.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-vigjcHCFsR6KjnWTEVfaCxcMYapEuaK9FZa1MpewwQ1S+Xud3v0okfkj1RySsD6RF1NRHIjSlQSalTnKIaj3nA=="],
|
||||
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.90.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-KBvR3A9fO7fCi2vCP8ifWvlia7tGEQV9NaYh+IGwa/7Groy48Mt/UaYqMK9/zOtAWl20BUCf6RPqzJ32fRw33Q=="],
|
||||
|
||||
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.93.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-0Ot3BEe/AAr2/uQhe55r8CmPlperYk2mQmxdutOru7oU0kir6IiEVHb1TG3GORRlfra97lPHVDLhgmihiKzLrg=="],
|
||||
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.90.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-+x42rDHQGbTCuT3EzpWAzhP3NoVPE/cJsG4gnrakOSg0olV+GCdMpPU23Nvrl3zZMnXxFZdTtDv4D3SuaA5ZeQ=="],
|
||||
|
||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.93.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ZzzIIVs/Qkm8trUWYKF0OYub5ALlv50/3gsEZbKAvWgz+yNJX6uRmQ8ySPXU2Q0/Y9m4JCOjhpmC8XUYbPHX5Q=="],
|
||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.90.0", "", { "os": "win32", "cpu": "x64" }, "sha512-30JiaFEBUB9peEOcvVM8ggo88SoN/IdSr9DW505JdBji/R6dM66gKEiG65hw6qcaF2f4mO0cEJ+RwRZprmun9g=="],
|
||||
|
||||
"@panzoom/panzoom": ["@panzoom/panzoom@4.6.1", "", {}, "sha512-ogf/KhHHjj+DYAvHfaf3TXMQ8OE36pJtKpabLlx1OmpjcgtpCvkUoCiNONA8kuVRPGJdLiqMf0n8LRFXj1OyuA=="],
|
||||
|
||||
@@ -1362,17 +1362,17 @@
|
||||
|
||||
"@tsconfig/strictest": ["@tsconfig/strictest@2.0.6", "", {}, "sha512-tPOhmDhIUcDjvpDDYyiUdssP84Eqm7n5KxJe5J3/g+s6xoDIPAf+SIn06dhw7VkhxIvLOnhDDrX7tsqMHNEhDg=="],
|
||||
|
||||
"@turbo/darwin-64": ["@turbo/darwin-64@2.11.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-HMMeUIEAsmyIbSYn1ySvF/4gGMa0joiTMq4dQDuloIAnOpbtFT3JEiVsYnASdTWDXvplbRbZlqjU1EBeSR9G1A=="],
|
||||
"@turbo/darwin-64": ["@turbo/darwin-64@2.11.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-By4idRap5+nLnMuRzLB4qkOPRlvNdyY1ne4VJYDyUoUB11H94k7uif9mbe3JT8JSNXs1D68uMcBj6hJ/jMQRvA=="],
|
||||
|
||||
"@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.11.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+8iySNgqYWY6PZYUQzYu6zn0C04z2OEq1vQ6oMGsJ9sxN6wOpg1gzi1AJ5VKDHviWvMUjhqng51hTEQZOuiqYQ=="],
|
||||
"@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.11.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-pyEYlVcuexOPa92p0Wlwl9YT1Is5D60lxN3ItWm3g30YLvFaUq86TF4BBWg5ZAc0uMTnrOzCvuCsOBTdzUWnRQ=="],
|
||||
|
||||
"@turbo/linux-64": ["@turbo/linux-64@2.11.11", "", { "os": [ "linux", "android", ], "cpu": "x64" }, "sha512-uImTKFYCFKsoFxjaXeJXlMPv4uU3OIIDjyzoIwYVqOtu9LnCZ/5/fzu/WP6+G9YfwGAPRplTHkKFfcI5t97RGw=="],
|
||||
"@turbo/linux-64": ["@turbo/linux-64@2.11.10", "", { "os": [ "linux", "android", ], "cpu": "x64" }, "sha512-1tYeR/IDZ5HEdsb0jNq2L2xam5nMQ+g80tlV2BZmv4OFw+pMcUM0mMmUcfc5wXPPNHVNPuDMjh9Y8G8HgXPLZA=="],
|
||||
|
||||
"@turbo/linux-arm64": ["@turbo/linux-arm64@2.11.11", "", { "os": [ "linux", "android", ], "cpu": "arm64" }, "sha512-Y7xffSVfyyYRGzNy6PLdrFL4xXN6iTuR3W0SyJvH/yd3d4defA6dansZwJpPDVnIpD8a2Qn256DwY/Qin4Ip4g=="],
|
||||
"@turbo/linux-arm64": ["@turbo/linux-arm64@2.11.10", "", { "os": [ "linux", "android", ], "cpu": "arm64" }, "sha512-HuekQxvVGhUd46g1Im/DKdOtglHr4/gguZAvzEpPUgtxNkztSa8lWhQEGQ+EmPQ0n7w19qjThFU+OfEEd0uvlw=="],
|
||||
|
||||
"@turbo/windows-64": ["@turbo/windows-64@2.11.11", "", { "os": "win32", "cpu": "x64" }, "sha512-e2WqNtkPGo3QDwNNwwBo89Dx3PtSJ9Wp9QuRNzn80rrRnSHB+1mfBMZTpdHjA8/G/sG9rl76TdWdpgVsimjRdg=="],
|
||||
"@turbo/windows-64": ["@turbo/windows-64@2.11.10", "", { "os": "win32", "cpu": "x64" }, "sha512-UJOP3BkbreY3/JlMgJR6ZiimxYIBn+c+B4tnBIxD0E9c3Estmk+XoVNVBNBottZLNRXe3/ScgOU4+/k8tIWysg=="],
|
||||
|
||||
"@turbo/windows-arm64": ["@turbo/windows-arm64@2.11.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-LURivfmgv34Osm8NR1gZGx4vdlux9KAgRM+FoooXNG0838ff0+akWZ76iPSke0NS2rsf7Z4Gw+YSaygzNTZuRA=="],
|
||||
"@turbo/windows-arm64": ["@turbo/windows-arm64@2.11.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-xOkEjF3ws/b/YNlc+bvJHMYBn+vL+QbEISZFVi0qS+ImmhA1X3/gmNmBrjjIG3dg6aeN+n6gQitzSkXQ286qJQ=="],
|
||||
|
||||
"@tusbar/cache-control": ["@tusbar/cache-control@1.0.2", "", {}, "sha512-PXfjYTYBVvMPYCLDWj+xIOA9ITFbbhWCHzLcqUCJ5TPGm4JO4cxpGb7x3K8Q1K1ADgNgfBxLsDcTMVRydtZB9A=="],
|
||||
|
||||
@@ -2636,7 +2636,7 @@
|
||||
|
||||
"netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="],
|
||||
|
||||
"next": ["next@16.4.5", "", { "dependencies": { "@next/env": "16.4.5", "@swc/helpers": "0.5.23", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.5.23", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.4.5", "@next/swc-darwin-x64": "16.4.5", "@next/swc-linux-arm64-gnu": "16.4.5", "@next/swc-linux-arm64-musl": "16.4.5", "@next/swc-linux-x64-gnu": "16.4.5", "@next/swc-linux-x64-musl": "16.4.5", "@next/swc-win32-arm64-msvc": "16.4.5", "@next/swc-win32-x64-msvc": "16.4.5", "sharp": "^0.35.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "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-rmdfsWosjTUO+6R0S3KokoIk6Kj0sWDRTe86tZHdqaWH/oXq/udX3/4xb+YQi7aWbyEFoglDU54kaifLCdXbBw=="],
|
||||
"next": ["next@16.4.3", "", { "dependencies": { "@next/env": "16.4.3", "@swc/helpers": "0.5.23", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.5.23", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.4.3", "@next/swc-darwin-x64": "16.4.3", "@next/swc-linux-arm64-gnu": "16.4.3", "@next/swc-linux-arm64-musl": "16.4.3", "@next/swc-linux-x64-gnu": "16.4.3", "@next/swc-linux-x64-musl": "16.4.3", "@next/swc-win32-arm64-msvc": "16.4.3", "@next/swc-win32-x64-msvc": "16.4.3", "sharp": "^0.35.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "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-OqxKTGi9u80FydydsMNYNjnuje9Au+kvHlt2GZ//ftdpDHm1dxKqAaENoOOTX5wKzn+9vaKUNIfZeyZUuLhCnA=="],
|
||||
|
||||
"next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="],
|
||||
|
||||
@@ -2696,7 +2696,7 @@
|
||||
|
||||
"oxfmt": ["oxfmt@0.62.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.62.0", "@oxfmt/binding-android-arm64": "0.62.0", "@oxfmt/binding-darwin-arm64": "0.62.0", "@oxfmt/binding-darwin-x64": "0.62.0", "@oxfmt/binding-freebsd-x64": "0.62.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.62.0", "@oxfmt/binding-linux-arm-musleabihf": "0.62.0", "@oxfmt/binding-linux-arm64-gnu": "0.62.0", "@oxfmt/binding-linux-arm64-musl": "0.62.0", "@oxfmt/binding-linux-ppc64-gnu": "0.62.0", "@oxfmt/binding-linux-riscv64-gnu": "0.62.0", "@oxfmt/binding-linux-riscv64-musl": "0.62.0", "@oxfmt/binding-linux-s390x-gnu": "0.62.0", "@oxfmt/binding-linux-x64-gnu": "0.62.0", "@oxfmt/binding-linux-x64-musl": "0.62.0", "@oxfmt/binding-openharmony-arm64": "0.62.0", "@oxfmt/binding-win32-arm64-msvc": "0.62.0", "@oxfmt/binding-win32-ia32-msvc": "0.62.0", "@oxfmt/binding-win32-x64-msvc": "0.62.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-vxgGHTmnDU9j4CX7dDBLzxgmHxfda/yPcgJkGCMUSCwRmz+euo/V08xXLNgXTeqAB9Fhf3Pe2nO1RNKLCVgphQ=="],
|
||||
|
||||
"oxlint": ["oxlint@1.93.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.93.0", "@oxlint/binding-android-arm64": "1.93.0", "@oxlint/binding-darwin-arm64": "1.93.0", "@oxlint/binding-darwin-x64": "1.93.0", "@oxlint/binding-freebsd-x64": "1.93.0", "@oxlint/binding-linux-arm-gnueabihf": "1.93.0", "@oxlint/binding-linux-arm-musleabihf": "1.93.0", "@oxlint/binding-linux-arm64-gnu": "1.93.0", "@oxlint/binding-linux-arm64-musl": "1.93.0", "@oxlint/binding-linux-ppc64-gnu": "1.93.0", "@oxlint/binding-linux-riscv64-gnu": "1.93.0", "@oxlint/binding-linux-riscv64-musl": "1.93.0", "@oxlint/binding-linux-s390x-gnu": "1.93.0", "@oxlint/binding-linux-x64-gnu": "1.93.0", "@oxlint/binding-linux-x64-musl": "1.93.0", "@oxlint/binding-openharmony-arm64": "1.93.0", "@oxlint/binding-win32-arm64-msvc": "1.93.0", "@oxlint/binding-win32-ia32-msvc": "1.93.0", "@oxlint/binding-win32-x64-msvc": "1.93.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2005", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-19JMsQFX+YvEbcUTFQxjTwhvs0Ibg0D6CFneSLgpwnACWcY/6LjhpGpkPodh0T5aIT1pjMTLlYaeBFzaVgugTA=="],
|
||||
"oxlint": ["oxlint@1.90.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.90.0", "@oxlint/binding-android-arm64": "1.90.0", "@oxlint/binding-darwin-arm64": "1.90.0", "@oxlint/binding-darwin-x64": "1.90.0", "@oxlint/binding-freebsd-x64": "1.90.0", "@oxlint/binding-linux-arm-gnueabihf": "1.90.0", "@oxlint/binding-linux-arm-musleabihf": "1.90.0", "@oxlint/binding-linux-arm64-gnu": "1.90.0", "@oxlint/binding-linux-arm64-musl": "1.90.0", "@oxlint/binding-linux-ppc64-gnu": "1.90.0", "@oxlint/binding-linux-riscv64-gnu": "1.90.0", "@oxlint/binding-linux-riscv64-musl": "1.90.0", "@oxlint/binding-linux-s390x-gnu": "1.90.0", "@oxlint/binding-linux-x64-gnu": "1.90.0", "@oxlint/binding-linux-x64-musl": "1.90.0", "@oxlint/binding-openharmony-arm64": "1.90.0", "@oxlint/binding-win32-arm64-msvc": "1.90.0", "@oxlint/binding-win32-ia32-msvc": "1.90.0", "@oxlint/binding-win32-x64-msvc": "1.90.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2005", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-RkTN9EmgIUpLuhNoLhO3OliMGJlvb3Dk7XVjBZnfoMCHrVpuz5ESd97klfiyYeV7XfA2lNLnDCPMkUI+Qw5How=="],
|
||||
|
||||
"p-filter": ["p-filter@2.1.0", "", { "dependencies": { "p-map": "^2.0.0" } }, "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw=="],
|
||||
|
||||
@@ -3130,7 +3130,7 @@
|
||||
|
||||
"tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="],
|
||||
|
||||
"turbo": ["turbo@2.11.11", "", { "optionalDependencies": { "@turbo/darwin-64": "2.11.11", "@turbo/darwin-arm64": "2.11.11", "@turbo/linux-64": "2.11.11", "@turbo/linux-arm64": "2.11.11", "@turbo/windows-64": "2.11.11", "@turbo/windows-arm64": "2.11.11" }, "bin": { "turbo": "bin/turbo" } }, "sha512-AI4UJbUE/2cVZdoXJ4PODc8qvrjhQQX9Fa93eKGOI6Ims/w7+kUIb9T1jhlgSnZcf+gtUruci/ohSwqtNNC5Yw=="],
|
||||
"turbo": ["turbo@2.11.10", "", { "optionalDependencies": { "@turbo/darwin-64": "2.11.10", "@turbo/darwin-arm64": "2.11.10", "@turbo/linux-64": "2.11.10", "@turbo/linux-arm64": "2.11.10", "@turbo/windows-64": "2.11.10", "@turbo/windows-arm64": "2.11.10" }, "bin": { "turbo": "bin/turbo" } }, "sha512-3GJYwig8ygEI89oaOZdduJX8/aw6O9eRPYHoIt6T3FZl9hkKjiyIspufJoVgqXihPoJu8M5CSV0DlZvzfohBCw=="],
|
||||
|
||||
"type": ["type@2.7.3", "", {}, "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="],
|
||||
|
||||
|
||||
+4
-5
@@ -7,8 +7,8 @@
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.31.1",
|
||||
"oxfmt": "^0.62.0",
|
||||
"oxlint": "^1.93.0",
|
||||
"turbo": "^2.11.11",
|
||||
"oxlint": "^1.90.0",
|
||||
"turbo": "^2.11.10",
|
||||
"vercel": "50.37.3"
|
||||
},
|
||||
"packageManager": "bun@1.3.7",
|
||||
@@ -67,8 +67,7 @@
|
||||
"patchedDependencies": {
|
||||
"decode-named-character-reference@1.0.2": "patches/decode-named-character-reference@1.0.2.patch",
|
||||
"@vercel/next@4.4.2": "patches/@vercel%2Fnext@4.4.2.patch",
|
||||
"mermaid@11.16.1": "patches/mermaid@11.16.1.patch",
|
||||
"next@16.4.5": "patches/next@16.4.5.patch",
|
||||
"@shikijs/langs@3.21.0": "patches/@shikijs%2Flangs@3.21.0.patch"
|
||||
"next@16.4.3": "patches/next@16.4.3.patch",
|
||||
"mermaid@11.16.1": "patches/mermaid@11.16.1.patch"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
# @gitbook/colors
|
||||
|
||||
## 0.4.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c12872: Expand 3-digit hex colors correctly in `hexToRgbArray`.
|
||||
|
||||
## 0.4.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"version": "0.4.5",
|
||||
"version": "0.4.4",
|
||||
"devDependencies": {
|
||||
"bun-types": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
|
||||
import { colorScale, hexToRgbArray } from './transformations';
|
||||
import { colorScale } from './transformations';
|
||||
|
||||
describe('colorScale exact base', () => {
|
||||
it('takes a very light tint as the exact background on step 1 (clean/bold)', () => {
|
||||
@@ -67,15 +67,3 @@ describe('colorScale exact base', () => {
|
||||
expect(scale[0]).not.toBe('#F5F3EF');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hexToRgbArray', () => {
|
||||
it('parses a 6-digit hex color', () => {
|
||||
expect(hexToRgbArray('#1a2b3c')).toEqual([26, 43, 60]);
|
||||
});
|
||||
|
||||
it('expands a 3-digit hex color', () => {
|
||||
expect(hexToRgbArray('#abc')).toEqual([170, 187, 204]);
|
||||
expect(hexToRgbArray('abc')).toEqual([170, 187, 204]);
|
||||
expect(hexToRgbArray('#fff')).toEqual([255, 255, 255]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -311,9 +311,7 @@ export function hexToRgbArray(hex: string): RGBColor {
|
||||
const originalHex = hex;
|
||||
|
||||
let value = hex.replace('#', '');
|
||||
if (value.length === 3) {
|
||||
value = [...value].map((digit) => digit + digit).join('');
|
||||
}
|
||||
if (hex.length === 3) value = value + value;
|
||||
|
||||
const r = value.substring(0, 2);
|
||||
const g = value.substring(2, 4);
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
# @gitbook/embed
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 31e88d1: Relicense under Apache 2.0 and drop the dependency on `@gitbook/icons`.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -542,7 +542,3 @@ button: {
|
||||
icon: 'assistant'
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the [Apache License 2.0](./LICENSE).
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"version": "0.7.0",
|
||||
"license": "Apache-2.0",
|
||||
"version": "0.6.0",
|
||||
"dependencies": {
|
||||
"@gitbook/api": "catalog:",
|
||||
"@gitbook/icons": "workspace:",
|
||||
"bidc": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -42,8 +42,7 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md",
|
||||
"CHANGELOG.md",
|
||||
"LICENSE"
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import type { AIToolCallResult, AIToolDefinition } from '@gitbook/api';
|
||||
|
||||
/**
|
||||
* Name of a Font Awesome icon (e.g. `bolt`), or a GitBook custom icon.
|
||||
*/
|
||||
// Kept as a plain string so the package doesn't depend on @gitbook/icons and its licence.
|
||||
type IconName = string;
|
||||
import type { IconName } from '@gitbook/icons';
|
||||
|
||||
/**
|
||||
* Confirmation action to be displayed to the user before executing a tool.
|
||||
|
||||
@@ -1,55 +1,5 @@
|
||||
# gitbook
|
||||
|
||||
## 0.28.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b53e73c: Link suggested follow-up questions in markdown AI answers to the `.md` ask route so agents get markdown back.
|
||||
- 4a40547: Fix the page outline not scrolling to keep the active section visible on long pages.
|
||||
- 7ddd023: Fix search prewarming on public sites.
|
||||
- Updated dependencies [31e88d1]
|
||||
- @gitbook/embed@0.7.0
|
||||
|
||||
## 0.28.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a023a71: Warn visitors not to share sensitive personal info in the Assistant context popover.
|
||||
- 6344646: Fix bash code blocks colouring the last letter of a word before `>` differently, as in `<name>`.
|
||||
- 7e096d5: Bump Next.js to 16.4.3, keeping the dev-mode OOM patch.
|
||||
- 198cafe: Bump Next.js to 16.4.5 and OpenNext (Cloudflare 1.20.16, AWS 4.1.15), keeping the dev-mode OOM patch.
|
||||
- f61578f: Preconnect each asset origin once, skip same-origin icon URLs, and open the fonts preconnect in CORS mode so font requests can reuse it.
|
||||
- 26ec43e: Stop caching failed searches, so a rate-limited or failing search is retried on the next query instead of being served from cache for 15 minutes.
|
||||
- 8689736: Remove italic from dfn styling
|
||||
- 04f39f1: Declare the Tailwind layer order in each component stylesheet, so a route whose first stylesheet is one of them still puts `base` before `components` and preflight does not strip their padding and borders.
|
||||
- a512777: Forward the visitor's user agent on ask and Assistant calls so questions are classified by who asked.
|
||||
- 508f1bc: Load the inline expression runtime only on pages whose code blocks or text use expressions, so other pages ship less JavaScript.
|
||||
- 04f39f1: Pack the class lists that every block, heading anchor and table cell repeats into shared CSS classes, and carry a table cell's width once as a custom property instead of spelling it out as both width and min-width, so a large page carries far less markup.
|
||||
- bd431f1: Split llms-full.txt into parts by size so large sites no longer fail with "content too large"
|
||||
- a5d58bc: Follow site and space redirects when the MCP getPage tool resolves a page URL.
|
||||
- e6b8502: Fix the MCP `getPage` tool returning "Page not found" for the Markdown URL of a page (`<page>.md`).
|
||||
- e745c88: Add a search input to filter models by name on OpenAPI models pages.
|
||||
- 96c5683: Let analytics tools like GA4 track outbound link clicks by using native link navigation.
|
||||
- 347a1cc: Set `Partitioned` on visitor cookies set inside an iframe so authenticated embeds work cross-site.
|
||||
- 3837c48: Fix encoded or non-normalized links on proxied sites redirecting to the internal proxy path instead of the public URL.
|
||||
- ea01850: Support a secondary brand colour for secondary buttons and `$secondary` text, background, icon and tag colours. Sites without one render as before.
|
||||
- c00a7b3: Resolve the published content with the full URL in a single lookup and always send the visitor country.
|
||||
- 063e685: Resolve dark-mode image URLs in published Markdown.
|
||||
- 09a8310: Serve a disallow-all robots.txt instead of redirecting to sign-in on authenticated access sites.
|
||||
- b7b8ae6: Keep lists, paragraphs and code blocks as HTML in Updates RSS feeds, instead of running all the text together
|
||||
- 4a72ead: Only apply a site preview customization override to the section or variant it was made for.
|
||||
- 38f60f2: Render soft line breaks in paragraphs that contain buttons.
|
||||
- 1383a79: Fix visitors being logged out right after signing in on sites with a logout link in the header.
|
||||
- be658e1: Truncate long tab titles one by one and show the selected tab's full title, instead of hiding tabs behind a "…" menu
|
||||
- Updated dependencies [6c12872]
|
||||
- Updated dependencies [04f39f1]
|
||||
- Updated dependencies [1b29a70]
|
||||
- Updated dependencies [4dfe630]
|
||||
- @gitbook/colors@0.4.5
|
||||
- @gitbook/react-contentkit@0.7.18
|
||||
- @gitbook/openapi-parser@3.1.0
|
||||
- @gitbook/react-openapi@2.0.1
|
||||
|
||||
## 0.28.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -283,6 +283,11 @@ const testCases: TestsCase[] = [
|
||||
contentBaseURL: 'https://vimeo.com',
|
||||
tests: [{ name: 'Home', url: '/legal' }],
|
||||
},
|
||||
{
|
||||
name: 'help.aikido.dev',
|
||||
contentBaseURL: 'https://help.aikido.dev',
|
||||
tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
|
||||
},
|
||||
{
|
||||
name: 'doc.demarche.numerique.gouv.fr',
|
||||
contentBaseURL: 'https://doc.demarche.numerique.gouv.fr',
|
||||
@@ -584,6 +589,11 @@ const testCases: TestsCase[] = [
|
||||
contentBaseURL: 'https://help.blotato.com',
|
||||
tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
|
||||
},
|
||||
{
|
||||
name: 'docs.cartographer3d.com',
|
||||
contentBaseURL: 'https://docs.cartographer3d.com',
|
||||
tests: [{ name: 'Home', url: '/' }],
|
||||
},
|
||||
{
|
||||
name: 'docs.acestudio.ai',
|
||||
contentBaseURL: 'https://docs.acestudio.ai',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "0.28.2",
|
||||
"version": "0.28.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@base-ui/react": "catalog:",
|
||||
@@ -20,8 +20,8 @@
|
||||
"@gitbook/react-openapi": "workspace:*",
|
||||
"@mermaid-js/mermaid-zenuml": "^0.2.2",
|
||||
"@modelcontextprotocol/sdk": "1.17.5",
|
||||
"@opennextjs/aws": "4.1.15",
|
||||
"@opennextjs/cloudflare": "1.20.16",
|
||||
"@opennextjs/aws": "4.1.11",
|
||||
"@opennextjs/cloudflare": "1.20.12",
|
||||
"@panzoom/panzoom": "^4.6.1",
|
||||
"@sindresorhus/fnv1a": "^3.1.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
@@ -51,7 +51,7 @@
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"motion": "^12.23.24",
|
||||
"negotiator": "^1.0.0",
|
||||
"next": "^16.4.5",
|
||||
"next": "^16.4.3",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.2.3",
|
||||
"object-hash": "^3.0.0",
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import { getSiteURLDataFromMiddleware } from '@/lib/middleware';
|
||||
import { getServerActionBaseContext } from '@/lib/server-actions';
|
||||
|
||||
export async function POST() {
|
||||
const [context, siteURLData] = await Promise.all([
|
||||
getServerActionBaseContext(),
|
||||
getSiteURLDataFromMiddleware(),
|
||||
]);
|
||||
const apiClient = await context.dataFetcher.api();
|
||||
|
||||
await apiClient.orgs.prewarmSiteSearch(siteURLData.organization, siteURLData.site);
|
||||
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
+47
-19
@@ -1,10 +1,13 @@
|
||||
import { type NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
import type { SearchSiteContentRequest } from '@/components/Search/search-types';
|
||||
import { orderSearchResultGroups } from './orderSearchResults';
|
||||
import type {
|
||||
OrderedComputedResult,
|
||||
SearchSiteContentRequest,
|
||||
} from '@/components/Search/search-types';
|
||||
import { throwIfDataError } from '@/lib/data';
|
||||
import { getSiteURLDataFromMiddleware } from '@/lib/middleware';
|
||||
import { transformSitePageResult } from '@/lib/search';
|
||||
import { computeSearchResults } from '@/lib/search-results';
|
||||
import { getServerActionBaseContext } from '@/lib/server-actions';
|
||||
import { findSiteSpaceBy, getLinkerForSiteSpace } from '@/lib/sites';
|
||||
|
||||
@@ -53,24 +56,49 @@ export async function POST(request: NextRequest) {
|
||||
? getLinkerForSiteSpace(context.linker, currentSiteSpace.siteSpace, revision.pages)
|
||||
: context.linker;
|
||||
|
||||
const results = computeSearchResults(searchResults, (spaceItem, pageItem) => {
|
||||
const isCurrentRevisionSpace = Boolean(revision && spaceItem.id === siteURLData.space);
|
||||
const found =
|
||||
isCurrentRevisionSpace && currentSiteSpace
|
||||
? currentSiteSpace
|
||||
: findSiteSpaceBy(structure, (siteSpace) => siteSpace.space.id === spaceItem.id);
|
||||
const results = orderSearchResultGroups<OrderedComputedResult>(
|
||||
searchResults.map((resultItem) => {
|
||||
if (resultItem.type === 'record') {
|
||||
const result: OrderedComputedResult = {
|
||||
type: 'record',
|
||||
id: resultItem.id,
|
||||
title: resultItem.title,
|
||||
description: resultItem.description,
|
||||
href: resultItem.url,
|
||||
score: resultItem.score,
|
||||
};
|
||||
|
||||
return transformSitePageResult({
|
||||
asEmbeddable: Boolean(asEmbeddable),
|
||||
linker: isCurrentRevisionSpace ? revisionLinker : context.linker,
|
||||
pageItem,
|
||||
spaceItem,
|
||||
siteSpace: found?.siteSpace,
|
||||
siteSection: found?.siteSection ?? undefined,
|
||||
siteSectionGroup: found?.siteSectionGroup ?? undefined,
|
||||
revisionPages: isCurrentRevisionSpace ? revision?.pages : undefined,
|
||||
});
|
||||
});
|
||||
return { type: 'context' as const, results: [result] };
|
||||
}
|
||||
|
||||
const isCurrentRevisionSpace = Boolean(revision && resultItem.id === siteURLData.space);
|
||||
const found =
|
||||
isCurrentRevisionSpace && currentSiteSpace
|
||||
? currentSiteSpace
|
||||
: findSiteSpaceBy(
|
||||
structure,
|
||||
(siteSpace) => siteSpace.space.id === resultItem.id
|
||||
);
|
||||
|
||||
return {
|
||||
type: 'pages' as const,
|
||||
results: resultItem.pages.flatMap((pageItem) => {
|
||||
const result = transformSitePageResult({
|
||||
asEmbeddable: Boolean(asEmbeddable),
|
||||
linker: isCurrentRevisionSpace ? revisionLinker : context.linker,
|
||||
pageItem,
|
||||
spaceItem: resultItem,
|
||||
siteSpace: found?.siteSpace,
|
||||
siteSection: found?.siteSection ?? undefined,
|
||||
siteSectionGroup: found?.siteSectionGroup ?? undefined,
|
||||
revisionPages: isCurrentRevisionSpace ? revision?.pages : undefined,
|
||||
});
|
||||
|
||||
return result ? [{ rank: pageItem.rank, result }] : [];
|
||||
}),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return NextResponse.json(results);
|
||||
}
|
||||
|
||||
@@ -146,10 +146,6 @@ export function AIChatInput(props: {
|
||||
<Icon icon="message-question" className="size-3.5 opacity-7" />
|
||||
{t(language, 'ai_chat_context_previous_messages')}
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<Icon icon="lock" className="size-3.5 opacity-7" />
|
||||
{t(language, 'ai_chat_context_sensitive_info')}
|
||||
</li>
|
||||
</ul>
|
||||
<p>{t(language, 'ai_chat_context_disclaimer')}</p>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ export function AnnotationPopover(props: { children: React.ReactNode; body: Reac
|
||||
>
|
||||
<dfn
|
||||
data-annotation=""
|
||||
className="not-italic cursor-help underline decoration-dotted decoration-1 underline-offset-2"
|
||||
className="cursor-help underline decoration-dotted decoration-1 underline-offset-2"
|
||||
// oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- we want to be able to focus the definition to open the tooltip
|
||||
tabIndex={0}
|
||||
>
|
||||
|
||||
@@ -709,19 +709,6 @@ function joinLineContent(line: HighlightLine): string {
|
||||
return visit(line.tokens);
|
||||
}
|
||||
|
||||
it('keeps the last letter of a bash word before `>` in the same token', async () => {
|
||||
const tokenContents = async (code: string) => {
|
||||
const lines = await highlightWithInlines(singleLineBlock('bash', code));
|
||||
return lines[0]!.tokens.map((t) => (t.type === 'shiki' ? t.token.content : ''));
|
||||
};
|
||||
|
||||
const placeholder = await tokenContents('cli create --name <resource name>');
|
||||
expect(placeholder.find((c) => c.includes('nam'))).toContain('name');
|
||||
|
||||
const fdRedirect = await tokenContents('cmd 2>&1');
|
||||
expect(fdRedirect.find((c) => c.includes('2'))).toContain('2>&1');
|
||||
});
|
||||
|
||||
function singleLineBlock(syntax: string | undefined, text: string): DocumentBlockCode {
|
||||
return {
|
||||
object: 'block',
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useRouter } from 'next/navigation';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { createStore, useStore } from 'zustand';
|
||||
|
||||
import type { GitBookIntegrationTool } from '@gitbook/browser-types';
|
||||
import type { GitBookEmbeddableConfiguration, ParentToFrameMessage } from '@gitbook/embed';
|
||||
|
||||
import { integrationsAssistantTools } from '../Integrations';
|
||||
@@ -108,8 +107,7 @@ export function EmbeddableIframeAPI(props: { baseURL: string }) {
|
||||
const { settings } = message;
|
||||
embeddableConfiguration.setState(settings);
|
||||
integrationsAssistantTools.setState({
|
||||
// The embed types icons as plain strings to avoid depending on @gitbook/icons.
|
||||
tools: settings.tools as GitBookIntegrationTool[],
|
||||
tools: settings.tools,
|
||||
});
|
||||
|
||||
const defaultPage =
|
||||
|
||||
@@ -49,8 +49,7 @@ export function ScrollSectionsList({ sections }: { sections: DocumentSection[] }
|
||||
|
||||
React.useEffect(() => {
|
||||
if (activeId && activeItemRef.current && scrollContainerRef.current) {
|
||||
// The list's wrapper is the element that scrolls, not the list itself.
|
||||
scrollContainerRef.current.parentElement?.scrollTo({
|
||||
scrollContainerRef.current?.scrollTo({
|
||||
top: activeItemRef.current.offsetTop - ACTIVE_ITEM_OFFSET,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { SiteExternalLink, SiteSection, SiteSectionGroup, SiteSpace } from
|
||||
|
||||
import { hasMultipleSiteSections } from '../SiteSections';
|
||||
import type { GitBookSiteContext } from '@/lib/context';
|
||||
import { getSearchSpaceLookup } from '@/lib/search';
|
||||
import type { DirectSearchProps } from '@/lib/search-results';
|
||||
import { getLocalizedTitle } from '@/lib/sites';
|
||||
|
||||
export type SearchSection = Pick<SiteSection, 'id' | 'icon' | 'object'> & {
|
||||
@@ -29,7 +27,6 @@ export interface SearchBaseProps {
|
||||
withSiteVariants: boolean;
|
||||
indexURL: string;
|
||||
searchURL: string;
|
||||
directSearch?: DirectSearchProps;
|
||||
}
|
||||
|
||||
export function getSearchBaseProps(context: GitBookSiteContext): SearchBaseProps {
|
||||
@@ -41,9 +38,6 @@ export function getSearchBaseProps(context: GitBookSiteContext): SearchBaseProps
|
||||
|
||||
return {
|
||||
searchURL: context.linker.toPathInSpace('~gitbook/search'),
|
||||
directSearch: context.directSearch
|
||||
? { ...context.directSearch, spaces: getSearchSpaceLookup(context.structure) }
|
||||
: undefined,
|
||||
section,
|
||||
sections,
|
||||
siteSpace,
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Spike only: lets a measurement harness switch the search arms from the browser without a rebuild,
|
||||
// via `localStorage.gb_search_spike = '{"direct": false, "debounceMs": 200}'`.
|
||||
// Delete this module (and its two call sites in useSearchResults.ts) when the spike ends.
|
||||
|
||||
const STORAGE_KEY = 'gb_search_spike';
|
||||
|
||||
type SearchSpikeOverrides = {
|
||||
/** `false` forces the search route, `true` uses the API directly whenever the page allows it. */
|
||||
direct?: boolean;
|
||||
/** Replaces the search debounce. */
|
||||
debounceMs?: number;
|
||||
};
|
||||
|
||||
export function getSearchSpikeOverrides(): SearchSpikeOverrides {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const parsed: unknown = JSON.parse(raw);
|
||||
if (!parsed || typeof parsed !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { direct, debounceMs } = parsed as Record<string, unknown>;
|
||||
return {
|
||||
direct: typeof direct === 'boolean' ? direct : undefined,
|
||||
debounceMs:
|
||||
typeof debounceMs === 'number' && Number.isFinite(debounceMs) && debounceMs >= 0
|
||||
? debounceMs
|
||||
: undefined,
|
||||
};
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,6 @@ export function useSearchController(
|
||||
withSections,
|
||||
siteSpaces,
|
||||
searchURL,
|
||||
directSearch,
|
||||
indexURL,
|
||||
} = props;
|
||||
|
||||
@@ -260,7 +259,6 @@ export function useSearchController(
|
||||
scope: state?.scope ?? 'default',
|
||||
suggestions: config.suggestions,
|
||||
searchURL,
|
||||
directSearch,
|
||||
indexURL,
|
||||
lang: siteSpace.space.language,
|
||||
withSections,
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { readStreamableValue } from 'ai/rsc';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import React from 'react';
|
||||
import { assert } from 'ts-essentials';
|
||||
|
||||
import type { SearchRecordResult, SearchSpaceResult } from '@gitbook/api';
|
||||
|
||||
import { useTrackEvent } from '../Insights';
|
||||
import {
|
||||
type RecommendedQuestionResult,
|
||||
@@ -16,19 +13,10 @@ import { useRecentSearchQueries } from './recent-queries';
|
||||
import { type MergedPageResult, fuseSearchResults } from './reciprocalRankFusion';
|
||||
import { computeRemoteSearchScope } from './remote-scope';
|
||||
import type { OrderedComputedResult, SearchSiteContentScope } from './search-types';
|
||||
import { getSearchSpikeOverrides } from './searchSpikeOverrides';
|
||||
import { streamRecommendedQuestions } from './server-actions';
|
||||
import { type LocalPageResult, useLocalSearchResults } from './useLocalSearchResults';
|
||||
import type { SearchScope } from './useSearch';
|
||||
import { useAI } from '@/components/AI';
|
||||
import { getEmbeddableLinker } from '@/lib/embeddable-linker';
|
||||
import { createSiteLinker } from '@/lib/links';
|
||||
import { removeTrailingSlash } from '@/lib/paths';
|
||||
import {
|
||||
type DirectSearchProps,
|
||||
computePublishedSearchResults,
|
||||
toSearchSiteContentBody,
|
||||
} from '@/lib/search-results';
|
||||
|
||||
export type ResultType =
|
||||
| OrderedComputedResult
|
||||
@@ -41,9 +29,6 @@ export type { LocalPageResult, MergedPageResult };
|
||||
// Small helper extracted for unit testing of scope → local filter mapping
|
||||
// computeFilterSiteSpaceIds is imported from './filter' for testability
|
||||
|
||||
/** Delay between the last keystroke and the remote search request. */
|
||||
const SEARCH_DEBOUNCE_MS = 200;
|
||||
|
||||
/**
|
||||
* We cache the recommended questions globally to avoid calling the API multiple times
|
||||
* when re-opening the search modal. The cache is per space, so that we can
|
||||
@@ -65,8 +50,6 @@ export function useSearchResults(props: {
|
||||
suggestions?: string[];
|
||||
/** URL for the search API route (e.g. from linker.toPathInSpace('~gitbook/search')). */
|
||||
searchURL: string;
|
||||
/** Target to query the search API directly from the browser, when the page allows it. */
|
||||
directSearch?: DirectSearchProps;
|
||||
/** URL for the local index JSON (e.g. from linker.toPathInSite('~gitbook/site-index')). */
|
||||
indexURL: string;
|
||||
/** BCP-47 language code of the current site space, used to filter local search results. */
|
||||
@@ -85,7 +68,6 @@ export function useSearchResults(props: {
|
||||
scope,
|
||||
suggestions,
|
||||
searchURL,
|
||||
directSearch,
|
||||
indexURL,
|
||||
lang,
|
||||
withSections,
|
||||
@@ -226,15 +208,10 @@ export function useSearchResults(props: {
|
||||
let cancelled = false;
|
||||
const abortController = new AbortController();
|
||||
const timeout = setTimeout(async () => {
|
||||
const fetchSearch = (scope: SearchSiteContentScope): Promise<OrderedComputedResult[]> =>
|
||||
fetchSearchResults({
|
||||
searchURL,
|
||||
directSearch,
|
||||
scope,
|
||||
query,
|
||||
signal: abortController.signal,
|
||||
asEmbeddable,
|
||||
});
|
||||
const fetchSearch = (
|
||||
scope: Parameters<typeof fetchSearchResults>[1]
|
||||
): Promise<OrderedComputedResult[]> =>
|
||||
fetchSearchResults(searchURL, scope, query, abortController.signal, asEmbeddable);
|
||||
|
||||
try {
|
||||
const resultsPromise = fetchSearch(
|
||||
@@ -284,7 +261,7 @@ export function useSearchResults(props: {
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
}, getSearchSpikeOverrides().debounceMs ?? SEARCH_DEBOUNCE_MS);
|
||||
}, 200);
|
||||
|
||||
abortRef.current = () => {
|
||||
cancelled = true;
|
||||
@@ -309,7 +286,6 @@ export function useSearchResults(props: {
|
||||
disabled,
|
||||
suggestions,
|
||||
searchURL,
|
||||
directSearch,
|
||||
asEmbeddable,
|
||||
]);
|
||||
|
||||
@@ -362,107 +338,14 @@ export function useSearchResults(props: {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch search results from the search API, or from the search route when the page can't query it.
|
||||
*/
|
||||
async function fetchSearchResults(input: {
|
||||
searchURL: string;
|
||||
directSearch: DirectSearchProps | undefined;
|
||||
scope: SearchSiteContentScope;
|
||||
query: string;
|
||||
signal: AbortSignal;
|
||||
asEmbeddable: boolean | undefined;
|
||||
}): Promise<OrderedComputedResult[]> {
|
||||
const { searchURL, directSearch, scope, query, signal, asEmbeddable } = input;
|
||||
|
||||
if (directSearch && canSearchDirectly(directSearch)) {
|
||||
try {
|
||||
return await fetchDirectSearchResults({
|
||||
directSearch,
|
||||
scope,
|
||||
query,
|
||||
signal,
|
||||
asEmbeddable: Boolean(asEmbeddable),
|
||||
});
|
||||
} catch (error) {
|
||||
if (signal.aborted) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fetchRouteSearchResults(searchURL, scope, query, signal, asEmbeddable);
|
||||
}
|
||||
|
||||
function canSearchDirectly(directSearch: DirectSearchProps): boolean {
|
||||
if (getSearchSpikeOverrides().direct === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const { exp } = jwtDecode<{ exp?: number }>(directSearch.apiToken);
|
||||
// Same margin as the static routes, which stop serving a token this close to expiry.
|
||||
return typeof exp === 'number' && exp > Date.now() / 1000 + 120;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchDirectSearchResults(input: {
|
||||
directSearch: DirectSearchProps;
|
||||
scope: SearchSiteContentScope;
|
||||
query: string;
|
||||
signal: AbortSignal;
|
||||
asEmbeddable: boolean;
|
||||
}): Promise<OrderedComputedResult[]> {
|
||||
const { directSearch, scope, query, signal, asEmbeddable } = input;
|
||||
const { apiURL, apiToken, organizationId, siteId, spaces } = directSearch;
|
||||
|
||||
if (query.length <= 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`${removeTrailingSlash(apiURL)}/v1/orgs/${organizationId}/sites/${siteId}/search`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(toSearchSiteContentBody(query, scope)),
|
||||
signal,
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Direct search request failed: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
items?: (SearchSpaceResult | SearchRecordResult)[];
|
||||
};
|
||||
if (!Array.isArray(data?.items)) {
|
||||
throw new Error('Direct search response has no items');
|
||||
}
|
||||
|
||||
const linker = createSiteLinker(directSearch.linker);
|
||||
return computePublishedSearchResults({
|
||||
asEmbeddable,
|
||||
linker: asEmbeddable ? getEmbeddableLinker(linker) : linker,
|
||||
searchResults: data.items,
|
||||
spaces,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch search results from the search API route.
|
||||
*/
|
||||
async function fetchRouteSearchResults(
|
||||
async function fetchSearchResults(
|
||||
searchURL: string,
|
||||
scope: SearchSiteContentScope,
|
||||
query: string,
|
||||
signal: AbortSignal,
|
||||
signal?: AbortSignal,
|
||||
asEmbeddable?: boolean
|
||||
): Promise<OrderedComputedResult[]> {
|
||||
const response = await fetch(searchURL, {
|
||||
|
||||
@@ -65,16 +65,11 @@ export async function SiteLayout(props: {
|
||||
const scripts = withTracking ? context.scripts : [];
|
||||
|
||||
// React dedupes preconnects by href, so reduce to the origin; relative URLs are same-origin.
|
||||
[GITBOOK_ICONS_URL, GITBOOK_ASSETS_URL].forEach((url) => {
|
||||
[GITBOOK_API_PUBLIC_URL, GITBOOK_ICONS_URL, GITBOOK_ASSETS_URL].forEach((url) => {
|
||||
if (url && URL.canParse(url)) {
|
||||
ReactDOM.preconnect(new URL(url).origin);
|
||||
}
|
||||
});
|
||||
// Search queries the API with a CORS fetch without credentials, which only reuses an
|
||||
// anonymous connection.
|
||||
if (URL.canParse(GITBOOK_API_PUBLIC_URL)) {
|
||||
ReactDOM.preconnect(new URL(GITBOOK_API_PUBLIC_URL).origin, { crossOrigin: 'anonymous' });
|
||||
}
|
||||
|
||||
// Start the search-index download from the HTML itself. `crossOrigin` must match the
|
||||
// client `fetch()` (cors + same-origin credentials) or the preload is ignored and the
|
||||
|
||||
@@ -137,7 +137,6 @@ export const ar: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'الصفحة التي أنت عليها الآن',
|
||||
ai_chat_context_info_provided_by_the_site: 'معلومات عنك يوفرها الموقع',
|
||||
ai_chat_context_previous_messages: 'الرسائل في محادثتك',
|
||||
ai_chat_context_sensitive_info: 'لا تشارك معلومات شخصية حساسة',
|
||||
ai_chat_context_disclaimer: 'قد تحتوي إجابات الذكاء الاصطناعي على أخطاء.',
|
||||
ai_chat_input_placeholder: 'اسأل أو ابحث أو اشرح...',
|
||||
ai_chat_queued_message: 'سيتم إرسال هذه الرسالة بعد أن ينتهي ${1}',
|
||||
|
||||
@@ -141,7 +141,6 @@ export const bg: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Страницата, на която сте в момента',
|
||||
ai_chat_context_info_provided_by_the_site: 'Информация за вас, предоставена от сайта',
|
||||
ai_chat_context_previous_messages: 'Съобщения във вашия разговор',
|
||||
ai_chat_context_sensitive_info: 'Не споделяйте чувствителна лична информация',
|
||||
ai_chat_context_disclaimer: 'AI отговорите може да съдържат грешки.',
|
||||
ai_chat_input_placeholder: 'Попитайте, потърсете или обяснете...',
|
||||
ai_chat_queued_message: 'Това съобщение ще бъде изпратено, след като ${1} приключи',
|
||||
|
||||
@@ -139,7 +139,6 @@ export const cs: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Stránka, na které se právě nacházíte',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informace o vás poskytnuté webem',
|
||||
ai_chat_context_previous_messages: 'Zprávy ve vaší konverzaci',
|
||||
ai_chat_context_sensitive_info: 'Nesdílejte citlivé osobní údaje',
|
||||
ai_chat_context_disclaimer: 'Odpovědi AI mohou obsahovat chyby.',
|
||||
ai_chat_input_placeholder: 'Zeptejte se, hledejte nebo vysvětlete...',
|
||||
ai_chat_queued_message: 'Tato zpráva se odešle, až ${1} dokončí odpověď',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const da: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Siden du er på nu',
|
||||
ai_chat_context_info_provided_by_the_site: 'Oplysninger om dig fra webstedet',
|
||||
ai_chat_context_previous_messages: 'Beskeder i din samtale',
|
||||
ai_chat_context_sensitive_info: 'Del ikke følsomme personoplysninger',
|
||||
ai_chat_context_disclaimer: 'AI-svar kan indeholde fejl.',
|
||||
ai_chat_input_placeholder: 'Spørg, søg eller forklar...',
|
||||
ai_chat_queued_message: 'Denne besked sendes, når ${1} er færdig',
|
||||
|
||||
@@ -145,7 +145,6 @@ export const de: TranslationLanguage = {
|
||||
ai_chat_context_info_provided_by_the_site:
|
||||
'Von der Website bereitgestellte Informationen über Sie',
|
||||
ai_chat_context_previous_messages: 'Nachrichten in Ihrem Gespräch',
|
||||
ai_chat_context_sensitive_info: 'Teilen Sie keine sensiblen persönlichen Daten',
|
||||
ai_chat_context_disclaimer: 'KI-Antworten können Fehler enthalten.',
|
||||
ai_chat_input_placeholder: 'Fragen, suchen oder erklären...',
|
||||
ai_chat_queued_message: 'Diese Nachricht wird gesendet, sobald ${1} fertig ist',
|
||||
|
||||
@@ -143,7 +143,6 @@ export const el: TranslationLanguage = {
|
||||
ai_chat_context_info_provided_by_the_site:
|
||||
'Πληροφορίες για εσάς που παρέχονται από τον ιστότοπο',
|
||||
ai_chat_context_previous_messages: 'Μηνύματα στη συνομιλία σας',
|
||||
ai_chat_context_sensitive_info: 'Μην κοινοποιείτε ευαίσθητες προσωπικές πληροφορίες',
|
||||
ai_chat_context_disclaimer: 'Οι απαντήσεις AI μπορεί να περιέχουν λάθη.',
|
||||
ai_chat_input_placeholder: 'Ρωτήστε, αναζητήστε ή εξηγήστε...',
|
||||
ai_chat_queued_message: 'Αυτό το μήνυμα θα σταλεί μόλις ολοκληρώσει ${1}',
|
||||
|
||||
@@ -137,7 +137,6 @@ export const en = {
|
||||
ai_chat_context_pages_youve_read: "The page you're on now",
|
||||
ai_chat_context_info_provided_by_the_site: 'Info about you provided by the site',
|
||||
ai_chat_context_previous_messages: 'Messages in your conversation',
|
||||
ai_chat_context_sensitive_info: "Don't share sensitive personal info",
|
||||
ai_chat_context_disclaimer: 'AI responses may contain mistakes.',
|
||||
ai_chat_input_placeholder: 'Ask, search, or explain...',
|
||||
ai_chat_queued_message: 'This message will be sent after ${1} finishes',
|
||||
|
||||
@@ -143,7 +143,6 @@ export const es: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'La página en la que estás ahora',
|
||||
ai_chat_context_info_provided_by_the_site: 'Información sobre ti proporcionada por el sitio',
|
||||
ai_chat_context_previous_messages: 'Mensajes de tu conversación',
|
||||
ai_chat_context_sensitive_info: 'No compartas información personal confidencial',
|
||||
ai_chat_context_disclaimer: 'Las respuestas de IA pueden contener errores.',
|
||||
ai_chat_input_placeholder: 'Pregunta, busca o explica...',
|
||||
ai_chat_queued_message: 'Este mensaje se enviará cuando ${1} termine',
|
||||
|
||||
@@ -139,7 +139,6 @@ export const et: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Leht, kus te praegu asute',
|
||||
ai_chat_context_info_provided_by_the_site: 'Saidi pakutud teave teie kohta',
|
||||
ai_chat_context_previous_messages: 'Teie vestluse sõnumid',
|
||||
ai_chat_context_sensitive_info: 'Ärge jagage tundlikku isikuteavet',
|
||||
ai_chat_context_disclaimer: 'AI vastused võivad sisaldada vigu.',
|
||||
ai_chat_input_placeholder: 'Küsige, otsige või selgitage...',
|
||||
ai_chat_queued_message: 'See sõnum saadetakse, kui ${1} on lõpetanud',
|
||||
|
||||
@@ -140,7 +140,6 @@ export const fi: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Sivu, jolla olet nyt',
|
||||
ai_chat_context_info_provided_by_the_site: 'Sivuston tarjoamat tiedot sinusta',
|
||||
ai_chat_context_previous_messages: 'Viestit keskustelussasi',
|
||||
ai_chat_context_sensitive_info: 'Älä jaa arkaluonteisia henkilötietoja',
|
||||
ai_chat_context_disclaimer: 'AI-vastaukset voivat sisältää virheitä.',
|
||||
ai_chat_input_placeholder: 'Kysy, hae tai selitä...',
|
||||
ai_chat_queued_message: 'Tämä viesti lähetetään, kun ${1} on valmis',
|
||||
|
||||
@@ -139,7 +139,6 @@ export const fr: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'La page sur laquelle vous êtes actuellement',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informations vous concernant fournies par le site',
|
||||
ai_chat_context_previous_messages: 'Messages de votre conversation',
|
||||
ai_chat_context_sensitive_info: 'Ne partagez pas d’informations personnelles sensibles',
|
||||
ai_chat_context_disclaimer: 'Les réponses générées peuvent contenir des erreurs.',
|
||||
ai_chat_input_placeholder: 'Demander, rechercher ou expliquer...',
|
||||
ai_chat_queued_message: 'Ce message sera envoyé une fois que ${1} aura terminé',
|
||||
|
||||
@@ -136,7 +136,6 @@ export const he: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'הדף שאתה נמצא בו כעת',
|
||||
ai_chat_context_info_provided_by_the_site: 'מידע עליך שסופק על ידי האתר',
|
||||
ai_chat_context_previous_messages: 'הודעות בשיחה שלך',
|
||||
ai_chat_context_sensitive_info: 'אל תשתפו מידע אישי רגיש',
|
||||
ai_chat_context_disclaimer: 'תשובות AI עשויות להכיל טעויות.',
|
||||
ai_chat_input_placeholder: 'שאל, חפש או הסבר...',
|
||||
ai_chat_queued_message: 'הודעה זו תישלח לאחר ש-${1} יסיים',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const hi: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'वह पृष्ठ जिस पर आप अभी हैं',
|
||||
ai_chat_context_info_provided_by_the_site: 'साइट द्वारा प्रदान की गई आपके बारे में जानकारी',
|
||||
ai_chat_context_previous_messages: 'आपकी बातचीत के संदेश',
|
||||
ai_chat_context_sensitive_info: 'संवेदनशील व्यक्तिगत जानकारी साझा न करें',
|
||||
ai_chat_context_disclaimer: 'AI उत्तरों में गलतियां हो सकती हैं।',
|
||||
ai_chat_input_placeholder: 'पूछें, खोजें या समझाएं...',
|
||||
ai_chat_queued_message: 'यह संदेश ${1} के समाप्त होने के बाद भेजा जाएगा',
|
||||
|
||||
@@ -139,7 +139,6 @@ export const hr: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Stranica na kojoj se trenutno nalazite',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informacije o vama koje pruža web-mjesto',
|
||||
ai_chat_context_previous_messages: 'Poruke u vašem razgovoru',
|
||||
ai_chat_context_sensitive_info: 'Ne dijelite osjetljive osobne podatke',
|
||||
ai_chat_context_disclaimer: 'AI odgovori mogu sadržavati pogreške.',
|
||||
ai_chat_input_placeholder: 'Pitajte, pretražite ili objasnite...',
|
||||
ai_chat_queued_message: 'Ova poruka bit će poslana kada ${1} završi',
|
||||
|
||||
@@ -141,7 +141,6 @@ export const hu: TranslationLanguage = {
|
||||
ai_chat_context_info_provided_by_the_site:
|
||||
'Az Önről szóló, a webhely által megadott információk',
|
||||
ai_chat_context_previous_messages: 'Üzenetek a beszélgetésében',
|
||||
ai_chat_context_sensitive_info: 'Ne osszon meg érzékeny személyes adatokat',
|
||||
ai_chat_context_disclaimer: 'Az AI-válaszok hibákat tartalmazhatnak.',
|
||||
ai_chat_input_placeholder: 'Kérdezzen, keressen vagy magyarázzon...',
|
||||
ai_chat_queued_message: 'Ez az üzenet akkor lesz elküldve, amikor ${1} befejezi',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const id: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Halaman tempat Anda berada sekarang',
|
||||
ai_chat_context_info_provided_by_the_site: 'Info tentang Anda yang disediakan oleh situs',
|
||||
ai_chat_context_previous_messages: 'Pesan dalam percakapan Anda',
|
||||
ai_chat_context_sensitive_info: 'Jangan bagikan informasi pribadi yang sensitif',
|
||||
ai_chat_context_disclaimer: 'Jawaban AI dapat berisi kesalahan.',
|
||||
ai_chat_input_placeholder: 'Tanya, cari, atau jelaskan...',
|
||||
ai_chat_queued_message: 'Pesan ini akan dikirim setelah ${1} selesai',
|
||||
|
||||
@@ -142,7 +142,6 @@ export const it: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'La pagina su cui ti trovi ora',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informazioni su di te fornite dal sito',
|
||||
ai_chat_context_previous_messages: 'Messaggi nella tua conversazione',
|
||||
ai_chat_context_sensitive_info: 'Non condividere informazioni personali sensibili',
|
||||
ai_chat_context_disclaimer: "Le risposte dell'IA possono contenere errori.",
|
||||
ai_chat_input_placeholder: 'Chiedi, cerca o spiega...',
|
||||
ai_chat_queued_message: 'Questo messaggio verrà inviato quando ${1} avrà finito',
|
||||
|
||||
@@ -139,7 +139,6 @@ export const ja: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: '現在表示中のページ',
|
||||
ai_chat_context_info_provided_by_the_site: 'サイトから提供されるあなたに関する情報',
|
||||
ai_chat_context_previous_messages: '会話内のメッセージ',
|
||||
ai_chat_context_sensitive_info: '機密性の高い個人情報は共有しないでください',
|
||||
ai_chat_context_disclaimer: 'AIの回答には誤りが含まれる場合があります。',
|
||||
ai_chat_input_placeholder: '質問、検索、または説明...',
|
||||
ai_chat_queued_message: '${1}の応答が完了したら、このメッセージが送信されます',
|
||||
|
||||
@@ -139,7 +139,6 @@ export const ko: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: '현재 보고 있는 페이지',
|
||||
ai_chat_context_info_provided_by_the_site: '사이트에서 제공하는 회원님에 대한 정보',
|
||||
ai_chat_context_previous_messages: '대화의 메시지',
|
||||
ai_chat_context_sensitive_info: '민감한 개인 정보를 공유하지 마세요',
|
||||
ai_chat_context_disclaimer: 'AI 응답에는 오류가 있을 수 있습니다.',
|
||||
ai_chat_input_placeholder: '질문, 검색 또는 설명...',
|
||||
ai_chat_queued_message: '${1}의 응답이 끝나면 이 메시지가 전송됩니다',
|
||||
|
||||
@@ -139,7 +139,6 @@ export const lt: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Puslapis, kuriame šiuo metu esate',
|
||||
ai_chat_context_info_provided_by_the_site: 'Svetainės pateikta informacija apie jus',
|
||||
ai_chat_context_previous_messages: 'Pranešimai jūsų pokalbyje',
|
||||
ai_chat_context_sensitive_info: 'Nebendrinkite jautrios asmeninės informacijos',
|
||||
ai_chat_context_disclaimer: 'AI atsakymuose gali būti klaidų.',
|
||||
ai_chat_input_placeholder: 'Klauskite, ieškokite arba paaiškinkite...',
|
||||
ai_chat_queued_message: 'Ši žinutė bus išsiųsta, kai ${1} baigs',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const lv: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Lapa, kurā pašlaik atrodaties',
|
||||
ai_chat_context_info_provided_by_the_site: 'Vietnes sniegtā informācija par jums',
|
||||
ai_chat_context_previous_messages: 'Ziņojumi jūsų sarunā',
|
||||
ai_chat_context_sensitive_info: 'Nekopīgojiet sensitīvu personisko informāciju',
|
||||
ai_chat_context_disclaimer: 'AI atbildēs var būt kļūdas.',
|
||||
ai_chat_input_placeholder: 'Jautājiet, meklējiet vai skaidrojiet...',
|
||||
ai_chat_queued_message: 'Šī ziņa tiks nosūtīta, kad ${1} būs pabeidzis',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const ms: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Halaman yang anda berada sekarang',
|
||||
ai_chat_context_info_provided_by_the_site: 'Maklumat tentang anda yang disediakan oleh laman',
|
||||
ai_chat_context_previous_messages: 'Mesej dalam perbualan anda',
|
||||
ai_chat_context_sensitive_info: 'Jangan kongsi maklumat peribadi yang sensitif',
|
||||
ai_chat_context_disclaimer: 'Jawapan AI mungkin mengandungi kesilapan.',
|
||||
ai_chat_input_placeholder: 'Tanya, cari atau jelaskan...',
|
||||
ai_chat_queued_message: 'Mesej ini akan dihantar setelah ${1} selesai',
|
||||
|
||||
@@ -141,7 +141,6 @@ export const nl: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'De pagina waar je nu op bent',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informatie over jou verstrekt door de site',
|
||||
ai_chat_context_previous_messages: 'Berichten in je gesprek',
|
||||
ai_chat_context_sensitive_info: 'Deel geen gevoelige persoonlijke gegevens',
|
||||
ai_chat_context_disclaimer: 'AI-antwoorden kunnen fouten bevatten.',
|
||||
ai_chat_input_placeholder: 'Vraag, zoek of leg uit...',
|
||||
ai_chat_queued_message: 'Dit bericht wordt verzonden zodra ${1} klaar is',
|
||||
|
||||
@@ -141,7 +141,6 @@ export const no: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Siden du er på nå',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informasjon om deg gitt av nettstedet',
|
||||
ai_chat_context_previous_messages: 'Meldinger i samtalen din',
|
||||
ai_chat_context_sensitive_info: 'Ikke del sensitive personopplysninger',
|
||||
ai_chat_context_disclaimer: 'AI-svar kan inneholde feil.',
|
||||
ai_chat_input_placeholder: 'Spør, søk eller forklar...',
|
||||
ai_chat_queued_message: 'Denne meldingen sendes når ${1} er ferdig',
|
||||
|
||||
@@ -140,7 +140,6 @@ export const pl: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Strona, na której jesteś teraz',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informacje o Tobie podane przez stronę',
|
||||
ai_chat_context_previous_messages: 'Wiadomości w Twojej rozmowie',
|
||||
ai_chat_context_sensitive_info: 'Nie udostępniaj poufnych danych osobowych',
|
||||
ai_chat_context_disclaimer: 'Odpowiedzi AI mogą zawierać błędy.',
|
||||
ai_chat_input_placeholder: 'Zapytaj, wyszukaj lub wyjaśnij...',
|
||||
ai_chat_queued_message: 'Ta wiadomość zostanie wysłana, gdy ${1} zakończy',
|
||||
|
||||
@@ -143,7 +143,6 @@ export const pt_br: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'A página em que você está agora',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informações sobre você fornecidas pelo site',
|
||||
ai_chat_context_previous_messages: 'Mensagens na sua conversa',
|
||||
ai_chat_context_sensitive_info: 'Não compartilhe informações pessoais sensíveis',
|
||||
ai_chat_context_disclaimer: 'Respostas de IA podem conter erros.',
|
||||
ai_chat_input_placeholder: 'Pergunte, pesquise ou explique...',
|
||||
ai_chat_queued_message: 'Esta mensagem será enviada quando ${1} terminar',
|
||||
|
||||
@@ -140,7 +140,6 @@ export const pt: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'A página em que se encontra agora',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informações sobre si fornecidas pelo site',
|
||||
ai_chat_context_previous_messages: 'Mensagens na sua conversa',
|
||||
ai_chat_context_sensitive_info: 'Não partilhe informações pessoais sensíveis',
|
||||
ai_chat_context_disclaimer: 'As respostas de IA podem conter erros.',
|
||||
ai_chat_input_placeholder: 'Pergunte, pesquise ou explique...',
|
||||
ai_chat_queued_message: 'Esta mensagem será enviada quando ${1} terminar',
|
||||
|
||||
@@ -142,7 +142,6 @@ export const ro: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Pagina pe care te afli acum',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informații despre tine furnizate de site',
|
||||
ai_chat_context_previous_messages: 'Mesaje din conversația ta',
|
||||
ai_chat_context_sensitive_info: 'Nu partajați informații personale sensibile',
|
||||
ai_chat_context_disclaimer: 'Răspunsurile AI pot conține greșeli.',
|
||||
ai_chat_input_placeholder: 'Întreabă, caută sau explică...',
|
||||
ai_chat_queued_message: 'Acest mesaj va fi trimis după ce ${1} termină',
|
||||
|
||||
@@ -142,7 +142,6 @@ export const ru: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Страница, на которой вы сейчас находитесь',
|
||||
ai_chat_context_info_provided_by_the_site: 'Информация о вас, предоставленная сайтом',
|
||||
ai_chat_context_previous_messages: 'Сообщения в вашем разговоре',
|
||||
ai_chat_context_sensitive_info: 'Не передавайте конфиденциальную личную информацию',
|
||||
ai_chat_context_disclaimer: 'Ответы ИИ могут содержать ошибки.',
|
||||
ai_chat_input_placeholder: 'Спросите, найдите или объясните...',
|
||||
ai_chat_queued_message: 'Это сообщение будет отправлено, когда ${1} закончит',
|
||||
|
||||
@@ -141,7 +141,6 @@ export const sk: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Stránka, na ktorej sa práve nachádzate',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informácie o vás poskytnuté stránkou',
|
||||
ai_chat_context_previous_messages: 'Správy vo vašej konverzácii',
|
||||
ai_chat_context_sensitive_info: 'Nezdieľajte citlivé osobné údaje',
|
||||
ai_chat_context_disclaimer: 'Odpovede AI môžu obsahovať chyby.',
|
||||
ai_chat_input_placeholder: 'Pýtajte sa, hľadajte alebo vysvetľujte...',
|
||||
ai_chat_queued_message: 'Táto správa sa odošle, keď ${1} skončí',
|
||||
|
||||
@@ -140,7 +140,6 @@ export const sl: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Stran, na kateri se trenutno nahajate',
|
||||
ai_chat_context_info_provided_by_the_site: 'Informacije o vas, ki jih zagotavlja spletno mesto',
|
||||
ai_chat_context_previous_messages: 'Sporočila v vašem pogovoru',
|
||||
ai_chat_context_sensitive_info: 'Ne delite občutljivih osebnih podatkov',
|
||||
ai_chat_context_disclaimer: 'Odgovori AI lahko vsebujejo napake.',
|
||||
ai_chat_input_placeholder: 'Vprašajte, iščite ali razložite...',
|
||||
ai_chat_queued_message: 'To sporočilo bo poslano, ko ${1} zaključi',
|
||||
|
||||
@@ -140,7 +140,6 @@ export const sv: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Sidan du är på nu',
|
||||
ai_chat_context_info_provided_by_the_site: 'Information om dig från webbplatsen',
|
||||
ai_chat_context_previous_messages: 'Meddelanden i din konversation',
|
||||
ai_chat_context_sensitive_info: 'Dela inte känsliga personuppgifter',
|
||||
ai_chat_context_disclaimer: 'AI-svar kan innehålla fel.',
|
||||
ai_chat_input_placeholder: 'Fråga, sök eller förklara...',
|
||||
ai_chat_queued_message: 'Det här meddelandet skickas när ${1} är klar',
|
||||
|
||||
@@ -135,7 +135,6 @@ export const th: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'หน้าที่คุณอยู่ตอนนี้',
|
||||
ai_chat_context_info_provided_by_the_site: 'ข้อมูลเกี่ยวกับคุณที่เว็บไซต์ให้ไว้',
|
||||
ai_chat_context_previous_messages: 'ข้อความในการสนทนาของคุณ',
|
||||
ai_chat_context_sensitive_info: 'โปรดอย่าแชร์ข้อมูลส่วนบุคคลที่ละเอียดอ่อน',
|
||||
ai_chat_context_disclaimer: 'คำตอบจาก AI อาจมีข้อผิดพลาด',
|
||||
ai_chat_input_placeholder: 'ถาม ค้นหา หรืออธิบาย...',
|
||||
ai_chat_queued_message: 'ข้อความนี้จะถูกส่งหลังจากที่ ${1} เสร็จสิ้น',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const tr: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Şu anda bulunduğunuz sayfa',
|
||||
ai_chat_context_info_provided_by_the_site: 'Site tarafından sağlanan sizinle ilgili bilgiler',
|
||||
ai_chat_context_previous_messages: 'Konuşmanızdaki mesajlar',
|
||||
ai_chat_context_sensitive_info: 'Hassas kişisel bilgileri paylaşmayın',
|
||||
ai_chat_context_disclaimer: 'AI yanıtları hata içerebilir.',
|
||||
ai_chat_input_placeholder: 'Sor, ara veya açıkla...',
|
||||
ai_chat_queued_message: 'Bu mesaj, ${1} yanıtını tamamladıktan sonra gönderilecek',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const uk: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Сторінка, на якій ви зараз перебуваєте',
|
||||
ai_chat_context_info_provided_by_the_site: 'Інформація про вас, надана сайтом',
|
||||
ai_chat_context_previous_messages: 'Повідомлення у вашій розмові',
|
||||
ai_chat_context_sensitive_info: 'Не діліться конфіденційною особистою інформацією',
|
||||
ai_chat_context_disclaimer: 'Відповіді AI можуть містити помилки.',
|
||||
ai_chat_input_placeholder: 'Запитайте, знайдіть або поясніть...',
|
||||
ai_chat_queued_message: 'Це повідомлення буде надіслано, коли ${1} завершить',
|
||||
|
||||
@@ -138,7 +138,6 @@ export const vi: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: 'Trang bạn đang ở hiện tại',
|
||||
ai_chat_context_info_provided_by_the_site: 'Thông tin về bạn do trang web cung cấp',
|
||||
ai_chat_context_previous_messages: 'Tin nhắn trong cuộc trò chuyện của bạn',
|
||||
ai_chat_context_sensitive_info: 'Không chia sẻ thông tin cá nhân nhạy cảm',
|
||||
ai_chat_context_disclaimer: 'Câu trả lời AI có thể chứa lỗi.',
|
||||
ai_chat_input_placeholder: 'Hỏi, tìm kiếm hoặc giải thích...',
|
||||
ai_chat_queued_message: 'Tin nhắn này sẽ được gửi sau khi ${1} hoàn tất',
|
||||
|
||||
@@ -134,7 +134,6 @@ export const yue: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: '你而家喺嘅頁面',
|
||||
ai_chat_context_info_provided_by_the_site: '網站提供嘅關於你嘅資訊',
|
||||
ai_chat_context_previous_messages: '你對話入面嘅訊息',
|
||||
ai_chat_context_sensitive_info: '唔好分享敏感個人資料',
|
||||
ai_chat_context_disclaimer: 'AI 回答可能有錯。',
|
||||
ai_chat_input_placeholder: '發問、搜尋或說明...',
|
||||
ai_chat_queued_message: '呢個訊息會喺 ${1} 完成後發送',
|
||||
|
||||
@@ -134,7 +134,6 @@ export const zh_tw: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: '您目前所在的頁面',
|
||||
ai_chat_context_info_provided_by_the_site: '網站提供的關於您的資訊',
|
||||
ai_chat_context_previous_messages: '您對話中的訊息',
|
||||
ai_chat_context_sensitive_info: '請勿分享敏感個人資料',
|
||||
ai_chat_context_disclaimer: 'AI 回答可能包含錯誤。',
|
||||
ai_chat_input_placeholder: '提問、搜尋或說明...',
|
||||
ai_chat_queued_message: '這則訊息將在 ${1} 完成後傳送',
|
||||
|
||||
@@ -135,7 +135,6 @@ export const zh: TranslationLanguage = {
|
||||
ai_chat_context_pages_youve_read: '您当前所在的页面',
|
||||
ai_chat_context_info_provided_by_the_site: '网站提供的关于您的信息',
|
||||
ai_chat_context_previous_messages: '您对话中的消息',
|
||||
ai_chat_context_sensitive_info: '请勿分享敏感个人信息',
|
||||
ai_chat_context_disclaimer: '人工智能的回答可能包含错误。',
|
||||
ai_chat_input_placeholder: '询问、搜索或解释...',
|
||||
ai_chat_queued_message: '此消息将在 ${1} 完成后发送',
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/** Request markers for ChatGPT's server-side fetchers. */
|
||||
export function isChatGPTRequest(request: Pick<Request, 'headers'>): boolean {
|
||||
const normalizedUserAgent = request.headers.get('user-agent')?.toLowerCase() ?? '';
|
||||
const normalizedSignatureAgent = request.headers.get('signature-agent')?.toLowerCase() ?? '';
|
||||
|
||||
return (
|
||||
normalizedUserAgent.includes('chatgpt-user') ||
|
||||
normalizedUserAgent.includes('chatgpt agent') ||
|
||||
normalizedUserAgent.includes('oai-searchbot') ||
|
||||
normalizedSignatureAgent.includes('chatgpt.com')
|
||||
);
|
||||
}
|
||||
@@ -20,14 +20,9 @@ import type {
|
||||
TranslationLanguage,
|
||||
} from '@gitbook/api';
|
||||
|
||||
import { GITBOOK_API_PUBLIC_URL, GITBOOK_URL } from './env';
|
||||
import { GITBOOK_URL } from './env';
|
||||
import { type ImageResizer, createImageResizer } from './images';
|
||||
import {
|
||||
type GitBookLinker,
|
||||
type SiteLinkerInput,
|
||||
createSiteLinker,
|
||||
linkerForPublishedURL,
|
||||
} from './links';
|
||||
import { type GitBookLinker, createLinker, linkerForPublishedURL } from './links';
|
||||
import type { AskVisitorAgent } from '@/lib/ask-visitor';
|
||||
import {
|
||||
type GitBookDataFetcher,
|
||||
@@ -36,7 +31,6 @@ import {
|
||||
throwIfDataError,
|
||||
} from '@/lib/data';
|
||||
import { getLogger } from '@/lib/logger';
|
||||
import type { DirectSearchTarget } from '@/lib/search-results';
|
||||
import {
|
||||
findSiteSpaceBy,
|
||||
getFallbackSiteSpacePath,
|
||||
@@ -109,6 +103,9 @@ export type SiteURLData = Pick<
|
||||
*/
|
||||
isAiAgent?: boolean;
|
||||
|
||||
/** Whether the request comes from ChatGPT. Only set for Markdown and LLM routes. */
|
||||
isChatGPT?: boolean;
|
||||
|
||||
/**
|
||||
* Headers of the visitor asking through `?ask=`, forwarded to the API to classify the asker.
|
||||
* Only set for the ask route, which is static and can't read the request headers.
|
||||
@@ -139,11 +136,6 @@ export type GitBookBaseContext = {
|
||||
* Translation language of the space.
|
||||
*/
|
||||
locale?: TranslationLanguage;
|
||||
|
||||
/**
|
||||
* Target for the browser to query the site search API directly, when the request allows it.
|
||||
*/
|
||||
directSearch?: DirectSearchTarget;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -227,6 +219,9 @@ export type GitBookSiteContext = GitBookSpaceContext & {
|
||||
|
||||
/** Whether the request comes from a detected AI agent. Only set for markdown routes. */
|
||||
isAiAgent?: boolean;
|
||||
|
||||
/** Whether the request comes from ChatGPT. Only set for Markdown and LLM routes. */
|
||||
isChatGPT?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -251,14 +246,28 @@ export function getBaseContext(input: {
|
||||
apiToken: siteURLData.apiToken ?? null,
|
||||
});
|
||||
|
||||
const linkerInput: SiteLinkerInput = {
|
||||
urlMode,
|
||||
siteHost: siteURL.host,
|
||||
siteBasePath: siteURLData.siteBasePath,
|
||||
spaceBasePath: siteURLData.basePath,
|
||||
gitbookURL: GITBOOK_URL || undefined,
|
||||
};
|
||||
const linker = createSiteLinker(linkerInput);
|
||||
const gitbookURL = GITBOOK_URL ? new URL(GITBOOK_URL) : undefined;
|
||||
const linker =
|
||||
urlMode === 'url-host'
|
||||
? createLinker({
|
||||
host: siteURL.host,
|
||||
siteBasePath: siteURLData.siteBasePath,
|
||||
spaceBasePath: siteURLData.basePath,
|
||||
})
|
||||
: createLinker({
|
||||
protocol: gitbookURL?.protocol,
|
||||
host: gitbookURL?.host,
|
||||
siteBasePath: `/url/${siteURL.host}${siteURLData.siteBasePath}`,
|
||||
spaceBasePath: `/url/${siteURL.host}${siteURLData.basePath}`,
|
||||
});
|
||||
|
||||
if (urlMode === 'url') {
|
||||
// Create link in the same format for links to other sites/sections.
|
||||
linker.toLinkForContent = (rawURL: string) => {
|
||||
const urlObject = new URL(rawURL);
|
||||
return `/url/${urlObject.host}${urlObject.pathname}${urlObject.search}${urlObject.hash}`;
|
||||
};
|
||||
}
|
||||
|
||||
const imageResizer = createImageResizer({
|
||||
imagesContextId: siteURLData.imagesContextId,
|
||||
@@ -267,25 +276,10 @@ export function getBaseContext(input: {
|
||||
linker: linker,
|
||||
});
|
||||
|
||||
const directSearch: DirectSearchTarget | undefined =
|
||||
siteURLData.apiToken &&
|
||||
!siteURLData.revision &&
|
||||
!siteURLData.changeRequest &&
|
||||
!siteURLData.preview
|
||||
? {
|
||||
apiURL: GITBOOK_API_PUBLIC_URL,
|
||||
apiToken: siteURLData.apiToken,
|
||||
organizationId: siteURLData.organization,
|
||||
siteId: siteURLData.site,
|
||||
linker: linkerInput,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
dataFetcher,
|
||||
linker,
|
||||
imageResizer,
|
||||
directSearch,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -312,6 +306,7 @@ export async function fetchSiteContextByURLLookup(
|
||||
preview: data.preview ?? false,
|
||||
displayAgentInstructions: data.displayAgentInstructions,
|
||||
isAiAgent: data.isAiAgent,
|
||||
isChatGPT: data.isChatGPT,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -336,6 +331,7 @@ export async function fetchSiteContextByIds(
|
||||
preview: boolean;
|
||||
displayAgentInstructions?: boolean;
|
||||
isAiAgent?: boolean;
|
||||
isChatGPT?: boolean;
|
||||
}
|
||||
): Promise<GitBookSiteContext> {
|
||||
const { dataFetcher } = baseContext;
|
||||
@@ -466,6 +462,7 @@ export async function fetchSiteContextByIds(
|
||||
preview: ids.preview,
|
||||
displayAgentInstructions: ids.displayAgentInstructions,
|
||||
isAiAgent: ids.isAiAgent,
|
||||
isChatGPT: ids.isChatGPT,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
|
||||
|
||||
const cacheLife = mock((_profile: unknown) => {});
|
||||
const cacheTag = mock((..._tags: string[]) => {});
|
||||
|
||||
const realNextCache = await import('next/cache');
|
||||
mock.module('next/cache', () => ({ ...realNextCache, cacheLife, cacheTag }));
|
||||
|
||||
const { createDataFetcher } = await import('./api');
|
||||
|
||||
const originalFetch = globalThis.fetch;
|
||||
|
||||
afterAll(() => mock.restore());
|
||||
|
||||
describe('searchSiteContent', () => {
|
||||
beforeEach(() => {
|
||||
cacheLife.mockClear();
|
||||
cacheTag.mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.fetch = originalFetch;
|
||||
});
|
||||
|
||||
function mockFetch(impl: () => Promise<Response>) {
|
||||
globalThis.fetch = mock(impl);
|
||||
}
|
||||
|
||||
function search() {
|
||||
return createDataFetcher().searchSiteContent({
|
||||
organizationId: 'org-1',
|
||||
siteId: 'site-1',
|
||||
query: 'test',
|
||||
scope: { mode: 'all' },
|
||||
});
|
||||
}
|
||||
|
||||
it('caches successful results for hours with the site and response tags', async () => {
|
||||
mockFetch(async () =>
|
||||
Response.json(
|
||||
{ items: [] },
|
||||
{ headers: { 'x-gitbook-cache-tag': 'space:space-1,space:space-2' } }
|
||||
)
|
||||
);
|
||||
|
||||
const result = await search();
|
||||
|
||||
expect(result).toEqual({ data: [] });
|
||||
expect(cacheLife.mock.calls).toEqual([['hours']]);
|
||||
expect(cacheTag.mock.calls.flat()).toEqual([
|
||||
'site:site-1',
|
||||
'space:space-1',
|
||||
'space:space-2',
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not cache a transient API error', async () => {
|
||||
mockFetch(async () =>
|
||||
Response.json({ error: { code: 429, message: 'Namespace saturated' } }, { status: 429 })
|
||||
);
|
||||
|
||||
const result = await search();
|
||||
|
||||
expect(result.error?.code).toBe(429);
|
||||
expect(cacheLife.mock.calls).toEqual([[{ stale: 0, revalidate: 0, expire: 0 }]]);
|
||||
});
|
||||
|
||||
it('does not cache a network failure', async () => {
|
||||
mockFetch(() => Promise.reject(new TypeError('fetch failed')));
|
||||
|
||||
const result = await search();
|
||||
|
||||
expect(result.error?.code).toBe(500);
|
||||
expect(cacheLife.mock.calls).toEqual([[{ stale: 0, revalidate: 0, expire: 0 }]]);
|
||||
});
|
||||
|
||||
it('keeps the default cache life for a stable 404', async () => {
|
||||
mockFetch(async () =>
|
||||
Response.json({ error: { code: 404, message: 'Site not found' } }, { status: 404 })
|
||||
);
|
||||
|
||||
const result = await search();
|
||||
|
||||
expect(result.error?.code).toBe(404);
|
||||
expect(cacheLife).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -6,14 +6,14 @@ import {
|
||||
GitBookAPI,
|
||||
type HttpResponse,
|
||||
type RenderIntegrationUI,
|
||||
type SiteSearchScope,
|
||||
} from '@gitbook/api';
|
||||
import { getCacheTag, getComputedContentSourceCacheTags } from '@gitbook/cache-tags';
|
||||
|
||||
import { cache } from '../cache';
|
||||
import { DataFetcherError, wrapDataFetcherError } from './errors';
|
||||
import { DataFetcherError, isTransientDataFetcherError, wrapDataFetcherError } from './errors';
|
||||
import type { GitBookDataFetcher } from './types';
|
||||
import { GITBOOK_API_TOKEN, GITBOOK_API_URL, GITBOOK_USER_AGENT } from '@/lib/env';
|
||||
import { toSearchSiteContentBody } from '@/lib/search-results';
|
||||
import { trace } from '@/lib/tracing';
|
||||
|
||||
interface DataFetcherInput {
|
||||
@@ -785,12 +785,21 @@ const getEmbedByUrl = cache(
|
||||
}
|
||||
);
|
||||
|
||||
// We don't use remote cache for this one because of the number of potential cache entry causing 429 on vercel runtime cache when revalidating
|
||||
const searchSiteContent = cache(
|
||||
async (
|
||||
input: DataFetcherInput,
|
||||
params: Parameters<GitBookDataFetcher['searchSiteContent']>[0]
|
||||
) => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
'use cache';
|
||||
cacheTag(
|
||||
getCacheTag({
|
||||
tag: 'site',
|
||||
site: params.siteId,
|
||||
})
|
||||
);
|
||||
|
||||
const result = await wrapDataFetcherError(async () => {
|
||||
return trace(
|
||||
`searchSiteContent(${params.organizationId}, ${params.siteId}, ${params.query})`,
|
||||
async () => {
|
||||
@@ -799,16 +808,39 @@ const searchSiteContent = cache(
|
||||
const res = await api.orgs.searchSiteContent(
|
||||
organizationId,
|
||||
siteId,
|
||||
toSearchSiteContentBody(query, scope),
|
||||
{
|
||||
query,
|
||||
...(scope.mode === 'current' && scope.restrictTo
|
||||
? {
|
||||
// `restrictTo` only exists in the newer `scope` request shape,
|
||||
// and the published @gitbook/api types don't include it yet.
|
||||
scope: {
|
||||
mode: 'default',
|
||||
currentSiteSpace: scope.siteSpaceId,
|
||||
restrictTo: scope.restrictTo,
|
||||
} as SiteSearchScope,
|
||||
}
|
||||
: scope),
|
||||
},
|
||||
{},
|
||||
{
|
||||
...noCacheFetchOptions,
|
||||
}
|
||||
);
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('hours');
|
||||
return res.data.items;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Don't serve transient errors for the default 15 minutes. Only safe because search runs in
|
||||
// request handlers: a page cache calling it would inherit this short life during API incidents.
|
||||
if (result.error && isTransientDataFetcherError(result.error)) {
|
||||
cacheLife({ stale: 0, revalidate: 0, expire: 0 });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { DataFetcherError, getExposableError } from './errors';
|
||||
const INTERNAL_PATHS = [
|
||||
// Simple `~gitbook` endpoints. `image`, `__evt` and `visitor` are served by the middleware
|
||||
// before the lookup, but are listed so this stays a complete registry.
|
||||
/^~gitbook\/(pdf|search|search-prewarm|icon|site-index|image|__evt|visitor)$/,
|
||||
/^~gitbook\/(pdf|search|icon|site-index|image|__evt|visitor)$/,
|
||||
/^~gitbook\/ogimage\/[^/]+$/,
|
||||
/^~gitbook\/auth\/(login|logout)$/,
|
||||
/^~gitbook\/oauth2\/v1\/[^/]+\/authorize$/,
|
||||
|
||||
@@ -197,50 +197,6 @@ export function createLinker(
|
||||
return linker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializable inputs of the linker of a site request.
|
||||
*/
|
||||
export type SiteLinkerInput = {
|
||||
urlMode: 'url' | 'url-host';
|
||||
siteHost: string;
|
||||
siteBasePath: string;
|
||||
spaceBasePath: string;
|
||||
/** Main host GitBook runs on, used in `url` mode. */
|
||||
gitbookURL: string | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the linker of a site request, for the URL mode it is served in.
|
||||
*/
|
||||
export function createSiteLinker(input: SiteLinkerInput): GitBookLinker {
|
||||
const { urlMode, siteHost, siteBasePath, spaceBasePath } = input;
|
||||
const gitbookURL = input.gitbookURL ? new URL(input.gitbookURL) : undefined;
|
||||
|
||||
const linker =
|
||||
urlMode === 'url-host'
|
||||
? createLinker({
|
||||
host: siteHost,
|
||||
siteBasePath,
|
||||
spaceBasePath,
|
||||
})
|
||||
: createLinker({
|
||||
protocol: gitbookURL?.protocol,
|
||||
host: gitbookURL?.host,
|
||||
siteBasePath: `/url/${siteHost}${siteBasePath}`,
|
||||
spaceBasePath: `/url/${siteHost}${spaceBasePath}`,
|
||||
});
|
||||
|
||||
if (urlMode === 'url') {
|
||||
// Create link in the same format for links to other sites/sections.
|
||||
linker.toLinkForContent = (rawURL: string) => {
|
||||
const urlObject = new URL(rawURL);
|
||||
return `/url/${urlObject.host}${urlObject.pathname}${urlObject.search}${urlObject.hash}`;
|
||||
};
|
||||
}
|
||||
|
||||
return linker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new linker that intercepts links that belongs to the published site and rewrite them
|
||||
* relative to the URL being served.
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
|
||||
import { isChatGPTRequest } from './chatgpt';
|
||||
import { getMarkdownContentType } from './markdown-content-type';
|
||||
|
||||
describe('ChatGPT Markdown compatibility', () => {
|
||||
const requestWith = (headers: Record<string, string>) => ({ headers: new Headers(headers) });
|
||||
|
||||
it('detects ChatGPT requests without matching other agents', () => {
|
||||
expect(isChatGPTRequest(requestWith({ 'user-agent': 'ChatGPT-User/1.0' }))).toBe(true);
|
||||
expect(isChatGPTRequest(requestWith({ 'user-agent': 'ChatGPT Agent' }))).toBe(true);
|
||||
expect(
|
||||
isChatGPTRequest(
|
||||
requestWith({
|
||||
'user-agent':
|
||||
'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OAI-SearchBot/1.4; +https://openai.com/searchbot',
|
||||
})
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
isChatGPTRequest(
|
||||
requestWith({
|
||||
'user-agent': 'SomeClient/1.0',
|
||||
'signature-agent': '"https://chatgpt.com"',
|
||||
})
|
||||
)
|
||||
).toBe(true);
|
||||
expect(isChatGPTRequest(requestWith({ 'user-agent': 'GPTBot/1.2' }))).toBe(false);
|
||||
expect(isChatGPTRequest(requestWith({ 'user-agent': 'ClaudeBot/1.0' }))).toBe(false);
|
||||
});
|
||||
|
||||
it('uses plain text only for ChatGPT responses', () => {
|
||||
expect(getMarkdownContentType(true)).toBe('text/plain; charset=utf-8');
|
||||
expect(getMarkdownContentType(false)).toBe('text/markdown; charset=utf-8');
|
||||
expect(getMarkdownContentType()).toBe('text/markdown; charset=utf-8');
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user