diff --git a/package.json b/package.json index a52180c5..f64b00a4 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,15 @@ "start": "docusaurus start", "predev": "node ./scripts/update-endpoints.js", "dev": "yarn start", - "prebuild": "node ./scripts/update-endpoints.js && node ./scripts/validate-blog-social-images.js", + "prebuild": "node ./scripts/update-endpoints.js && node ./scripts/validate-blog-social-images.js && node ./scripts/generate-og-images.js", "build": "docusaurus build", "swizzle": "docusaurus swizzle", "update-endpoints": "node ./scripts/update-endpoints.js", "update-cli-help": "node ./scripts/update-cli-help.js", "update-evm-config-schema": "curl https://raw.githubusercontent.com/enviodev/hyperindex/main/codegenerator/cli/npm/envio/evm.schema.json > ./static/schemas/config.evm.json", "generate-config-schema-doc": "node ./scripts/generate-config-schema-doc.js", + "generate-og-images": "node ./scripts/generate-og-images.js", + "preview-og": "node ./scripts/generate-og-images.js --preview", "predeploy": "yarn update-endpoints && yarn update-cli-help && yarn update-evm-config-schema && yarn generate-config-schema-doc", "deploy": "docusaurus deploy", "clear": "docusaurus clear", @@ -45,6 +47,7 @@ "@docusaurus/module-type-aliases": "^3.3.2", "@docusaurus/types": "3.0.0", "docusaurus-plugin-llms": "^0.2.2", + "sharp": "^0.34.5", "vercel": "^50.40.0" }, "browserslist": { diff --git a/scripts/generate-og-images.js b/scripts/generate-og-images.js new file mode 100644 index 00000000..92cd681b --- /dev/null +++ b/scripts/generate-og-images.js @@ -0,0 +1,445 @@ +#!/usr/bin/env node + +/** + * Generates OG (Open Graph) meta images for all docs pages. + * + * Usage: + * node scripts/generate-og-images.js # generate for all docs + * node scripts/generate-og-images.js --force # overwrite existing images + * node scripts/generate-og-images.js --dry-run # print what would be done + */ + +const fs = require("fs"); +const path = require("path"); +const sharp = require("sharp"); + +const FORCE = process.argv.includes("--force"); +const DRY_RUN = process.argv.includes("--dry-run"); +// --preview [path/to/doc.md] — render one image to static/og-preview.png, no file edits +const PREVIEW_IDX = process.argv.indexOf("--preview"); +const PREVIEW = PREVIEW_IDX !== -1; +const PREVIEW_FILE = PREVIEW && process.argv[PREVIEW_IDX + 1] && !process.argv[PREVIEW_IDX + 1].startsWith("--") + ? path.resolve(process.argv[PREVIEW_IDX + 1]) + : null; + +const REPO_ROOT = path.resolve(__dirname, ".."); +const DOCS_DIR = path.join(REPO_ROOT, "docs"); +const STATIC_DIR = path.join(REPO_ROOT, "static"); +const OG_DIR = path.join(STATIC_DIR, "docs-assets", "og"); + +// Image dimensions (standard OG image) +const WIDTH = 1200; +const HEIGHT = 630; + +// Brand colors +const COLOR_BG = "#0F0F0F"; +const COLOR_ACCENT = "#FF8267"; +const COLOR_WHITE = "#FFFFFF"; +const COLOR_GRAY = "#A0A0A0"; + +// Envio logo as base64 +const logoPath = path.join(STATIC_DIR, "img", "envio-logo.png"); +const logoBase64 = fs.readFileSync(logoPath).toString("base64"); +const logoDataUri = `data:image/png;base64,${logoBase64}`; + +// Logo rendered at 25% of original (459x145 → ~172x54) +const LOGO_W = 172; +const LOGO_H = 54; +const LOGO_X = 90; +const LOGO_Y = 60; + +// ─── LAYOUT CONFIG ──────────────────────────────────────────────────────────── +// Edit these values to adjust the visual design, then run `yarn preview-og`. + +const SECTION_FONT_SIZE = 28; // font size of the small section label (e.g. "HyperIndex") +const SECTION_X = 90; // horizontal position (px from left) of the section label +const SECTION_Y = 280; // vertical position (px from top) of the section label + +// Title font sizes tried largest-first; the first one that fits within the image +// width is used. Each entry is [fontSize, lineHeight]. +const TITLE_SIZE_STEPS = [ + [72, 86], // short titles (≤ ~24 chars) + [60, 72], // medium titles (≤ ~29 chars) + [52, 64], // longer titles (≤ ~34 chars) + [44, 54], // very long (≤ ~40 chars) +]; + +const TITLE_START_Y = 360; // vertical position of the first title line + +// Gap (px) between the last title line and the first description line +const TITLE_DESC_GAP = 0; + +// Gradient opacities (0 = invisible, 1 = full color) +const GLOW_LARGE_OPACITY = 0.18; // top-right glow — main accent burst +const GLOW_SMALL_OPACITY = 0.05; // bottom-left glow — subtle secondary + +const DESC_X = 85; // horizontal position (px from left) of the description text +const DESC_FONT_SIZE = 30; // font size of the description text +const DESC_LINE_HEIGHT = 40; // vertical spacing between description lines + +// ─── END LAYOUT CONFIG ──────────────────────────────────────────────────────── + +/** Escape XML special characters for SVG text */ +function escXml(str) { + return String(str) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +/** + * Split a string into plain/code segments on backtick boundaries. + * "`config.yaml` file" → [{type:"code", content:"config.yaml"}, {type:"text", content:" file"}] + */ +function parseSegments(text) { + const segments = []; + const parts = text.split("`"); + for (let i = 0; i < parts.length; i++) { + if (parts[i] === "") continue; + segments.push({ type: i % 2 === 0 ? "text" : "code", content: parts[i] }); + } + return segments; +} + +/** + * Render one line of text as SVG, turning `backtick` spans into code boxes. + * + * @param {number} startX - left edge of the line + * @param {number} y - baseline y of the line + * @param {string} text - raw text, may contain `backtick` spans + * @param {number} fontSize - font size in px + * @param {string} color - default text color (hex) + * @param {boolean} bold - whether the default text is bold + */ +function renderLine(startX, y, text, fontSize, color, bold = false) { + const segments = parseSegments(text); + const svgParts = []; + + // Approximate char widths (px per character at given fontSize) + const plainCharW = fontSize * (bold ? 0.58 : 0.52); // DejaVu Sans (bold is wider) + const codeCharW = fontSize * 0.60; // DejaVu Sans Mono + + // Code box vertical metrics + const boxPadX = fontSize * 0.20; // horizontal padding inside the box + const boxPadY = fontSize * 0.12; // vertical padding inside the box + const boxH = fontSize + boxPadY * 2; + const boxY = y - fontSize * 0.82 - boxPadY; // top of the box rectangle + const boxColor = "#2a2a2a"; // code box background fill + const codeColor = "#e8e8e8"; // code text color + + let curX = startX; + + for (const seg of segments) { + if (seg.type === "text") { + const w = seg.content.length * plainCharW; + const weight = bold ? ' font-weight="bold"' : ""; + svgParts.push( + `${escXml(seg.content)}` + ); + curX += w; + } else { + const innerW = seg.content.length * codeCharW; + const boxW = innerW + boxPadX * 2; + // Background rect + svgParts.push( + `` + ); + // Monospace text + svgParts.push( + `${escXml(seg.content)}` + ); + curX += boxW + fontSize * 0.20; // gap after code box + } + } + + return svgParts.join("\n "); +} + +/** + * Wrap text into lines no longer than maxChars. + * Returns an array of line strings. + */ +function wrapText(text, maxChars) { + const words = text.split(/\s+/); + const lines = []; + let current = ""; + for (const word of words) { + if ((current + (current ? " " : "") + word).length <= maxChars) { + current = current ? `${current} ${word}` : word; + } else { + if (current) lines.push(current); + current = word.length > maxChars ? word.slice(0, maxChars - 1) + "…" : word; + } + } + if (current) lines.push(current); + return lines; +} + +/** + * Pick title font size and chars-per-line based on title length. + * Approximate: DejaVu Sans Bold avg char width ≈ fontSize * 0.58. + * Available width = 1200 - 80 (left) - 80 (right) = 1040px. + */ +function titleLayout(title) { + const avail = 1040; // px + for (const [fontSize, lineHeight] of TITLE_SIZE_STEPS) { + const avgCharPx = fontSize * 0.58; + const charsPerLine = Math.floor(avail / avgCharPx); + const lines = wrapText(title, charsPerLine).slice(0, 2); + // Truncate second line with ellipsis if more would follow + if (lines.length === 2 && wrapText(title, charsPerLine).length > 2) { + const maxChars = charsPerLine; + lines[1] = + lines[1].length >= maxChars - 1 + ? lines[1].slice(0, maxChars - 1) + "…" + : lines[1]; + } + return { lines, fontSize, lineHeight }; + } + // Fallback + return { lines: [title.slice(0, 24) + "…"], fontSize: 44, lineHeight: 54 }; +} + +/** + * Build an SVG string for an OG image. + */ +function buildSvg({ section, title, description }) { + const { lines: titleLines, fontSize: TITLE_FONT_SIZE, lineHeight: TITLE_LINE_HEIGHT } = + titleLayout(title); + + // Description: max 2 lines. Chars per line derived from DESC_FONT_SIZE so it + // stays within the image width (avgCharPx ≈ fontSize * 0.52). + const DESC_CHARS = Math.floor(1040 / (DESC_FONT_SIZE * 0.52)); + const descLines = description ? wrapText(description, DESC_CHARS).slice(0, 2) : []; + if (descLines.length === 2 && description && wrapText(description, DESC_CHARS).length > 2) { + descLines[1] = + descLines[1].length >= DESC_CHARS - 1 + ? descLines[1].slice(0, DESC_CHARS - 1) + "…" + : descLines[1]; + } + + const DESC_START_Y = TITLE_START_Y + titleLines.length * TITLE_LINE_HEIGHT + TITLE_DESC_GAP; + + const titleSvg = titleLines + .map((line, i) => + renderLine(90, TITLE_START_Y + i * TITLE_LINE_HEIGHT, line, TITLE_FONT_SIZE, COLOR_WHITE, true) + ) + .join("\n "); + + const descSvg = descLines + .map((line, i) => + renderLine(DESC_X, DESC_START_Y + i * DESC_LINE_HEIGHT, line, DESC_FONT_SIZE, COLOR_GRAY) + ) + .join("\n "); + + return ` + + + + + + + + + + + + + + + + + + + + + + + + ${escXml(section)} + + + ${titleSvg} + + + ${descSvg} +`; +} + +/** Parse YAML-ish frontmatter from markdown content. Returns object or null. */ +function parseFrontmatter(content) { + const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/); + if (!match) return null; + const fm = {}; + for (const line of match[1].split(/\r?\n/)) { + const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*)/); + if (!kv) continue; + fm[kv[1]] = kv[2].trim().replace(/^["']|["']$/g, ""); + } + return fm; +} + +/** Return the byte range of the frontmatter block (including ---). */ +function frontmatterRange(content) { + const match = content.match(/^(---\r?\n[\s\S]*?\r?\n---)/); + if (!match) return null; + return { block: match[1], end: match[1].length }; +} + +/** Add or update the `image` field inside an existing frontmatter block. */ +function setFrontmatterImage(content, imagePath) { + const range = frontmatterRange(content); + if (!range) return content; + + const { block, end } = range; + const rest = content.slice(end); + + // If `image:` already exists in frontmatter, replace it + if (/^image:/m.test(block)) { + const updated = block.replace(/^image:.*$/m, `image: ${imagePath}`); + return updated + rest; + } + + // Otherwise insert before closing --- + const updatedBlock = block.replace(/(\r?\n---$)/, `\nimage: ${imagePath}$1`); + return updatedBlock + rest; +} + +/** Determine section label from file path relative to docs/ */ +function getSection(filePath) { + const rel = path.relative(DOCS_DIR, filePath); + const parts = rel.split(path.sep); + // parts[0] = HyperIndex | HyperSync | HyperRPC + // parts[1] = Advanced | Guides | ... (optional) + return parts[0] || "Envio"; +} + +/** Convert a file path to an output PNG path under static/docs-assets/og/ */ +function getOutputPath(filePath) { + const rel = path.relative(DOCS_DIR, filePath); + const withoutExt = rel.replace(/\.(md|mdx)$/, ""); + return path.join(OG_DIR, `${withoutExt}.png`); +} + +/** Convert output path to static-relative URL for frontmatter */ +function toStaticUrl(outputPath) { + return "/" + path.relative(STATIC_DIR, outputPath); +} + +/** Recursively collect all .md and .mdx files, skipping LLM variants */ +function collectDocs(dir) { + const results = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + // Skip LLM variant directories + if (entry.name.endsWith("-LLM") || entry.name === "unused") continue; + results.push(...collectDocs(full)); + } else if (entry.isFile() && /\.(md|mdx)$/.test(entry.name)) { + results.push(full); + } + } + return results; +} + +async function processFile(filePath) { + const content = fs.readFileSync(filePath, "utf8"); + const fm = parseFrontmatter(content); + + if (!fm) { + console.warn(` SKIP (no frontmatter): ${path.relative(REPO_ROOT, filePath)}`); + return { status: "skip" }; + } + + const title = fm.title || fm.sidebar_label || fm.id || path.basename(filePath, path.extname(filePath)); + const description = fm.description || ""; + const section = getSection(filePath); + const outputPath = getOutputPath(filePath); + const staticUrl = toStaticUrl(outputPath); + + // Skip if image already set and not forcing + if (fm.image && !FORCE) { + console.log(` SKIP (has image): ${path.relative(REPO_ROOT, filePath)}`); + return { status: "skip" }; + } + + if (DRY_RUN) { + console.log(` WOULD generate: ${staticUrl}`); + return { status: "dry-run" }; + } + + // Ensure output directory exists + fs.mkdirSync(path.dirname(outputPath), { recursive: true }); + + // Build SVG and convert to PNG + const svg = buildSvg({ section, title, description }); + await sharp(Buffer.from(svg)).png().toFile(outputPath); + + // Update frontmatter in source file + const updated = setFrontmatterImage(content, staticUrl); + fs.writeFileSync(filePath, updated, "utf8"); + + console.log(` OK: ${path.relative(REPO_ROOT, filePath)} → ${staticUrl}`); + return { status: "ok" }; +} + +async function runPreview() { + const PREVIEW_OUT = path.join(STATIC_DIR, "og-preview.png"); + + let section, title, description; + + if (PREVIEW_FILE) { + const content = fs.readFileSync(PREVIEW_FILE, "utf8"); + const fm = parseFrontmatter(content); + if (!fm) { + console.error("No frontmatter found in the specified file."); + process.exit(1); + } + section = getSection(PREVIEW_FILE); + title = fm.title || fm.sidebar_label || fm.id || path.basename(PREVIEW_FILE, path.extname(PREVIEW_FILE)); + description = fm.description || ""; + console.log(`Preview source: ${path.relative(REPO_ROOT, PREVIEW_FILE)}`); + } else { + // Default sample data so you can tweak the design without needing a real file + section = "HyperIndex"; + title = "Getting Started with Envio"; + description = "Get started with Envio indexer setup, templates, and local or hosted deployment quickly."; + console.log("Preview source: sample data (pass a file path to use real content)"); + } + + const svg = buildSvg({ section, title, description }); + await sharp(Buffer.from(svg)).png().toFile(PREVIEW_OUT); + console.log(`Preview written to: ${path.relative(REPO_ROOT, PREVIEW_OUT)}`); +} + +async function main() { + if (PREVIEW) { + await runPreview(); + return; + } + + console.log(`Generating OG images for docs (force=${FORCE}, dry-run=${DRY_RUN})…`); + + const files = collectDocs(DOCS_DIR); + console.log(`Found ${files.length} docs files.`); + + let ok = 0, skipped = 0, errors = 0; + + for (const file of files) { + try { + const result = await processFile(file); + if (result.status === "ok") ok++; + else skipped++; + } catch (err) { + console.error(` ERROR: ${path.relative(REPO_ROOT, file)}: ${err.message}`); + errors++; + } + } + + console.log(`\nDone. Generated: ${ok}, Skipped: ${skipped}, Errors: ${errors}`); + if (errors > 0) process.exit(1); +} + +main(); diff --git a/yarn.lock b/yarn.lock index 6d573056..750892fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2634,6 +2634,13 @@ dependencies: "@edge-runtime/primitives" "4.1.0" +"@emnapi/runtime@^1.7.0": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.9.2.tgz#8b469a3db160817cadb1de9050211a9d1ea84fa2" + integrity sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw== + dependencies: + tslib "^2.4.0" + "@emotion/is-prop-valid@1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" @@ -2995,6 +3002,153 @@ resolved "https://registry.yarnpkg.com/@hono/node-server/-/node-server-1.19.13.tgz#4838c766a1237253d4dde3281cf7d5c65186fd32" integrity sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ== +"@img/colour@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.1.0.tgz#b0c2c2fa661adf75effd6b4964497cd80010bb9d" + integrity sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ== + +"@img/sharp-darwin-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz#6e0732dcade126b6670af7aa17060b926835ea86" + integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.4" + +"@img/sharp-darwin-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz#19bc1dd6eba6d5a96283498b9c9f401180ee9c7b" + integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.4" + +"@img/sharp-libvips-darwin-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz#2894c0cb87d42276c3889942e8e2db517a492c43" + integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== + +"@img/sharp-libvips-darwin-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz#e63681f4539a94af9cd17246ed8881734386f8cc" + integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg== + +"@img/sharp-libvips-linux-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz#b1b288b36864b3bce545ad91fa6dadcf1a4ad318" + integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw== + +"@img/sharp-libvips-linux-arm@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz#b9260dd1ebe6f9e3bdbcbdcac9d2ac125f35852d" + integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A== + +"@img/sharp-libvips-linux-ppc64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz#4b83ecf2a829057222b38848c7b022e7b4d07aa7" + integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA== + +"@img/sharp-libvips-linux-riscv64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz#880b4678009e5a2080af192332b00b0aaf8a48de" + integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA== + +"@img/sharp-libvips-linux-s390x@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz#74f343c8e10fad821b38f75ced30488939dc59ec" + integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ== + +"@img/sharp-libvips-linux-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz#df4183e8bd8410f7d61b66859a35edeab0a531ce" + integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz#c8d6b48211df67137541007ee8d1b7b1f8ca8e06" + integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw== + +"@img/sharp-libvips-linuxmusl-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz#be11c75bee5b080cbee31a153a8779448f919f75" + integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg== + +"@img/sharp-linux-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz#7aa7764ef9c001f15e610546d42fce56911790cc" + integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.4" + +"@img/sharp-linux-arm@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz#5fb0c3695dd12522d39c3ff7a6bc816461780a0d" + integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.4" + +"@img/sharp-linux-ppc64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz#9c213a81520a20caf66978f3d4c07456ff2e0813" + integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.4" + +"@img/sharp-linux-riscv64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz#cdd28182774eadbe04f62675a16aabbccb833f60" + integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw== + optionalDependencies: + "@img/sharp-libvips-linux-riscv64" "1.2.4" + +"@img/sharp-linux-s390x@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz#93eac601b9f329bb27917e0e19098c722d630df7" + integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.4" + +"@img/sharp-linux-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz#55abc7cd754ffca5002b6c2b719abdfc846819a8" + integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.4" + +"@img/sharp-linuxmusl-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz#d6515ee971bb62f73001a4829b9d865a11b77086" + integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + +"@img/sharp-linuxmusl-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz#d97978aec7c5212f999714f2f5b736457e12ee9f" + integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + +"@img/sharp-wasm32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz#2f15803aa626f8c59dd7c9d0bbc766f1ab52cfa0" + integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw== + dependencies: + "@emnapi/runtime" "^1.7.0" + +"@img/sharp-win32-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz#3706e9e3ac35fddfc1c87f94e849f1b75307ce0a" + integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g== + +"@img/sharp-win32-ia32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz#0b71166599b049e032f085fb9263e02f4e4788de" + integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg== + +"@img/sharp-win32-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz#a81ffb00e69267cd0a1d626eaedb8a8430b2b2f8" + integrity sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw== + "@isaacs/balanced-match@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" @@ -7891,7 +8045,7 @@ destroy@1.2.0: resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-libc@^2.0.0: +detect-libc@^2.0.0, detect-libc@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== @@ -16396,7 +16550,7 @@ semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.5.4: resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== -semver@^7.5.3: +semver@^7.5.3, semver@^7.7.3: version "7.7.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== @@ -16562,6 +16716,40 @@ shallowequal@1.1.0, shallowequal@^1.1.0: resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== +sharp@^0.34.5: + version "0.34.5" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.5.tgz#b6f148e4b8c61f1797bde11a9d1cfebbae2c57b0" + integrity sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg== + dependencies: + "@img/colour" "^1.0.0" + detect-libc "^2.1.2" + semver "^7.7.3" + optionalDependencies: + "@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@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"