Skip to content

basalt / teams/src / Teams

Class: Teams ​

Defined in: teams/src/teams.ts:157

Team membership and email invitations for multi-user tenants. Decoupled from auth and tenancy: identifiers are passed in. Optionally mirrors role changes into a RoleAssigner (e.g. @basaltkit/permissions).

Constructors ​

Constructor ​

> new Teams(options?): Teams

Defined in: teams/src/teams.ts:168

Parameters ​

options? ​

TeamsOptions = {}

Returns ​

Teams

Methods ​

accept() ​

> accept(token, userId, acceptingEmail?): Promise<Membership>

Defined in: teams/src/teams.ts:305

Consumes an invitation token and enrolls userId at the invited role. Idempotent for an already-accepted membership of the same user.

Parameters ​

token ​

string

userId ​

string

acceptingEmail? ​

string

Returns ​

Promise<Membership>


addMember() ​

> addMember(tenantId, userId, role, opts?): Promise<Membership>

Defined in: teams/src/teams.ts:227

Directly adds/updates a membership — used to seed a team's first owner.

Parameters ​

tenantId ​

string

userId ​

string

role ​

string

opts? ​
actingUserId? ​

string

Returns ​

Promise<Membership>


can() ​

> can(tenantId, userId, required): Promise<boolean>

Defined in: teams/src/teams.ts:441

True when the user holds required or a higher-ranked role in the team.

Only a ranked required role has a hierarchy, and only a ranked member role can climb it. A required role outside roleRank (a custom role from grantableRoles, or a typo such as 'Admin') is matched exactly — it never ranks 0 and admits every member. An empty or non-string required is always false.

Parameters ​

tenantId ​

string

userId ​

string

required ​

string

Returns ​

Promise<boolean>


changeRole() ​

> changeRole(tenantId, userId, role, opts?): Promise<Membership>

Defined in: teams/src/teams.ts:449

Parameters ​

tenantId ​

string

userId ​

string

role ​

string

opts? ​
actingUserId? ​

string

Returns ​

Promise<Membership>


invitation() ​

> invitation(id): Promise<PublicInvitation | null>

Defined in: teams/src/teams.ts:416

Parameters ​

id ​

string

Returns ​

Promise<PublicInvitation | null>


invite() ​

> invite(input): Promise<{ invitation: PublicInvitation; token: string; }>

Defined in: teams/src/teams.ts:263

Creates (or refreshes) an invitation and emits team:invited for the app to email. Returns the public invitation plus the token (for building the link). One pending invite per email per team — a new one supersedes it.

Parameters ​

input ​
actingUserId? ​

string

When set, enforce that the inviter can't grant a role above their own.

email ​

string

invitedBy? ​

string

role? ​

string

tenantId ​

string

Returns ​

Promise<{ invitation: PublicInvitation; token: string; }>


isKnownRole() ​

> isKnownRole(role): role is string

Defined in: teams/src/teams.ts:195

True for a role this service knows: ranked in roleRank or listed in grantableRoles. The meta.teamRole guard refuses anything else with UnknownTeamRoleError, so a typo can never rank 0 and admit everyone.

Parameters ​

role ​

unknown

Returns ​

role is string


members() ​

> members(tenantId): Promise<Membership[]>

Defined in: teams/src/teams.ts:336

Parameters ​

tenantId ​

string

Returns ​

Promise<Membership[]>


membersWithUsers() ​

> membersWithUsers(tenantId): Promise<TeamMemberWithUser[]>

Defined in: teams/src/teams.ts:358

The tenant's memberships with each member's contact details attached — the primitive behind "notify everyone with this role", and the ONE place the user lookup is batched.

Requires a users directory (an @basaltkit/auth UserSource fits). When it implements findByIds the whole team resolves in a single bulk lookup; otherwise it falls back to one findById per member, so an app gets the fast path automatically the day its driver grows one, with no code change.

Tenant safety: the ids come from THIS tenant's membership records and nowhere else — a caller never chooses which accounts are looked up — and a user the directory returns that was not asked for is discarded. A membership whose account does not exist is skipped (see TeamMemberWithUser); the membership record itself is left alone.

Order follows members.

Parameters ​

tenantId ​

string

Returns ​

Promise<TeamMemberWithUser[]>


pendingInvites() ​

> pendingInvites(tenantId): Promise<PublicInvitation[]>

Defined in: teams/src/teams.ts:411

Parameters ​

tenantId ​

string

Returns ​

Promise<PublicInvitation[]>


rankOf() ​

> rankOf(role): number

Defined in: teams/src/teams.ts:180

Parameters ​

role ​

string

Returns ​

number


removeMember() ​

> removeMember(tenantId, userId, opts?): Promise<void>

Defined in: teams/src/teams.ts:486

Removes a membership. When actingUserId is given (HTTP routes), the actor must be a member and may only remove themselves or someone who does not outrank them — an admin can't remove an owner. Omit the actor for trusted server-side flows.

Parameters ​

tenantId ​

string

userId ​

string

opts? ​
actingUserId? ​

string

Returns ​

Promise<void>


revokeInvite() ​

> revokeInvite(id): Promise<void>

Defined in: teams/src/teams.ts:421

Parameters ​

id ​

string

Returns ​

Promise<void>


roleOf() ​

> roleOf(tenantId, userId): Promise<string | null>

Defined in: teams/src/teams.ts:428

Parameters ​

tenantId ​

string

userId ​

string

Returns ​

Promise<string | null>


roleRecipients() ​

> roleRecipients(tenantId, role, opts?): Promise<TeamMemberWithUser[]>

Defined in: teams/src/teams.ts:398

Who to notify for a role — a thin filter over membersWithUsers, so it costs no extra lookup.

A ranked role (one present in roleRank) includes everyone at or above it: roleRecipients(t, 'admin') also returns the owners, which is what "tell the admins" almost always means. Roles outside roleRank have no hierarchy — every unranked role ranks 0, so treating them by rank would notify all of them — and are therefore matched exactly; ranked roles can be narrowed the same way with { exact: true }.

Parameters ​

tenantId ​

string

role ​

string

opts? ​
exact? ​

boolean

Returns ​

Promise<TeamMemberWithUser[]>

Released under the MIT License.