Skip to content

feat: host creator contest on peanut.me - #2605

Draft
0xkkonrad wants to merge 2 commits into
devfrom
feat/creator-contest-embed
Draft

feat: host creator contest on peanut.me#2605
0xkkonrad wants to merge 2 commits into
devfrom
feat/creator-contest-embed

Conversation

@0xkkonrad

@0xkkonrad 0xkkonrad commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a full-viewport /creator-contest route on peanut.me that embeds the independently deployed contest
  • reserve the route so the recipient catch-all cannot intercept it
  • allow the contest origin in the report-only frame-src policy
  • delegate the storage-access Permissions Policy required by the child fallback flow
  • cover the iframe URL and security attributes with a unit test

The contest remains on its existing Vercel deployment, so this needs no DNS migration and does not couple its release cycle to peanut-ui.

Merge blocker: freelancer handoff

Keep this PR in draft until the child app is updated and the authenticated flow passes in the embed. The unauthenticated page already renders; the session behavior is the blocker.

  1. Send this HTTP header on every contest HTML route:
    Content-Security-Policy: frame-ancestors 'self' https://peanut.me
    Merge it into any existing CSP. Do not use a meta tag, and do not add X-Frame-Options: SAMEORIGIN or DENY. Add only exact preview/test parent origins in non-production environments.
  2. Make the session cookie host-only and iframe-safe:
    HttpOnly; Secure; SameSite=None; Partitioned; Path=/
    Prefer a __Host- cookie name. Set and clear it with the same attributes, and rotate it on login.
  3. Re-check authorization on every mutation. For custom mutating route handlers, validate Origin or a CSRF token because SameSite=None removes the usual SameSite CSRF defense. Do not put auth tokens in postMessage or localStorage. A direct iframe keeps Server Action requests on the child origin, so do not add peanut.me or a wildcard to serverActions.allowedOrigins.
  4. Add a user-gesture Storage Access API path plus a clear “Open contest in a new tab” fallback for browsers that deny embedded storage. The parent sandbox already grants scripts, forms, same-origin, popups, and storage access by user activation.
  5. Test inside https://peanut.me/creator-contest: home → signup/login → dashboard → reload → logout, including Chrome, Firefox, Safari/private mode, and third-party-cookie blocking. Also verify an unrelated origin cannot frame the app.

No CORS or DNS change is required for this direct iframe setup. The freelancer source repo was not found among accessible Peanut or personal repositories, so that child-side patch needs repo access or a transfer into the Peanut organization.

Verification

  • Prettier check: pass
  • ESLint on changed files: pass
  • TypeScript typecheck: pass
  • Jest: 184 suites passed; 2,417 tests passed; 3 skipped
  • Local embed smoke test at 375 × 667: parent URL remains stable, child loads, and signup navigation stays inside the iframe
  • All required final-head checks pass, including Vercel production preview build, analysis, E2E, unit, typecheck, lint, format, and CodeRabbit
  • Deployed smoke test: /creator-contest returns 200 and loads the child frame with no child-origin request failures

Screenshot

Mobile creator contest embed

375 × 667 local preview. The small Next.js development indicator in the lower-left is not present in production.

Summary by CodeRabbit

  • New Features
    • Added a dedicated Creator Contest page with a full-screen embedded contest experience.
    • The contest opens in a secure, sandboxed frame with appropriate privacy and navigation protections.
    • Added page metadata to keep the contest out of search engine results.
  • Bug Fixes
    • Reserved the contest page as a dedicated route to ensure it loads correctly without conflicting with other site paths.

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview Aug 4, 2026 3:28pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a non-indexed /creator-contest page that embeds the Peanut contest site in a full-screen sandboxed iframe. Registers the route and permits the contest origin in the report-only CSP frame-src directive. Tests verify the iframe attributes.

Changes

Creator contest page

Layer / File(s) Summary
Contest page and iframe contract
src/app/creator-contest/page.tsx, src/app/creator-contest/__tests__/page.test.tsx
Adds SEO metadata and a full-screen sandboxed iframe for the Peanut contest site. Tests verify its title, URL, sandbox permissions, and referrer policy.
Route registration and CSP allowlist
src/constants/routes.ts, next.config.js
Adds creator-contest to the dedicated routes and allows the contest origin in the report-only frame-src directive.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant CreatorContestPage
  participant PeanutContestSite
  Browser->>CreatorContestPage: Request /creator-contest
  CreatorContestPage-->>Browser: Return sandboxed iframe
  Browser->>PeanutContestSite: Load contest URL
  PeanutContestSite-->>Browser: Render contest content
Loading

Possibly related PRs

Suggested reviewers: hugo0, kushagrasarathe

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: adding a Peanut contest route hosted on peanut.me.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/creator-contest-embed

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.

@0xkkonrad

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 2420 ran, 0 failed, 0 skipped, 31.6s

📊 Coverage (unit)

metric %
statements 62.1%
branches 45.1%
functions 51.7%
lines 62.6%
⏱ 10 slowest test cases
time test
2.5s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
0.9s src/utils/__tests__/demo-api.test.ts › isDemoMode() is false when not running under Capacitor
0.3s src/utils/__tests__/sentry.utils.test.ts › defaults to the client budget under a browser global
0.3s src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx › Bank withdrawal keeps the $1 minimum for sub-$1 amounts
0.3s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › every sticker stays within canvas at any count
0.3s src/utils/__tests__/sentry.utils.test.ts › still lets a per-call timeoutMs win over the default
0.2s src/utils/__tests__/auth-token.test.ts › should read from cookies
0.2s src/app/actions/__tests__/api-headers-extended.test.ts › should not include apiKey in validateInviteCode body
0.2s src/utils/__tests__/auth-token.test.ts › authReady does not park — hydrates the plain token without an unlock
0.2s src/utils/__tests__/auth-token.test.ts › is none — never guarded — when only the guarded marker is present
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 6792.73 → 6795.67 (+2.94)
Findings: +1 net (+2 new, -1 resolved)

🆕 New findings (2)

  • medium complexity — src/constants/routes.ts — CC 15, MI 60.97, SLOC 47
  • low missing-return-type — src/app/creator-contest/page.tsx:9 — CreatorContestPage: exported fn missing return type annotation

✅ Resolved (1)

  • src/constants/routes.ts — CC 15, MI 60.99, SLOC 47

📈 Painscore deltas (top movers)

File Before After Δ
src/app/creator-contest/page.tsx 0.0 2.8 +2.8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant