mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-11-09 13:12:14 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 140fc02e5c | |||
| 6c128729b2 | |||
| fa8f0bccf0 | |||
| 6344646974 | |||
| 192863526f | |||
| 09a8310c9d | |||
| a023a7131b | |||
| 198cafe978 | |||
| 268fa83683 | |||
| 123454d2ac | |||
| e6b8502036 | |||
| 3837c484a6 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Warn visitors not to share sensitive personal info in the Assistant context popover.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Fix bash code blocks colouring the last letter of a word before `>` differently, as in `<name>`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Bump Next.js to 16.4.5 and OpenNext (Cloudflare 1.20.16, AWS 4.1.15), keeping the dev-mode OOM patch.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/colors": patch
|
||||
---
|
||||
|
||||
Expand 3-digit hex colors correctly in `hexToRgbArray`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Remove italic from dfn styling
|
||||
@@ -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
|
||||
---
|
||||
|
||||
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
|
||||
---
|
||||
|
||||
Serve a disallow-all robots.txt instead of redirecting to sign-in on authenticated access sites.
|
||||
@@ -161,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).
|
||||
@@ -129,8 +129,8 @@
|
||||
"@gitbook/react-openapi": "workspace:*",
|
||||
"@mermaid-js/mermaid-zenuml": "^0.2.2",
|
||||
"@modelcontextprotocol/sdk": "1.17.5",
|
||||
"@opennextjs/aws": "4.1.11",
|
||||
"@opennextjs/cloudflare": "1.20.12",
|
||||
"@opennextjs/aws": "4.1.15",
|
||||
"@opennextjs/cloudflare": "1.20.16",
|
||||
"@panzoom/panzoom": "^4.6.1",
|
||||
"@sindresorhus/fnv1a": "^3.1.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
@@ -160,7 +160,7 @@
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"motion": "^12.23.24",
|
||||
"negotiator": "^1.0.0",
|
||||
"next": "^16.4.3",
|
||||
"next": "^16.4.5",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.2.3",
|
||||
"object-hash": "^3.0.0",
|
||||
@@ -342,8 +342,9 @@
|
||||
},
|
||||
"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 +889,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.3", "", {}, "sha512-a7tz1QCcWWkwC/rPJcPMJk/UNRu9CFhDd3OHYE5hddbJrs8BqRTalxI6GlKCWEGzRLHN+S/B7a4PAHCtm25aBQ=="],
|
||||
"@next/env": ["@next/env@16.4.5", "", {}, "sha512-JwSPwpdkZL5VMl2jA/q+JI8MZdweAL3xmw5/tb9y/TLtmS0YXZnmYDzSihwk8xTj1OL+WM53gTqaj96yuLp6Xw=="],
|
||||
|
||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.4.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4yq5EXBt+VDtAZwTyfijaFp5D2C5oz3Ikw5a2kiX2K9nw72vrZX2q5UuAlkPtUMO1tQz6JTKpaKWjS7OOefTDQ=="],
|
||||
"@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-x64": ["@next/swc-darwin-x64@16.4.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-1Rvkn/LUhnEF8WxnRkOrqGhbwXui1bkWFxONKIbN+r7C+9KHDSZ+iUoj4CzymVMWUyZIyx9szcb9+kbKhD500A=="],
|
||||
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.4.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-uWq4qkHapBDS1oFltWS4YxTb9pLHAtLNcpbuK6SmRsebLYZqpBML/j/C0op+50JYGTpZgVL/DWNt/6oWlamrrw=="],
|
||||
|
||||
"@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-gnu": ["@next/swc-linux-arm64-gnu@16.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-FdRcyOx5u5P51mlAqLB9EXdd8jZO5fsdHtk4BAQSkqOywCsbTNN/rmw+jO7pnmjNdAtu2AG46NzbCL2FPDrrgw=="],
|
||||
|
||||
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.4.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-WwYbhWkhYBvBtib1K4W0kL8MW2snBD2A5b3SN4vPpqalZbZs5+bQ1yzAdepVoOqrFfEW3dmREy4Zs1MrWcrFbw=="],
|
||||
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-cyvmmgtRXR8aGVT86wi9Py53IlfyCx7P2fZxuAXAoTummDnhKtUyjrMeXfapqp4qgD+gT5RqyGD/VfA16jEK7Q=="],
|
||||
|
||||
"@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-gnu": ["@next/swc-linux-x64-gnu@16.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-hPc+Fl+N22DAvqZHq559NmamXboOX5Lu8I5Wl0DezfrhTk1Zz21NQeYoZDmNI/NjTcrdsVxM72Fzn2lI+Q+vAw=="],
|
||||
|
||||
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.4.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Vmjd9D7DpA4Vv3cUlr82QWgJD/BQZmns801vtC5VWHg6jCIA4a5vMKpQnfrM2pyCrp2eV0ENdUg4PlN3bAc2Yw=="],
|
||||
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-gbACYE8IP/jlprNTpiWXHb8N9CofOzpnEwH2SrIz1dUbiJf1FbDssDupCAPeP1Taxe8mgG20sGZamJI7KFOdZw=="],
|
||||
|
||||
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.4.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-lG1pPdPLk7gTyGb00n5JIMLdBJgjb+UEhSdZvFbhUMg0DyC6z4B7RnpSKF9VCd4imkLObVbXOFA0kFCpw7yFow=="],
|
||||
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.4.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-+8gj++ZMo8H20Xh2ijjNqyFk5LPLw0AC4Fs4Tq/G94rjjQXhOjN4jgSWsWKPFsyY26hfIeemJIwKtMxOsp5GBA=="],
|
||||
|
||||
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.4.3", "", { "os": "win32", "cpu": "x64" }, "sha512-NmQC9RkJdnPXRaMxtkCzobB3teVjqF33oSOnwDfi+XYGWWYpt+xlGK3mtktSKLbdjwaWbJu2OkkMiRFGUUncKg=="],
|
||||
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.4.5", "", { "os": "win32", "cpu": "x64" }, "sha512-qNZj66pYXnaWLiF9R9GUbfBdrCv7kC6TaZfIwB2KH5WPc/8pEM3nVOj8hpQhWJU8S94rlH5MPDcX15+RrgUhiw=="],
|
||||
|
||||
"@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 +935,9 @@
|
||||
|
||||
"@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
|
||||
"@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/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/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=="],
|
||||
"@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=="],
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
@@ -2636,7 +2637,7 @@
|
||||
|
||||
"netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="],
|
||||
|
||||
"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": ["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-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=="],
|
||||
|
||||
|
||||
+3
-2
@@ -67,7 +67,8 @@
|
||||
"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",
|
||||
"next@16.4.3": "patches/next@16.4.3.patch",
|
||||
"mermaid@11.16.1": "patches/mermaid@11.16.1.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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
|
||||
import { colorScale } from './transformations';
|
||||
import { colorScale, hexToRgbArray } from './transformations';
|
||||
|
||||
describe('colorScale exact base', () => {
|
||||
it('takes a very light tint as the exact background on step 1 (clean/bold)', () => {
|
||||
@@ -67,3 +67,15 @@ 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,7 +311,9 @@ export function hexToRgbArray(hex: string): RGBColor {
|
||||
const originalHex = hex;
|
||||
|
||||
let value = hex.replace('#', '');
|
||||
if (hex.length === 3) value = value + value;
|
||||
if (value.length === 3) {
|
||||
value = [...value].map((digit) => digit + digit).join('');
|
||||
}
|
||||
|
||||
const r = value.substring(0, 2);
|
||||
const g = value.substring(2, 4);
|
||||
|
||||
@@ -283,11 +283,6 @@ 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',
|
||||
@@ -589,11 +584,6 @@ 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',
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"@gitbook/react-openapi": "workspace:*",
|
||||
"@mermaid-js/mermaid-zenuml": "^0.2.2",
|
||||
"@modelcontextprotocol/sdk": "1.17.5",
|
||||
"@opennextjs/aws": "4.1.11",
|
||||
"@opennextjs/cloudflare": "1.20.12",
|
||||
"@opennextjs/aws": "4.1.15",
|
||||
"@opennextjs/cloudflare": "1.20.16",
|
||||
"@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.3",
|
||||
"next": "^16.4.5",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.2.3",
|
||||
"object-hash": "^3.0.0",
|
||||
|
||||
@@ -146,6 +146,10 @@ 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="cursor-help underline decoration-dotted decoration-1 underline-offset-2"
|
||||
className="not-italic 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,6 +709,19 @@ 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',
|
||||
|
||||
@@ -137,6 +137,7 @@ 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,6 +141,7 @@ 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,6 +139,7 @@ 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,6 +138,7 @@ 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,6 +145,7 @@ 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,6 +143,7 @@ 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,6 +137,7 @@ 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,6 +143,7 @@ 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,6 +139,7 @@ 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,6 +140,7 @@ 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,6 +139,7 @@ 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,6 +136,7 @@ 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,6 +138,7 @@ 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,6 +139,7 @@ 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,6 +141,7 @@ 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,6 +138,7 @@ 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,6 +142,7 @@ 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,6 +139,7 @@ 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,6 +139,7 @@ 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,6 +139,7 @@ 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,6 +138,7 @@ 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,6 +138,7 @@ 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,6 +141,7 @@ 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,6 +141,7 @@ 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,6 +140,7 @@ 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,6 +143,7 @@ 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,6 +140,7 @@ 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,6 +142,7 @@ 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,6 +142,7 @@ 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,6 +141,7 @@ 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,6 +140,7 @@ 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,6 +140,7 @@ 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,6 +135,7 @@ 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,6 +138,7 @@ 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,6 +138,7 @@ 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,6 +138,7 @@ 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,6 +134,7 @@ 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,6 +134,7 @@ 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,6 +135,7 @@ 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} 完成后发送',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
|
||||
import { getURLLookup, getURLLookupPathname, normalizeURL } from './urls';
|
||||
import { getURLLookup, getURLLookupPathname, normalizeRequestURL, normalizeURL } from './urls';
|
||||
|
||||
describe('getURLLookupPathname', () => {
|
||||
const previewRoot = 'https://sites.gitbook.com/preview/site_example/section';
|
||||
@@ -162,6 +162,51 @@ describe('getURLLookup', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeRequestURL', () => {
|
||||
it('does not redirect a normalized URL', () => {
|
||||
const url = new URL('https://docs.mycompany.com/hello');
|
||||
expect(normalizeRequestURL(url, 'url-host')).toEqual({ isNormalized: true });
|
||||
});
|
||||
|
||||
it('redirects a non-normalized URL to the normalized one', () => {
|
||||
const result = normalizeRequestURL(
|
||||
new URL('https://docs.mycompany.com/hello/tes%74'),
|
||||
'url-host'
|
||||
);
|
||||
expect(result).toBeInstanceOf(Response);
|
||||
const response = result as Response;
|
||||
expect(response.status).toBe(302);
|
||||
expect(response.headers.get('location')).toBe('https://docs.mycompany.com/hello/test');
|
||||
});
|
||||
|
||||
it('does not redirect a non-normalized proxied URL to the internal proxy URL', () => {
|
||||
const url = new URL(
|
||||
'https://proxy.gitbook.site/sites/site_abc/getting-started/quickstar%74'
|
||||
);
|
||||
expect(normalizeRequestURL(url, 'url-host')).toEqual({ isNormalized: false });
|
||||
});
|
||||
|
||||
it('redirects a non-normalized proxied URL in url mode', () => {
|
||||
const result = normalizeRequestURL(
|
||||
new URL('https://proxy.gitbook.site/sites/site_abc/quickstar%74'),
|
||||
'url'
|
||||
);
|
||||
expect(result).toBeInstanceOf(Response);
|
||||
expect((result as Response).headers.get('location')).toBe(
|
||||
'https://proxy.gitbook.site/sites/site_abc/quickstart'
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'https://docs.mycompany.com/hello/%ZZ',
|
||||
'https://proxy.gitbook.site/sites/site_abc/%ZZ',
|
||||
])('returns a 400 for an invalid URL %s', (url) => {
|
||||
const result = normalizeRequestURL(new URL(url), 'url-host');
|
||||
expect(result).toBeInstanceOf(Response);
|
||||
expect((result as Response).status).toBe(400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeURL', () => {
|
||||
it('should remove trailing slashes', () => {
|
||||
expect(normalizeURL(new URL('https://docs.mycompany.com/hello/'))).toEqual(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { joinPath, removeTrailingSlash } from '../paths';
|
||||
import { isProxyRootRequest } from '../proxy';
|
||||
import { isProxyRequest, isProxyRootRequest } from '../proxy';
|
||||
import { DataFetcherError, getExposableError } from './errors';
|
||||
|
||||
/**
|
||||
@@ -105,21 +105,28 @@ export function getURLLookupPathname(
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the URL in a request and redirect if the normalized URL is different from the original one.
|
||||
* Normalize the URL in a request before the lookup. Returns an error response if it is invalid,
|
||||
* or a redirect to the normalized URL if it can be built from the request URL.
|
||||
*/
|
||||
export function normalizeRequestURL(url: URL): Response | null {
|
||||
export function normalizeRequestURL(
|
||||
url: URL,
|
||||
mode: 'url' | 'url-host'
|
||||
): Response | { isNormalized: boolean } {
|
||||
let normalizedURL: URL;
|
||||
try {
|
||||
const normalizedURL = normalizeURL(url);
|
||||
|
||||
if (normalizedURL.toString() !== url.toString()) {
|
||||
return Response.redirect(normalizedURL.toString(), 302);
|
||||
}
|
||||
|
||||
return null;
|
||||
normalizedURL = normalizeURL(url);
|
||||
} catch (error) {
|
||||
const sanitized = getExposableError(error);
|
||||
return new Response(sanitized.message, { status: sanitized.code });
|
||||
}
|
||||
|
||||
const isNormalized = normalizedURL.toString() === url.toString();
|
||||
// A proxied site's public URL is only known after the lookup, which redirects to the canonical URL.
|
||||
if (!isNormalized && !(mode !== 'url' && isProxyRequest(url))) {
|
||||
return Response.redirect(normalizedURL.toString(), 302);
|
||||
}
|
||||
|
||||
return { isNormalized };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,6 +50,16 @@ describe('extractPagePath', () => {
|
||||
it('returns empty string when URL equals root base URL', () => {
|
||||
expect(extractPagePath('https://docs.example.com/', 'https://docs.example.com/')).toBe('');
|
||||
});
|
||||
|
||||
it('extracts path from the markdown URL of a page', () => {
|
||||
expect(
|
||||
extractPagePath('https://docs.example.com/api/guides/installation.md', baseURL)
|
||||
).toBe('guides/installation');
|
||||
expect(extractPagePath('https://docs.example.com/api/.md', baseURL)).toBe('');
|
||||
expect(extractPagePath('https://docs.example.com/api/notes.md.html', baseURL)).toBe(
|
||||
'notes.md.html'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveFirstDocument', () => {
|
||||
|
||||
@@ -412,7 +412,8 @@ function flattenPages(
|
||||
* Returns the path segment after the base, or undefined if the URL doesn't match.
|
||||
*/
|
||||
export function extractPagePath(url: string, baseURL: string): string | undefined {
|
||||
const urlPath = getURLPathname(url);
|
||||
// Pages are also served as Markdown at `<page>.md`, the form llms.txt links to.
|
||||
const urlPath = getURLPathname(url)?.replace(/\.md$/, '');
|
||||
const basePath = getURLPathname(baseURL);
|
||||
|
||||
if (urlPath === undefined || basePath === undefined) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
|
||||
import {
|
||||
DISALLOW_ALL_ROBOTS_TXT_LINES,
|
||||
createRobotsTxtResponse,
|
||||
isRobotsTxtRequest,
|
||||
} from './robots';
|
||||
|
||||
describe('isRobotsTxtRequest', () => {
|
||||
it('matches robots.txt at the root of the host', () => {
|
||||
expect(isRobotsTxtRequest(new URL('https://docs.example.com/robots.txt'))).toBe(true);
|
||||
});
|
||||
|
||||
it('matches robots.txt under a site base path', () => {
|
||||
expect(isRobotsTxtRequest(new URL('https://example.com/docs/v2/robots.txt'))).toBe(true);
|
||||
});
|
||||
|
||||
it('ignores other paths', () => {
|
||||
expect(isRobotsTxtRequest(new URL('https://docs.example.com/'))).toBe(false);
|
||||
expect(isRobotsTxtRequest(new URL('https://docs.example.com/sitemap.xml'))).toBe(false);
|
||||
expect(isRobotsTxtRequest(new URL('https://docs.example.com/my-robots.txt'))).toBe(false);
|
||||
expect(isRobotsTxtRequest(new URL('https://docs.example.com/robots.txt/page'))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createRobotsTxtResponse', () => {
|
||||
it('serves a disallow-all robots.txt as plain text', async () => {
|
||||
const response = createRobotsTxtResponse(DISALLOW_ALL_ROBOTS_TXT_LINES);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get('content-type')).toBe('text/plain');
|
||||
expect(await response.text()).toBe(
|
||||
'User-agent: *\nContent-Signal: ai-train=no, search=no, ai-input=no\nDisallow: /\n'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export const DISALLOW_ALL_ROBOTS_TXT_LINES = [
|
||||
'User-agent: *',
|
||||
'Content-Signal: ai-train=no, search=no, ai-input=no',
|
||||
'Disallow: /',
|
||||
];
|
||||
|
||||
export function createRobotsTxtResponse(lines: string[]) {
|
||||
return new NextResponse(`${lines.join('\n')}\n`, {
|
||||
headers: { 'Content-Type': 'text/plain' },
|
||||
});
|
||||
}
|
||||
|
||||
// Matches under any base path, like the signed-in route: a sign-in redirect doesn't tell us the site's base path.
|
||||
export function isRobotsTxtRequest(siteRequestURL: URL) {
|
||||
return siteRequestURL.pathname.endsWith('/robots.txt');
|
||||
}
|
||||
@@ -55,6 +55,11 @@ import {
|
||||
parsePreviewCustomizationCookie,
|
||||
serializePreviewCustomizationCookie,
|
||||
} from '@/lib/preview';
|
||||
import {
|
||||
DISALLOW_ALL_ROBOTS_TXT_LINES,
|
||||
createRobotsTxtResponse,
|
||||
isRobotsTxtRequest,
|
||||
} from '@/lib/robots';
|
||||
import {
|
||||
type ResponseCookies,
|
||||
getPathScopedCookieName,
|
||||
@@ -169,10 +174,11 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
||||
}
|
||||
|
||||
// Normalize URL after extracting the URL from the request to make sure the client is redirected to the proper one
|
||||
const normalizationResponse = normalizeRequestURL(siteRequestURL);
|
||||
if (normalizationResponse) {
|
||||
return normalizationResponse;
|
||||
const normalization = normalizeRequestURL(siteRequestURL, mode);
|
||||
if (normalization instanceof Response) {
|
||||
return normalization;
|
||||
}
|
||||
const isNormalizedURL = normalization.isNormalized;
|
||||
|
||||
const imagesContextId = getImageResizingContextId(siteRequestURL);
|
||||
/**
|
||||
@@ -273,6 +279,12 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
||||
});
|
||||
}
|
||||
|
||||
// Crawlers can't sign in: redirecting them to the login page makes search engines
|
||||
// report a broken robots.txt and keep crawling, so tell them to stay away instead.
|
||||
if (siteURLData.target === 'external' && isRobotsTxtRequest(siteRequestURL)) {
|
||||
return createRobotsTxtResponse(DISALLOW_ALL_ROBOTS_TXT_LINES);
|
||||
}
|
||||
|
||||
// When it is a server action, we cannot just return a redirect response as it may cause CORS issues on redirect.
|
||||
// For these cases, we return a 303 response with an `X-Action-Redirect` header that the client can handle.
|
||||
// This is what server actions do when returning a redirect response.
|
||||
@@ -338,6 +350,7 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
||||
//
|
||||
// Make sure the URL is clean of any va token after a successful lookup,
|
||||
// and of any visitor.* params that may have been passed to the URL.
|
||||
// Proxied requests that were not normalized are also redirected here, to the canonical URL.
|
||||
//
|
||||
// We only redirect if the request is not coming from the revalidation worker, as we don't
|
||||
// want to redirect in that case. It can carry unsigned claims without any token, so we rely
|
||||
@@ -348,7 +361,7 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
||||
//
|
||||
const normalizedVisitorURL = normalizeVisitorURL(incomingURL);
|
||||
if (
|
||||
normalizedVisitorURL.toString() !== incomingURL.toString() &&
|
||||
(!isNormalizedURL || normalizedVisitorURL.toString() !== incomingURL.toString()) &&
|
||||
!isRevalidationRequest(request.headers)
|
||||
) {
|
||||
if (visitorToken?.source === 'url') {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SiteVisibility } from '@gitbook/api';
|
||||
|
||||
import { type GitBookSiteContext, checkIsRootSiteContext } from '@/lib/context';
|
||||
import { DISALLOW_ALL_ROBOTS_TXT_LINES, createRobotsTxtResponse } from '@/lib/robots';
|
||||
import { isSiteIndexable } from '@/lib/seo';
|
||||
|
||||
/**
|
||||
@@ -49,10 +50,8 @@ export async function serveRobotsTxt(context: GitBookSiteContext) {
|
||||
'',
|
||||
])
|
||||
: []),
|
||||
'User-agent: *',
|
||||
'Content-Signal: ai-train=no, search=no, ai-input=no',
|
||||
'Disallow: /',
|
||||
...DISALLOW_ALL_ROBOTS_TXT_LINES,
|
||||
];
|
||||
|
||||
return new Response(`${lines.join('\n')}\n`, { headers: { 'Content-Type': 'text/plain' } });
|
||||
return createRobotsTxtResponse(lines);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,29 @@ it(
|
||||
{ timeout: 15_000 }
|
||||
);
|
||||
|
||||
it(
|
||||
'should get a page through MCP from its markdown URL',
|
||||
async () => {
|
||||
const client = await connectMCPClient(
|
||||
getContentTestURL(
|
||||
'https://gitbook-open-e2e-sites.gitbook.io/api-multi-versions-share-links/8tNo6MeXg7CkFMzSSz81/~gitbook/mcp/auth'
|
||||
)
|
||||
);
|
||||
|
||||
const response = await client.callTool({
|
||||
name: 'getPage',
|
||||
arguments: {
|
||||
url: 'https://gitbook-open-e2e-sites.gitbook.io/api-multi-versions-share-links/8tNo6MeXg7CkFMzSSz81/3.0/other-page.md',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.isError).toBeFalsy();
|
||||
// @ts-expect-error - response.content is of type unknown
|
||||
expect(response.content[0]?.text).toContain('# Other Page');
|
||||
},
|
||||
{ timeout: 15_000 }
|
||||
);
|
||||
|
||||
describe('MCP on a site behind visitor authentication', () => {
|
||||
const VA_SITE_URL = 'https://gitbook-open-e2e-sites.gitbook.io/va-site-redirects-fallback';
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
diff --git a/dist/shellscript.mjs b/dist/shellscript.mjs
|
||||
index ccf9c0f62f48a803f0640e758244a950f17ba53e..6956ab14623f71cf5bc88c5c6437502abba7ec0f 100644
|
||||
--- a/dist/shellscript.mjs
|
||||
+++ b/dist/shellscript.mjs
|
||||
@@ -3,3 +3,6 @@ const lang = Object.freeze(JSON.parse("{\"displayName\":\"Shell\",\"name\":\"she
|
||||
export default [
|
||||
lang
|
||||
]
|
||||
+
|
||||
+// Upstream keeps the last letter of `name>` out of the word: https://github.com/jeff-hykin/better-shell-syntax/issues/111
|
||||
+lang.repository.argument_context.patterns[0].match = '[\\t ]*+(?!\\d+>)([^\\t\\n "$\\&-);<>\\\\`|]+)';
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/dist/compiled/next-server/app-page.runtime.dev.js b/dist/compiled/next-server/app-page.runtime.dev.js
|
||||
index 8c24deba180e52b8732b0b98447a14a4c973a1d9..23647ebd4bcb763a383cc2b5a01c4bd9eba504fd 100644
|
||||
index ee264ffef478ba5dbc51e83d3c4efc9b9fa84ab0..5774304e84f7d33362d4cb37a97a571783a9fa2a 100644
|
||||
--- a/dist/compiled/next-server/app-page.runtime.dev.js
|
||||
+++ b/dist/compiled/next-server/app-page.runtime.dev.js
|
||||
@@ -1,5 +1,5 @@
|
||||
Reference in New Issue
Block a user