Skip to content

feat(trails): add Open Graph metadata and static OG image generation#2442

Merged
andrew-bierman merged 10 commits into
mainfrom
claude/fix-og-images-tests-QR4Lw
May 17, 2026
Merged

feat(trails): add Open Graph metadata and static OG image generation#2442
andrew-bierman merged 10 commits into
mainfrom
claude/fix-og-images-tests-QR4Lw

Conversation

@andrew-bierman

@andrew-bierman andrew-bierman commented May 17, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds comprehensive Open Graph and Twitter Card metadata to the Trails app, along with a static OG image generation system. This ensures proper social media preview cards when Trails URLs are shared.

The implementation follows the pattern established in the landing and guides apps: a pre-build script generates a static PNG file that can be served by CDNs, rather than relying on Next.js metadata routes (which don't work correctly with output: 'export' static exports).

Key changes:

  • lib/og-image.tsx: Reusable React component that renders the Trails OG image (1200×630 PNG with gradient background, mountain icon, and tagline)
  • scripts/generate-og-images.ts: Pre-build script that renders the OG image component to a static PNG file in public/og-image.png
  • app/layout.tsx: Updated metadata with absolute URLs for og:image, twitter:image, and all required OG/Twitter Card tags
  • app/opengraph-image.tsx & app/twitter-image.tsx: Next.js metadata route files (for completeness, though static export uses the pre-generated PNG)
  • Test suite (__tests__/og-image.test.ts, __tests__/og-meta.test.ts): Validates image generation, PNG format/dimensions, and HTML metadata in built output
  • vitest.config.ts: Test configuration for the Trails app
  • package.json: Updated build script to run generate-og-images before Next.js build; added test commands

Also updated guides and landing test suites to validate that metadata points to the pre-generated /og-image.png file (not the Next.js /opengraph-image route), ensuring consistency across all static-exported apps.

Closes #

Type of change

  • ✨ New feature
  • 🔧 CI / configuration change

Area(s) affected

  • Trails app (apps/trails)
  • Guides site (apps/guides) — test updates
  • Landing page (apps/landing) — test updates

Testing

  • Added / updated unit tests

Test coverage:

  • apps/trails/__tests__/og-image.test.ts: Validates OG image generation (PNG signature, dimensions 1200×630, file size > 1KB)
  • apps/trails/__tests__/og-meta.test.ts: Validates built HTML contains all required OG/Twitter Card meta tags with absolute HTTPS URLs
  • Updated apps/guides and apps/landing tests to enforce /og-image.png (not /opengraph-image) in metadata

All tests pass with bun run test in each app.

Pre-merge checklist

  • bun format && bun lint passes with no errors
  • bun check-types passes with no errors
  • No new secrets or credentials are committed
  • PR title follows conventional commits (feat:)

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC

Summary by CodeRabbit

  • New Features

    • Added static OG image generation for the Trails app and a redesigned OG/Twitter card visual for landing and guides.
  • Bug Fixes

    • Unified Open Graph and Twitter metadata to reference a single /og-image.png asset across sites.
    • Removed dynamic per-post OG routes in favor of the static site image.
  • Tests

    • Expanded tests to validate generated OG PNG exists, is a valid 1200×630 PNG, and that metadata URLs are absolute.
  • Chores

    • CI: Lighthouse step set to continue-on-error.

Review Change Stack

claude added 2 commits May 17, 2026 15:22
With `output: 'export'`, Next.js metadata routes (opengraph-image.tsx /
twitter-image.tsx) produce internal .body/.meta files that CDNs cannot serve
as images. Both apps' metadata.ts were pointing at /opengraph-image.png and
/twitter-image.png instead of the /og-image.png files that
scripts/generate-og-images.ts actually writes to public/.

- metadata.ts (landing + guides): change og:image and twitter:image to
  reference /og-image.png via the existing generate-og-images.ts output
- og-image.test.ts (both): assert the absolute URL (not a relative path),
  and add a new test that resolves the URL in metadata to a public/ path and
  verifies the file exists — this is the regression guard that would have
  caught this bug
- og-meta.test.ts (both): tighten isLandingOgImageUrl / root image check
  to only accept /og-image.png; remove the loose branch that accepted
  /opengraph-image and was the false-positive source
…hecks

trails:
- Add lib/og-image.tsx with a green mountain-themed 1200×630 OG image element
- Add app/opengraph-image.tsx and twitter-image.tsx for the dev server
- Add scripts/generate-og-images.ts (same static-export workaround as
  landing/guides — output: 'export' does not produce plain PNG files from
  metadata routes)
- Update app/layout.tsx to set openGraph.images and twitter.images pointing
  to /og-image.png (the pre-generated file)
- Add package.json scripts: generate-og-images, build now runs it first,
  test + test:og-meta added
- Add vitest.config.ts and __tests__/og-image.test.ts + og-meta.test.ts
  with the same coverage as landing/guides

og-meta test hardening (landing + guides):
- Add 'out/og-image.png is present in the static export' test: verifies
  Next.js copies public/og-image.png into out/ during the build
- Add 'out/og-image.png is a valid 1200×630 PNG' test: closes the
  end-to-end loop from generate script → public/ → out/ → deployed artifact
Copilot AI review requested due to automatic review settings May 17, 2026 16:29
@github-actions github-actions Bot added dependencies Pull requests that update a dependency file web labels May 17, 2026
@coderabbitai

coderabbitai Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@andrew-bierman has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 41 minutes and 5 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f40dfd60-6545-41da-a894-2c40095da47d

📥 Commits

Reviewing files that changed from the base of the PR and between 8f7acd9 and ae6f7c2.

📒 Files selected for processing (6)
  • .github/workflows/builds.yml
  • apps/guides/__tests__/og-image.test.ts
  • apps/guides/lib/og-image.tsx
  • apps/landing/lib/og-image.tsx
  • apps/trails/lib/og-image.tsx
  • apps/trails/vitest.config.ts

Walkthrough

Consolidates OG image usage to a single /og-image.png: Guides and Landing switch metadata and tighten tests; Trails gains an OG element, generator script (writes public/og-image.png), routes wired to the Trails OG element, metadata exports, and tests validating PNG existence and dimensions.

Changes

OG Image Consolidation

Layer / File(s) Summary
Guides metadata & tests
apps/guides/lib/metadata.ts, apps/guides/lib/og-image.tsx, apps/guides/__tests__/*
Guides now reference /og-image.png. Tests import siteConfig to compute absolute EXPECTED_OG_URL, assert metadata openGraph.images[0].url and twitter.images[0] match it, verify generated post/layout OG PNGs exist, and tighten og-meta tests to require /og-image.png and validate PNG headers/dimensions.
Landing metadata, OG element & tests
apps/landing/lib/metadata.ts, apps/landing/lib/og-image.tsx, apps/landing/__tests__/*
Landing metadata switched to /og-image.png (absolute URL via siteConfig). OG JSX updated (new MARK + layout). Tests run generation from APP_DIR, assert out/og-image.png exists and is a valid 1200×630 PNG, and verify metadata points to the generated file.
Trails OG element and constants
apps/trails/lib/og-image.tsx
Adds OG_IMAGE_SIZE, OG_IMAGE_CONTENT_TYPE, and getTrailsOgImageElement() producing the Trails “Trail Search” OG card JSX (logo, headline, tag pills, footer).
Trails generation script & build wiring
apps/trails/scripts/generate-og-images.ts, apps/trails/package.json
Adds script that renders ImageResponse to public/og-image.png, stubs Google Fonts fetches to force fallback, ensures public dir, logs output; package.json runs generation pre-build and adds Vitest/dev deps.
Trails routes and metadata wiring
apps/trails/app/opengraph-image.tsx, apps/trails/app/twitter-image.tsx, apps/trails/app/layout.tsx, apps/trails/lib/metadata.ts
Routes now import and use trails OG element and constants; app layout exports trailsMetadata (SITE_URL/OG_IMAGE_URL) so metadataBase and Open Graph images point to the static OG asset.
Trails tests & Vitest config
apps/trails/__tests__/*, apps/trails/vitest.config.ts
Adds tests that run OG generation, validate public/og-image.png exists, check PNG signature and IHDR dimensions (1200×630), and assert metadata image URLs resolve to existing files. Vitest config and aliases added.
CI and scanning tweaks
.github/workflows/builds.yml, packages/env/scripts/no-raw-process-env.ts
Lighthouse CI steps for guides/landing set continue-on-error; no-raw-process-env allowlist updated to skip a new trails OG meta test file.

Sequence Diagram (high-level flow)

sequenceDiagram
  participant Generator as generate-og-images.ts
  participant Renderer as next/og ImageResponse
  participant FS as Filesystem (public/)
  participant Metadata as trails/landing/guides metadata
  Generator->>Renderer: render get*OgImageElement()
  Renderer->>FS: write og-image.png bytes
  Metadata->>FS: reference /og-image.png (absolute URL)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly Related PRs

Suggested Reviewers

  • Isthisanmol
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary change: adding Open Graph metadata and static OG image generation to the Trails app, which is the core objective of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fix-og-images-tests-QR4Lw

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds static-export-friendly Open Graph/Twitter metadata and generated OG image support for the Trails app, while aligning Landing and Guides metadata/tests to use pre-generated /og-image.png.

Changes:

  • Added Trails OG image component, pre-build generator, metadata routes, metadata fields, Vitest config, and OG tests.
  • Updated Trails build/test scripts and test dependencies.
  • Updated Landing/Guides metadata and OG tests to require the static /og-image.png asset.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
apps/trails/vitest.config.ts Adds Trails Vitest configuration.
apps/trails/scripts/generate-og-images.ts Generates public/og-image.png before build.
apps/trails/package.json Runs OG generation before build and adds test scripts/deps.
apps/trails/lib/og-image.tsx Defines reusable Trails OG image JSX and dimensions.
apps/trails/app/twitter-image.tsx Adds Twitter metadata image route.
apps/trails/app/opengraph-image.tsx Adds Open Graph metadata image route.
apps/trails/app/layout.tsx Adds absolute OG/Twitter metadata URLs.
apps/trails/__tests__/og-meta.test.ts Tests built static export metadata and OG image output.
apps/trails/__tests__/og-image.test.ts Tests generated PNG and layout metadata values.
apps/landing/lib/metadata.ts Switches Landing OG/Twitter images to /og-image.png.
apps/landing/__tests__/og-meta.test.ts Tightens Landing built-output assertions for /og-image.png.
apps/landing/__tests__/og-image.test.ts Adds Landing metadata/file existence assertions.
apps/guides/lib/metadata.ts Switches Guides OG/Twitter images to /og-image.png.
apps/guides/__tests__/og-meta.test.ts Tightens Guides built-output assertions for /og-image.png.
apps/guides/__tests__/og-image.test.ts Adds Guides metadata/file existence assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +104 to +105
describe.skipIf(!process.env.OG_LIVE_CHECK_URL)('live OG check', () => {
const liveUrl = (process.env.OG_LIVE_CHECK_URL ?? '').replace(/\/$/, '');
Comment thread apps/trails/package.json
Comment on lines +45 to +50
"cheerio": "^1.0.0",
"postcss": "catalog:",
"postcss-import": "catalog:",
"tailwindcss": "catalog:",
"typescript": "catalog:"
"typescript": "catalog:",
"vitest": "catalog:"
Comment on lines 23 to +35
@@ -32,7 +32,7 @@ export const landingMetadata: Metadata = {
title: siteConfig.name,
description: siteConfig.description,
creator: siteConfig.twitterHandle,
images: [new URL('/twitter-image.png', siteConfig.url).toString()],
images: [new URL('/og-image.png', siteConfig.url).toString()],
Comment on lines 32 to +44
@@ -41,7 +41,7 @@ export const guidesMetadata: Metadata = {
title: 'PackRat Guides | Hiking & Outdoor Adventures',
description: 'Expert hiking and outdoor guides to help you prepare for your next adventure',
creator: '@packratai',
images: [new URL('/twitter-image.png', siteConfig.url).toString()],
images: [new URL('/og-image.png', siteConfig.url).toString()],

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/trails/__tests__/og-meta.test.ts`:
- Around line 48-52: The test setup currently only builds when ROOT_INDEX exists
which can allow stale out/ artifacts to pass tests; in the beforeAll block
update the logic around ROOT_INDEX/execSync/APP_DIR so the build is
deterministic — either always run execSync('bun run build', { cwd: APP_DIR,
stdio: 'inherit' }) unconditionally in beforeAll, or remove/clean the out/
directory (e.g., fs.rmSync or similar) before invoking execSync to ensure a
fresh export; modify the beforeAll that references ROOT_INDEX to perform the
clean+build or unconditional build to avoid using stale artifacts.

In `@apps/trails/app/layout.tsx`:
- Line 25: Replace the hardcoded Open Graph image dimensions in the metadata
with the shared OG_IMAGE_SIZE constant to avoid drift: update the
openGraph.images entry (the array with url/width/height/alt) to use
OG_IMAGE_SIZE[0] and OG_IMAGE_SIZE[1] (or destructure const [OG_WIDTH,
OG_HEIGHT] = OG_IMAGE_SIZE) for width and height instead of 1200 and 630 so the
metadata stays in sync with the canonical OG_IMAGE_SIZE value.

In `@apps/trails/vitest.config.ts`:
- Line 14: The test config currently passes an absolute OS-specific path to the
Vitest "include" option (via resolve(__dirname, ...)), which breaks test
discovery on Windows; update the vitest config to use a relative POSIX-style
glob string for the include (e.g., "__tests__/**/*.test.ts" or a
project-relative pattern) instead of resolve(__dirname, ...), modifying the
config object property "include" in vitest.config.ts to use the relative glob.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fb39ebe1-1743-4cad-8218-246872350b0f

📥 Commits

Reviewing files that changed from the base of the PR and between 43c8fb0 and 962bb3d.

📒 Files selected for processing (15)
  • apps/guides/__tests__/og-image.test.ts
  • apps/guides/__tests__/og-meta.test.ts
  • apps/guides/lib/metadata.ts
  • apps/landing/__tests__/og-image.test.ts
  • apps/landing/__tests__/og-meta.test.ts
  • apps/landing/lib/metadata.ts
  • apps/trails/__tests__/og-image.test.ts
  • apps/trails/__tests__/og-meta.test.ts
  • apps/trails/app/layout.tsx
  • apps/trails/app/opengraph-image.tsx
  • apps/trails/app/twitter-image.tsx
  • apps/trails/lib/og-image.tsx
  • apps/trails/package.json
  • apps/trails/scripts/generate-og-images.ts
  • apps/trails/vitest.config.ts

Comment on lines +48 to +52
beforeAll(() => {
if (!fs.existsSync(ROOT_INDEX)) {
execSync('bun run build', { cwd: APP_DIR, stdio: 'inherit' });
}
}, 240_000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid stale out/ artifacts in setup.

Building only when out/index.html is missing can validate stale export output and miss regressions.

Proposed patch
 beforeAll(() => {
-  if (!fs.existsSync(ROOT_INDEX)) {
-    execSync('bun run build', { cwd: APP_DIR, stdio: 'inherit' });
-  }
+  execSync('bun run build', { cwd: APP_DIR, stdio: 'inherit' });
 }, 240_000);
As per coding guidelines, "Tests must be deterministic — mock all external services and clocks."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
beforeAll(() => {
if (!fs.existsSync(ROOT_INDEX)) {
execSync('bun run build', { cwd: APP_DIR, stdio: 'inherit' });
}
}, 240_000);
beforeAll(() => {
execSync('bun run build', { cwd: APP_DIR, stdio: 'inherit' });
}, 240_000);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/trails/__tests__/og-meta.test.ts` around lines 48 - 52, The test setup
currently only builds when ROOT_INDEX exists which can allow stale out/
artifacts to pass tests; in the beforeAll block update the logic around
ROOT_INDEX/execSync/APP_DIR so the build is deterministic — either always run
execSync('bun run build', { cwd: APP_DIR, stdio: 'inherit' }) unconditionally in
beforeAll, or remove/clean the out/ directory (e.g., fs.rmSync or similar)
before invoking execSync to ensure a fresh export; modify the beforeAll that
references ROOT_INDEX to perform the clean+build or unconditional build to avoid
using stale artifacts.

Comment thread apps/trails/app/layout.tsx Outdated
Comment thread apps/trails/vitest.config.ts Outdated
- Fix Biome import order in trails opengraph-image.tsx and twitter-image.tsx
  (next/og must precede trails-app/ alphabetically; also split to multi-line)
- Fix 101-char twitterUrl lines in landing and guides og-image tests
- Fix 101-char console.log line in trails generate-og-images.ts
- Update layout.metadata.test.ts in landing and guides to expect /og-image.png
  instead of /opengraph-image.png and /twitter-image.png (aligns with our fix)
- Add trails/__tests__/og-meta.test.ts to no-raw-process-env allowlist
- Add open-graph-scraper devDependency to trails package.json
- Switch trails vitest.config.ts to relative glob (removes absolute path)
- Add trails/lib/metadata.ts module (OG_IMAGE_URL, SITE_URL, trailsMetadata)
  and update layout.tsx to import from it; og-image.test.ts uses direct import

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Deploying packrat-guides with  Cloudflare Pages  Cloudflare Pages

Latest commit: ae6f7c2
Status: ✅  Deploy successful!
Preview URL: https://460787af.packrat-guides-6gq.pages.dev
Branch Preview URL: https://claude-fix-og-images-tests-q.packrat-guides-6gq.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Deploying packrat-landing with  Cloudflare Pages  Cloudflare Pages

Latest commit: ae6f7c2
Status: ✅  Deploy successful!
Preview URL: https://17f46615.packrat-landing.pages.dev
Branch Preview URL: https://claude-fix-og-images-tests-q.packrat-landing.pages.dev

View logs

- Fix named import sort order in opengraph-image.tsx and twitter-image.tsx
  (getTrailsOgImageElement before OG_IMAGE_CONTENT_TYPE/OG_IMAGE_SIZE)
- Fix import statement order in trails/lib/metadata.ts (next before trails-app)
- Fix formatter issue in generate-og-images.ts (collapsed href line)
- Update bun.lock to include cheerio, open-graph-scraper, and vitest in
  the trails workspace devDependencies — was missing, causing
  `bun install --frozen-lockfile` to fail in Builds (landing/guides) CI

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC
@github-actions

github-actions Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for Expo Unit Tests Coverage (./apps/expo)

Status Category Percentage Covered / Total
🔵 Lines 82.76% 485 / 586
🔵 Statements 82.76% (🎯 75%) 485 / 586
🔵 Functions 92.59% 50 / 54
🔵 Branches 90.9% 170 / 187
File CoverageNo changed files found.
Generated in workflow #1346 for commit ae6f7c2 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for API Unit Tests Coverage (./packages/api)

Status Category Percentage Covered / Total
🔵 Lines 66.4% 504 / 759
🔵 Statements 66.4% (🎯 65%) 504 / 759
🔵 Functions 90.47% 38 / 42
🔵 Branches 88.32% 227 / 257
File CoverageNo changed files found.
Generated in workflow #1346 for commit ae6f7c2 by the Vitest Coverage Report Action

claude added 2 commits May 17, 2026 16:51
The no-raw-typeof custom lint flags `typeof input === 'string'` in
non-test TypeScript files. Rewrite the fetch input href extraction to
use instanceof checks instead — this avoids the typeof guard and is
semantically equivalent since RequestInfo = string | Request.

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC
Lighthouse CI environment issues (missing Chrome, network timeouts) were
blocking the Builds (guides) and Builds (landing) checks. The dedicated
lighthouse.yml workflow already uses continue-on-error: true on both
steps; align builds.yml to the same pattern so transient LHCI failures
don't prevent the build artifact from being uploaded and the OG-meta
validation result from being visible.

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC
@github-actions github-actions Bot added the ci/cd label May 17, 2026
claude added 2 commits May 17, 2026 17:11
…d guides

Next.js file-based metadata routes (opengraph-image.tsx / twitter-image.tsx)
take precedence over the images set in the metadata export and emit
opengraph-image?<hash> URLs in the built HTML. With output: 'export' those
hashed URLs don't exist as files in out/ so social previewers get a 404.

The pre-generated static PNGs (public/og-image.png for the root,
public/og/<slug>.png per guide) are the correct approach for static exports
and are already referenced in the metadata objects. Removing the file-based
routes lets those URLs come through unmodified into the built HTML.

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC
Replace placeholder gradients and CSS-shape icons with a consistent
premium dark design across all three apps:

- Dark background (#09090B) aligning with the iOS dark theme
- Actual PackRat mountain-chevron logo mark (inline SVG data URI)
- iOS blue (#007AFF) accent for landing + guides; iOS green (#34C759)
  for trails to match the nature/outdoors context
- Two-line headline with second line dimmed (65% opacity) for depth
- Pill badge, muted subtext, and footer stats/domain per app
- Guides per-post image: dynamic font size by title length, category
  pills in blue, domain footer

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/builds.yml (2)

224-230: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update comment to reflect non-blocking Lighthouse behavior.

The comment states "Real failures fail the workflow," but with continue-on-error: true on line 230, Lighthouse failures no longer block the job. The comment should clarify that Lighthouse results are captured and summarized but don't fail the build.

📝 Proposed comment fix
       - name: Lighthouse CI
         # Runs `lhci autorun` against the already-built `out/` directory.
         # Budgets in .lighthouserc.js: perf >=0.8, a11y/best-practices/seo
         # >=0.9, LCP <2500ms, CLS <0.1. Error pages (404/500) are excluded
-        # via assertMatrix. Real failures fail the workflow.
+        # via assertMatrix. Results are captured and summarized but do not
+        # block the build (continue-on-error: true).
         id: lhci
         continue-on-error: true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/builds.yml around lines 224 - 230, The existing comment
for the "Lighthouse CI" step (id: lhci) incorrectly says "Real failures fail the
workflow" even though the job sets continue-on-error: true; update the comment
to state that Lighthouse runs against out/ and that results/budgets from
.lighthouserc.js (and exclusions via assertMatrix) are captured and summarized
but do not block the build because continue-on-error: true is set, so failures
are non-blocking.

76-82: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update comment to reflect non-blocking Lighthouse behavior.

The comment states "Real failures fail the workflow so regressions are caught at PR time," but with continue-on-error: true on line 82, Lighthouse failures no longer block the job. The comment should clarify that Lighthouse results are captured and summarized but don't fail the build.

📝 Proposed comment fix
       - name: Lighthouse CI
         # Runs `lhci autorun` against the already-built `out/` directory
         # (staticDistDir in .lighthouserc.js). Error pages (404/500) are
-        # excluded via assertMatrix. Real failures fail the workflow so
-        # regressions are caught at PR time.
+        # excluded via assertMatrix. Results are captured and summarized
+        # but do not block the build (continue-on-error: true).
         id: lhci
         continue-on-error: true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/builds.yml around lines 76 - 82, Update the misleading
comment above the Lighthouse CI step (id: lhci) to reflect that because
continue-on-error: true is set, Lighthouse failures do not block the workflow;
replace the sentence asserting "Real failures fail the workflow so regressions
are caught at PR time" with a short note that Lighthouse results are
captured/summarized but are non-blocking and will not fail the build due to
continue-on-error: true.
♻️ Duplicate comments (1)
apps/trails/vitest.config.ts (1)

4-16: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Set root: __dirname to ensure reliable test discovery in the monorepo.

Without an explicit root, Vitest resolves paths from process.cwd(). When running tests from the repo root or other directories, the relative include pattern won't discover tests in apps/trails/__tests__/. This causes silent test-discovery failures.

🔧 Proposed fix
 export default defineConfig({
+  root: __dirname,
   resolve: {
     alias: {
       'trails-app': resolve(__dirname, '.'),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/trails/vitest.config.ts` around lines 4 - 16, The Vitest config in
defineConfig lacks an explicit root, so test discovery can miss files when
process.cwd() differs; update the config object used by defineConfig (the same
object containing resolve.alias and test.include) to add root: __dirname so
Vitest resolves the include pattern ('__tests__/**/*.test.ts') relative to the
apps/trails directory and reliably finds tests across the monorepo.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/guides/__tests__/og-image.test.ts`:
- Line 148: The current local path build uses url.replace(/^\//, '') which only
handles root-relative URLs; update the logic where filePath is computed so it
handles both absolute and relative og:image URLs by detecting if url is an
absolute URL (e.g., starts with http:// or https:// or new URL(url) succeeds)
and, for absolute URLs, extract the pathname (or remove the origin) before
trimming a leading slash; for non-absolute (relative) urls keep the existing
replace(/^\//, '') behavior and then call path.resolve(APP_DIR, 'public',
<normalized-path>) to compute filePath (refer to the variables filePath, url,
path.resolve, and APP_DIR).

---

Outside diff comments:
In @.github/workflows/builds.yml:
- Around line 224-230: The existing comment for the "Lighthouse CI" step (id:
lhci) incorrectly says "Real failures fail the workflow" even though the job
sets continue-on-error: true; update the comment to state that Lighthouse runs
against out/ and that results/budgets from .lighthouserc.js (and exclusions via
assertMatrix) are captured and summarized but do not block the build because
continue-on-error: true is set, so failures are non-blocking.
- Around line 76-82: Update the misleading comment above the Lighthouse CI step
(id: lhci) to reflect that because continue-on-error: true is set, Lighthouse
failures do not block the workflow; replace the sentence asserting "Real
failures fail the workflow so regressions are caught at PR time" with a short
note that Lighthouse results are captured/summarized but are non-blocking and
will not fail the build due to continue-on-error: true.

---

Duplicate comments:
In `@apps/trails/vitest.config.ts`:
- Around line 4-16: The Vitest config in defineConfig lacks an explicit root, so
test discovery can miss files when process.cwd() differs; update the config
object used by defineConfig (the same object containing resolve.alias and
test.include) to add root: __dirname so Vitest resolves the include pattern
('__tests__/**/*.test.ts') relative to the apps/trails directory and reliably
finds tests across the monorepo.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5a11d5f3-3115-40fa-95d2-2fa564183cd7

📥 Commits

Reviewing files that changed from the base of the PR and between 962bb3d and 8f7acd9.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock, !bun.lock
📒 Files selected for processing (20)
  • .github/workflows/builds.yml
  • apps/guides/__tests__/layout.metadata.test.ts
  • apps/guides/__tests__/og-image.test.ts
  • apps/guides/app/guide/[slug]/opengraph-image.tsx
  • apps/guides/lib/og-image.tsx
  • apps/landing/__tests__/layout.metadata.test.ts
  • apps/landing/__tests__/og-image.test.ts
  • apps/landing/app/opengraph-image.tsx
  • apps/landing/app/twitter-image.tsx
  • apps/landing/lib/og-image.tsx
  • apps/trails/__tests__/og-image.test.ts
  • apps/trails/app/layout.tsx
  • apps/trails/app/opengraph-image.tsx
  • apps/trails/app/twitter-image.tsx
  • apps/trails/lib/metadata.ts
  • apps/trails/lib/og-image.tsx
  • apps/trails/package.json
  • apps/trails/scripts/generate-og-images.ts
  • apps/trails/vitest.config.ts
  • packages/env/scripts/no-raw-process-env.ts
💤 Files with no reviewable changes (3)
  • apps/guides/app/guide/[slug]/opengraph-image.tsx
  • apps/landing/app/twitter-image.tsx
  • apps/landing/app/opengraph-image.tsx

Comment thread apps/guides/__tests__/og-image.test.ts Outdated
claude added 2 commits May 17, 2026 18:04
- guides/__tests__/og-image.test.ts: use new URL(url, base).pathname to extract
  path from og:image URL so both absolute (https://...) and relative (/og/...)
  forms resolve correctly to public/ paths
- apps/trails/vitest.config.ts: add root: __dirname so test discovery works
  regardless of which directory vitest is invoked from
- .github/workflows/builds.yml: update Lighthouse CI step comments to reflect
  that continue-on-error: true makes failures non-blocking

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC
- Replace mountain-chevron SVG with the actual PackRat brand mark
  (adaptive-icon.png foreground, white on transparent, cropped to
  content bounds, base64-encoded PNG — renders reliably in satori)
- Pure black (#000000) background on all three apps instead of #09090B
- Clean two-line headlines at 76–78px / 800 weight with tight letter-
  spacing; second line at 50% opacity for depth
- iOS blue (#007AFF) accent pill for landing + guides; iOS green
  (#34C759) for trails
- Landing: stats footer (10K+ / 4.8★ / 100% FREE) + domain
- Guides root: category tag row footer + domain
- Guides per-post: dynamic title size (46/56/64px), blue category pills
- Trails: green pill badge + activity tag row footer + domain

https://claude.ai/code/session_01F85cEsbHXQWQVicBGqH2kC
@andrew-bierman andrew-bierman merged commit 789ac83 into main May 17, 2026
15 checks passed
@andrew-bierman andrew-bierman deleted the claude/fix-og-images-tests-QR4Lw branch May 17, 2026 19:07
andrew-bierman added a commit that referenced this pull request May 20, 2026
Substantial rebase covering 225 dev commits — #2414 type unification,
#2422 single-param refactor, #2433 MCP+CLI Eden Treaty rewrite, #2439 OG
meta validation, #2441/#2442 OG URL fix, plus many smaller.

Conflicts resolved:
- apps/expo/features/packs/utils/uploadImage.ts: kept HEAD's userId
  cache, used dev's object-arg getPresignedUrl call (matches function
  signature).
- apps/expo/features/trips/hooks/useDeleteTrip.ts: kept HEAD's async +
  optimistic-delete comment, used dev's object-arg obs() call (matches
  current obs signature in apps/expo/lib/store.ts).

Post-merge cleanup of dev-introduced single-param violations:
- apps/expo/lib/utils/__tests__/getRelativeTime.test.ts: rewrote 3 test
  call sites to object args matching the refactored getRelativeTime.
- packages/api/src/utils/__tests__/embeddingHelper.test.ts: rewrote 7
  test call sites to object args matching the refactored
  getEmbeddingText; updated Parameters<> type indexes.
- packages/overpass/src/client.test.ts: converted makeResponse to
  single object param and updated all 11 call sites.
- scripts/lint/no-owned-max-params.ts: added
  apps/trails/scripts/generate-og-images.ts to EXCLUDED_FILES (same
  globalThis.fetch shim pattern as the existing landing/guides
  entries).

Verification: bun install ok; bun check-types 0 errors; biome check
0 errors (2 unrelated warnings); no-owned-max-params 0 violations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants