feat: add USESEND_INVITE_ONLY flag for invite-restricted signup#398
feat: add USESEND_INVITE_ONLY flag for invite-restricted signup#398schemann wants to merge 1 commit into
Conversation
Adds a tri-state env var to control who can register: keep the current open behavior (false), route uninvited users to the waitlist (waitlist), or hard-block them in the signIn callback before any user record is created (true). Existing users and ADMIN_EMAIL can always sign in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@schemann is attempting to deploy a commit to the kmkoushik's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
WalkthroughThis PR introduces invite-only and waitlist signup modes via a new 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@apps/web/src/server/auth.ts`:
- Around line 119-133: The signIn handler uses raw user.email for comparisons
and DB lookups, which can fail for mixed-case or spaced emails; normalize the
email once (e.g., const normalizedEmail = user.email.trim().toLowerCase()) at
the start of signIn and then use normalizedEmail for the env.ADMIN_EMAIL
comparison, for db.user.findUnique({ where: { email: ... } }) and
db.teamInvite.findMany lookups so checks succeed regardless of
casing/whitespace.
- Around line 152-157: The waitlist branch currently applies to every new user
when env.USESEND_INVITE_ONLY === "waitlist", which also catches the
bootstrap/admin account; update the condition to exempt the admin by checking
env.ADMIN_EMAIL and comparing it to user.email and only mark isWaitlisted when
the user is not the admin. Concretely, in the block that calls
db.user.update(...) (and uses invitesAvailable and user), if user.email ===
env.ADMIN_EMAIL then do not set isWaitlisted (you can still set isBetaUser as
needed), otherwise set isWaitlisted: true as before.
🪄 Autofix (Beta)
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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 217c1e17-df13-45cd-afc0-9e3fa5c877aa
📒 Files selected for processing (3)
.env.exampleapps/web/src/env.jsapps/web/src/server/auth.ts
| signIn: async ({ user }) => { | ||
| if (env.USESEND_INVITE_ONLY !== "true") return true; | ||
| if (!user.email) return false; | ||
|
|
||
| const existing = await db.user.findUnique({ | ||
| where: { email: user.email }, | ||
| }); | ||
| if (existing) return true; | ||
|
|
||
| if (env.ADMIN_EMAIL && user.email === env.ADMIN_EMAIL) return true; | ||
|
|
||
| const invites = await db.teamInvite.findMany({ | ||
| where: { email: user.email }, | ||
| }); | ||
| return invites.length > 0; |
There was a problem hiding this comment.
Normalize email before admin/invite gating checks.
Line 121 onward uses raw user.email for equality and DB lookups. Mixed-case emails can fail matches and incorrectly block allowed sign-ins.
Suggested fix
signIn: async ({ user }) => {
if (env.USESEND_INVITE_ONLY !== "true") return true;
- if (!user.email) return false;
+ const normalizedEmail = user.email?.trim().toLowerCase();
+ if (!normalizedEmail) return false;
const existing = await db.user.findUnique({
- where: { email: user.email },
+ where: { email: normalizedEmail },
});
if (existing) return true;
- if (env.ADMIN_EMAIL && user.email === env.ADMIN_EMAIL) return true;
+ if (
+ env.ADMIN_EMAIL?.trim().toLowerCase() === normalizedEmail
+ ) return true;
const invites = await db.teamInvite.findMany({
- where: { email: user.email },
+ where: { email: normalizedEmail },
});
return invites.length > 0;
},🤖 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 `@apps/web/src/server/auth.ts` around lines 119 - 133, The signIn handler uses
raw user.email for comparisons and DB lookups, which can fail for mixed-case or
spaced emails; normalize the email once (e.g., const normalizedEmail =
user.email.trim().toLowerCase()) at the start of signIn and then use
normalizedEmail for the env.ADMIN_EMAIL comparison, for db.user.findUnique({
where: { email: ... } }) and db.teamInvite.findMany lookups so checks succeed
regardless of casing/whitespace.
| if (env.USESEND_INVITE_ONLY === "waitlist" && !invitesAvailable) { | ||
| await db.user.update({ | ||
| where: { id: user.id }, | ||
| data: { isBetaUser: true, isWaitlisted: true }, | ||
| }); | ||
| return; |
There was a problem hiding this comment.
Preserve ADMIN_EMAIL exemption in waitlist mode.
Line 152 waitlists every uninvited new user, including ADMIN_EMAIL. That conflicts with the stated exemption for admin sign-in/bootstrap.
Suggested fix
- if (env.USESEND_INVITE_ONLY === "waitlist" && !invitesAvailable) {
+ if (
+ env.USESEND_INVITE_ONLY === "waitlist" &&
+ !invitesAvailable &&
+ user.email?.trim().toLowerCase() !== env.ADMIN_EMAIL?.trim().toLowerCase()
+ ) {
await db.user.update({
where: { id: user.id },
data: { isBetaUser: true, isWaitlisted: true },
});
return;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (env.USESEND_INVITE_ONLY === "waitlist" && !invitesAvailable) { | |
| await db.user.update({ | |
| where: { id: user.id }, | |
| data: { isBetaUser: true, isWaitlisted: true }, | |
| }); | |
| return; | |
| if ( | |
| env.USESEND_INVITE_ONLY === "waitlist" && | |
| !invitesAvailable && | |
| user.email?.trim().toLowerCase() !== env.ADMIN_EMAIL?.trim().toLowerCase() | |
| ) { | |
| await db.user.update({ | |
| where: { id: user.id }, | |
| data: { isBetaUser: true, isWaitlisted: true }, | |
| }); | |
| return; | |
| } |
🤖 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 `@apps/web/src/server/auth.ts` around lines 152 - 157, The waitlist branch
currently applies to every new user when env.USESEND_INVITE_ONLY === "waitlist",
which also catches the bootstrap/admin account; update the condition to exempt
the admin by checking env.ADMIN_EMAIL and comparing it to user.email and only
mark isWaitlisted when the user is not the admin. Concretely, in the block that
calls db.user.update(...) (and uses invitesAvailable and user), if user.email
=== env.ADMIN_EMAIL then do not set isWaitlisted (you can still set isBetaUser
as needed), otherwise set isWaitlisted: true as before.
Adds a tri-state env var to control who can register: keep the current open behavior (false), route uninvited users to the waitlist (waitlist), or hard-block them in the signIn callback before any user record is created (true). Existing users and ADMIN_EMAIL can always sign in.
Summary by cubic
Adds a tri-state
USESEND_INVITE_ONLYenv flag to control new signups: open, waitlist, or invite-only hard block. Existing users andADMIN_EMAILcan always sign in.USESEND_INVITE_ONLYsupportsfalse(default),waitlist, andtrue.signInwhen set totrue: no user record is created; only invited emails, existing users, andADMIN_EMAILare allowed.isWaitlisted(andisBetaUser) for review.apps/web/src/env.jsand documented in.env.example.Written for commit e73c9e9. Summary will update on new commits.
Summary by CodeRabbit