fix: accept bare business domains in the audit signup form - #13
Conversation
The website field used type="url", which browsers only accept with an explicit scheme, while the placeholder promised 'yourwebsite.com'. A bare domain entry like example.com failed native validation before it could reach the signup handler. Switch the field to type="text" with inputmode="url" and a pattern that accepts an optional scheme plus a dotted domain, keeping required and the server-side normalizeWebsite URL-safety gate untouched. Malformed entries (spaces, missing dot, empty TLD) stay rejected by the pattern. Add a check-site regression that pins the pattern's accept/reject behavior on both signup forms, and a worker test proving example.com + a test email hits the existing /api/signups handler and stores the normalized https:// URL. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
📝 WalkthroughWalkthroughSignup website fields now use text inputs with custom domain validation. Regression checks cover both signup pages, and worker tests verify bare-domain normalization, email persistence, and redirect behavior. ChangesSignup website validation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 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 `@public/index.html`:
- Line 24: Update both website input fields to validate ports within the valid
URL range (0–65535), preventing values such as example.com:65536 from reaching
signup storage. Also add example.com:65536 to INVALID_WEBSITES in check-site
validation.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b36ea543-3583-4f5c-87ef-c74f331138e8
📒 Files selected for processing (4)
public/audit.htmlpublic/index.htmlscripts/check-site.mjsscripts/test-agent-worker.mjs
| <p class="sub">We read the one page your revenue depends on the way a customer with intent reads it, and show you the exact points at which they go.</p> | ||
| <form class="lead two" id="start" action="/api/signups" method="post"> | ||
| <input type="url" name="website" required placeholder="yourwebsite.com"> | ||
| <input type="text" name="website" required inputmode="url" autocomplete="url" placeholder="yourwebsite.com" pattern="(https?://)?([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}(:[0-9]+)?(/[^\s]*)?" title="Enter your domain, like example.com"> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
printf '%s\n' '--- plan candidates ---'
find . -maxdepth 3 -type f \( -iname '*plan*' -o -name 'AGENTS.md' -o -name 'CONTRIBUTING.md' \) -print
printf '%s\n' '--- target files ---'
git ls-files | grep -E '(^|/)(public/index\.html|public/audit\.html|src/worker\.js|scripts/check-site\.mjs)$'
printf '%s\n' '--- relevant source ---'
sed -n '1,220p' AGENTS.md 2>/dev/null || true
sed -n '1,220p' PLAN.md 2>/dev/null || true
sed -n '1,220p' plan.md 2>/dev/null || trueRepository: nish3451/TinyStudio.io
Length of output: 797
🏁 Script executed:
printf '%s\n' '--- plans mentioning the reviewed files or website validation ---'
rg -n -i 'public/index\.html|public/audit\.html|normalizeWebsite|INVALID_WEBSITES|website|current plan' specs docs/plans --glob '*plan.md' --glob '*.md' | head -200
printf '%s\n' '--- target file sizes ---'
wc -l public/index.html public/audit.html src/worker.js scripts/check-site.mjs
printf '%s\n' '--- index and audit validation inputs ---'
sed -n '15,35p' public/index.html
sed -n '20,38p' public/audit.html
printf '%s\n' '--- worker normalization and signup references ---'
rg -n -C 12 'normalizeWebsite|website|signup|email' src/worker.js
printf '%s\n' '--- check-site invalid website data and checks ---'
rg -n -C 10 'INVALID_WEBSITES|65535|website|pattern' scripts/check-site.mjsRepository: nish3451/TinyStudio.io
Length of output: 24980
🏁 Script executed:
printf '%s\n' '--- applicable plan context ---'
sed -n '1,180p' specs/001-public-buyer-page/plan.md
sed -n '1,150p' docs/plans/2026-06-18-002-fix-minimal-input-agent-desk-plan.md
printf '%s\n' '--- exact normalization and signup code ---'
sed -n '248,366p' src/worker.js
printf '%s\n' '--- repository state ---'
git status --short
printf '%s\n' '--- executable behavioral probe ---'
node - <<'JS'
const fs = require("fs");
const index = fs.readFileSync("public/index.html", "utf8");
const audit = fs.readFileSync("public/audit.html", "utf8");
const field = (html) => html.match(/<input\b[^>]*name="website"[^>]*>/i)?.[0] || "";
const patternOf = (html) => field(html).match(/\bpattern="([^"]+)"/i)?.[1];
const normalizeWebsite = (value) => {
if (typeof value !== "string") return null;
const raw = value.trim().slice(0, 300);
if (!raw) return null;
const candidate = /^https?:\/\//i.test(raw) ? raw : `https://${raw}`;
try {
const parsed = new URL(candidate);
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
if (!parsed.hostname.includes(".")) return null;
return parsed.origin + (parsed.pathname === "/" ? "" : parsed.pathname);
} catch {
return null;
}
};
for (const value of ["example.com:65535", "example.com:65536", "example.com:999999", "example.com:00065536"]) {
const browserResults = [index, audit].map((html) => {
const regex = new RegExp(`^(?:${patternOf(html)})$`, "i");
return regex.test(value);
});
console.log(JSON.stringify({ value, browserResults, normalized: normalizeWebsite(value) }));
}
JSRepository: nish3451/TinyStudio.io
Length of output: 10943
Reject out-of-range website ports.
The pattern accepts example.com:65536, but normalizeWebsite returns null for this value and the signup still stores the email. Apply URL port-range validation in both website fields and add example.com:65536 to INVALID_WEBSITES in scripts/check-site.mjs.
🤖 Prompt for 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.
In `@public/index.html` at line 24, Update both website input fields to validate
ports within the valid URL range (0–65535), preventing values such as
example.com:65536 from reaching signup storage. Also add example.com:65536 to
INVALID_WEBSITES in check-site validation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4c18d64bb0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| <p class="sub">We read the one page your revenue depends on the way a customer with intent reads it, and show you the exact points at which they go.</p> | ||
| <form class="lead two" id="start" action="/api/signups" method="post"> | ||
| <input type="url" name="website" required placeholder="yourwebsite.com"> | ||
| <input type="text" name="website" required inputmode="url" autocomplete="url" placeholder="yourwebsite.com" pattern="(https?://)?([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}(:[0-9]+)?(/[^\s]*)?" title="Enter your domain, like example.com"> |
There was a problem hiding this comment.
Reject ports that the server cannot normalize
When a user enters a value such as example.com:99999, this pattern passes native form validation, but normalizeWebsite cannot construct the URL and returns null; the signup handler nevertheless stores the row and redirects to the success page. This produces an audit request without the required website, so the pattern should reject ports outside the URL parser's valid range or the handler should reject a null normalized website.
Useful? React with 👍 / 👎.
| <p class="sub">We read the one page your revenue depends on the way a customer with intent reads it, and show you the exact points at which they go.</p> | ||
| <form class="lead two" id="start" action="/api/signups" method="post"> | ||
| <input type="url" name="website" required placeholder="yourwebsite.com"> | ||
| <input type="text" name="website" required inputmode="url" autocomplete="url" placeholder="yourwebsite.com" pattern="(https?://)?([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}(:[0-9]+)?(/[^\s]*)?" title="Enter your domain, like example.com"> |
There was a problem hiding this comment.
Preserve internationalized top-level domains
For businesses using an internationalized TLD, valid URLs such as https://example.xn--p1ai now fail native validation because the final label is restricted to ASCII letters. The previous type="url" field accepted these absolute URLs, so this change blocks affected customers from submitting either signup form; the domain validation should accommodate valid IDN/punycode hostnames.
Useful? React with 👍 / 👎.
| <p class="sub">We read the one page your revenue depends on the way a customer with intent reads it, and show you the exact points at which they go.</p> | ||
| <form class="lead two" id="start" action="/api/signups" method="post"> | ||
| <input type="url" name="website" required placeholder="yourwebsite.com"> | ||
| <input type="text" name="website" required inputmode="url" autocomplete="url" placeholder="yourwebsite.com" pattern="(https?://)?([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}(:[0-9]+)?(/[^\s]*)?" title="Enter your domain, like example.com"> |
There was a problem hiding this comment.
If a user pastes a valid URL with an uppercase scheme, such as HTTPS://example.com, the browser rejects it because HTML patterns are case-sensitive and this expression only matches lowercase http. This regresses an input accepted by type="url"; moreover, the new check compiles the extracted pattern with the i flag, so it does not reproduce the form's behavior and masks this discrepancy.
Useful? React with 👍 / 👎.
Summary
Fix the audit-intake placeholder mismatch: both signup forms promised
yourwebsite.combut the website field usedtype="url", so browsers rejected bare domains likeexample.combefore they could reach the signup handler.public/index.html,public/audit.html: switch the website field totype="text"withinputmode="url",autocomplete="url", and a pattern that accepts an optional scheme plus a dotted domain (with optional port/path). Malformed entries (spaces, missing dot, empty TLD) stay rejected; the field staysrequiredand the server-sidenormalizeWebsiteURL-safety gate is untouched.scripts/check-site.mjs: browser-pattern regression pinning accept/reject behavior for the website field on both signup forms.scripts/test-agent-worker.mjs: worker test provingexample.com+ a test email hits the existing/api/signupshandler and stores the normalizedhttps://example.comURL.No product design changes beyond the sealed candidate.
Test evidence
npm run check— passed ("TinyStudio.io Agent Desk checks passed.")npm test— 52 tests, 52 pass, 0 fail (worker: 51, UI: 1)sgscan— same 2 pre-existingdjango-no-csrf-tokenwarnings on the untouched<form>lines as on baseorigin/main; candidate introduces no new findings (base and branch both exit 1 with identical findings)intended-outcome: Bare domains like
example.comare accepted by both audit signup forms at the browser level and stored normalized ashttps://example.com, with malformed entries still rejected.verify:
node scripts/check-site.mjspasses the new accept/reject pattern regression onpublic/index.htmlandpublic/audit.html, andnode --test scripts/test-agent-worker.mjspasses the new test proving a bare-domain signup hits/api/signupsand storeshttps://example.com.Summary by CodeRabbit
Bug Fixes
Tests