commit 04b0b47a0cb69b891b5104ec336c62bade03c1a2 Author: NunoSempere Date: Fri Nov 4 23:02:31 2022 +0000 Initial commit from Create Next App diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..a2569c2 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "root": true, + "extends": "next/core-web-vitals" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e9f224 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# Dependencies +/node_modules +/.pnp +.pnp.js + +# Testing +/coverage + +# Next.js +/.next/ +/out/ + +# Production +build +dist + +# Misc +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Local ENV files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Vercel +.vercel + +# Turborepo +.turbo + +# typescript +*.tsbuildinfo \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3698fe8 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +--- +name: Open Graph Image Generation +slug: og-image-generation +description: Compute and generate dynamic social card images with React components. +framework: Next.js +useCase: Edge Functions +css: Tailwind +deployUrl: https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/vercel-og-nextjs&project-name=vercel-og-nextjs&repository-name=vercel-og-nextjs +demoUrl: https://og-examples.vercel.sh/api/static +relatedTemplates: + - nextjs-boilerplate + - aws-s3-image-upload-nextjs + - platforms-starter-kit + - blog-starter-kit +--- + +# Vercel OG + Next.js + +This example shows how to use [Vercel OG](https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation) with Next.js. + +## Demo + +- [Static Text](https://og-examples.vercel.sh/api/static) +- [Vercel Card](https://og-examples.vercel.sh/api/vercel) +- [Dynamic Text from URL Query](https://og-examples.vercel.sh/api/param) +- [Embed SVG Image](https://og-examples.vercel.sh/api/image-svg) +- [Dynamic PNG Image Based on URL Queries](https://og-examples.vercel.sh/api/dynamic-image?username=vercel) +- [Custom Font](https://og-examples.vercel.sh/api/custom-font) +- [Emoji](https://og-examples.vercel.sh/api/emoji) +- [Languages](https://og-examples.vercel.sh/api/language) +- [Encrypted Token](https://og-examples.vercel.sh/encrypted/a) + +## How to Use + +You can choose from one of the following two methods to use this repository: + +### One-Click Deploy + +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=vercel-examples): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/vercel-og-nextjs&project-name=vercel-og-nextjs&repository-name=vercel-og-nextjs) + +### Clone and Deploy + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example https://github.com/vercel/examples/tree/main/edge-functions/vercel-og-nextjs +# or +yarn create next-app --example https://github.com/vercel/examples/tree/main/edge-functions/vercel-og-nextjs +``` + +Next, run Next.js in development mode: + +```bash +npm install +npm run dev + +# or + +yarn +yarn dev +``` + +Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=edge-middleware-eap) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/assets/RecursiveMonoCslSt-Bold.ttf b/assets/RecursiveMonoCslSt-Bold.ttf new file mode 100644 index 0000000..3398745 Binary files /dev/null and b/assets/RecursiveMonoCslSt-Bold.ttf differ diff --git a/assets/TYPEWR__.TTF b/assets/TYPEWR__.TTF new file mode 100644 index 0000000..d6b9989 Binary files /dev/null and b/assets/TYPEWR__.TTF differ diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..8b61df4 --- /dev/null +++ b/next.config.js @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +module.exports = { + reactStrictMode: true, +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3f1b435 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "repository": "https://github.com/vercel/examples.git", + "license": "MIT", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@vercel/og": "0.0.14", + "next": "latest", + "react": "latest", + "react-dom": "latest" + }, + "devDependencies": { + "@types/node": "^18.0.6", + "@types/react": "^18.0.15", + "typescript": "^4.7.4" + } +} diff --git a/pages/api/custom-font.tsx b/pages/api/custom-font.tsx new file mode 100644 index 0000000..88ea5e3 --- /dev/null +++ b/pages/api/custom-font.tsx @@ -0,0 +1,42 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} + +const font = fetch(new URL('../../assets/TYPEWR__.TTF', import.meta.url)).then( + (res) => res.arrayBuffer() +) + +export default async function handler() { + const fontData = await font + + return new ImageResponse( + ( +
+ Hello world! +
+ ), + { + width: 1200, + height: 630, + fonts: [ + { + name: 'Typewriter', + data: fontData, + style: 'normal', + }, + ], + } + ) +} diff --git a/pages/api/dynamic-image.tsx b/pages/api/dynamic-image.tsx new file mode 100644 index 0000000..ae914be --- /dev/null +++ b/pages/api/dynamic-image.tsx @@ -0,0 +1,51 @@ +import { ImageResponse } from '@vercel/og' +import { NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler(req: NextRequest) { + const { searchParams } = req.nextUrl + const username = searchParams.get('username') + if (!username) { + return new ImageResponse(<>{'Visit with "?username=vercel"'}, { + width: 1200, + height: 630, + }) + } + + return new ImageResponse( + ( +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + avatar +

github.com/{username}

+
+ ), + { + width: 1200, + height: 630, + } + ) +} diff --git a/pages/api/emoji.tsx b/pages/api/emoji.tsx new file mode 100644 index 0000000..5dff4ef --- /dev/null +++ b/pages/api/emoji.tsx @@ -0,0 +1,35 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler() { + return new ImageResponse( + ( +
+ 👋, 🌎 +
+ ), + { + width: 1200, + height: 630, + // Supported options: 'twemoji', 'blobmoji', 'noto', 'openmoji', 'fluent', 'fluentFlat' + // Default to 'twemoji' + emoji: 'twemoji', + } + ) +} diff --git a/pages/api/encrypted.tsx b/pages/api/encrypted.tsx new file mode 100644 index 0000000..24ed1a2 --- /dev/null +++ b/pages/api/encrypted.tsx @@ -0,0 +1,68 @@ +// This function verifies the token to prevent generating images with random +// parameters (`id`). +// Check pages/encrypted/[id].tsx for more info. + +import { ImageResponse } from '@vercel/og' +import { NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +const key = crypto.subtle.importKey( + 'raw', + new TextEncoder().encode('my_secret'), + { name: 'HMAC', hash: { name: 'SHA-256' } }, + false, + ['sign'] +) + +function toHex(arrayBuffer) { + return Array.prototype.map + .call(new Uint8Array(arrayBuffer), (n) => n.toString(16).padStart(2, '0')) + .join('') +} + +export default async function handler(req: NextRequest) { + const { searchParams } = req.nextUrl + + const id = searchParams.get('id') + const token = searchParams.get('token') + + const verifyToken = toHex( + await crypto.subtle.sign( + 'HMAC', + await key, + new TextEncoder().encode(JSON.stringify({ id })) + ) + ) + + if (token !== verifyToken) { + return new Response('Invalid token.', { status: 401 }) + } + + return new ImageResponse( + ( +
+

Card generated, id={id}.

+
+ ), + { + width: 1200, + height: 630, + } + ) +} diff --git a/pages/api/image-svg.tsx b/pages/api/image-svg.tsx new file mode 100644 index 0000000..ee74fa8 --- /dev/null +++ b/pages/api/image-svg.tsx @@ -0,0 +1,33 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler() { + return new ImageResponse( + ( +
+ + + +
+ ), + { + width: 1200, + height: 630, + } + ) +} diff --git a/pages/api/language.tsx b/pages/api/language.tsx new file mode 100644 index 0000000..9258f97 --- /dev/null +++ b/pages/api/language.tsx @@ -0,0 +1,32 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler() { + return new ImageResponse( + ( +
+ 👋 Hello 你好 नमस्ते こんにちは สวัสดีค่ะ 안녕 добрий день Hallá +
+ ), + { + width: 1200, + height: 630, + } + ) +} diff --git a/pages/api/param.tsx b/pages/api/param.tsx new file mode 100644 index 0000000..e2f9990 --- /dev/null +++ b/pages/api/param.tsx @@ -0,0 +1,79 @@ +import { ImageResponse } from '@vercel/og' +import { NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +export default function handler(req: NextRequest) { + try { + const { searchParams } = new URL(req.url) + + // ?title= + const hasTitle = searchParams.has('title') + const title = hasTitle + ? searchParams.get('title')?.slice(0, 100) + : 'My default title' + + return new ImageResponse( + ( + <div + style={{ + backgroundColor: 'black', + backgroundSize: '150px 150px', + height: '100%', + width: '100%', + display: 'flex', + textAlign: 'center', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column', + flexWrap: 'nowrap', + }} + > + <div + style={{ + display: 'flex', + alignItems: 'center', + alignContent: 'center', + justifyContent: 'center', + justifyItems: 'center', + }} + > + {/* eslint-disable-next-line @next/next/no-img-element */} + <img + alt="Vercel" + height={200} + src="data:image/svg+xml,%3Csvg width='116' height='100' fill='white' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M57.5 0L115 100H0L57.5 0z' /%3E%3C/svg%3E" + style={{ margin: '0 30px' }} + width={232} + /> + </div> + <div + style={{ + fontSize: 60, + fontStyle: 'normal', + letterSpacing: '-0.025em', + color: 'white', + marginTop: 30, + padding: '0 120px', + lineHeight: 1.4, + whiteSpace: 'pre-wrap', + }} + > + {title} + </div> + </div> + ), + { + width: 1200, + height: 630, + } + ) + } catch (e: any) { + console.log(`${e.message}`) + return new Response(`Failed to generate the image`, { + status: 500, + }) + } +} diff --git a/pages/api/static.tsx b/pages/api/static.tsx new file mode 100644 index 0000000..938df92 --- /dev/null +++ b/pages/api/static.tsx @@ -0,0 +1,30 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} + +export default function handler() { + return new ImageResponse( + ( + <div + style={{ + fontSize: 128, + background: 'white', + width: '100%', + height: '100%', + display: 'flex', + textAlign: 'center', + alignItems: 'center', + justifyContent: 'center', + }} + > + Hello world! + </div> + ), + { + width: 1200, + height: 600, + } + ) +} diff --git a/pages/api/tailwind.tsx b/pages/api/tailwind.tsx new file mode 100644 index 0000000..6849c10 --- /dev/null +++ b/pages/api/tailwind.tsx @@ -0,0 +1,55 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler() { + return new ImageResponse( + ( + // Modified based on https://tailwindui.com/components/marketing/sections/cta-sections + <div + style={{ + height: '100%', + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'white', + }} + > + <div tw="bg-gray-50 flex"> + <div tw="flex flex-col md:flex-row w-full py-12 px-4 md:items-center justify-between p-8"> + <h2 tw="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left"> + <span>Ready to dive in?</span> + <span tw="text-indigo-600">Start your free trial today.</span> + </h2> + <div tw="mt-8 flex md:mt-0"> + <div tw="flex rounded-md shadow"> + <a + href="#" + tw="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white" + > + Get started + </a> + </div> + <div tw="ml-3 flex rounded-md shadow"> + <a + href="#" + tw="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600" + > + Learn more + </a> + </div> + </div> + </div> + </div> + </div> + ), + { + width: 1200, + height: 630, + } + ) +} diff --git a/pages/api/vercel.tsx b/pages/api/vercel.tsx new file mode 100644 index 0000000..e0ca4f8 --- /dev/null +++ b/pages/api/vercel.tsx @@ -0,0 +1,50 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler() { + return new ImageResponse( + ( + <div + style={{ + backgroundColor: '#fff', + backgroundImage: + 'radial-gradient(circle at 25px 25px, lightgray 2%, transparent 0%), radial-gradient(circle at 75px 75px, lightgray 2%, transparent 0%)', + backgroundSize: '100px 100px', + height: '100%', + width: '100%', + textAlign: 'center', + alignContent: 'center', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column', + display: 'flex', + }} + > + {/* eslint-disable-next-line @next/next/no-img-element */} + <img + alt="Vercel" + width={255} + height={225} + src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTE2IiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTU3LjUgMEwxMTUgMTAwSDBMNTcuNSAweiIgLz48L3N2Zz4=" + style={{ margin: '0 75px' }} + /> + <div + style={{ + fontSize: 60, + marginTop: 30, + lineHeight: 1.8, + }} + > + Vercel Edge Network + </div> + </div> + ), + { + width: 1200, + height: 600, + } + ) +} diff --git a/pages/encrypted/[id].tsx b/pages/encrypted/[id].tsx new file mode 100644 index 0000000..2fb0f01 --- /dev/null +++ b/pages/encrypted/[id].tsx @@ -0,0 +1,43 @@ +// This SSG page generates the token to prevent generating OG images with random +// parameters (`id`). +// Check pages/api/encrypted.tsx for more info. + +import { createHmac } from 'node:crypto' + +export async function getStaticProps({ params }) { + const hmac = createHmac('sha256', 'my_secret') + hmac.update(JSON.stringify({ id: params.id })) + const token = hmac.digest('hex') + + return { + props: { + id: params.id, + token, + }, + } +} + +export function getStaticPaths() { + return { + paths: [ + { params: { id: 'a' } }, + { params: { id: 'b' } }, + { params: { id: 'c' } }, + ], + fallback: false, + } +} + +export default function Page({ id, token }) { + return ( + <div> + <h1>Encrypted Open Graph Image.</h1> + <p>Only /a, /b, /c with correct tokens are accessible:</p> + <a href={`/api/encrypted?id=${id}&token=${token}`} target="_blank" rel="noreferrer"> + <code> + /api/encrypted?id={id}&token={token} + </code> + </a> + </div> + ) +} diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 0000000..5e19fdc --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,25 @@ +import Head from 'next/head' + +export default function Page() { + return ( + <div> + <Head> + <meta name="og:title" content="Vercel Edge Network" /> + <meta name="og:description" content="Vercel Edge Network" /> + <meta + name="og:image" + content={ + // Because OG images must have a absolute URL, we use the + // `VERCEL_URL` environment variable to get the deployment’s URL. + // More info: + // https://vercel.com/docs/concepts/projects/environment-variables + `${ + process.env.VERCEL_URL ? 'https://' + process.env.VERCEL_URL : '' + }/api/vercel` + } + /> + </Head> + <h1>A page with Open Graph Image.</h1> + </div> + ) +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..4ddd8ff Binary files /dev/null and b/public/favicon.ico differ diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..044ece5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "moduleResolution": "node", + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..e54f47b --- /dev/null +++ b/yarn.lock @@ -0,0 +1,320 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@next/env@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.0.2.tgz#5fbd7b4146175ae406edfb4a38b62de8c880c09d" + integrity sha512-Qb6WPuRriGIQ19qd6NBxpcrFOfj8ziN7l9eZUfwff5gl4zLXluqtuZPddYZM/oWjN53ZYcuRXzL+oowKyJeYtA== + +"@next/swc-android-arm-eabi@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.0.2.tgz#66669b8aab5062f554b8e9905d855679aabf0342" + integrity sha512-X54UQCTFyOGnJP//Z71dPPlp4BCYcQL2ncikKXQcPzVpqPs4C3m+tKC8ivBNH6edAXkppwsLRz1/yQwgSZ9Swg== + +"@next/swc-android-arm64@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.0.2.tgz#c0641d30525e0fb22bf1e2baf6c461d2d9e52f1a" + integrity sha512-1P00Kv8uKaLubqo7JzPrTqgFAzSOmfb8iwqJrOb9in5IvTRtNGlkR4hU0sXzqbQNM/+SaYxze6Z5ry1IDyb/cQ== + +"@next/swc-darwin-arm64@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.2.tgz#d7e01a33393e83456dbfdc41446bb8a923968ff7" + integrity sha512-1zGIOkInkOLRv0QQGZ+3wffYsyKI4vIy62LYTvDWUn7TAYqnmXwougp9NSLqDeagLwgsv2URrykyAFixA/YqxA== + +"@next/swc-darwin-x64@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.0.2.tgz#d4a3fbe51edf871a675d89a7afdc78174d1e5841" + integrity sha512-ECDAjoMP1Y90cARaelS6X+k6BQx+MikAYJ8f/eaJrLur44NIOYc9HA/dgcTp5jenguY4yT8V+HCquLjAVle6fA== + +"@next/swc-freebsd-x64@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.0.2.tgz#1b54c3f38d3b36f86663a8dfcc81ea05e01f5172" + integrity sha512-2DcL/ofQdBnQX3IoI9sjlIAyLCD1oZoUBuhrhWbejvBQjutWrI0JTEv9uG69WcxWhVMm3BCsjv8GK2/68OKp7A== + +"@next/swc-linux-arm-gnueabihf@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.0.2.tgz#18495cff32c0b2182cfbf677614219d7072214da" + integrity sha512-Y3OQF1CSBSWW2vGkmvOIuOUNqOq8qX7f1ZpcKUVWP3/Uq++DZmVi9d18lgnSe1I3QFqc+nXWyun9ljsN83j0sw== + +"@next/swc-linux-arm64-gnu@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.0.2.tgz#5fb2563651166c3c6f32bf9e2f9cc6a16a9ef783" + integrity sha512-mNyzwsFF6kwZYEjnGicx9ksDZYEZvyzEc1BtCu8vdZi/v8UeixQwCiAT6FyYX9uxMPEkzk8qiU0t0u9gvltsKw== + +"@next/swc-linux-arm64-musl@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.0.2.tgz#b9f33c5e17cfe04aa5769b717284cf80865761e6" + integrity sha512-M6SdYjWgRrY3tJBxz0663zCRPTu5BRONmxlftKWWHv9LjAJ59neTLaGj4rp0A08DkJglZIoCkLOzLrzST6TGag== + +"@next/swc-linux-x64-gnu@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.0.2.tgz#29efcc2fd0122689d7e06c5b6b0883fe495db2bf" + integrity sha512-pi63RoxvG4ES1KS06Zpm0MATVIXTs/TIbLbdckeLoM40u1d3mQl/+hSSrLRSxzc2OtyL8fh92sM4gkJrQXAMAw== + +"@next/swc-linux-x64-musl@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.0.2.tgz#d68fdf6eefc57813fa91559c7089b49d6131ecab" + integrity sha512-9Pv91gfYnDONgjtRm78n64b/c54+azeHtlnqBLTnIFWSMBDRl1/WDkhKWIj3fBGPLimtK7Tko3ULR3og9RRUPw== + +"@next/swc-win32-arm64-msvc@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.0.2.tgz#acdcb3023045f60cca510f659a2349895e6405bd" + integrity sha512-Nvewe6YZaizAkGHHprbMkYqQulBjZCHKBGKeFPwoPtOA+a2Qi4pZzc/qXFyC5/2A6Z0mr2U1zg9rd04WBYMwBw== + +"@next/swc-win32-ia32-msvc@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.0.2.tgz#a78ee9211471768febac9df915c2a8dbbcd05e41" + integrity sha512-ZUBYGZw5G3QrqDpRq1EWi3aHmvPZM8ijK5TFL6UbH16cYQ0JpANmuG2P66KB93Qe/lWWzbeAZk/tj1XqwoCuPA== + +"@next/swc-win32-x64-msvc@13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.0.2.tgz#e86c2de910cd68a17974db5556d4588737412c68" + integrity sha512-fA9uW1dm7C0mEYGcKlbmLcVm2sKcye+1kPxh2cM4jVR+kQQMtHWsjIzeSpe2grQLSDan06z4n6hbr8b1c3hA8w== + +"@resvg/resvg-wasm@2.0.0-alpha.4": + version "2.0.0-alpha.4" + resolved "https://registry.yarnpkg.com/@resvg/resvg-wasm/-/resvg-wasm-2.0.0-alpha.4.tgz#fc2f86186a9641df030d8f9f3f9d995899cd1ecb" + integrity sha512-pWIG9a/x1ky8gXKRhPH1OPKpHFoMN1ISLbJ+O+gPXQHIAKhNd5I28RlWf7q576hAOQA9JZTlo3p/M2uyLzJmmw== + +"@shuding/opentype.js@1.4.0-beta.0": + version "1.4.0-beta.0" + resolved "https://registry.yarnpkg.com/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz#5d1e7e9e056f546aad41df1c5043f8f85d39e24b" + integrity sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA== + dependencies: + fflate "^0.7.3" + string.prototype.codepointat "^0.2.1" + +"@swc/helpers@0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de" + integrity sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw== + dependencies: + tslib "^2.4.0" + +"@types/node@^18.0.6": + version "18.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" + integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== + +"@types/prop-types@*": + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + +"@types/react@^18.0.15": + version "18.0.25" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.25.tgz#8b1dcd7e56fe7315535a4af25435e0bb55c8ae44" + integrity sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@types/yoga-layout@1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@types/yoga-layout/-/yoga-layout-1.9.2.tgz#efaf9e991a7390dc081a0b679185979a83a9639a" + integrity sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw== + +"@vercel/og@0.0.14": + version "0.0.14" + resolved "https://registry.yarnpkg.com/@vercel/og/-/og-0.0.14.tgz#22f2a029718778505b81e261957c41dd87a86fe3" + integrity sha512-OWdN/CJZOWtrlLAKiwZnFn7GrA/2EqEobuSvxZ8OZkb/ukgogOWQBrwr+t/748qsgGCyqc6BiQYJIe9PGr9QVA== + dependencies: + "@resvg/resvg-wasm" "2.0.0-alpha.4" + satori "0.0.37" + yoga-wasm-web "0.1.2" + +camelize@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3" + integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== + +caniuse-lite@^1.0.30001406: + version "1.0.30001430" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz#638a8ae00b5a8a97e66ff43733b2701f81b101fa" + integrity sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg== + +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +css-background-parser@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/css-background-parser/-/css-background-parser-0.1.0.tgz#48a17f7fe6d4d4f1bca3177ddf16c5617950741b" + integrity sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA== + +css-box-shadow@1.0.0-3: + version "1.0.0-3" + resolved "https://registry.yarnpkg.com/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz#9eaeb7140947bf5d649fc49a19e4bbaa5f602713" + integrity sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg== + +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg== + +css-to-react-native@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" + integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== + dependencies: + camelize "^1.0.0" + css-color-keywords "^1.0.0" + postcss-value-parser "^4.0.2" + +csstype@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" + integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== + +fflate@^0.7.3: + version "0.7.4" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.4.tgz#61587e5d958fdabb5a9368a302c25363f4f69f50" + integrity sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw== + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +next@latest: + version "13.0.2" + resolved "https://registry.yarnpkg.com/next/-/next-13.0.2.tgz#b8c8642c70f736ed91105645391d335fc51c8f62" + integrity sha512-uQ5z5e4D9mOe8+upy6bQdYYjo/kk1v3jMW87kTy2TgAyAsEO+CkwRnMgyZ4JoHEnhPZLHwh7dk0XymRNLe1gFw== + dependencies: + "@next/env" "13.0.2" + "@swc/helpers" "0.4.11" + caniuse-lite "^1.0.30001406" + postcss "8.4.14" + styled-jsx "5.1.0" + use-sync-external-store "1.2.0" + optionalDependencies: + "@next/swc-android-arm-eabi" "13.0.2" + "@next/swc-android-arm64" "13.0.2" + "@next/swc-darwin-arm64" "13.0.2" + "@next/swc-darwin-x64" "13.0.2" + "@next/swc-freebsd-x64" "13.0.2" + "@next/swc-linux-arm-gnueabihf" "13.0.2" + "@next/swc-linux-arm64-gnu" "13.0.2" + "@next/swc-linux-arm64-musl" "13.0.2" + "@next/swc-linux-x64-gnu" "13.0.2" + "@next/swc-linux-x64-musl" "13.0.2" + "@next/swc-win32-arm64-msvc" "13.0.2" + "@next/swc-win32-ia32-msvc" "13.0.2" + "@next/swc-win32-x64-msvc" "13.0.2" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@8.4.14: + version "8.4.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" + integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +react-dom@latest: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react@latest: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +satori@0.0.37: + version "0.0.37" + resolved "https://registry.yarnpkg.com/satori/-/satori-0.0.37.tgz#f7c8b8b861b9c843a80fe24ee38b6c174a14fba6" + integrity sha512-0qlb8/AcRL6bQup90VDDeBacbQ36MFj5378jh6NSUWGfuk5aPrOhFsD/FbfIAtDI/kf+hsFP4DUOI5K72FqVsQ== + dependencies: + "@shuding/opentype.js" "1.4.0-beta.0" + css-background-parser "^0.1.0" + css-box-shadow "1.0.0-3" + css-to-react-native "^3.0.0" + postcss-value-parser "^4.2.0" + yoga-layout-prebuilt "^1.10.0" + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +string.prototype.codepointat@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc" + integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg== + +styled-jsx@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.0.tgz#4a5622ab9714bd3fcfaeec292aa555871f057563" + integrity sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ== + dependencies: + client-only "0.0.1" + +tslib@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== + +typescript@^4.7.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + +use-sync-external-store@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + +yoga-layout-prebuilt@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.10.0.tgz#2936fbaf4b3628ee0b3e3b1df44936d6c146faa6" + integrity sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g== + dependencies: + "@types/yoga-layout" "1.9.2" + +yoga-wasm-web@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yoga-wasm-web/-/yoga-wasm-web-0.1.2.tgz#05d3fc9cbdfd57ac9682debb5001aca075489a39" + integrity sha512-8SkgawHcA0RUbMrnhxbaQkZDBi8rMed8pQHixkFF9w32zGhAwZ9/cOHWlpYfr6RCx42Yp3siV45/jPEkJxsk6w==