diff --git a/.changeset/tame-forks-type.md b/.changeset/tame-forks-type.md new file mode 100644 index 0000000000..f3a28812a6 --- /dev/null +++ b/.changeset/tame-forks-type.md @@ -0,0 +1,6 @@ +--- +"@clerk/backend": patch +"@clerk/types": patch +--- + +Introduces the CRUD of organization domains under the `organizations` API. diff --git a/packages/backend/src/api/endpoints/OrganizationApi.ts b/packages/backend/src/api/endpoints/OrganizationApi.ts index b11b4d0657..b86e2cb238 100644 --- a/packages/backend/src/api/endpoints/OrganizationApi.ts +++ b/packages/backend/src/api/endpoints/OrganizationApi.ts @@ -1,9 +1,10 @@ -import type { ClerkPaginationRequest } from '@clerk/types'; +import type { ClerkPaginationRequest, OrganizationEnrollmentMode } from '@clerk/types'; import runtime from '../../runtime'; import { joinPaths } from '../../util/path'; import type { Organization, + OrganizationDomain, OrganizationInvitation, OrganizationInvitationStatus, OrganizationMembership, @@ -99,6 +100,29 @@ type RevokeOrganizationInvitationParams = { requestingUserId: string; }; +type GetOrganizationDomainListParams = { + organizationId: string; + limit?: number; + offset?: number; +}; + +type CreateOrganizationDomainParams = { + organizationId: string; + name: string; + enrollmentMode: OrganizationEnrollmentMode; + verified?: boolean; +}; + +type UpdateOrganizationDomainParams = { + organizationId: string; + domainId: string; +} & Partial; + +type DeleteOrganizationDomainParams = { + organizationId: string; + domainId: string; +}; + export class OrganizationAPI extends AbstractAPI { public async getOrganizationList(params?: GetOrganizationListParams) { return this.request>({ @@ -285,4 +309,53 @@ export class OrganizationAPI extends AbstractAPI { }, }); } + + public async getOrganizationDomainList(params: GetOrganizationDomainListParams) { + const { organizationId, limit, offset } = params; + this.requireId(organizationId); + + return this.request>({ + method: 'GET', + path: joinPaths(basePath, organizationId, 'domains'), + queryParams: { limit, offset }, + }); + } + + public async createOrganizationDomain(params: CreateOrganizationDomainParams) { + const { organizationId, name, enrollmentMode, verified = true } = params; + this.requireId(organizationId); + + return this.request({ + method: 'POST', + path: joinPaths(basePath, organizationId, 'domains'), + bodyParams: { + name, + enrollmentMode, + verified, + }, + }); + } + + public async updateOrganizationDomain(params: UpdateOrganizationDomainParams) { + const { organizationId, domainId, ...bodyParams } = params; + this.requireId(organizationId); + this.requireId(domainId); + + return this.request({ + method: 'PATCH', + path: joinPaths(basePath, organizationId, 'domains', domainId), + bodyParams, + }); + } + + public async deleteOrganizationDomain(params: DeleteOrganizationDomainParams) { + const { organizationId, domainId } = params; + this.requireId(organizationId); + this.requireId(domainId); + + return this.request({ + method: 'DELETE', + path: joinPaths(basePath, organizationId, 'domains', domainId), + }); + } } diff --git a/packages/backend/src/api/resources/OrganizationDomain.ts b/packages/backend/src/api/resources/OrganizationDomain.ts new file mode 100644 index 0000000000..c9baddeee1 --- /dev/null +++ b/packages/backend/src/api/resources/OrganizationDomain.ts @@ -0,0 +1,33 @@ +import type { OrganizationDomainJSON, OrganizationEnrollmentMode } from '@clerk/types'; + +import { OrganizationDomainVerification } from './Verification'; + +export class OrganizationDomain { + constructor( + readonly id: string, + readonly organizationId: string, + readonly name: string, + readonly enrollmentMode: OrganizationEnrollmentMode, + readonly verification: OrganizationDomainVerification | null, + readonly totalPendingInvitations: number, + readonly totalPendingSuggestions: number, + readonly createdAt: number, + readonly updatedAt: number, + readonly affiliationEmailAddress: string | null, + ) {} + + static fromJSON(data: OrganizationDomainJSON) { + return new OrganizationDomain( + data.id, + data.organization_id, + data.name, + data.enrollment_mode, + data.verification && OrganizationDomainVerification.fromJSON(data.verification), + data.total_pending_invitations, + data.total_pending_suggestions, + data.created_at, + data.updated_at, + data.affiliation_email_address, + ); + } +} diff --git a/packages/backend/src/api/resources/Verification.ts b/packages/backend/src/api/resources/Verification.ts index c6015812dd..35cbfb4d36 100644 --- a/packages/backend/src/api/resources/Verification.ts +++ b/packages/backend/src/api/resources/Verification.ts @@ -1,3 +1,5 @@ +import type { OrganizationDomainVerificationJSON } from '@clerk/types'; + import type { VerificationJSON } from './JSON'; export class Verification { @@ -21,3 +23,16 @@ export class Verification { ); } } + +export class OrganizationDomainVerification { + constructor( + readonly status: string, + readonly strategy: string, + readonly attempts: number | null = null, + readonly expireAt: number | null = null, + ) {} + + static fromJSON(data: OrganizationDomainVerificationJSON): OrganizationDomainVerification { + return new OrganizationDomainVerification(data.status, data.strategy, data.attempts, data.expires_at); + } +} diff --git a/packages/backend/src/api/resources/index.ts b/packages/backend/src/api/resources/index.ts index 4652a7e8b2..9a0ec1a376 100644 --- a/packages/backend/src/api/resources/index.ts +++ b/packages/backend/src/api/resources/index.ts @@ -44,3 +44,5 @@ export type { WebhookEvent, WebhookEventType, } from './Webhooks'; + +export * from './OrganizationDomain'; diff --git a/packages/types/src/json.ts b/packages/types/src/json.ts index 3d0f1424b6..88a07f0077 100644 --- a/packages/types/src/json.ts +++ b/packages/types/src/json.ts @@ -353,7 +353,7 @@ export interface OrganizationInvitationJSON extends ClerkResourceJSON { updated_at: number; } -interface OrganizationDomainVerificationJSON { +export interface OrganizationDomainVerificationJSON { status: OrganizationDomainVerificationStatus; strategy: 'email_code'; // only available value for now attempts: number;