feat(api): AllTrails OG preview endpoint#2316
Conversation
…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.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe 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
Sequence DiagramssequenceDiagram
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
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Coverage Report for API Unit Tests Coverage (./packages/api)
File CoverageNo changed files found. |
Coverage Report for Expo Unit Tests Coverage (./apps/expo)
File CoverageNo changed files found. |
Deploying with
|
| 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 |
There was a problem hiding this comment.
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/previewroute that fetches an AllTrails URL and extractsog:title,og:description,og:imagewith redirect/hostname SSRF guards. - Adds MCP tool registration for
preview_alltrails_urlthat 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
extractOgTagusesnew RegExp(...), which will be flagged by the repo’s customno-raw-regexcheck (it explicitly forbidsnew RegExpin non-test code). Consider switching to precompiled regex literals (one per OG property) or building the patterns withmagic-regexpso CIbun check:allpasses.
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.
feat(api): AllTrails OG preview endpoint
Summary
POST /api/alltrails/previewendpoint that server-side fetches an AllTrails URL and extracts OpenGraph metadata (title, description, image)https://alltrails.com(and subdomains) URLs are acceptedredirect: 'manual'and validates Location header hostname before following any redirectTest plan
POST /api/alltrails/previewwith a valid AllTrails URL returns{ title, description, image, url }🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Chores