diff --git a/package.json b/package.json
index 9d11ac361a..61476a7020 100644
--- a/package.json
+++ b/package.json
@@ -84,6 +84,7 @@
"rss": "1.2.2",
"scroll-into-view-if-needed": "^3.1.0",
"server-only": "0.0.1",
+ "sharp": "^0.34.5",
"string-similarity": "^4.0.4",
"string-strip-html": "^13.4.8",
"tailwindcss": "^3.4.17",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d5abe88ba5..66c36a77bd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -70,7 +70,7 @@ importers:
version: 15.5.9
'@plaiceholder/next':
specifier: ^3.0.0
- version: 3.0.0(next@14.2.35(@babel/core@7.28.3)(@playwright/test@1.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(plaiceholder@3.0.0(sharp@0.34.4))(sharp@0.34.4)
+ version: 3.0.0(next@14.2.35(@babel/core@7.28.3)(@playwright/test@1.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(plaiceholder@3.0.0(sharp@0.34.5))(sharp@0.34.5)
'@sparticuz/chromium':
specifier: ^138.0.2
version: 138.0.2
@@ -163,7 +163,7 @@ importers:
version: 1.6.4
plaiceholder:
specifier: ^3.0.0
- version: 3.0.0(sharp@0.34.4)
+ version: 3.0.0(sharp@0.34.5)
playwright-core:
specifier: ^1.54.2
version: 1.57.0
@@ -200,6 +200,9 @@ importers:
server-only:
specifier: 0.0.1
version: 0.0.1
+ sharp:
+ specifier: ^0.34.5
+ version: 0.34.5
string-similarity:
specifier: ^4.0.4
version: 4.0.4
@@ -1606,124 +1609,135 @@ packages:
resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
engines: {node: '>=18'}
- '@img/sharp-darwin-arm64@0.34.4':
- resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==}
+ '@img/sharp-darwin-arm64@0.34.5':
+ resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [darwin]
- '@img/sharp-darwin-x64@0.34.4':
- resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==}
+ '@img/sharp-darwin-x64@0.34.5':
+ resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [darwin]
- '@img/sharp-libvips-darwin-arm64@1.2.3':
- resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==}
+ '@img/sharp-libvips-darwin-arm64@1.2.4':
+ resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
cpu: [arm64]
os: [darwin]
- '@img/sharp-libvips-darwin-x64@1.2.3':
- resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==}
+ '@img/sharp-libvips-darwin-x64@1.2.4':
+ resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
cpu: [x64]
os: [darwin]
- '@img/sharp-libvips-linux-arm64@1.2.3':
- resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==}
+ '@img/sharp-libvips-linux-arm64@1.2.4':
+ resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
cpu: [arm64]
os: [linux]
- '@img/sharp-libvips-linux-arm@1.2.3':
- resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==}
+ '@img/sharp-libvips-linux-arm@1.2.4':
+ resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
cpu: [arm]
os: [linux]
- '@img/sharp-libvips-linux-ppc64@1.2.3':
- resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==}
+ '@img/sharp-libvips-linux-ppc64@1.2.4':
+ resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
cpu: [ppc64]
os: [linux]
- '@img/sharp-libvips-linux-s390x@1.2.3':
- resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==}
+ '@img/sharp-libvips-linux-riscv64@1.2.4':
+ resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-s390x@1.2.4':
+ resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
cpu: [s390x]
os: [linux]
- '@img/sharp-libvips-linux-x64@1.2.3':
- resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==}
+ '@img/sharp-libvips-linux-x64@1.2.4':
+ resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
cpu: [x64]
os: [linux]
- '@img/sharp-libvips-linuxmusl-arm64@1.2.3':
- resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==}
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
+ resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
cpu: [arm64]
os: [linux]
- '@img/sharp-libvips-linuxmusl-x64@1.2.3':
- resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==}
+ '@img/sharp-libvips-linuxmusl-x64@1.2.4':
+ resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
cpu: [x64]
os: [linux]
- '@img/sharp-linux-arm64@0.34.4':
- resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==}
+ '@img/sharp-linux-arm64@0.34.5':
+ resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
- '@img/sharp-linux-arm@0.34.4':
- resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==}
+ '@img/sharp-linux-arm@0.34.5':
+ resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
- '@img/sharp-linux-ppc64@0.34.4':
- resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==}
+ '@img/sharp-linux-ppc64@0.34.5':
+ resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ppc64]
os: [linux]
- '@img/sharp-linux-s390x@0.34.4':
- resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==}
+ '@img/sharp-linux-riscv64@0.34.5':
+ resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@img/sharp-linux-s390x@0.34.5':
+ resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
- '@img/sharp-linux-x64@0.34.4':
- resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==}
+ '@img/sharp-linux-x64@0.34.5':
+ resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
- '@img/sharp-linuxmusl-arm64@0.34.4':
- resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==}
+ '@img/sharp-linuxmusl-arm64@0.34.5':
+ resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
- '@img/sharp-linuxmusl-x64@0.34.4':
- resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==}
+ '@img/sharp-linuxmusl-x64@0.34.5':
+ resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
- '@img/sharp-wasm32@0.34.4':
- resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==}
+ '@img/sharp-wasm32@0.34.5':
+ resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [wasm32]
- '@img/sharp-win32-arm64@0.34.4':
- resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==}
+ '@img/sharp-win32-arm64@0.34.5':
+ resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [win32]
- '@img/sharp-win32-ia32@0.34.4':
- resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==}
+ '@img/sharp-win32-ia32@0.34.5':
+ resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ia32]
os: [win32]
- '@img/sharp-win32-x64@0.34.4':
- resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==}
+ '@img/sharp-win32-x64@0.34.5':
+ resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [win32]
@@ -5897,8 +5911,8 @@ packages:
resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
engines: {node: '>=8'}
- sharp@0.34.4:
- resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==}
+ sharp@0.34.5:
+ resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
shebang-command@2.0.0:
@@ -8403,90 +8417,98 @@ snapshots:
'@img/colour@1.0.0': {}
- '@img/sharp-darwin-arm64@0.34.4':
+ '@img/sharp-darwin-arm64@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-darwin-arm64': 1.2.3
+ '@img/sharp-libvips-darwin-arm64': 1.2.4
optional: true
- '@img/sharp-darwin-x64@0.34.4':
+ '@img/sharp-darwin-x64@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-darwin-x64': 1.2.3
+ '@img/sharp-libvips-darwin-x64': 1.2.4
+ optional: true
+
+ '@img/sharp-libvips-darwin-arm64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-darwin-x64@1.2.4':
optional: true
- '@img/sharp-libvips-darwin-arm64@1.2.3':
+ '@img/sharp-libvips-linux-arm64@1.2.4':
optional: true
- '@img/sharp-libvips-darwin-x64@1.2.3':
+ '@img/sharp-libvips-linux-arm@1.2.4':
optional: true
- '@img/sharp-libvips-linux-arm64@1.2.3':
+ '@img/sharp-libvips-linux-ppc64@1.2.4':
optional: true
- '@img/sharp-libvips-linux-arm@1.2.3':
+ '@img/sharp-libvips-linux-riscv64@1.2.4':
optional: true
- '@img/sharp-libvips-linux-ppc64@1.2.3':
+ '@img/sharp-libvips-linux-s390x@1.2.4':
optional: true
- '@img/sharp-libvips-linux-s390x@1.2.3':
+ '@img/sharp-libvips-linux-x64@1.2.4':
optional: true
- '@img/sharp-libvips-linux-x64@1.2.3':
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
optional: true
- '@img/sharp-libvips-linuxmusl-arm64@1.2.3':
+ '@img/sharp-libvips-linuxmusl-x64@1.2.4':
optional: true
- '@img/sharp-libvips-linuxmusl-x64@1.2.3':
+ '@img/sharp-linux-arm64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.2.4
optional: true
- '@img/sharp-linux-arm64@0.34.4':
+ '@img/sharp-linux-arm@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-linux-arm64': 1.2.3
+ '@img/sharp-libvips-linux-arm': 1.2.4
optional: true
- '@img/sharp-linux-arm@0.34.4':
+ '@img/sharp-linux-ppc64@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-linux-arm': 1.2.3
+ '@img/sharp-libvips-linux-ppc64': 1.2.4
optional: true
- '@img/sharp-linux-ppc64@0.34.4':
+ '@img/sharp-linux-riscv64@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-linux-ppc64': 1.2.3
+ '@img/sharp-libvips-linux-riscv64': 1.2.4
optional: true
- '@img/sharp-linux-s390x@0.34.4':
+ '@img/sharp-linux-s390x@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-linux-s390x': 1.2.3
+ '@img/sharp-libvips-linux-s390x': 1.2.4
optional: true
- '@img/sharp-linux-x64@0.34.4':
+ '@img/sharp-linux-x64@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-linux-x64': 1.2.3
+ '@img/sharp-libvips-linux-x64': 1.2.4
optional: true
- '@img/sharp-linuxmusl-arm64@0.34.4':
+ '@img/sharp-linuxmusl-arm64@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-linuxmusl-arm64': 1.2.3
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
optional: true
- '@img/sharp-linuxmusl-x64@0.34.4':
+ '@img/sharp-linuxmusl-x64@0.34.5':
optionalDependencies:
- '@img/sharp-libvips-linuxmusl-x64': 1.2.3
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.4
optional: true
- '@img/sharp-wasm32@0.34.4':
+ '@img/sharp-wasm32@0.34.5':
dependencies:
'@emnapi/runtime': 1.8.1
optional: true
- '@img/sharp-win32-arm64@0.34.4':
+ '@img/sharp-win32-arm64@0.34.5':
optional: true
- '@img/sharp-win32-ia32@0.34.4':
+ '@img/sharp-win32-ia32@0.34.5':
optional: true
- '@img/sharp-win32-x64@0.34.4':
+ '@img/sharp-win32-x64@0.34.5':
optional: true
'@inquirer/ansi@1.0.1': {}
@@ -8819,7 +8841,7 @@ snapshots:
ini: 4.1.3
nopt: 7.2.1
proc-log: 4.2.0
- semver: 7.7.2
+ semver: 7.7.3
walk-up-path: 3.0.1
transitivePeerDependencies:
- bluebird
@@ -8833,7 +8855,7 @@ snapshots:
proc-log: 4.2.0
promise-inflight: 1.0.1
promise-retry: 2.0.1
- semver: 7.7.2
+ semver: 7.7.3
which: 4.0.0
transitivePeerDependencies:
- bluebird
@@ -8855,7 +8877,7 @@ snapshots:
json-parse-even-better-errors: 3.0.2
normalize-package-data: 6.0.2
proc-log: 4.2.0
- semver: 7.7.2
+ semver: 7.7.3
transitivePeerDependencies:
- bluebird
@@ -8868,11 +8890,11 @@ snapshots:
'@pkgr/core@0.2.9': {}
- '@plaiceholder/next@3.0.0(next@14.2.35(@babel/core@7.28.3)(@playwright/test@1.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(plaiceholder@3.0.0(sharp@0.34.4))(sharp@0.34.4)':
+ '@plaiceholder/next@3.0.0(next@14.2.35(@babel/core@7.28.3)(@playwright/test@1.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(plaiceholder@3.0.0(sharp@0.34.5))(sharp@0.34.5)':
dependencies:
next: 14.2.35(@babel/core@7.28.3)(@playwright/test@1.57.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- plaiceholder: 3.0.0(sharp@0.34.4)
- sharp: 0.34.4
+ plaiceholder: 3.0.0(sharp@0.34.5)
+ sharp: 0.34.5
'@playwright/test@1.57.0':
dependencies:
@@ -9825,7 +9847,7 @@ snapshots:
path-case: 3.0.4
sentence-case: 3.0.4
snake-case: 3.0.4
- tslib: 2.6.3
+ tslib: 2.8.1
character-entities-html4@2.1.0: {}
@@ -11481,7 +11503,7 @@ snapshots:
is-lower-case@2.0.2:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
is-map@2.0.3: {}
@@ -11548,7 +11570,7 @@ snapshots:
is-upper-case@2.0.2:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
is-weakmap@2.0.2: {}
@@ -11804,7 +11826,7 @@ snapshots:
lower-case-first@2.0.2:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
lower-case@2.0.2:
dependencies:
@@ -12599,7 +12621,7 @@ snapshots:
normalize-package-data@6.0.2:
dependencies:
hosted-git-info: 7.0.2
- semver: 7.7.2
+ semver: 7.7.3
validate-npm-package-license: 3.0.4
normalize-path@2.1.1:
@@ -12610,7 +12632,7 @@ snapshots:
npm-install-checks@6.3.0:
dependencies:
- semver: 7.7.2
+ semver: 7.7.3
npm-normalize-package-bin@3.0.1: {}
@@ -12618,7 +12640,7 @@ snapshots:
dependencies:
hosted-git-info: 7.0.2
proc-log: 4.2.0
- semver: 7.7.2
+ semver: 7.7.3
validate-npm-package-name: 5.0.1
npm-pick-manifest@9.1.0:
@@ -12626,7 +12648,7 @@ snapshots:
npm-install-checks: 6.3.0
npm-normalize-package-bin: 3.0.1
npm-package-arg: 11.0.3
- semver: 7.7.2
+ semver: 7.7.3
npm-run-path@5.3.0:
dependencies:
@@ -12878,9 +12900,9 @@ snapshots:
exsolve: 1.0.7
pathe: 2.0.3
- plaiceholder@3.0.0(sharp@0.34.4):
+ plaiceholder@3.0.0(sharp@0.34.5):
dependencies:
- sharp: 0.34.4
+ sharp: 0.34.5
playwright-core@1.57.0: {}
@@ -13521,34 +13543,36 @@ snapshots:
dependencies:
kind-of: 6.0.3
- sharp@0.34.4:
+ sharp@0.34.5:
dependencies:
'@img/colour': 1.0.0
detect-libc: 2.1.2
semver: 7.7.3
optionalDependencies:
- '@img/sharp-darwin-arm64': 0.34.4
- '@img/sharp-darwin-x64': 0.34.4
- '@img/sharp-libvips-darwin-arm64': 1.2.3
- '@img/sharp-libvips-darwin-x64': 1.2.3
- '@img/sharp-libvips-linux-arm': 1.2.3
- '@img/sharp-libvips-linux-arm64': 1.2.3
- '@img/sharp-libvips-linux-ppc64': 1.2.3
- '@img/sharp-libvips-linux-s390x': 1.2.3
- '@img/sharp-libvips-linux-x64': 1.2.3
- '@img/sharp-libvips-linuxmusl-arm64': 1.2.3
- '@img/sharp-libvips-linuxmusl-x64': 1.2.3
- '@img/sharp-linux-arm': 0.34.4
- '@img/sharp-linux-arm64': 0.34.4
- '@img/sharp-linux-ppc64': 0.34.4
- '@img/sharp-linux-s390x': 0.34.4
- '@img/sharp-linux-x64': 0.34.4
- '@img/sharp-linuxmusl-arm64': 0.34.4
- '@img/sharp-linuxmusl-x64': 0.34.4
- '@img/sharp-wasm32': 0.34.4
- '@img/sharp-win32-arm64': 0.34.4
- '@img/sharp-win32-ia32': 0.34.4
- '@img/sharp-win32-x64': 0.34.4
+ '@img/sharp-darwin-arm64': 0.34.5
+ '@img/sharp-darwin-x64': 0.34.5
+ '@img/sharp-libvips-darwin-arm64': 1.2.4
+ '@img/sharp-libvips-darwin-x64': 1.2.4
+ '@img/sharp-libvips-linux-arm': 1.2.4
+ '@img/sharp-libvips-linux-arm64': 1.2.4
+ '@img/sharp-libvips-linux-ppc64': 1.2.4
+ '@img/sharp-libvips-linux-riscv64': 1.2.4
+ '@img/sharp-libvips-linux-s390x': 1.2.4
+ '@img/sharp-libvips-linux-x64': 1.2.4
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.4
+ '@img/sharp-linux-arm': 0.34.5
+ '@img/sharp-linux-arm64': 0.34.5
+ '@img/sharp-linux-ppc64': 0.34.5
+ '@img/sharp-linux-riscv64': 0.34.5
+ '@img/sharp-linux-s390x': 0.34.5
+ '@img/sharp-linux-x64': 0.34.5
+ '@img/sharp-linuxmusl-arm64': 0.34.5
+ '@img/sharp-linuxmusl-x64': 0.34.5
+ '@img/sharp-wasm32': 0.34.5
+ '@img/sharp-win32-arm64': 0.34.5
+ '@img/sharp-win32-ia32': 0.34.5
+ '@img/sharp-win32-x64': 0.34.5
shebang-command@2.0.0:
dependencies:
@@ -13652,7 +13676,7 @@ snapshots:
sponge-case@1.0.1:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
sprintf-js@1.0.3: {}
@@ -13840,7 +13864,7 @@ snapshots:
swap-case@2.0.2:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
symbol-tree@3.2.4: {}
@@ -13933,7 +13957,7 @@ snapshots:
title-case@3.0.3:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
title@4.0.1:
dependencies:
@@ -14234,11 +14258,11 @@ snapshots:
upper-case-first@2.0.2:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
upper-case@2.0.2:
dependencies:
- tslib: 2.6.3
+ tslib: 2.8.1
uri-js@4.4.1:
dependencies:
diff --git a/src/app/(main)/ai/components/by-the-numbers.tsx b/src/app/(main)/ai/components/by-the-numbers.tsx
new file mode 100644
index 0000000000..778cddd981
--- /dev/null
+++ b/src/app/(main)/ai/components/by-the-numbers.tsx
@@ -0,0 +1,246 @@
+"use client"
+
+import { SectionLabel } from "@/app/conf/_design-system/section-label"
+import {
+ highlightGraphQLSchema,
+ highlightGraphQL,
+ highlightJSON,
+ SYNTAX_CSS,
+} from "./syntax-highlight"
+
+const schemaWithDocs = `"""A product in the catalog."""
+type Product {
+ """Human-readable display name."""
+ name: String!
+
+ """Price in minor units (cents)."""
+ price: Int!
+
+ """Units in stock. 0 means unavailable."""
+ stock: Int!
+}
+
+type Query {
+ """Full-text search across the catalog."""
+ products(query: String!): [Product!]!
+}`
+
+const introspectionQuery = `{
+ __type(name: "Product") {
+ description
+ fields {
+ name
+ description
+ }
+ }
+}`
+
+const introspectionResponse = `{
+ "__type": {
+ "description": "A product in the catalog.",
+ "fields": [
+ { "name": "name", "description": "Human-readable display name." },
+ { "name": "price", "description": "Price in minor units (cents)." },
+ { "name": "stock", "description": "Units in stock. 0 means unavailable." }
+ ]
+ }
+}`
+
+const stats = [
+ {
+ label: "Token reduction",
+ graphQL: "90%",
+ graphQLDesc: "fewer tokens",
+ rest: "10× more",
+ restDesc: "token waste",
+ explanation:
+ "GraphQL lets AI agents request only the fields they need. REST endpoints return fixed payloads — often 10x the data an LLM actually needs to process. Every extra token costs money and context window space.",
+ },
+ {
+ label: "API calls per task",
+ graphQL: "1",
+ graphQLDesc: "single request",
+ rest: "3–7",
+ restDesc: "sequential calls",
+ explanation:
+ "GraphQL's composability means agents can fetch nested, related data in one query. REST requires multiple endpoints, forcing agents to make sequential calls and stitch responses client-side.",
+ },
+ {
+ label: "Tool definitions",
+ graphQL: "0",
+ graphQLDesc: "auto-discovered",
+ rest: "3",
+ restDesc: "files to wire",
+ explanation:
+ "REST frameworks can auto-generate OpenAPI, so this isn't about hand-writing schemas. The edge is plug-and-play: GraphQL's introspection and per-field, per-type, and per-query documentation are built into the spec and discoverable from one endpoint. With REST, an agent needs the API, its schema, and an instruction file (AGENT.md) — and you must point it to each. One GraphQL schema replaces all three.",
+ },
+ {
+ label: "Type safety",
+ graphQL: "100%",
+ graphQLDesc: "typed responses",
+ rest: "100%",
+ restDesc: "if used with correct tooling",
+ explanation:
+ "Both are typed — OpenAPI gives REST schemas too. The real difference for agents is traversal: one GraphQL query follows relationships across types, so an agent never needs to hold the entire type graph in context at once. REST splits data across endpoints, forcing agents to remember deep, nested relationships to compose what one field resolves.",
+ },
+]
+
+export function ByTheNumbers() {
+ return (
+
+ Where GraphQL pays off when AI agents talk to your API.
+
+ {stat.label}
+
+ {stat.explanation}
+
+ Both protocols are typed; the gap is in traversal and discoverability,
+ not in whether types exist.
+
+ Descriptions written with{" "}
+ GraphQL vs REST for AI
+
+
+
+
+
+
+
+ {stats.map(stat => (
+
+ Metric
+
+
+ GraphQL
+
+
+ REST
+
+
+ Why
+
+
+
+ ))}
+
+
+ {stat.label}
+
+
+ {stat.graphQL}
+
+ {stat.graphQLDesc}
+
+
+
+ {stat.rest}
+
+ {stat.restDesc}
+
+
+
+ {stat.explanation}
+
+
+ Docs live in the schema — and agents can query them
+
+
+ """
+ {" "}
+ are stored on the type and every field. An agent reads them back with
+ the built-in{" "}
+
+ __type
+ {" "}
+ introspection query — no separate docs file or AGENT.md to point it
+ to.
+
+
+
+ + The GraphQL AI Working Group is open to everyone. Help define how + GraphQL powers the next generation of intelligent systems — + contribute to specs, share use cases, and collaborate with the + community. +
++ When AI agents need to interact with APIs, GraphQL's + self-describing schemas, strong typing, and composable queries make + it the natural choice. No hand-written tool definitions. No + token-wasting REST payloads. Just structured, predictable data. +
+ ++ Here's what happens when an AI agent uses a GraphQL API to answer + a real business question — from initial request to typed response. +
+ + ++ {step.description} +
+ + {/* Code snippet */} +
+
+
+ + Pick a prompt below and watch an AI agent introspect the schema, + compose a precise GraphQL query, and fetch structured results — all in + real time. +
+ ++ Select an example prompt to begin +
++ Watch the AI → GraphQL translation step by step +
+
+ {`# AI sends introspection query
+{
+ __schema {
+ queryType { name }
+ types {
+ name
+ kind
+ fields { name type { name kind } }
+ }
+ }
+}`}
+
+ + __schema → types discovered: +
++ ✓ Self-describing schema — no hand-written tool definitions required +
+
+ '
+ : ""),
+ }}
+ />
+
+
+
+
+
+
+
+ + What just happened +
++ {prompt.explanation} +
+
+
+
+