Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/tame-forks-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@clerk/backend": patch
"@clerk/types": patch
---

Introduces the CRUD of organization domains under the `organizations` API.
75 changes: 74 additions & 1 deletion packages/backend/src/api/endpoints/OrganizationApi.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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<CreateOrganizationDomainParams>;

type DeleteOrganizationDomainParams = {
organizationId: string;
domainId: string;
};

export class OrganizationAPI extends AbstractAPI {
public async getOrganizationList(params?: GetOrganizationListParams) {
return this.request<PaginatedResourceResponse<Organization[]>>({
Expand Down Expand Up @@ -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<PaginatedResourceResponse<OrganizationDomain[]>>({
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<OrganizationDomain>({
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<OrganizationDomain>({
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<OrganizationDomain>({
method: 'DELETE',
path: joinPaths(basePath, organizationId, 'domains', domainId),
});
}
}
33 changes: 33 additions & 0 deletions packages/backend/src/api/resources/OrganizationDomain.ts
Original file line number Diff line number Diff line change
@@ -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,
);
}
}
15 changes: 15 additions & 0 deletions packages/backend/src/api/resources/Verification.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { OrganizationDomainVerificationJSON } from '@clerk/types';

import type { VerificationJSON } from './JSON';

export class Verification {
Expand All @@ -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);
}
}
2 changes: 2 additions & 0 deletions packages/backend/src/api/resources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ export type {
WebhookEvent,
WebhookEventType,
} from './Webhooks';

export * from './OrganizationDomain';
2 changes: 1 addition & 1 deletion packages/types/src/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down