feat(terragon-auth): add credits to auth token and handle setup completion#944
feat(terragon-auth): add credits to auth token and handle setup completion#944
Conversation
- Add Rybbit tracking script with site-id c9d633bbdaac via Next.js Script component - Update CSP in vercel.json to allow app.rybbit.io in script-src and connect-src 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…etion - Add credits, subscriptionAllowance, purchasedCredits to auth token payload - Handle TERRAGON_SETUP_COMPLETE message when user completes onboarding - Handle TERRAGON_AUTH_COMPLETE message for auth flow completion - Add comprehensive tests for new postMessage handlers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughThe PR refactors the Terragon inbox integration from an iframe-based embedding approach to a direct SSO redirect flow. It enriches the authentication token payload with credits and subscription fields, introduces a testable redirect utility, updates tests to verify the new redirect behavior, integrates Rybbit analytics, and updates security policies. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User / Browser
participant App as Inbox Page
participant AuthAPI as /api/terragon/auth
participant Terragon as Terragon Service
User->>App: Visit /inbox
App->>App: Check authentication status
alt User Unauthenticated
App->>User: Display login prompt
else User Authenticated
App->>AuthAPI: Fetch SSO token (POST with user identity & credits)
AuthAPI->>AuthAPI: Create JWT with credentials
AuthAPI-->>App: Return gwauth token
App->>App: Compose redirect URL with token param
App->>Terragon: Redirect to Terragon with gwauth token in query
Terragon-->>User: Load inbox with authenticated session
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
- Change /inbox page from iframe embedding to direct redirect approach - Add redirectTo() utility in utils.ts for testable navigation - Redirect authenticated users to Terragon URL with gwauth SSO token - Show sign-in prompt for unauthenticated users - Add error UI with retry functionality when auth bridge fails - Fix useEffect to prevent re-triggering redirect after error - Update tests to mock redirectTo utility instead of window.location - All 16 inbox tests pass with proper test isolation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Auto-Fix Status UpdateTriggered by: PR synchronize event (push to branch) CI Check StatusAll required checks are now passing:
Local Test ResultsI ran the test suite locally to verify everything is working correctly:
Changes VerifiedThe PR changes look good:
Action RequiredNo code changes needed. All CI checks pass and there are no outstanding review comments requesting changes. The PR appears ready for human review and merge. |
There was a problem hiding this comment.
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 (1)
src/app/api/terragon/auth/route.ts (1)
137-145:⚠️ Potential issue | 🟠 MajorDo not trust client-supplied credits in the token payload.
These values are taken directly from the request body and then signed; any client with a valid API key could spoof higher credits/allowances. Consider sourcing credits (and tier) from the backend during API-key validation, or cross-checking against backend user data before signing the token.
🤖 Fix all issues with AI agents
In `@src/lib/utils.ts`:
- Around line 213-214: The redirectTo function accesses window directly which
will break in server environments; update the redirectTo(url: string)
implementation to first guard with if (typeof window === "undefined") { /* no-op
or throw */ } and only then set window.location.href = url; ensure you choose
and document behavior (no-op or throw) and keep the symbol name redirectTo
unchanged so imports still work.
🧹 Nitpick comments (2)
src/app/layout.tsx (1)
55-60: Move analytics config into NEXT_PUBLIC_ env vars.Hardcoding the script URL and site id makes environment-specific configuration harder to manage. Consider reading both from
NEXT_PUBLIC_env vars and rendering the script only when they’re present.♻️ Suggested change
- {/* Rybbit Analytics */} - <Script - src="https://app.rybbit.io/api/script.js" - data-site-id="c9d633bbdaac" - strategy="afterInteractive" - /> + {/* Rybbit Analytics */} + {process.env.NEXT_PUBLIC_RYBBIT_SCRIPT_SRC && + process.env.NEXT_PUBLIC_RYBBIT_SITE_ID && ( + <Script + src={process.env.NEXT_PUBLIC_RYBBIT_SCRIPT_SRC} + data-site-id={process.env.NEXT_PUBLIC_RYBBIT_SITE_ID} + strategy="afterInteractive" + /> + )}As per coding guidelines: Use environment variables for all configuration values; prefix frontend-only vars with NEXT_PUBLIC_.
src/app/api/terragon/auth/route.ts (1)
119-122: Add schema validation for the request body (credits should be numeric).
request.json()is untyped, so the new credits fields can arrive as strings or negative values. A schema parse lets you coerce/validate and apply defaults consistently.♻️ Suggested change
+import { z } from "zod"; + +const bodySchema = z.object({ + userId: z.string().min(1), + email: z.string().email(), + username: z.string().optional(), + tier: z.string().optional(), + credits: z.coerce.number().nonnegative().default(0), + subscriptionAllowance: z.coerce.number().nonnegative().default(0), + purchasedCredits: z.coerce.number().nonnegative().default(0), +}); + // Parse request body -const body = await request.json(); -const { userId, email, username, tier, credits, subscriptionAllowance, purchasedCredits } = body; +const { + userId, + email, + username, + tier, + credits, + subscriptionAllowance, + purchasedCredits, +} = bodySchema.parse(await request.json());As per coding guidelines: Use Zod for form validation and schema definition in all form components and API routes.
| export function redirectTo(url: string): void { | ||
| window.location.href = url; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if src/lib/utils.ts exists and examine the redirectTo function
head -n 230 src/lib/utils.ts | tail -n 40Repository: Alpaca-Network/gatewayz-frontend
Length of output: 1113
🏁 Script executed:
# Check for 'use client' directive and overall file structure
head -n 20 src/lib/utils.tsRepository: Alpaca-Network/gatewayz-frontend
Length of output: 752
🏁 Script executed:
# Search for all usages of redirectTo function
rg -n "redirectTo\s*\(" --type=ts --type=tsxRepository: Alpaca-Network/gatewayz-frontend
Length of output: 103
🏁 Script executed:
# Also check if redirectTo is imported/exported anywhere
rg -n "redirectTo" src/lib/utils.ts -A 2 -B 2Repository: Alpaca-Network/gatewayz-frontend
Length of output: 279
🏁 Script executed:
# Search for redirectTo usages with proper file types
rg -n "redirectTo" --type ts -A 2 -B 1Repository: Alpaca-Network/gatewayz-frontend
Length of output: 18902
🏁 Script executed:
# Also check if there are any .tsx files that use redirectTo
fd "\.tsx?$" src/ | xargs grep -l "redirectTo" 2>/dev/null || echo "No matches found"Repository: Alpaca-Network/gatewayz-frontend
Length of output: 538
🏁 Script executed:
# Get more context on redirectTo usages
git grep "redirectTo" 2>/dev/null | head -20 || rg "redirectTo" -A 3 -B 1Repository: Alpaca-Network/gatewayz-frontend
Length of output: 1963
🏁 Script executed:
# Check the very beginning of src/app/inbox/page.tsx to see if it has 'use client' directive
head -n 5 src/app/inbox/page.tsxRepository: Alpaca-Network/gatewayz-frontend
Length of output: 264
🏁 Script executed:
# Also verify if src/lib/utils.ts has any 'use client' directive
head -n 5 src/lib/utils.tsRepository: Alpaca-Network/gatewayz-frontend
Length of output: 239
🏁 Script executed:
# Check the exact context of redirectTo calls in inbox/page.tsx
sed -n '30,90p' src/app/inbox/page.tsxRepository: Alpaca-Network/gatewayz-frontend
Length of output: 2084
🏁 Script executed:
# Final verification: search for any server-side context usage of redirectTo
rg "redirectTo" -B 5 -A 1 | grep -i "server\|api\|getServer\|middleware" || echo "No server-side context found"Repository: Alpaca-Network/gatewayz-frontend
Length of output: 3532
🏁 Script executed:
# Check if there are any TypeScript errors or type issues reported for the function
grep -r "redirectTo" src/ --include="*.ts" --include="*.tsx" | grep -i "error\|throws\|catch" || echo "No error handling currently in place"Repository: Alpaca-Network/gatewayz-frontend
Length of output: 534
Add window guard to prevent server-side usage of redirectTo.
Since this utility lives in a shared module, check if window exists before accessing it. This prevents accidental misuse if the function is ever imported in a server context.
♻️ Suggested change
export function redirectTo(url: string): void {
+ if (typeof window === "undefined") {
+ throw new Error("redirectTo can only be used in a browser context.");
+ }
window.location.href = url;
}🤖 Prompt for AI Agents
In `@src/lib/utils.ts` around lines 213 - 214, The redirectTo function accesses
window directly which will break in server environments; update the
redirectTo(url: string) implementation to first guard with if (typeof window ===
"undefined") { /* no-op or throw */ } and only then set window.location.href =
url; ensure you choose and document behavior (no-op or throw) and keep the
symbol name redirectTo unchanged so imports still work.
🤖 Auto-Fix Status UpdateTriggered by: PR synchronize event CI Check StatusAll required checks are now passing:
Local VerificationI ran tests locally to verify:
SummaryNo code changes needed. All CI checks pass and there are no outstanding review comments requesting changes. The PR appears ready for human review and merge. Automated by Terragon Auto-Fix Agent |
Summary
Related PR
Test plan
🤖 Generated with Claude Code
Greptile Overview
Greptile Summary
Extended Terragon authentication to include GatewayZ credits information and added handlers for setup completion events.
Key Changes:
credits,subscriptionAllowance, andpurchasedCreditsto auth token payload for display in TerragonTERRAGON_SETUP_COMPLETEmessage handler for GitHub onboarding completionTERRAGON_AUTH_COMPLETEmessage handler for auth flow completionConfidence Score: 5/5
Important Files Changed
credits,subscriptionAllowance,purchasedCredits) to auth token payload, all defaulting to 0 with nullish coalescingTERRAGON_SETUP_COMPLETEandTERRAGON_AUTH_COMPLETEmessagesSequence Diagram
sequenceDiagram participant User participant InboxPage as Inbox Page (Frontend) participant AuthRoute as /api/terragon/auth participant Backend as GatewayZ Backend participant Terragon as Terragon iframe User->>InboxPage: Access /inbox InboxPage->>InboxPage: Check auth status via GatewayzAuthContext alt User authenticated InboxPage->>AuthRoute: POST with userId, email, tier, credits data AuthRoute->>Backend: Validate API key via /api/user/me Backend-->>AuthRoute: Valid user data AuthRoute->>AuthRoute: Encrypt payload with credits fields AuthRoute-->>InboxPage: Return encrypted auth token InboxPage->>InboxPage: Build iframe URL with embed and awaitAuth params InboxPage->>Terragon: Load iframe (no token in URL) Terragon-->>InboxPage: iframe onLoad event InboxPage->>Terragon: postMessage GATEWAYZ_AUTH with token alt Terragon requests auth Terragon->>InboxPage: postMessage GATEWAYZ_AUTH_REQUEST InboxPage->>Terragon: postMessage GATEWAYZ_AUTH with token end alt GitHub onboarding complete Terragon->>InboxPage: postMessage TERRAGON_SETUP_COMPLETE InboxPage->>InboxPage: Log completion, hide loading end alt Auth flow complete Terragon->>InboxPage: postMessage TERRAGON_AUTH_COMPLETE InboxPage->>InboxPage: Log completion, hide loading end else User unauthenticated InboxPage->>User: Show sign-in prompt endSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.