diff --git a/.changeset/swift-rocks-nail.md b/.changeset/swift-rocks-nail.md new file mode 100644 index 0000000000..b37f9affbc --- /dev/null +++ b/.changeset/swift-rocks-nail.md @@ -0,0 +1,7 @@ +--- +'@clerk/clerk-sdk-node': patch +'@clerk/backend': patch +'@clerk/nextjs': patch +--- + +Add OrganizationPermissionAPI for CRUD operations regarding instance level organization permissions. diff --git a/packages/backend/src/api/endpoints/OrganizationPermissionApi.ts b/packages/backend/src/api/endpoints/OrganizationPermissionApi.ts new file mode 100644 index 0000000000..64e7ee66e5 --- /dev/null +++ b/packages/backend/src/api/endpoints/OrganizationPermissionApi.ts @@ -0,0 +1,69 @@ +import { joinPaths } from '../../util/path'; +import type { DeletedObject, Permission } from '../resources'; +import { AbstractAPI } from './AbstractApi'; + +const basePath = '/organizations_permissions'; + +type GetOrganizationPermissionListParams = { + limit?: number; + offset?: number; + query?: string; + orderBy?: string; +}; + +type CreateParams = { + name: string; + key: string; + description: string; +}; + +type GetOrganizationPermissionParams = { permissionId: string }; + +type UpdateParams = { + name?: string; + key?: string; + description?: string; +}; + +export class OrganizationPermissionAPI extends AbstractAPI { + public async getOrganizationPermissionList(params?: GetOrganizationPermissionListParams) { + return this.request({ + method: 'GET', + path: basePath, + queryParams: params, + }); + } + + public async createOrganizationPermission(params: CreateParams) { + return this.request({ + method: 'POST', + path: basePath, + bodyParams: params, + }); + } + + public async getOrganizationPermission(params: GetOrganizationPermissionParams) { + this.requireId(params.permissionId); + + return this.request({ + method: 'GET', + path: joinPaths(basePath, params.permissionId), + }); + } + + public async updateOrganizationPermission(permissionId: string, params: UpdateParams) { + this.requireId(permissionId); + return this.request({ + method: 'PATCH', + path: joinPaths(basePath, permissionId), + bodyParams: params, + }); + } + + public async deleteOrganizationPermission(permissionId: string) { + return this.request({ + method: 'DELETE', + path: joinPaths(basePath, permissionId), + }); + } +} diff --git a/packages/backend/src/api/endpoints/index.ts b/packages/backend/src/api/endpoints/index.ts index bd05e6af47..a498b1e835 100644 --- a/packages/backend/src/api/endpoints/index.ts +++ b/packages/backend/src/api/endpoints/index.ts @@ -7,6 +7,7 @@ export * from './EmailApi'; export * from './InterstitialApi'; export * from './InvitationApi'; export * from './OrganizationApi'; +export * from './OrganizationPermissionApi'; export * from './PhoneNumberApi'; export * from './RedirectUrlApi'; export * from './SessionApi'; diff --git a/packages/backend/src/api/factory.ts b/packages/backend/src/api/factory.ts index e187b82ebf..d616e23243 100644 --- a/packages/backend/src/api/factory.ts +++ b/packages/backend/src/api/factory.ts @@ -7,6 +7,7 @@ import { InterstitialAPI, InvitationAPI, OrganizationAPI, + OrganizationPermissionAPI, PhoneNumberAPI, RedirectUrlAPI, SessionAPI, @@ -22,7 +23,6 @@ export type ApiClient = ReturnType; export function createBackendApiClient(options: CreateBackendApiOptions) { const request = buildRequest(options); - return { allowlistIdentifiers: new AllowlistIdentifierAPI(request), clients: new ClientAPI(request), @@ -31,6 +31,7 @@ export function createBackendApiClient(options: CreateBackendApiOptions) { interstitial: new InterstitialAPI(request), invitations: new InvitationAPI(request), organizations: new OrganizationAPI(request), + organizationPermissions: new OrganizationPermissionAPI(request), phoneNumbers: new PhoneNumberAPI(request), redirectUrls: new RedirectUrlAPI(request), sessions: new SessionAPI(request), diff --git a/packages/backend/src/api/resources/Enums.ts b/packages/backend/src/api/resources/Enums.ts index 7cc6005377..160514d4e3 100644 --- a/packages/backend/src/api/resources/Enums.ts +++ b/packages/backend/src/api/resources/Enums.ts @@ -20,6 +20,11 @@ export type OAuthStrategy = `oauth_${OAuthProvider}`; export type OrganizationInvitationStatus = 'pending' | 'accepted' | 'revoked'; +export type PermissionType = 'system' | 'user'; + +/** + * @deprecated In the next major release this type will change to string + */ export type OrganizationMembershipRole = 'basic_member' | 'guest_member' | 'admin'; export type SignInStatus = 'needs_identifier' | 'needs_factor_one' | 'needs_factor_two' | 'complete'; diff --git a/packages/backend/src/api/resources/JSON.ts b/packages/backend/src/api/resources/JSON.ts index a0f56731fb..41113c9470 100644 --- a/packages/backend/src/api/resources/JSON.ts +++ b/packages/backend/src/api/resources/JSON.ts @@ -2,6 +2,7 @@ import type { InvitationStatus, OrganizationInvitationStatus, OrganizationMembershipRole, + PermissionType, SignInStatus, SignUpAttributeRequirements, SignUpStatus, @@ -20,6 +21,7 @@ export enum ObjectType { Organization = 'organization', OrganizationInvitation = 'organization_invitation', OrganizationMembership = 'organization_membership', + Permission = 'permission', PhoneNumber = 'phone_number', RedirectUrl = 'redirect_url', Session = 'session', @@ -172,6 +174,17 @@ export interface OrganizationMembershipPublicUserDataJSON { user_id: string; } +export interface PermissionJSON extends ClerkResourceJSON { + object: ObjectType.Permission; + id: string; + name: string; + key: string; + description: string; + type: PermissionType; + created_at: number; + updated_at: number; +} + export interface PhoneNumberJSON extends ClerkResourceJSON { object: ObjectType.PhoneNumber; phone_number: string; diff --git a/packages/backend/src/api/resources/Permission.ts b/packages/backend/src/api/resources/Permission.ts new file mode 100644 index 0000000000..7124643801 --- /dev/null +++ b/packages/backend/src/api/resources/Permission.ts @@ -0,0 +1,18 @@ +import type { PermissionType } from './Enums'; +import type { PermissionJSON } from './JSON'; + +export class Permission { + constructor( + readonly id: string, + readonly name: string, + readonly key: string, + readonly description: string, + readonly type: PermissionType, + readonly createdAt: number, + readonly updatedAt: number, + ) {} + + static fromJSON(data: PermissionJSON) { + return new Permission(data.id, data.name, data.key, data.description, data.type, data.created_at, data.updated_at); + } +} diff --git a/packages/backend/src/api/resources/index.ts b/packages/backend/src/api/resources/index.ts index 936494c56e..14d0367f98 100644 --- a/packages/backend/src/api/resources/index.ts +++ b/packages/backend/src/api/resources/index.ts @@ -22,6 +22,7 @@ export * from './Invitation'; export * from './JSON'; export * from './OauthAccessToken'; export * from './Organization'; +export * from './Permission'; export * from './OrganizationInvitation'; export * from './OrganizationMembership'; export * from './PhoneNumber'; diff --git a/packages/backend/src/exports.test.ts b/packages/backend/src/exports.test.ts index 5201a7d2eb..8ad994591b 100644 --- a/packages/backend/src/exports.test.ts +++ b/packages/backend/src/exports.test.ts @@ -24,6 +24,7 @@ export default (QUnit: QUnit) => { 'OrganizationInvitation', 'OrganizationMembership', 'OrganizationMembershipPublicUserData', + 'Permission', 'PhoneNumber', 'RedirectUrl', 'SMSMessage', diff --git a/packages/nextjs/src/server/__tests__/__snapshots__/exports.test.ts.snap b/packages/nextjs/src/server/__tests__/__snapshots__/exports.test.ts.snap index 5c587ad57e..03027bdabb 100644 --- a/packages/nextjs/src/server/__tests__/__snapshots__/exports.test.ts.snap +++ b/packages/nextjs/src/server/__tests__/__snapshots__/exports.test.ts.snap @@ -18,6 +18,7 @@ exports[`/server public exports should not include a breaking change 1`] = ` "OrganizationInvitation", "OrganizationMembership", "OrganizationMembershipPublicUserData", + "Permission", "PhoneNumber", "RedirectUrl", "SMSMessage", diff --git a/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap b/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap index 4ab27968dd..d1d6e5a069 100644 --- a/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap +++ b/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap @@ -20,6 +20,7 @@ exports[`module exports should not change unless explicitly set 1`] = ` "OrganizationInvitation", "OrganizationMembership", "OrganizationMembershipPublicUserData", + "Permission", "PhoneNumber", "RedirectUrl", "SMSMessage", @@ -52,6 +53,7 @@ exports[`module exports should not change unless explicitly set 1`] = ` "invitations", "loadInterstitialFromLocal", "makeAuthObjectSerializable", + "organizationPermissions", "organizations", "phoneNumbers", "prunePrivateMetadata", diff --git a/packages/sdk-node/src/index.ts b/packages/sdk-node/src/index.ts index dd156938f4..b2729cee52 100644 --- a/packages/sdk-node/src/index.ts +++ b/packages/sdk-node/src/index.ts @@ -27,6 +27,7 @@ const { emails, invitations, organizations, + organizationPermissions, clients, allowlistIdentifiers, domains, @@ -40,6 +41,7 @@ export { emails, invitations, organizations, + organizationPermissions, phoneNumbers, sessions, smsMessages,