diff --git a/.changeset/orange-files-end.md b/.changeset/orange-files-end.md new file mode 100644 index 00000000000..8e5b5bbcec9 --- /dev/null +++ b/.changeset/orange-files-end.md @@ -0,0 +1,18 @@ +--- +'@clerk/clerk-js': minor +'@clerk/clerk-react': minor +'@clerk/types': minor +--- + +Remove MemberRole Type`MemberRole` would always include the old role keys `admin`, `member`, `guest_member`. +If developers still depend on them after the introduction of custom roles, the can provide them as their custom types for authorization. + +```ts +// clerk.d.ts +export {} + +interface ClerkAuthorization { + permission: ''; + role: 'admin' | 'basic_member' | 'guest_member'; +} +``` diff --git a/packages/clerk-js/src/core/resources/OrganizationInvitation.ts b/packages/clerk-js/src/core/resources/OrganizationInvitation.ts index f5d9c6c9cb4..f4165842c71 100644 --- a/packages/clerk-js/src/core/resources/OrganizationInvitation.ts +++ b/packages/clerk-js/src/core/resources/OrganizationInvitation.ts @@ -1,7 +1,7 @@ import type { CreateBulkOrganizationInvitationParams, CreateOrganizationInvitationParams, - MembershipRole, + OrganizationCustomRoleKey, OrganizationInvitationJSON, OrganizationInvitationResource, OrganizationInvitationStatus, @@ -16,7 +16,7 @@ export class OrganizationInvitation extends BaseResource implements Organization organizationId!: string; publicMetadata: OrganizationInvitationPublicMetadata = {}; status!: OrganizationInvitationStatus; - role!: MembershipRole; + role!: OrganizationCustomRoleKey; createdAt!: Date; updatedAt!: Date; diff --git a/packages/clerk-js/src/core/resources/OrganizationMembership.ts b/packages/clerk-js/src/core/resources/OrganizationMembership.ts index a6815fb896e..1dbcfcaa0e1 100644 --- a/packages/clerk-js/src/core/resources/OrganizationMembership.ts +++ b/packages/clerk-js/src/core/resources/OrganizationMembership.ts @@ -2,7 +2,7 @@ import type { ClerkPaginatedResponse, ClerkResourceReloadParams, GetUserOrganizationMembershipParams, - MembershipRole, + OrganizationCustomRoleKey, OrganizationMembershipJSON, OrganizationMembershipResource, OrganizationPermissionKey, @@ -18,7 +18,7 @@ export class OrganizationMembership extends BaseResource implements Organization publicUserData!: PublicUserData; organization!: Organization; permissions: OrganizationPermissionKey[] = []; - role!: MembershipRole; + role!: OrganizationCustomRoleKey; createdAt!: Date; updatedAt!: Date; @@ -117,7 +117,7 @@ export class OrganizationMembership extends BaseResource implements Organization } export type UpdateOrganizationMembershipParams = { - role: MembershipRole; + role: OrganizationCustomRoleKey; }; export type GetOrganizationMembershipsClass = ( diff --git a/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts b/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts index 074a5af4d8d..dc795224dc6 100644 --- a/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts +++ b/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts @@ -1,7 +1,7 @@ import type { ClerkPaginatedResponse, GetUserOrganizationInvitationsParams, - MembershipRole, + OrganizationCustomRoleKey, OrganizationInvitationStatus, UserOrganizationInvitationJSON, UserOrganizationInvitationResource, @@ -17,7 +17,7 @@ export class UserOrganizationInvitation extends BaseResource implements UserOrga publicOrganizationData!: UserOrganizationInvitationResource['publicOrganizationData']; publicMetadata: OrganizationInvitationPublicMetadata = {}; status!: OrganizationInvitationStatus; - role!: MembershipRole; + role!: OrganizationCustomRoleKey; createdAt!: Date; updatedAt!: Date; diff --git a/packages/clerk-js/src/ui/common/Gate.tsx b/packages/clerk-js/src/ui/common/Gate.tsx index 9aefb2801d1..79d513bdadc 100644 --- a/packages/clerk-js/src/ui/common/Gate.tsx +++ b/packages/clerk-js/src/ui/common/Gate.tsx @@ -1,5 +1,5 @@ import { useSession } from '@clerk/shared/react'; -import type { CheckAuthorization, MembershipRole, OrganizationPermissionKey } from '@clerk/types'; +import type { CheckAuthorization, OrganizationCustomRoleKey, OrganizationPermissionKey } from '@clerk/types'; import type { ComponentType, PropsWithChildren, ReactNode } from 'react'; import React, { useEffect } from 'react'; @@ -10,7 +10,7 @@ type GateProps = PropsWithChildren< ( | { condition?: never; - role: MembershipRole; + role: OrganizationCustomRoleKey; permission?: never; } | { diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/InviteMembersForm.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/InviteMembersForm.tsx index 275317b146c..70bcccfee5c 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/InviteMembersForm.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/InviteMembersForm.tsx @@ -1,6 +1,6 @@ import { isClerkAPIResponseError } from '@clerk/shared/error'; import { useOrganization } from '@clerk/shared/react'; -import type { ClerkAPIError, MembershipRole } from '@clerk/types'; +import type { ClerkAPIError } from '@clerk/types'; import type { FormEvent } from 'react'; import { useState } from 'react'; @@ -76,7 +76,7 @@ export const InviteMembersForm = (props: InviteMembersFormProps) => { return organization .inviteMembers({ emailAddresses: emailAddressField.value.split(','), - role: submittedData.get('role') as MembershipRole, + role: submittedData.get('role') as string, }) .then(async () => { await invitations?.revalidate?.(); diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/MemberListTable.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/MemberListTable.tsx index d5e491271fe..38eb8200382 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/MemberListTable.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/MemberListTable.tsx @@ -1,4 +1,3 @@ -import type { MembershipRole } from '@clerk/types'; import React, { useMemo } from 'react'; import type { LocalizationKey } from '../../customizables'; @@ -121,7 +120,7 @@ export const RowContainer = (props: PropsOfComponent) => { export const RoleSelect = (props: { roles: { label: string; value: string }[] | undefined; - value: MembershipRole; + value: string; onChange: (params: string) => unknown; isDisabled?: boolean; triggerSx?: ThemableCssProp; diff --git a/packages/clerk-js/src/ui/utils/roleLocalizationKey.ts b/packages/clerk-js/src/ui/utils/roleLocalizationKey.ts index 3e4d01930dd..756b2ae8793 100644 --- a/packages/clerk-js/src/ui/utils/roleLocalizationKey.ts +++ b/packages/clerk-js/src/ui/utils/roleLocalizationKey.ts @@ -1,22 +1,23 @@ -import type { MembershipRole } from '@clerk/types'; - import type { LocalizationKey } from '../localization/localizationKeys'; import { localizationKeys } from '../localization/localizationKeys'; -const roleToLocalizationKey: Record = { +const roleToLocalizationKey: Record = { + /** + * These are old role keys. We still need to support localization for those to avoid breaking labels in UI components for old instances. + */ basic_member: localizationKeys('membershipRole__basicMember'), guest_member: localizationKeys('membershipRole__guestMember'), admin: localizationKeys('membershipRole__admin'), }; -export const roleLocalizationKey = (role: MembershipRole | undefined): LocalizationKey | undefined => { +export const roleLocalizationKey = (role: string | undefined): LocalizationKey | undefined => { if (!role) { return undefined; } return roleToLocalizationKey[role]; }; -export const customRoleLocalizationKey = (role: MembershipRole | undefined): LocalizationKey | undefined => { +export const customRoleLocalizationKey = (role: string | undefined): LocalizationKey | undefined => { if (!role) { return undefined; } diff --git a/packages/react/src/hooks/useAuth.ts b/packages/react/src/hooks/useAuth.ts index 3a0ff00ea96..2702bba50b6 100644 --- a/packages/react/src/hooks/useAuth.ts +++ b/packages/react/src/hooks/useAuth.ts @@ -2,7 +2,7 @@ import type { ActJWTClaim, CheckAuthorizationWithCustomPermissions, GetToken, - MembershipRole, + OrganizationCustomRoleKey, SignOut, } from '@clerk/types'; import { useCallback } from 'react'; @@ -64,7 +64,7 @@ type UseAuthReturn = sessionId: string; actor: ActJWTClaim | null; orgId: string; - orgRole: MembershipRole; + orgRole: OrganizationCustomRoleKey; orgSlug: string | null; has: CheckAuthorizationWithCustomPermissions; signOut: SignOut; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 67ffefcfd13..bd5f4a4f4c2 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -15,7 +15,7 @@ import type { DisplayThemeJSON } from './json'; import type { LocalizationResource } from './localization'; import type { OAuthProvider, OAuthScope } from './oauth'; import type { OrganizationResource } from './organization'; -import type { MembershipRole } from './organizationMembership'; +import type { OrganizationCustomRoleKey } from './organizationMembership'; import type { ActiveSessionResource } from './session'; import type { UserResource } from './user'; import type { Autocomplete, DeepPartial, DeepSnakeToCamel } from './utils'; @@ -935,12 +935,12 @@ export interface HandleEmailLinkVerificationParams { export type CreateOrganizationInvitationParams = { emailAddress: string; - role: MembershipRole; + role: OrganizationCustomRoleKey; }; export type CreateBulkOrganizationInvitationParams = { emailAddresses: string[]; - role: MembershipRole; + role: OrganizationCustomRoleKey; }; export interface CreateOrganizationParams { diff --git a/packages/types/src/json.ts b/packages/types/src/json.ts index 6e42a887d7f..92ae931a377 100644 --- a/packages/types/src/json.ts +++ b/packages/types/src/json.ts @@ -7,7 +7,7 @@ import type { ActJWTClaim } from './jwt'; import type { OAuthProvider } from './oauth'; import type { OrganizationDomainVerificationStatus, OrganizationEnrollmentMode } from './organizationDomain'; import type { OrganizationInvitationStatus } from './organizationInvitation'; -import type { MembershipRole, OrganizationPermissionKey } from './organizationMembership'; +import type { OrganizationCustomRoleKey, OrganizationPermissionKey } from './organizationMembership'; import type { OrganizationSettingsJSON } from './organizationSettings'; import type { OrganizationSuggestionStatus } from './organizationSuggestion'; import type { SamlIdpSlug } from './saml'; @@ -303,7 +303,7 @@ export interface OrganizationMembershipJSON extends ClerkResourceJSON { permissions: OrganizationPermissionKey[]; public_metadata: OrganizationMembershipPublicMetadata; public_user_data: PublicUserDataJSON; - role: MembershipRole; + role: OrganizationCustomRoleKey; created_at: number; updated_at: number; } @@ -315,7 +315,7 @@ export interface OrganizationInvitationJSON extends ClerkResourceJSON { organization_id: string; public_metadata: OrganizationInvitationPublicMetadata; status: OrganizationInvitationStatus; - role: MembershipRole; + role: OrganizationCustomRoleKey; created_at: number; updated_at: number; } @@ -403,7 +403,7 @@ export interface UserOrganizationInvitationJSON extends ClerkResourceJSON { public_organization_data: PublicOrganizationDataJSON; public_metadata: OrganizationInvitationPublicMetadata; status: OrganizationInvitationStatus; - role: MembershipRole; + role: OrganizationCustomRoleKey; created_at: number; updated_at: number; } diff --git a/packages/types/src/jwt.ts b/packages/types/src/jwt.ts index 0faf90999d8..3b078fd2986 100644 --- a/packages/types/src/jwt.ts +++ b/packages/types/src/jwt.ts @@ -1,4 +1,4 @@ -import type { MembershipRole } from './organizationMembership'; +import type { OrganizationCustomRoleKey } from './organizationMembership'; export interface JWT { encoded: { header: string; payload: string; signature: string }; @@ -84,7 +84,7 @@ export interface ClerkJWTClaims { /** * Active organization role */ - org_role?: MembershipRole; + org_role?: OrganizationCustomRoleKey; /** * Any other JWT Claim Set member. @@ -100,4 +100,4 @@ export interface ActJWTClaim { [x: string]: unknown; } -export type OrganizationsJWTClaim = Record; +export type OrganizationsJWTClaim = Record; diff --git a/packages/types/src/jwtv2.ts b/packages/types/src/jwtv2.ts index f1acea3d9bd..08c12d1b97f 100644 --- a/packages/types/src/jwtv2.ts +++ b/packages/types/src/jwtv2.ts @@ -1,4 +1,4 @@ -import type { MembershipRole, OrganizationCustomPermissionKey } from './organizationMembership'; +import type { OrganizationCustomPermissionKey, OrganizationCustomRoleKey } from './organizationMembership'; export interface Jwt { header: JwtHeader; @@ -94,7 +94,7 @@ export interface JwtPayload extends CustomJwtSessionClaims { /** * Active organization role */ - org_role?: MembershipRole; + org_role?: OrganizationCustomRoleKey; /** * Active organization role diff --git a/packages/types/src/organization.ts b/packages/types/src/organization.ts index ff5e43fe6c0..41a1396f071 100644 --- a/packages/types/src/organization.ts +++ b/packages/types/src/organization.ts @@ -1,6 +1,6 @@ import type { OrganizationDomainResource, OrganizationEnrollmentMode } from './organizationDomain'; import type { OrganizationInvitationResource, OrganizationInvitationStatus } from './organizationInvitation'; -import type { MembershipRole, OrganizationMembershipResource } from './organizationMembership'; +import type { OrganizationCustomRoleKey, OrganizationMembershipResource } from './organizationMembership'; import type { OrganizationMembershipRequestResource } from './organizationMembershipRequest'; import type { ClerkPaginatedResponse, ClerkPaginationParams } from './pagination'; import type { ClerkResource } from './resource'; @@ -67,7 +67,7 @@ export interface OrganizationResource extends ClerkResource { export type GetRolesParams = ClerkPaginationParams; export type GetMembersParams = ClerkPaginationParams<{ - role?: MembershipRole[]; + role?: OrganizationCustomRoleKey[]; }>; export type GetDomainsParams = ClerkPaginationParams<{ @@ -84,22 +84,22 @@ export type GetMembershipRequestParams = ClerkPaginationParams<{ export interface AddMemberParams { userId: string; - role: MembershipRole; + role: OrganizationCustomRoleKey; } export interface InviteMemberParams { emailAddress: string; - role: MembershipRole; + role: OrganizationCustomRoleKey; } export interface InviteMembersParams { emailAddresses: string[]; - role: MembershipRole; + role: OrganizationCustomRoleKey; } export interface UpdateMembershipParams { userId: string; - role: MembershipRole; + role: OrganizationCustomRoleKey; } export interface UpdateOrganizationParams { diff --git a/packages/types/src/organizationInvitation.ts b/packages/types/src/organizationInvitation.ts index 9c5bb2a5705..8873faf1495 100644 --- a/packages/types/src/organizationInvitation.ts +++ b/packages/types/src/organizationInvitation.ts @@ -1,4 +1,4 @@ -import type { MembershipRole } from './organizationMembership'; +import type { OrganizationCustomRoleKey } from './organizationMembership'; import type { ClerkResource } from './resource'; declare global { @@ -21,7 +21,7 @@ export interface OrganizationInvitationResource extends ClerkResource { emailAddress: string; organizationId: string; publicMetadata: OrganizationInvitationPublicMetadata; - role: MembershipRole; + role: OrganizationCustomRoleKey; status: OrganizationInvitationStatus; createdAt: Date; updatedAt: Date; diff --git a/packages/types/src/organizationMembership.ts b/packages/types/src/organizationMembership.ts index c74e7475b0c..75edd435d2d 100644 --- a/packages/types/src/organizationMembership.ts +++ b/packages/types/src/organizationMembership.ts @@ -43,7 +43,7 @@ export interface OrganizationMembershipResource extends ClerkResource { permissions: OrganizationPermissionKey[]; publicMetadata: OrganizationMembershipPublicMetadata; publicUserData: PublicUserData; - role: MembershipRole; + role: OrganizationCustomRoleKey; createdAt: Date; updatedAt: Date; destroy: () => Promise; @@ -56,24 +56,15 @@ export type OrganizationCustomPermissionKey = ClerkAuthorization extends Placeho : Base['permission'] : Base['permission']; +/** + * OrganizationCustomRoleKey will be string unless the developer has provided their own types through `ClerkAuthorization` + */ export type OrganizationCustomRoleKey = ClerkAuthorization extends Placeholder ? ClerkAuthorization['role'] extends string ? ClerkAuthorization['role'] : Base['role'] : Base['role']; -/** - * @deprecated This type is deprecated and will be removed in the next major release. - * Use `OrganizationCustomRoleKey` instead. - * MembershipRole includes `admin`, `basic_member`, `guest_member`. With the introduction of "Custom roles" - * these types will no longer match a developer's custom logic. - */ -export type MembershipRole = ClerkAuthorization extends Placeholder - ? ClerkAuthorization['role'] extends string - ? ClerkAuthorization['role'] | 'admin' | 'basic_member' | 'guest_member' - : Autocomplete<'admin' | 'basic_member' | 'guest_member'> - : Autocomplete<'admin' | 'basic_member' | 'guest_member'>; - export type OrganizationSystemPermissionKey = | 'org:sys_domains:manage' | 'org:sys_profile:manage' @@ -93,5 +84,5 @@ export type OrganizationPermissionKey = ClerkAuthorization extends Placeholder : Autocomplete; export type UpdateOrganizationMembershipParams = { - role: MembershipRole; + role: OrganizationCustomRoleKey; }; diff --git a/packages/types/src/session.ts b/packages/types/src/session.ts index ee493e5499b..3d29092b168 100644 --- a/packages/types/src/session.ts +++ b/packages/types/src/session.ts @@ -1,6 +1,5 @@ import type { ActJWTClaim } from './jwt'; import type { - MembershipRole, OrganizationCustomPermissionKey, OrganizationCustomRoleKey, OrganizationPermissionKey, @@ -28,7 +27,7 @@ export type CheckAuthorization = CheckAuthorizationFn; type CheckAuthorizationParams = | { - role: MembershipRole; + role: OrganizationCustomRoleKey; permission?: never; } | { diff --git a/packages/types/src/ssr.ts b/packages/types/src/ssr.ts index 7f69f07e674..1acd9d36bb0 100644 --- a/packages/types/src/ssr.ts +++ b/packages/types/src/ssr.ts @@ -1,6 +1,6 @@ import type { ActClaim, JwtPayload } from './jwtv2'; import type { OrganizationResource } from './organization'; -import type { MembershipRole, OrganizationCustomPermissionKey } from './organizationMembership'; +import type { OrganizationCustomPermissionKey, OrganizationCustomRoleKey } from './organizationMembership'; import type { SessionResource } from './session'; import type { UserResource } from './user'; import type { Serializable } from './utils'; @@ -16,7 +16,7 @@ export type InitialState = Serializable<{ userId: string | undefined; user: UserResource | undefined; orgId: string | undefined; - orgRole: MembershipRole | undefined; + orgRole: OrganizationCustomRoleKey | undefined; orgSlug: string | undefined; orgPermissions: OrganizationCustomPermissionKey[] | undefined; organization: OrganizationResource | undefined; diff --git a/packages/types/src/userOrganizationInvitation.ts b/packages/types/src/userOrganizationInvitation.ts index baff1f268d4..3a5707bd1c1 100644 --- a/packages/types/src/userOrganizationInvitation.ts +++ b/packages/types/src/userOrganizationInvitation.ts @@ -1,5 +1,5 @@ import type { OrganizationInvitationStatus } from './organizationInvitation'; -import type { MembershipRole } from './organizationMembership'; +import type { OrganizationCustomRoleKey } from './organizationMembership'; import type { ClerkResource } from './resource'; declare global { @@ -28,7 +28,7 @@ export interface UserOrganizationInvitationResource extends ClerkResource { slug: string | null; }; publicMetadata: UserOrganizationInvitationPublicMetadata; - role: MembershipRole; + role: OrganizationCustomRoleKey; status: OrganizationInvitationStatus; createdAt: Date; updatedAt: Date;