Skip to content

feat(api): AllTrails OG preview endpoint#2316

Merged
andrew-bierman merged 2 commits into
developmentfrom
feature/alltrails-preview
Apr 26, 2026
Merged

feat(api): AllTrails OG preview endpoint#2316
andrew-bierman merged 2 commits into
developmentfrom
feature/alltrails-preview

Conversation

@andrew-bierman
Copy link
Copy Markdown
Collaborator

@andrew-bierman andrew-bierman commented Apr 26, 2026

Summary

  • Adds POST /api/alltrails/preview endpoint that server-side fetches an AllTrails URL and extracts OpenGraph metadata (title, description, image)
  • Validates that only https://alltrails.com (and subdomains) URLs are accepted
  • SSRF-safe: uses redirect: 'manual' and validates Location header hostname before following any redirect
  • Includes integration tests for the happy path and all error cases

Test plan

  • POST /api/alltrails/preview with a valid AllTrails URL returns { title, description, image, url }
  • Returns 400 for non-alltrails.com URLs
  • Returns 400 if redirect target is outside alltrails.com
  • Returns 504 on timeout
  • Returns 502 when AllTrails returns non-2xx

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • AllTrails URL preview: Preview metadata from AllTrails URLs
    • Admin dashboard search: Filter users, packs, and catalog items by name or email
  • Bug Fixes

    • Fixed map provider behavior on mobile platforms
    • Improved weather data handling with safer optional chaining
  • Chores

    • Centralized query key management for improved performance
    • Enhanced authentication flow and rate limiting

…eader

Replace default redirect-following fetch with manual redirect handling.
Validates the Location header hostname against the alltrails.com allowlist
before issuing a second fetch, preventing server-side request forgery via
malicious redirect chains.
Copilot AI review requested due to automatic review settings April 26, 2026 21:10
@github-actions github-actions Bot added dependencies Pull requests that update a dependency file api mobile labels Apr 26, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b6adc8d-d61c-4d58-aa93-9c64bdff9ee1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR centralizes React Query key builders across the admin app, refactors CF Access identity detection to use a hook-based approach with Zod schema validation, removes HTML-based admin UI endpoints in favor of JSON APIs with optional field-based filtering, introduces a new AllTrails URL preview endpoint that fetches and parses OpenGraph metadata, implements rate limiting on token issuance, and registers new MCP trail tools.

Changes

Cohort / File(s) Summary
Query Keys Centralization
apps/admin/lib/queryKeys.ts, apps/admin/app/dashboard/page.tsx, apps/admin/app/dashboard/catalog/page.tsx, apps/admin/app/dashboard/packs/page.tsx, apps/admin/app/dashboard/users/page.tsx, apps/admin/components/edit-catalog-dialog.tsx, apps/admin/hooks/use-catalog-analytics.ts, apps/admin/hooks/use-platform-analytics.ts
Introduces centralized queryKeys registry module and migrates all hardcoded React Query key arrays across dashboard pages, components, and hooks to use parameterized key builders from queryKeys.admin.*, queryKeys.catalogAnalytics.*, and queryKeys.platform.*.
CF Access Identity Refactor
apps/admin/lib/cfAccess.ts, apps/admin/app/login/page.tsx, apps/admin/components/auth-guard.tsx
Replaces boolean CF access state with identity-based useCFAccessIdentity() hook backed by React Query. Updates CFAccessIdentityResponse type to use Zod-inferred schema with optional name field. Login and auth guard now check identity presence/pending state instead of tri-state boolean.
Admin Routes JSON Migration
packages/api/src/routes/admin/index.ts, packages/api/src/middleware/cfAccess.ts, packages/api/src/utils/env-validation.ts, packages/api/test/admin-auth-guard.test.ts, packages/api/test/admin-jwt.test.ts, packages/api/test/setup.ts
Removes HTML/HTMX endpoints and admin UI helpers; refactors admin routes to JSON-only with optional q parameter for case-insensitive filtering across users/packs/catalog. Updates CF Access JWT validation to use Zod schema. Adds rate limiting via TOKEN_RATE_LIMITER binding on token endpoint. Adds comprehensive auth guard and JWT issuance tests.
AllTrails Preview Feature
packages/api/src/routes/alltrails.ts, packages/mcp/src/tools/trails.ts, packages/api/test/alltrails.test.ts
Introduces POST /alltrails/preview endpoint that validates HTTPS AllTrails URLs, fetches HTML with timeout/SSRF protection, extracts OpenGraph metadata (og:title, og:description, og:image), and returns parsed results. Registers new MCP preview_alltrails_url tool that calls the endpoint.
Supporting Infrastructure
packages/api/src/__test-stubs__/elysia-env.ts, packages/api/src/middleware/__tests__/cfAccess.test.ts, packages/api/vitest.config.ts, packages/api/wrangler.jsonc, packages/api/test/utils/test-helpers.ts, packages/mcp/src/index.ts, packages/api/src/routes/index.ts
Adds Elysia environment stub to prevent AOT compilation in workerd sandbox, Cloudflare rate limiter configuration, CF Access JWT test helpers (makeCFJwt), Vitest module aliasing, and integrates new routes/tools.
Minor Updates
apps/expo/app/(app)/trip/location-search.tsx, apps/expo/features/packs/store/packWeightHistory.ts, apps/expo/features/trips/screens/TripDetailScreen.tsx, apps/expo/features/trips/screens/TripWeatherDetailsScreen.tsx
Removes explicit PROVIDER_GOOGLE from MapView instances; refactors weight history endpoint assignment; adds type safety to weather screen with WeatherApiForecastResponse and optional chaining on forecast data.

Sequence Diagrams

sequenceDiagram
    participant Client as Client (Browser)
    participant Hook as useCFAccessIdentity Hook
    participant Query as TanStack Query
    participant CF as CF Access Provider
    
    Client->>Hook: Mount component / check identity
    Hook->>Query: Execute query with cfAccessIdentity key
    Query->>CF: getCFAccessIdentity() if not cached
    CF-->>Query: Return identity or null
    Query-->>Hook: Resolve with cfIdentity + isPending
    Hook-->>Client: Trigger redirect or render child
Loading
sequenceDiagram
    participant Client as Client/MCP Tool
    participant API as /alltrails/preview Endpoint
    participant Validator as Zod Validator
    participant Fetch as HTTP Fetch
    participant Parser as HTML Parser
    
    Client->>API: POST with URL
    API->>Validator: Validate HTTPS AllTrails domain
    Validator-->>API: Valid or 400 error
    API->>Fetch: Fetch HTML with timeout + User-Agent
    Fetch-->>API: HTML content or error (504/502)
    API->>Parser: Extract og:title, og:description, og:image
    Parser-->>API: Parsed metadata
    API-->>Client: 200 with OG tags + resolved URL or 422 (missing title)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

api

Suggested reviewers

  • mikib0
  • Isthisanmol

Poem

🐰 With centralized keys and schemas so tight,
CF Access now flows with recursive delight,
AllTrails previews bloom with OG tags in hand,
Rate limits and JSON across the land!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.92% 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 'feat(api): AllTrails OG preview endpoint' directly and accurately summarizes the main change: adding an AllTrails OpenGraph preview endpoint to the API.
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 feature/alltrails-preview

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

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

Status Category Percentage Covered / Total
🔵 Lines 74.9% 582 / 777
🔵 Statements 74.9% (🎯 65%) 582 / 777
🔵 Functions 95.91% 47 / 49
🔵 Branches 88.23% 270 / 306
File CoverageNo changed files found.
Generated in workflow #813 for commit 2f8d6b1 by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

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

Status Category Percentage Covered / Total
🔵 Lines 81.38% 516 / 634
🔵 Statements 81.38% (🎯 75%) 516 / 634
🔵 Functions 92.85% 52 / 56
🔵 Branches 92.55% 199 / 215
File CoverageNo changed files found.
Generated in workflow #813 for commit 2f8d6b1 by the Vitest Coverage Report Action

@andrew-bierman andrew-bierman changed the base branch from main to development April 26, 2026 21:13
@cloudflare-workers-and-pages
Copy link
Copy Markdown
Contributor

Deploying packrat-guides with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2f8d6b1
Status:⚡️  Build in progress...

View logs

@cloudflare-workers-and-pages
Copy link
Copy Markdown
Contributor

cloudflare-workers-and-pages Bot commented Apr 26, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
packrat-admin 2f8d6b1 Commit Preview URL

Branch Preview URL
Apr 26 2026, 09:15 PM

@github-actions github-actions Bot removed dependencies Pull requests that update a dependency file mobile labels Apr 26, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new API capability to generate OpenGraph previews for AllTrails links (for use by MCP tools / app features), along with related test infrastructure and some broader admin/auth and admin SPA query-key refactors.

Changes:

  • Adds POST /api/alltrails/preview route that fetches an AllTrails URL and extracts og:title, og:description, og:image with redirect/hostname SSRF guards.
  • Adds MCP tool registration for preview_alltrails_url that calls the new API endpoint.
  • Introduces additional changes around admin auth (CF Access verification + admin token rate limiting), test harness adjustments for Elysia in workerd, and admin SPA TanStack Query key centralization.

Reviewed changes

Copilot reviewed 1 out of 1 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/mcp/src/tools/trails.ts Adds MCP tool to call the AllTrails preview endpoint.
packages/mcp/src/index.ts Registers the new trail tools with the MCP agent.
packages/api/wrangler.jsonc Adds a TOKEN_RATE_LIMITER rate limiting binding configuration.
packages/api/vitest.config.ts Adds a test-only alias to stub Elysia env/AOT behavior in workerd.
packages/api/test/utils/test-helpers.ts Adds a CF Access JWT builder helper for tests; updates jose imports.
packages/api/test/setup.ts Adds global mocks for Elysia AOT and CF Access middleware for integration tests.
packages/api/test/alltrails.test.ts Adds integration tests for the AllTrails preview endpoint.
packages/api/test/admin-jwt.test.ts Adds round-trip integration tests for admin JWT issuance/verification via HTTP.
packages/api/test/admin-auth-guard.test.ts Adds integration tests for adminAuthGuard behavior with/without CF Access configured.
packages/api/src/utils/env-validation.ts Adds optional TOKEN_RATE_LIMITER binding to validated env typing.
packages/api/src/routes/index.ts Registers alltrailsRoutes under /api.
packages/api/src/routes/alltrails.ts Implements the AllTrails OG preview endpoint (fetch + OG extraction + SSRF guards).
packages/api/src/routes/admin/index.ts Updates admin auth flow, adds /token rate limiting, removes HTML admin UI endpoints, and adds search to list endpoints.
packages/api/src/middleware/cfAccess.ts Hardens CF Access JWT parsing via zod schema validation.
packages/api/src/middleware/tests/cfAccess.test.ts Adds unit tests for verifyCFAccessRequest with local JWKS mocking.
packages/api/src/test-stubs/elysia-env.ts Adds test-only stub to force ELYSIA_AOT=false.
bun.lock Bumps workspace versions and adds @packrat/guards dependency to admin app entry.
apps/expo/features/trips/screens/TripWeatherDetailsScreen.tsx Replaces any weather state with typed forecast response usage.
apps/expo/features/trips/screens/TripDetailScreen.tsx Removes explicit Google provider usage from react-native-maps.
apps/expo/features/packs/store/packWeightHistory.ts Refactors Treaty client call to a named endpoint variable and localizes any cast.
apps/expo/app/(app)/trip/location-search.tsx Removes explicit Google provider usage from react-native-maps.
apps/admin/lib/queryKeys.ts Adds centralized TanStack Query key registry.
apps/admin/lib/cfAccess.ts Adds zod validation for CF identity and a TanStack Query hook wrapper.
apps/admin/hooks/use-platform-analytics.ts Switches inline query keys to centralized queryKeys.
apps/admin/hooks/use-catalog-analytics.ts Switches inline query keys to centralized queryKeys.
apps/admin/components/edit-catalog-dialog.tsx Uses centralized query keys for invalidation.
apps/admin/components/auth-guard.tsx Uses CF identity query hook instead of imperative isBehindCFAccess() check.
apps/admin/app/login/page.tsx Uses CF identity query hook to redirect when behind CF Access.
apps/admin/app/dashboard/users/page.tsx Uses centralized query keys (including invalidation).
apps/admin/app/dashboard/page.tsx Uses centralized query keys for dashboard queries.
apps/admin/app/dashboard/packs/page.tsx Uses centralized query keys (including invalidation).
apps/admin/app/dashboard/catalog/page.tsx Uses centralized query keys (including invalidation).
Comments suppressed due to low confidence (1)

packages/api/src/routes/alltrails.ts:14

  • extractOgTag uses new RegExp(...), which will be flagged by the repo’s custom no-raw-regex check (it explicitly forbids new RegExp in non-test code). Consider switching to precompiled regex literals (one per OG property) or building the patterns with magic-regexp so CI bun check:all passes.
function extractOgTag(html: string, property: string): string | null {
  const match =
    html.match(
      new RegExp(`<meta[^>]+property=["']${property}["'][^>]+content=["']([^"']+)["']`, 'i'),
    ) ??
    html.match(
      new RegExp(`<meta[^>]+content=["']([^"']+)["'][^>]+property=["']${property}["']`, 'i'),
    );

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

@andrew-bierman andrew-bierman merged commit 86e3612 into development Apr 26, 2026
10 of 12 checks passed
@andrew-bierman andrew-bierman deleted the feature/alltrails-preview branch April 26, 2026 21:16
andrew-bierman added a commit that referenced this pull request May 14, 2026
feat(api): AllTrails OG preview endpoint
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants