@@ -14,6 +14,7 @@ import { APIError } from "better-auth/api";
1414import { organization } from "better-auth/plugins" ;
1515import { Effect , Option , Schema } from "effect" ;
1616import type { Bindings } from "../http/types.js" ;
17+ import { inviteSignupAdmission } from "../settings/members/service.js" ;
1718import { cloudflareMagicLink } from "./cloudflare-magic-link.js" ;
1819import { emailPassword } from "./email-password.js" ;
1920import type { AuthenticationRequirements } from "./requirements.js" ;
@@ -53,12 +54,19 @@ const defaultAuthenticationPlugins = (
5354 if ( browserAuthenticationMode ( requirements , bindings ) === "email-password" ) {
5455 return [
5556 requirements . environment === "selfhost"
56- ? emailPassword ( undefined , selfhostSignupEnabled ( bindings ) )
57+ ? emailPassword (
58+ undefined ,
59+ selfhostSignupEnabled ( bindings ) ,
60+ bindings . DB === undefined
61+ ? undefined
62+ : ( callbackURL ) =>
63+ inviteSignupAdmission ( bindings . DB , callbackURL ) ,
64+ )
5765 : emailPassword ( undefined , true ) ,
5866 ] ;
5967 }
60- if ( bindings . DB === undefined )
61- throw new Error ( "D1 database binding is required." ) ;
68+ const db = bindings . DB ;
69+ if ( db === undefined ) throw new Error ( "D1 database binding is required." ) ;
6270 if ( bindings . EMAIL === undefined )
6371 throw new Error ( "Cloudflare email binding is required for deployed auth." ) ;
6472 const from = bindings . DX_AUTH_EMAIL_FROM ?. trim ( ) ;
@@ -67,7 +75,9 @@ const defaultAuthenticationPlugins = (
6775 const magicLink = cloudflareMagicLink ( {
6876 email : bindings . EMAIL ,
6977 from,
70- admitEmail : waitlistAdmission ( bindings . DB ) ,
78+ admitEmail : async ( email , callbackURL ) =>
79+ ( await inviteSignupAdmission ( db , callbackURL ) ) ||
80+ ( await waitlistAdmission ( db ) ( email ) ) ,
7181 verifyRequest : async ( token ) => {
7282 const error = await Effect . runPromise (
7383 verifyTurnstile ( {
@@ -149,6 +159,7 @@ const workspaceOrganization = (bindings: Bindings) => {
149159
150160 return organization ( {
151161 organizationLimit : 1 ,
162+ invitationLimit : 0 ,
152163 disableOrganizationDeletion : true ,
153164 allowUserToCreateOrganization : async ( user ) =>
154165 ! ( await workspaceMembershipExists ( db , user . id ) ) ,
@@ -162,6 +173,17 @@ const workspaceOrganization = (bindings: Bindings) => {
162173 beforeAddMember : async ( { member } ) => {
163174 await assertNoMembership ( member . userId ) ;
164175 } ,
176+ // Workspaces grow only through dx invite links (settings/members).
177+ beforeCreateInvitation : async ( ) => {
178+ throw new APIError ( "FORBIDDEN" , {
179+ message : "Use a workspace invite link." ,
180+ } ) ;
181+ } ,
182+ beforeAcceptInvitation : async ( ) => {
183+ throw new APIError ( "FORBIDDEN" , {
184+ message : "Use a workspace invite link." ,
185+ } ) ;
186+ } ,
165187 } ,
166188 } ) ;
167189} ;
0 commit comments