Repository navigation
Put the CAPTCHA challenge where the visitor is looking - #16
Conversation
`createTurnstileCaptcha` appended its container to `document.body`, so an interactive challenge rendered wherever the layout dropped it — below a gate that starts 96px down a 340px column. Attached, as it must be, but off-screen: sign-in appears to hang rather than to be waiting on someone. Cloudflare's managed mode challenges unfamiliar browsers, and one was seen live on 2026-08-05, so this is a path real visitors take. The widget now looks for `[data-captcha-mount]` and falls back to the body. The gate renders that mount in every state that can ask for a token — including "Loading…", which is where a first visit's anonymous sign-in happens, before any form exists and with no other UI to explain itself. It also renders with `appearance: 'interaction-only'`, so it occupies nothing until Cloudflare actually wants an answer; the default would show a box on every silent token, including that first-visit one. The mount is `display: none` while `:empty`, so a gate that is never challenged carries no gap. The comment claiming the container was "sized to nothing" was never true — nothing sized it. It is gone rather than corrected. Both new unit tests were checked against the old code and fail there. The browser assertion measures where a widget-sized probe actually lands rather than reading the empty element, whose display:none rect of zeros would have passed any position asked of it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6pCyUrdjterihUB8XQopQ
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughCAPTCHA widgets now mount in configured account-gate elements when available, with a body fallback. Account-gate states render shared mount points, and styles keep populated widgets centered and visible. Node and browser tests cover placement, fallback, appearance, and viewport fit. ChangesCAPTCHA mount integration
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant RequireAccount
participant createTurnstileCaptcha
participant CaptchaMount
RequireAccount->>createTurnstileCaptcha: request CAPTCHA widget
createTurnstileCaptcha->>CaptchaMount: find [data-captcha-mount]
createTurnstileCaptcha->>CaptchaMount: append interaction-only widget
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@src/styles/shell.css`:
- Around line 93-98: Remove the permanent margin declaration from
.captcha-mount, and apply the 14px 0 4px spacing only through a visibility state
or selector that is set when the CAPTCHA widget is actually visible. Preserve
the existing centering, flex, overflow, and empty-container hiding behavior.
🪄 Autofix
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: CHILL
Plan: Pro Plus
Run ID: aabe20be-02b0-400f-85fd-65ebacb2f8dd
📒 Files selected for processing (5)
src/platform/turnstile.jssrc/shell/RequireAccount.jsxsrc/styles/shell.csstest/browser/auth.test.jstest/node/turnstile.test.js
CodeRabbit caught this and it is right. `captcha()` attaches its container before Cloudflare has decided whether to show a challenge, so `.captcha-mount` is non-empty for the length of every token fetch — and with `appearance: 'interaction-only'` almost every one of those is silent. A margin on the wrapper is therefore reserved for an invisible widget and taken away again: a gap that flickers into the gate on each sign-in, including the one behind "Loading…" on a first visit. The margin is gone. Whatever room a visible challenge needs comes from the widget Cloudflare renders, which is the only thing that knows it is visible. `:empty` still earns its keep — with no site key there is no container and no call at all, which is every test and every local dev server. The comment that went with the old rule claimed the injected iframe was what stopped `:empty` matching, and brought the margin with it. That was wrong on both counts: our own container is appended first, and it is appended whether or not anything visible follows. Rewritten rather than trimmed, since the reasoning was the part that was broken. The browser test now pins the case: a hidden child stands in for a silent token, and the gate's height must not change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6pCyUrdjterihUB8XQopQ
createTurnstileCaptchaappended its container todocument.body, so an interactive challenge rendered wherever the layout dropped it — below a gate that starts 96px down a 340px column. Attached, as it has to be, but off-screen: sign-in appears to hang rather than to be waiting on someone. Cloudflare's managed mode challenges unfamiliar browsers and one was seen live on 2026-08-05, so this is a path real visitors take.What changed
[data-captcha-mount], falling back todocument.body.RequireAccountrenders that mount in every state that can ask for a token,"Loading…"included. That is the important one: a first visit's anonymous sign-in fires from the gate's effect before any form exists, and an unfamiliar browser is exactly what managed mode challenges — so the old code was worst precisely where a visitor had no other UI to explain itself.appearance: 'interaction-only', so the widget occupies nothing until Cloudflare actually wants an answer. The default renders a box on every silent token, including that first-visit one..captcha-mount:empty { display: none }, so a gate that is never challenged carries no gap.The comment claiming the container was "sized to nothing" is removed rather than corrected — nothing sized it.
Verification
Both new unit tests were run against the old code and fail there (container to the body; missing
appearance), while the two fallback tests pass under both, which is correct — they describe behaviour this does not change. Full local suite 441/441, build clean.Two things are not verified, and the PR should not be read as claiming they are:
test/browser/auth.test.jshas never run. It needs local Supabase, which needs Docker, which is unavailable on the machine this was written on — CI is the first thing to execute it.interaction-onlyhas never met real Cloudflare. Nothing in this repo has; the tests drive a fake widget.The browser assertion measures where a widget-sized probe actually lands rather than reading the empty element — a
display: nonerect of zeros reportstop: 0and would pass any position asked of it.🤖 Generated with Claude Code
https://claude.ai/code/session_01H6pCyUrdjterihUB8XQopQ
Summary by CodeRabbit
New Features
Bug Fixes