import { Session as Session$1, User as User$1 } from "../../types/models.mjs"; import { AccessControl, Role } from "../access/types.mjs"; import { Invitation, Member, Organization, OrganizationRole, Team, TeamMember } from "./schema.mjs"; import { AuthContext, Awaitable, GenericEndpointContext } from "@better-auth/core"; import { DBFieldAttribute } from "@better-auth/core/db"; //#region src/plugins/organization/types.d.ts interface OrganizationOptions { /** * Configure whether new users are able to create new organizations. * You can also pass a function that returns a boolean. * * @example * ```ts * allowUserToCreateOrganization: async (user) => { * const plan = await getUserPlan(user); * return plan.name === "pro"; * } * ``` * @default true */ allowUserToCreateOrganization?: (boolean | ((user: User$1 & Record) => Awaitable)) | undefined; /** * The maximum number of organizations a user can create. * * You can also pass a function that returns a boolean. The function should return `true` if the user has reached their organization limit, and `false` otherwise. * * @default unlimited * @example * ```ts * organizationLimit: async (user) => { * const plan = await getUserPlan(user); * // Return true if the user has reached their organization limit, false otherwise * return plan.name === "pro"; * } * ``` */ organizationLimit?: (number | ((user: User$1 & Record) => Awaitable)) | undefined; /** * The role that is assigned to the creator of the * organization. * * @default "owner" */ creatorRole?: string | undefined; /** * The maximum number of members allowed in an organization. * * You can also pass a function that returns the limit number * * @default 100 */ membershipLimit?: number | ((user: User$1, organization: Organization) => Promise | number) | undefined; /** * Configure the roles and permissions for the * organization plugin. */ ac?: AccessControl | undefined; /** * Custom permissions for roles. */ roles?: { [key in string]?: Role } | undefined; /** * Dynamic access control for the organization plugin. */ dynamicAccessControl?: { /** * Whether to enable dynamic access control for the organization plugin. * * @default false */ enabled?: boolean; /** * The maximum number of roles that can be created for an organization. * * @default Infinite */ maximumRolesPerOrganization?: number | ((organizationId: string) => Awaitable); } | undefined; /** * Support for team. */ teams?: { /** * Enable team features. */ enabled: boolean; /** * Default team configuration */ defaultTeam?: { /** * Enable creating a default team when an organization is created * * @default true */ enabled: boolean; /** * Pass a custom default team creator function */ customCreateDefaultTeam?: (organization: Organization & Record, ctx?: GenericEndpointContext) => Promise>; }; /** * Maximum number of teams an organization can have. * * You can pass a number or a function that returns a number * * @default "unlimited" * * @param organization * @param request * @returns */ maximumTeams?: ((data: { organizationId: string; session: { user: User$1; session: Session$1; } | null; }, ctx?: GenericEndpointContext) => Awaitable) | number; /** * The maximum number of members per team. * * if `undefined`, there is no limit. * * @default undefined */ maximumMembersPerTeam?: number | ((data: { teamId: string; session: { user: User$1; session: Session$1; }; organizationId: string; }) => Awaitable) | undefined; /** * By default, if an organization does only have one team, they'll not be able to remove it. * * You can disable this behavior by setting this to `false. * * @default false */ allowRemovingAllTeams?: boolean; }; /** * The expiration time for the invitation link. * * @default 48 hours */ invitationExpiresIn?: number | undefined; /** * The maximum invitation a user can send. * * @default 100 */ invitationLimit?: number | ((data: { user: User$1 & Record; organization: Organization & Record; member: Member & Record; }, ctx: AuthContext) => Awaitable) | undefined; /** * Cancel pending invitations on re-invite. * * @default false */ cancelPendingInvitationsOnReInvite?: boolean | undefined; /** * Require email verification before session-authenticated recipient * invitation calls that carry an invitation ID (accept, reject, get). * * When unset, Better Auth preserves the normal emailed-invitation flow for * built-in opaque invitation IDs, including the default generator and * `advanced.database.generateId: "uuid"`. It requires verification for * externally controlled or predictable invitation IDs, such as * `advanced.database.generateId: "serial"` / `false` or custom ID * generation. * * Set this option to `true` when invitation IDs may be visible outside the * invited user's mailbox, when organization invitation lists are exposed to * members, or when verified email should be the ownership proof for by-ID * invitation actions. Client-side `listUserInvitations` calls always require * a verified session email because they enumerate invitation IDs from * `session.user.email`. Server-side `listUserInvitations` calls without a * session (caller passes `ctx.query.email`) continue to bypass the gate * because the caller is trusted. * * @default undefined */ requireEmailVerificationOnInvitation?: boolean | undefined; /** * Send an email with the * invitation link to the user. * * Note: Better Auth doesn't * generate invitation URLs. * You'll need to construct the * URL using the invitation ID * and pass it to the * acceptInvitation endpoint for * the user to accept the * invitation. * * @example * ```ts * sendInvitationEmail: async (data) => { * const url = `https://yourapp.com/organization/ * accept-invitation?id=${data.id}`; * sendEmail(data.email, "Invitation to join * organization", `Click the link to join the * organization: ${url}`); * } * ``` */ sendInvitationEmail?: ((data: { /** * the invitation id */ id: string; /** * the role of the user */ role: string; /** * the email of the user */ email: string; /** * the organization the user is invited to join */ organization: Organization; /** * the invitation object */ invitation: Invitation; /** * the member who is inviting the user */ inviter: Member & { user: User$1; }; }, /** * The request object */ request?: Request) => Promise) | undefined; /** * The schema for the organization plugin. */ schema?: { session?: { fields?: { activeOrganizationId?: string; activeTeamId?: string; }; }; organization?: { modelName?: string; fields?: { [key in keyof Omit]?: string }; additionalFields?: { [key in string]: DBFieldAttribute }; }; member?: { modelName?: string; fields?: { [key in keyof Omit]?: string }; additionalFields?: { [key in string]: DBFieldAttribute }; }; invitation?: { modelName?: string; fields?: { [key in keyof Omit]?: string }; additionalFields?: { [key in string]: DBFieldAttribute }; }; team?: { modelName?: string; fields?: { [key in keyof Omit]?: string }; additionalFields?: { [key in string]: DBFieldAttribute }; }; teamMember?: { modelName?: string; fields?: { [key in keyof Omit]?: string }; }; organizationRole?: { modelName?: string; fields?: { [key in keyof Omit]?: string }; additionalFields?: { [key in string]: DBFieldAttribute }; }; } | undefined; /** * Disable organization deletion * * @default false */ disableOrganizationDeletion?: boolean | undefined; /** * Hooks for organization */ organizationHooks?: { /** * A callback that runs before the organization is created * * You can return a `data` object to override the default data. * * @example * ```ts * beforeCreateOrganization: async (data) => { * return { * data: { * ...data.organization, * }, * }; * } * ``` * * You can also throw `new APIError` to stop the organization creation. * * @example * ```ts * beforeCreateOrganization: async (data) => { * throw new APIError("BAD_REQUEST", { * message: "Organization creation is disabled", * }); * } */ beforeCreateOrganization?: (data: { organization: { name?: string; slug?: string; logo?: string | null; metadata?: Record; [key: string]: any; }; user: User$1 & Record; }) => Promise; }>; /** * A callback that runs after the organization is created */ afterCreateOrganization?: (data: { organization: Organization & Record; member: Member & Record; user: User$1 & Record; }) => Promise; /** * A callback that runs before the organization is updated * * You can return a `data` object to override the default data. * * @example * ```ts * beforeUpdateOrganization: async (data) => { * return { data: { ...data.organization } }; * } */ beforeUpdateOrganization?: (data: { organization: { name?: string; slug?: string; logo?: string | null; metadata?: Record; [key: string]: any; }; user: User$1 & Record; member: Member & Record; }) => Promise; [key: string]: any; }; }>; /** * A callback that runs after the organization is updated * * @example * ```ts * afterUpdateOrganization: async (data) => { * console.log(data.organization); * } * ``` */ afterUpdateOrganization?: (data: { /** * Updated organization object * * This could be `null` if an adapter doesn't return updated organization. */ organization: (Organization & Record) | null; user: User$1 & Record; member: Member & Record; }) => Promise; /** * A callback that runs before the organization is deleted */ beforeDeleteOrganization?: (data: { organization: Organization & Record; user: User$1 & Record; }) => Promise; /** * A callback that runs after the organization is deleted */ afterDeleteOrganization?: (data: { organization: Organization & Record; user: User$1 & Record; }) => Promise; /** * Member hooks */ /** * A callback that runs before a member is added to an organization * * You can return a `data` object to override the default data. * * @example * ```ts * beforeAddMember: async (data) => { * return { * data: { * ...data.member, * role: "custom-role" * } * }; * } * ``` */ beforeAddMember?: (data: { member: { userId: string; organizationId: string; role: string; [key: string]: any; }; user: User$1 & Record; organization: Organization & Record; }) => Promise; }>; /** * A callback that runs after a member is added to an organization */ afterAddMember?: (data: { member: Member & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before a member is removed from an organization */ beforeRemoveMember?: (data: { member: Member & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs after a member is removed from an organization */ afterRemoveMember?: (data: { member: Member & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before a member's role is updated * * You can return a `data` object to override the default data. */ beforeUpdateMemberRole?: (data: { member: Member & Record; newRole: string; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs after a member's role is updated */ afterUpdateMemberRole?: (data: { member: Member & Record; previousRole: string; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * Invitation hooks */ /** * A callback that runs before an invitation is created * * You can return a `data` object to override the default data. * * @example * ```ts * beforeCreateInvitation: async (data) => { * return { * data: { * ...data.invitation, * expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days * } * }; * } * ``` */ beforeCreateInvitation?: (data: { invitation: { email: string; role: string; organizationId: string; inviterId: string; teamId?: string; [key: string]: any; }; inviter: User$1 & Record; organization: Organization & Record; }) => Promise; }>; /** * A callback that runs after an invitation is created */ afterCreateInvitation?: (data: { invitation: Invitation & Record; inviter: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before an invitation is accepted */ beforeAcceptInvitation?: (data: { invitation: Invitation & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs after an invitation is accepted */ afterAcceptInvitation?: (data: { invitation: Invitation & Record; member: Member & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before an invitation is rejected */ beforeRejectInvitation?: (data: { invitation: Invitation & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs after an invitation is rejected */ afterRejectInvitation?: (data: { invitation: Invitation & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before an invitation is cancelled */ beforeCancelInvitation?: (data: { invitation: Invitation & Record; cancelledBy: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs after an invitation is cancelled */ afterCancelInvitation?: (data: { invitation: Invitation & Record; cancelledBy: User$1 & Record; organization: Organization & Record; }) => Promise; /** * Team hooks (when teams are enabled) */ /** * A callback that runs before a team is created * * You can return a `data` object to override the default data. */ beforeCreateTeam?: (data: { team: { name: string; organizationId: string; [key: string]: any; }; user?: User$1 & Record; organization: Organization & Record; }) => Promise; }>; /** * A callback that runs after a team is created */ afterCreateTeam?: (data: { team: Team & Record; user?: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before a team is updated * * You can return a `data` object to override the default data. */ beforeUpdateTeam?: (data: { team: Team & Record; updates: { name?: string; [key: string]: any; }; user: User$1 & Record; organization: Organization & Record; }) => Promise; }>; /** * A callback that runs after a team is updated */ afterUpdateTeam?: (data: { team: (Team & Record) | null; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before a team is deleted */ beforeDeleteTeam?: (data: { team: Team & Record; user?: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs after a team is deleted */ afterDeleteTeam?: (data: { team: Team & Record; user?: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before a member is added to a team */ beforeAddTeamMember?: (data: { teamMember: { teamId: string; userId: string; [key: string]: any; }; team: Team & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; }>; /** * A callback that runs after a member is added to a team */ afterAddTeamMember?: (data: { teamMember: TeamMember & Record; team: Team & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs before a member is removed from a team */ beforeRemoveTeamMember?: (data: { teamMember: TeamMember & Record; team: Team & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; /** * A callback that runs after a member is removed from a team */ afterRemoveTeamMember?: (data: { teamMember: TeamMember & Record; team: Team & Record; user: User$1 & Record; organization: Organization & Record; }) => Promise; } | undefined; } //#endregion export { OrganizationOptions };