diff --git a/biome.json b/biome.json
index f913aa2..f8f8494 100644
--- a/biome.json
+++ b/biome.json
@@ -34,7 +34,6 @@
{
"includes": [
"data/src/branches/**/Logo.tsx",
- "src/components/GameCard/GameCard.tsx",
"src/components/NavBar/**/*.tsx",
"src/components/LeagueTable/LeagueTable.tsx",
"src/components/FixtureCard/FixtureCard.tsx"
diff --git a/package.json b/package.json
index 045c51a..c6e18f0 100644
--- a/package.json
+++ b/package.json
@@ -45,11 +45,11 @@
"@vercel/speed-insights": "2.0.0",
"clsx": "2.1.1",
"next": "16.2.4",
+ "opentype.js": "1.3.4",
"react": "19.2.5",
"react-dom": "19.2.5",
"react-error-boundary": "6.1.1",
- "react-ios-pwa-prompt": "2.0.6",
- "react-textfit": "1.1.1"
+ "react-ios-pwa-prompt": "2.0.6"
},
"devDependencies": {
"@axe-core/playwright": "4.11.2",
@@ -59,9 +59,9 @@
"@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "16.3.2",
"@types/node": "25.6.0",
+ "@types/opentype.js": "^1",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
- "@types/react-textfit": "1.1.4",
"@vitejs/plugin-react": "5.1.4",
"@vitest/coverage-v8": "4.0.18",
"happy-dom": "20.9.0",
diff --git a/src/app/[domain]/game-card/_backgrounds.tsx b/src/app/[domain]/game-card/_backgrounds.tsx
new file mode 100644
index 0000000..e50f5f6
--- /dev/null
+++ b/src/app/[domain]/game-card/_backgrounds.tsx
@@ -0,0 +1,91 @@
+export function HomeBg() {
+ return (
+ // biome-ignore lint/a11y/noSvgWithoutTitle: rendered to PNG via Satori
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export function AwayBg() {
+ return (
+ // biome-ignore lint/a11y/noSvgWithoutTitle: rendered to PNG via Satori
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/[domain]/game-card/loading.tsx b/src/app/[domain]/game-card/loading.tsx
deleted file mode 100644
index 00bb5a1..0000000
--- a/src/app/[domain]/game-card/loading.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export default async function GameCardPageLoading() {
- return
Loading
;
-}
diff --git a/src/app/[domain]/game-card/page.tsx b/src/app/[domain]/game-card/page.tsx
deleted file mode 100644
index 4bbe8f2..0000000
--- a/src/app/[domain]/game-card/page.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import type { Metadata } from 'next';
-
-import { GameCard } from '@/components';
-import { branchData } from '@/data';
-import { getNextFixture } from '@/lib/data/fixtures';
-
-export const metadata: Metadata = {
- robots: {
- index: false,
- follow: false,
- },
-};
-
-export default async function GameCardPage(props: {
- params: Promise<{ domain: string }>;
-}) {
- const params = await props.params;
- const branch = branchData[params.domain];
-
- const [nextFixture] = await getNextFixture();
-
- return ;
-}
diff --git a/src/app/[domain]/game-card/route.tsx b/src/app/[domain]/game-card/route.tsx
new file mode 100644
index 0000000..5de5f5e
--- /dev/null
+++ b/src/app/[domain]/game-card/route.tsx
@@ -0,0 +1,354 @@
+import { ImageResponse } from 'next/og';
+import teams from '@/components/TeamLogo/teams';
+import { branchData, branchLogo, branchLogoSrc } from '@/data';
+import { getNextFixture } from '@/lib/data/fixtures';
+import { fitText } from '@/lib/og/fitText';
+import { getImageResponseFonts, getParsedFonts } from '@/lib/og/fonts';
+import { ARSENAL_TEAM_ID } from '@/lib/sportmonks/sportmonks';
+import { dateFromEpoch, epochToTime } from '@/lib/utils';
+
+import { AwayBg, HomeBg } from './_backgrounds';
+
+const SIZE = 1080;
+// Center X for logo, billing, and time: right:33% + translateX(50%) = 67% from left
+const CENTER_X = Math.round(SIZE * 0.6667);
+
+export async function GET(
+ req: Request,
+ { params }: { params: Promise<{ domain: string }> },
+) {
+ const { domain } = await params;
+
+ const branch = branchData[domain];
+ const Logo = branchLogo[domain];
+ const rasterSrc = branchLogoSrc[domain];
+
+ const fonts = getImageResponseFonts();
+ const { boldFont, regFont } = getParsedFonts();
+
+ const [fixture] = await getNextFixture();
+ const { participants, starting_at_timestamp } = fixture;
+
+ const url = new URL(req.url);
+ const simulateAway = url.searchParams.get('simulate') === 'away';
+
+ let localTeam = participants.find((p) => p.meta.location === 'home');
+ let visitorTeam = participants.find((p) => p.meta.location === 'away');
+ let isHomeGame = localTeam?.id === ARSENAL_TEAM_ID;
+
+ if (simulateAway && isHomeGame) {
+ [localTeam, visitorTeam] = [visitorTeam, localTeam];
+ isHomeGame = false;
+ }
+
+ const fixtureDate = dateFromEpoch(starting_at_timestamp, branch.timezone);
+ const fixtureTime = new Date(
+ epochToTime(starting_at_timestamp),
+ ).toLocaleTimeString('en-US', {
+ timeZone: branch.timezone,
+ timeStyle: 'short',
+ });
+
+ // Billing text sizing: max width 510px (leaving 30px breathing room from 540px container)
+ const localLabel = localTeam
+ ? localTeam.name + (localTeam.id !== ARSENAL_TEAM_ID ? ' vs' : '')
+ : '';
+ const visitorLabel = visitorTeam
+ ? (visitorTeam.id !== ARSENAL_TEAM_ID ? 'vs ' : '') + visitorTeam.name
+ : '';
+
+ // Arsenal's row (no "vs") scales up to 200px. The "vs + opponent" row is then
+ // sized to match Arsenal's actual rendered pixel width so both lines are equal.
+ let localSize: number;
+ let visitorSize: number;
+ if (isHomeGame && localTeam && visitorTeam) {
+ localSize = fitText(boldFont, localTeam.name, 510, 200, 32);
+ const arsenalWidth = boldFont.getAdvanceWidth(localTeam.name, localSize);
+ const visitorRowAt100 =
+ regFont.getAdvanceWidth('vs', 75) +
+ 15 +
+ boldFont.getAdvanceWidth(visitorTeam.name, 100);
+ visitorSize = Math.max(
+ 32,
+ Math.ceil((100 * arsenalWidth) / visitorRowAt100),
+ );
+ } else if (!isHomeGame && localTeam && visitorTeam) {
+ visitorSize = fitText(boldFont, visitorTeam.name, 510, 200, 32);
+ const arsenalWidth = boldFont.getAdvanceWidth(
+ visitorTeam.name,
+ visitorSize,
+ );
+ const localRowAt100 =
+ boldFont.getAdvanceWidth(localTeam.name, 100) +
+ 15 +
+ regFont.getAdvanceWidth('vs', 75);
+ localSize = Math.max(32, Math.ceil((100 * arsenalWidth) / localRowAt100));
+ } else {
+ localSize = fitText(boldFont, localLabel, 510, 200, 32);
+ visitorSize = fitText(boldFont, visitorLabel, 510, 200, 32);
+ }
+
+ // Time text sizing: max width 420px
+ const dateSize = fitText(regFont, fixtureDate, 420, 72, 24);
+ const timeSize = fitText(boldFont, `${fixtureTime} @ Doyle's`, 420, 72, 24);
+
+ const textShadow = '0 0 16px rgba(0,0,0,0.3)';
+ const badgeSize = 270;
+
+ return new ImageResponse(
+
+ {/* Background pattern */}
+
+
+ {/* Branch logo */}
+
+ {rasterSrc ? (
+ // biome-ignore lint/performance/noImgElement:
required inside ImageResponse
+ // biome-ignore lint/a11y/useAltText: rendered to PNG via Satori
+
+ ) : (
+ Logo &&
+ )}
+
+
+ {/* Team badges — left column, vertically centered */}
+ {localTeam && visitorTeam && (
+ <>
+
+ {teams.has(localTeam.id) ? (
+ // biome-ignore lint/a11y/noSvgWithoutTitle: rendered to PNG via Satori
+
+
+
+ ) : (
+ // biome-ignore lint/performance/noImgElement:
required inside ImageResponse — Next/Image is not compatible with next/og
+ // biome-ignore lint/a11y/useAltText: rendered to PNG via Satori, not served to browsers
+
+ )}
+ {teams.has(visitorTeam.id) ? (
+ // biome-ignore lint/a11y/noSvgWithoutTitle: rendered to PNG via Satori
+
+
+
+ ) : (
+ // biome-ignore lint/performance/noImgElement:
required inside ImageResponse — Next/Image is not compatible with next/og
+ // biome-ignore lint/a11y/useAltText: rendered to PNG via Satori, not served to browsers
+
+ )}
+
+
+ {/* Team name billing */}
+
+
+
+ {localTeam.name}
+
+ {localTeam.id !== ARSENAL_TEAM_ID && (
+
+ {'vs'}
+
+ )}
+
+
+ {visitorTeam.id !== ARSENAL_TEAM_ID && (
+
+ {'vs'}
+
+ )}
+
+ {visitorTeam.name}
+
+
+
+
+ {/* Date and kickoff time */}
+
+
+ {fixtureDate}
+
+
+ {`${fixtureTime} @ Doyle's`}
+
+
+ >
+ )}
+
,
+ {
+ width: SIZE,
+ height: SIZE,
+ fonts,
+ headers: {
+ 'Cache-Control':
+ 'public, max-age=45, s-maxage=45, stale-while-revalidate=120',
+ },
+ },
+ );
+}
diff --git a/src/components/GameCard/GameCard.module.scss b/src/components/GameCard/GameCard.module.scss
deleted file mode 100644
index 2c37d85..0000000
--- a/src/components/GameCard/GameCard.module.scss
+++ /dev/null
@@ -1,97 +0,0 @@
-$margin: 8vw;
-
-._ {
- position: relative;
- z-index: 50;
- margin: 0 -1em;
- aspect-ratio: 1/1;
- // background-color: white;
-
- h2 {
- position: initial;
- padding: initial;
- margin: 0;
- background-color: transparent;
- box-shadow: none;
- font-size: inherit;
- letter-spacing: -0.03em;
-
- &::after {
- display: none;
- }
-
- span {
- font-family: ars-reg, sans-serif;
- font-size: 0.75em;
- font-weight: 400;
- }
- }
-
- .Logo,
- .GameTime,
- .MainBilling {
- position: absolute;
- z-index: 10;
- right: 33%;
- transform: translateX(50%);
- }
-
- .MainBilling,
- .GameTime {
- text-align: center;
- text-shadow: 0 0 1rem rgb(0 0 0 / 30%);
- }
-
- .Logo {
- top: $margin;
- width: 25%;
- filter: drop-shadow(0 1.5vmin 3vmin rgb(0 0 0 / 30%));
- }
-
- .Badges {
- position: absolute;
- top: 50%;
- left: 8%;
- display: flex;
- flex-direction: column;
- gap: 5vw;
- transform: translateY(-50%);
-
- svg,
- img {
- width: 25vw;
- height: auto;
- fill: #fff;
- }
- }
-
- .MainBilling {
- top: 50%;
- width: 50%;
- transform: translate(50%, -40%);
-
- h2 {
- line-height: 0.9;
- }
- }
-
- .GameTime {
- bottom: $margin;
- width: 40%;
-
- h2 {
- line-height: 1;
- }
-
- > *:first-child {
- h2 {
- font-family: ars-reg, sans-serif;
- font-weight: 400;
- }
- }
- }
-
- .Background {
- display: block;
- }
-}
diff --git a/src/components/GameCard/GameCard.tsx b/src/components/GameCard/GameCard.tsx
deleted file mode 100644
index 79ac52a..0000000
--- a/src/components/GameCard/GameCard.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-import { branchLogo } from '@/data';
-import type { FixtureEntity } from '@/lib/sportmonks';
-import { TeamLogo } from '../TeamLogo/TeamLogo';
-import styles from './GameCard.module.scss';
-
-import { GameCardBilling } from './GameCardBilling';
-import { GameCardTime } from './GameCardTime';
-
-export function GameCard({
- branch,
- participants,
- starting_at_timestamp,
-}: { branch: { domain: string; timezone: string } } & FixtureEntity) {
- const Logo = branchLogo[branch.domain];
-
- const localTeam = participants.find((team) => team.meta.location === 'home');
- const visitorTeam = participants.find(
- (team) => team.meta.location === 'away',
- );
-
- const isHomeGame = localTeam?.id === 19;
-
- return (
-
- {Logo &&
}
- {localTeam && visitorTeam && (
- <>
-
-
-
-
-
-
- >
- )}
- {isHomeGame ? (
-
-
-
-
-
-
-
-
-
-
-
- ) : (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
- );
-}
diff --git a/src/components/GameCard/GameCardBilling.tsx b/src/components/GameCard/GameCardBilling.tsx
deleted file mode 100644
index 0bf37b2..0000000
--- a/src/components/GameCard/GameCardBilling.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-'use client';
-
-import { Textfit } from 'react-textfit';
-import type { EntityBase } from '@/lib/sportmonks';
-import styles from './GameCard.module.scss';
-
-export function GameCardBilling({
- localTeam,
- visitorTeam,
-}: {
- localTeam: EntityBase;
- visitorTeam: EntityBase;
-}) {
- return (
-
-
-
- {localTeam.name}
- {localTeam.id !== 19 && ' vs'}
-
-
-
-
- {visitorTeam.id !== 19 && 'vs '}
- {visitorTeam.name}
-
-
-
- );
-}
diff --git a/src/components/GameCard/GameCardTime.tsx b/src/components/GameCard/GameCardTime.tsx
deleted file mode 100644
index d69fadc..0000000
--- a/src/components/GameCard/GameCardTime.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-'use client';
-
-import { Textfit } from 'react-textfit';
-import { dateFromEpoch, epochToTime } from '@/lib/utils';
-import styles from './GameCard.module.scss';
-
-export function GameCardTime({
- starting_at_timestamp,
- timeZone,
-}: {
- starting_at_timestamp: number;
- timeZone: string;
-}) {
- const fixtureDate = dateFromEpoch(starting_at_timestamp, timeZone);
- const fixtureTime = new Date(
- epochToTime(starting_at_timestamp),
- ).toLocaleTimeString('en-US', {
- timeZone,
- timeStyle: 'short',
- });
-
- return (
-
-
- {fixtureDate}
-
-
- {fixtureTime} @ Doyle's
-
-
- );
-}
diff --git a/src/components/GameCard/bg.svg b/src/components/GameCard/bg.svg
deleted file mode 100644
index b0d7805..0000000
--- a/src/components/GameCard/bg.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/components/GameCard/bg_2023.svg b/src/components/GameCard/bg_2023.svg
deleted file mode 100644
index 8fb7c38..0000000
--- a/src/components/GameCard/bg_2023.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
diff --git a/src/components/GameCard/bg_2024.svg b/src/components/GameCard/bg_2024.svg
deleted file mode 100644
index ff0a32e..0000000
--- a/src/components/GameCard/bg_2024.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/components/GameCard/bg_2025_away.svg b/src/components/GameCard/bg_2025_away.svg
deleted file mode 100644
index cb4215b..0000000
--- a/src/components/GameCard/bg_2025_away.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/src/components/index.ts b/src/components/index.ts
index e732624..1a013a7 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -7,7 +7,6 @@ export * from './FixtureCard/FixtureCardBoundary';
export * from './FixtureCard/FixtureCardError';
export * from './FixtureCard/SettledFixtureCard';
export * from './FixtureCard/UnsettledFixtureCard';
-export * from './GameCard/GameCard';
export * from './LeagueLogo/LeagueLogo';
export * from './LeagueTable/LeagueTable';
export * from './LocalDateTime/LocalDateTime';
diff --git a/src/lib/og/fitText.ts b/src/lib/og/fitText.ts
new file mode 100644
index 0000000..9c3d484
--- /dev/null
+++ b/src/lib/og/fitText.ts
@@ -0,0 +1,14 @@
+import type { Font } from 'opentype.js';
+
+export function fitText(
+ font: Font,
+ text: string,
+ maxWidth: number,
+ maxFontSize: number,
+ minFontSize = 24,
+): number {
+ if (!text) return maxFontSize;
+ const w = font.getAdvanceWidth(text, maxFontSize);
+ if (w <= maxWidth) return maxFontSize;
+ return Math.max(Math.floor((maxFontSize * maxWidth) / w), minFontSize);
+}
diff --git a/src/lib/og/fonts.ts b/src/lib/og/fonts.ts
new file mode 100644
index 0000000..b44ffb8
--- /dev/null
+++ b/src/lib/og/fonts.ts
@@ -0,0 +1,61 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import { type Font, parse } from 'opentype.js';
+
+type FontCache = {
+ boldBuf: ArrayBuffer;
+ regBuf: ArrayBuffer;
+ boldFont: Font;
+ regFont: Font;
+};
+
+let _cache: FontCache | null = null;
+
+function toArrayBuffer(buf: Buffer): ArrayBuffer {
+ return buf.buffer.slice(
+ buf.byteOffset,
+ buf.byteOffset + buf.byteLength,
+ ) as ArrayBuffer;
+}
+
+function getCache(): FontCache {
+ if (_cache) return _cache;
+ const boldRaw = fs.readFileSync(
+ path.join(process.cwd(), 'src/fonts/ars-bold.woff'),
+ );
+ const regRaw = fs.readFileSync(
+ path.join(process.cwd(), 'src/fonts/ars-reg.woff'),
+ );
+ const boldBuf = toArrayBuffer(boldRaw);
+ const regBuf = toArrayBuffer(regRaw);
+ _cache = {
+ boldBuf,
+ regBuf,
+ boldFont: parse(boldBuf),
+ regFont: parse(regBuf),
+ };
+ return _cache;
+}
+
+export function getImageResponseFonts() {
+ const { boldBuf, regBuf } = getCache();
+ return [
+ {
+ name: 'ars-bold',
+ data: boldBuf,
+ weight: 700 as const,
+ style: 'normal' as const,
+ },
+ {
+ name: 'ars-reg',
+ data: regBuf,
+ weight: 400 as const,
+ style: 'normal' as const,
+ },
+ ];
+}
+
+export function getParsedFonts() {
+ const { boldFont, regFont } = getCache();
+ return { boldFont, regFont };
+}
diff --git a/yarn.lock b/yarn.lock
index 42184e3..bd3c5cf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2381,6 +2381,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/opentype.js@npm:^1":
+ version: 1.3.9
+ resolution: "@types/opentype.js@npm:1.3.9"
+ checksum: 10c0/5cfc2436d5bfc9d9688a90bd517d4789dcb3ff886c94420635002ca342c3c284392bd9f49e93d330769fc2e6187fa4e3fe1344da72f148b71c2b983dd5b68240
+ languageName: node
+ linkType: hard
+
"@types/react-dom@npm:19.2.3":
version: 19.2.3
resolution: "@types/react-dom@npm:19.2.3"
@@ -2390,16 +2397,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-textfit@npm:1.1.4":
- version: 1.1.4
- resolution: "@types/react-textfit@npm:1.1.4"
- dependencies:
- "@types/react": "npm:*"
- checksum: 10c0/7e70cfcc0a4411b28ac700a7a07a3dfbf848e51d3b3e01c1d2ba9a7d6021e3c6e7c522e2bc39b0946061c52c8c8c92e29820367a81c7c1cfdca3e1e26f280cd9
- languageName: node
- linkType: hard
-
-"@types/react@npm:*, @types/react@npm:19.2.14":
+"@types/react@npm:19.2.14":
version: 19.2.14
resolution: "@types/react@npm:19.2.14"
dependencies:
@@ -3103,9 +3101,9 @@ __metadata:
"@testing-library/jest-dom": "npm:6.9.1"
"@testing-library/react": "npm:16.3.2"
"@types/node": "npm:25.6.0"
+ "@types/opentype.js": "npm:^1"
"@types/react": "npm:19.2.14"
"@types/react-dom": "npm:19.2.3"
- "@types/react-textfit": "npm:1.1.4"
"@vercel/analytics": "npm:2.0.1"
"@vercel/speed-insights": "npm:2.0.0"
"@vitejs/plugin-react": "npm:5.1.4"
@@ -3115,11 +3113,11 @@ __metadata:
knip: "npm:6.5.0"
lefthook: "npm:2.1.6"
next: "npm:16.2.4"
+ opentype.js: "npm:1.3.4"
react: "npm:19.2.5"
react-dom: "npm:19.2.5"
react-error-boundary: "npm:6.1.1"
react-ios-pwa-prompt: "npm:2.0.6"
- react-textfit: "npm:1.1.1"
sass: "npm:1.99.0"
typescript: "npm:5.9.3"
vercel: "npm:51.8.0"
@@ -4642,7 +4640,7 @@ __metadata:
languageName: node
linkType: hard
-"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
+"js-tokens@npm:^4.0.0":
version: 4.0.0
resolution: "js-tokens@npm:4.0.0"
checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed
@@ -4864,17 +4862,6 @@ __metadata:
languageName: node
linkType: hard
-"loose-envify@npm:^1.4.0":
- version: 1.4.0
- resolution: "loose-envify@npm:1.4.0"
- dependencies:
- js-tokens: "npm:^3.0.0 || ^4.0.0"
- bin:
- loose-envify: cli.js
- checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e
- languageName: node
- linkType: hard
-
"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1":
version: 11.3.5
resolution: "lru-cache@npm:11.3.5"
@@ -5387,13 +5374,6 @@ __metadata:
languageName: node
linkType: hard
-"object-assign@npm:^4.1.1":
- version: 4.1.1
- resolution: "object-assign@npm:4.1.1"
- checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
- languageName: node
- linkType: hard
-
"obug@npm:^2.1.1":
version: 2.1.1
resolution: "obug@npm:2.1.1"
@@ -5428,6 +5408,18 @@ __metadata:
languageName: node
linkType: hard
+"opentype.js@npm:1.3.4":
+ version: 1.3.4
+ resolution: "opentype.js@npm:1.3.4"
+ dependencies:
+ string.prototype.codepointat: "npm:^0.2.1"
+ tiny-inflate: "npm:^1.0.3"
+ bin:
+ ot: bin/ot
+ checksum: 10c0/7de1c175c439a648f32f5113c619cdcd7ae09096cb791b5b1b8b24afdaf76ccdf8938297dab61ded48e032e8ebb54bcf444eedef562498f7e241dbebcf3da2f6
+ languageName: node
+ linkType: hard
+
"os-paths@npm:^4.0.1":
version: 4.4.0
resolution: "os-paths@npm:4.4.0"
@@ -5857,13 +5849,6 @@ __metadata:
languageName: node
linkType: hard
-"process@npm:^0.11.10":
- version: 0.11.10
- resolution: "process@npm:0.11.10"
- checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
- languageName: node
- linkType: hard
-
"promisepipe@npm:3.0.0":
version: 3.0.0
resolution: "promisepipe@npm:3.0.0"
@@ -5871,17 +5856,6 @@ __metadata:
languageName: node
linkType: hard
-"prop-types@npm:^15.7.2":
- version: 15.8.1
- resolution: "prop-types@npm:15.8.1"
- dependencies:
- loose-envify: "npm:^1.4.0"
- object-assign: "npm:^4.1.1"
- react-is: "npm:^16.13.1"
- checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077
- languageName: node
- linkType: hard
-
"proxy-agent@npm:6.4.0":
version: 6.4.0
resolution: "proxy-agent@npm:6.4.0"
@@ -5971,13 +5945,6 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^16.13.1":
- version: 16.13.1
- resolution: "react-is@npm:16.13.1"
- checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1
- languageName: node
- linkType: hard
-
"react-is@npm:^17.0.1":
version: 17.0.2
resolution: "react-is@npm:17.0.2"
@@ -5992,19 +5959,6 @@ __metadata:
languageName: node
linkType: hard
-"react-textfit@npm:1.1.1":
- version: 1.1.1
- resolution: "react-textfit@npm:1.1.1"
- dependencies:
- process: "npm:^0.11.10"
- prop-types: "npm:^15.7.2"
- peerDependencies:
- react: ^15.0.0 || ^16.0.0
- react-dom: ^15.0.0 || ^16.0.0
- checksum: 10c0/6dc8eb8d27a1c6e6c7bffd5c8c3bbe5394eaa733b7b7bc52334c59709e38577b6877006f56762a783a2bab80b073752771a045fb570b901aebd42b9e58930e2a
- languageName: node
- linkType: hard
-
"react@npm:19.2.5":
version: 19.2.5
resolution: "react@npm:19.2.5"
@@ -6564,6 +6518,13 @@ __metadata:
languageName: node
linkType: hard
+"string.prototype.codepointat@npm:^0.2.1":
+ version: 0.2.1
+ resolution: "string.prototype.codepointat@npm:0.2.1"
+ checksum: 10c0/83c4d2f83b6f3f8f377e0b36628b74a9efcaf5a725e6fb6354f15f30f0399c8f4b08956df883877b2b0f50dd2e644ed7e8b1f6d45bdee2dc5b3f4248796607fa
+ languageName: node
+ linkType: hard
+
"strip-final-newline@npm:^2.0.0":
version: 2.0.0
resolution: "strip-final-newline@npm:2.0.0"
@@ -6661,6 +6622,13 @@ __metadata:
languageName: node
linkType: hard
+"tiny-inflate@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "tiny-inflate@npm:1.0.3"
+ checksum: 10c0/fab687537254f6ec44c9a2e880048fe70da3542aba28f73cda3e74c95cabf342a339372f2a6c032e322324f01accc03ca26c04ba2bad9b3eb8cf3ee99bba7f9b
+ languageName: node
+ linkType: hard
+
"tinybench@npm:^2.9.0":
version: 2.9.0
resolution: "tinybench@npm:2.9.0"