From 9110938802460a28112f9fb49698ff18787bd44e Mon Sep 17 00:00:00 2001 From: Colin Barber Date: Thu, 29 Jan 2026 14:59:17 -0400 Subject: [PATCH 1/6] feat: Add organization role support --- src/authorization/authorization.spec.ts | 207 ++++++++++++++++++ src/authorization/authorization.ts | 104 +++++++++ .../fixtures/list-organization-roles.json | 27 +++ .../fixtures/organization-role.json | 11 + ...ate-organization-role-options.interface.ts | 12 + src/authorization/interfaces/index.ts | 4 + ...st-organization-roles-options.interface.ts | 4 + .../interfaces/organization-role.interface.ts | 33 +++ ...ate-organization-role-options.interface.ts | 9 + ...te-organization-role-options.serializer.ts | 12 + src/authorization/serializers/index.ts | 3 + .../organization-role.serializer.ts | 18 ++ ...te-organization-role-options.serializer.ts | 11 + 13 files changed, 455 insertions(+) create mode 100644 src/authorization/fixtures/list-organization-roles.json create mode 100644 src/authorization/fixtures/organization-role.json create mode 100644 src/authorization/interfaces/create-organization-role-options.interface.ts create mode 100644 src/authorization/interfaces/list-organization-roles-options.interface.ts create mode 100644 src/authorization/interfaces/organization-role.interface.ts create mode 100644 src/authorization/interfaces/update-organization-role-options.interface.ts create mode 100644 src/authorization/serializers/create-organization-role-options.serializer.ts create mode 100644 src/authorization/serializers/organization-role.serializer.ts create mode 100644 src/authorization/serializers/update-organization-role-options.serializer.ts diff --git a/src/authorization/authorization.spec.ts b/src/authorization/authorization.spec.ts index 18fea2c10..8aa69d7e5 100644 --- a/src/authorization/authorization.spec.ts +++ b/src/authorization/authorization.spec.ts @@ -8,8 +8,11 @@ import { import { WorkOS } from '../workos'; import environmentRoleFixture from './fixtures/environment-role.json'; import listEnvironmentRolesFixture from './fixtures/list-environment-roles.json'; +import organizationRoleFixture from './fixtures/organization-role.json'; +import listOrganizationRolesFixture from './fixtures/list-organization-roles.json'; const workos = new WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU'); +const testOrgId = 'org_01HXYZ123ABC456DEF789ABC'; describe('Authorization', () => { beforeEach(() => fetch.resetMocks()); @@ -236,4 +239,208 @@ describe('Authorization', () => { ); }); }); + + // === Organization Roles === + + describe('createOrganizationRole', () => { + it('creates an organization role', async () => { + fetchOnce(organizationRoleFixture, { status: 201 }); + + const role = await workos.authorization.createOrganizationRole({ + organizationId: testOrgId, + slug: 'org-admin', + name: 'Org Admin', + description: 'Organization administrator', + }); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles`, + ); + expect(fetchBody()).toEqual({ + slug: 'org-admin', + name: 'Org Admin', + description: 'Organization administrator', + }); + expect(role).toMatchObject({ + object: 'role', + id: 'role_01HXYZ123ABC456DEF789ORG', + slug: 'org-admin', + name: 'Org Admin', + type: 'OrganizationRole', + }); + }); + }); + + describe('listOrganizationRoles', () => { + it('returns organization roles', async () => { + fetchOnce(listOrganizationRolesFixture); + + const { data, object } = await workos.authorization.listOrganizationRoles( + { organizationId: testOrgId }, + ); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles`, + ); + expect(object).toEqual('list'); + expect(data).toHaveLength(2); + expect(data).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + slug: 'org-admin', + type: 'OrganizationRole', + }), + expect.objectContaining({ + slug: 'org-member', + type: 'OrganizationRole', + }), + ]), + ); + }); + + it('passes expand parameter', async () => { + fetchOnce(listOrganizationRolesFixture); + + await workos.authorization.listOrganizationRoles({ + organizationId: testOrgId, + expand: 'permissions', + }); + + expect(fetchSearchParams()).toEqual({ + expand: 'permissions', + }); + }); + }); + + describe('getOrganizationRole', () => { + it('gets an organization role by slug', async () => { + fetchOnce(organizationRoleFixture); + + const role = await workos.authorization.getOrganizationRole( + testOrgId, + 'org-admin', + ); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles/org-admin`, + ); + expect(role).toMatchObject({ + object: 'role', + slug: 'org-admin', + type: 'OrganizationRole', + }); + }); + }); + + describe('updateOrganizationRole', () => { + it('updates an organization role', async () => { + const updatedRoleFixture = { + ...organizationRoleFixture, + name: 'Super Org Admin', + description: 'Updated description', + }; + fetchOnce(updatedRoleFixture); + + const role = await workos.authorization.updateOrganizationRole( + testOrgId, + 'org-admin', + { + name: 'Super Org Admin', + description: 'Updated description', + }, + ); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles/org-admin`, + ); + expect(fetchBody()).toEqual({ + name: 'Super Org Admin', + description: 'Updated description', + }); + expect(role).toMatchObject({ + name: 'Super Org Admin', + description: 'Updated description', + }); + }); + }); + + describe('deleteOrganizationRole', () => { + it('deletes an organization role', async () => { + fetchOnce({}, { status: 204 }); + + await workos.authorization.deleteOrganizationRole(testOrgId, 'org-admin'); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles/org-admin`, + ); + }); + }); + + describe('setOrganizationRolePermissions', () => { + it('sets permissions for an organization role', async () => { + const updatedRoleFixture = { + ...organizationRoleFixture, + permissions: ['org:read', 'org:write'], + }; + fetchOnce(updatedRoleFixture); + + const role = await workos.authorization.setOrganizationRolePermissions( + testOrgId, + 'org-admin', + ['org:read', 'org:write'], + ); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles/org-admin/permissions`, + ); + expect(fetchBody()).toEqual({ + permissions: ['org:read', 'org:write'], + }); + expect(role.permissions).toEqual( + expect.arrayContaining(['org:read', 'org:write']), + ); + }); + }); + + describe('addOrganizationRolePermission', () => { + it('adds a permission to an organization role', async () => { + const updatedRoleFixture = { + ...organizationRoleFixture, + permissions: ['org:manage', 'members:invite', 'billing:read'], + }; + fetchOnce(updatedRoleFixture); + + const role = await workos.authorization.addOrganizationRolePermission( + testOrgId, + 'org-admin', + 'billing:read', + ); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles/org-admin/permissions`, + ); + expect(fetchBody()).toEqual({ + slug: 'billing:read', + }); + expect(role.permissions).toEqual( + expect.arrayContaining(['billing:read']), + ); + }); + }); + + describe('removeOrganizationRolePermission', () => { + it('removes a permission from an organization role', async () => { + fetchOnce({}, { status: 200 }); + + await workos.authorization.removeOrganizationRolePermission( + testOrgId, + 'org-admin', + 'members:invite', + ); + + expect(fetchURL()).toContain( + `/authorization/organizations/${testOrgId}/roles/org-admin/permissions/members:invite`, + ); + }); + }); }); diff --git a/src/authorization/authorization.ts b/src/authorization/authorization.ts index 509a91666..86b445a69 100644 --- a/src/authorization/authorization.ts +++ b/src/authorization/authorization.ts @@ -9,16 +9,28 @@ import { ListEnvironmentRolesOptions, SetEnvironmentRolePermissionsOptions, AddEnvironmentRolePermissionOptions, + OrganizationRole, + OrganizationRoleResponse, + OrganizationRoleList, + OrganizationRoleListResponse, + CreateOrganizationRoleOptions, + UpdateOrganizationRoleOptions, + ListOrganizationRolesOptions, } from './interfaces'; import { deserializeEnvironmentRole, serializeCreateEnvironmentRoleOptions, serializeUpdateEnvironmentRoleOptions, + deserializeOrganizationRole, + serializeCreateOrganizationRoleOptions, + serializeUpdateOrganizationRoleOptions, } from './serializers'; export class Authorization { constructor(private readonly workos: WorkOS) {} + // === Environment Roles === + async createEnvironmentRole( options: CreateEnvironmentRoleOptions, ): Promise { @@ -81,4 +93,96 @@ export class Authorization { ); return deserializeEnvironmentRole(data); } + + // === Organization Roles === + + async createOrganizationRole( + options: CreateOrganizationRoleOptions, + ): Promise { + const { organizationId, ...payload } = options; + const { data } = await this.workos.post( + `/authorization/organizations/${organizationId}/roles`, + serializeCreateOrganizationRoleOptions(options), + ); + return deserializeOrganizationRole(data); + } + + async listOrganizationRoles( + options: ListOrganizationRolesOptions, + ): Promise { + const { organizationId, ...query } = options; + const { data } = await this.workos.get( + `/authorization/organizations/${organizationId}/roles`, + { query }, + ); + return { + object: 'list', + data: data.data.map(deserializeOrganizationRole), + }; + } + + async getOrganizationRole( + organizationId: string, + slug: string, + ): Promise { + const { data } = await this.workos.get( + `/authorization/organizations/${organizationId}/roles/${slug}`, + ); + return deserializeOrganizationRole(data); + } + + async updateOrganizationRole( + organizationId: string, + slug: string, + options: UpdateOrganizationRoleOptions, + ): Promise { + const { data } = await this.workos.patch( + `/authorization/organizations/${organizationId}/roles/${slug}`, + serializeUpdateOrganizationRoleOptions(options), + ); + return deserializeOrganizationRole(data); + } + + async deleteOrganizationRole( + organizationId: string, + slug: string, + ): Promise { + await this.workos.delete( + `/authorization/organizations/${organizationId}/roles/${slug}`, + ); + } + + async setOrganizationRolePermissions( + organizationId: string, + slug: string, + permissions: string[], + ): Promise { + const { data } = await this.workos.put( + `/authorization/organizations/${organizationId}/roles/${slug}/permissions`, + { permissions }, + ); + return deserializeOrganizationRole(data); + } + + async addOrganizationRolePermission( + organizationId: string, + slug: string, + permissionSlug: string, + ): Promise { + const { data } = await this.workos.post( + `/authorization/organizations/${organizationId}/roles/${slug}/permissions`, + { slug: permissionSlug }, + ); + return deserializeOrganizationRole(data); + } + + async removeOrganizationRolePermission( + organizationId: string, + slug: string, + permissionSlug: string, + ): Promise { + await this.workos.delete( + `/authorization/organizations/${organizationId}/roles/${slug}/permissions/${permissionSlug}`, + ); + } } diff --git a/src/authorization/fixtures/list-organization-roles.json b/src/authorization/fixtures/list-organization-roles.json new file mode 100644 index 000000000..939259ea4 --- /dev/null +++ b/src/authorization/fixtures/list-organization-roles.json @@ -0,0 +1,27 @@ +{ + "object": "list", + "data": [ + { + "object": "role", + "id": "role_01HXYZ123ABC456DEF789ORG", + "name": "Org Admin", + "slug": "org-admin", + "description": "Organization administrator", + "permissions": ["org:manage", "members:invite"], + "type": "OrganizationRole", + "created_at": "2024-01-15T09:30:00.000Z", + "updated_at": "2024-01-15T09:30:00.000Z" + }, + { + "object": "role", + "id": "role_01HXYZ123ABC456DEF789MEM", + "name": "Org Member", + "slug": "org-member", + "description": null, + "permissions": ["projects:read"], + "type": "OrganizationRole", + "created_at": "2024-01-15T10:00:00.000Z", + "updated_at": "2024-01-15T10:00:00.000Z" + } + ] +} diff --git a/src/authorization/fixtures/organization-role.json b/src/authorization/fixtures/organization-role.json new file mode 100644 index 000000000..0ae05d0cb --- /dev/null +++ b/src/authorization/fixtures/organization-role.json @@ -0,0 +1,11 @@ +{ + "object": "role", + "id": "role_01HXYZ123ABC456DEF789ORG", + "name": "Org Admin", + "slug": "org-admin", + "description": "Organization administrator", + "permissions": ["org:manage", "members:invite"], + "type": "OrganizationRole", + "created_at": "2024-01-15T09:30:00.000Z", + "updated_at": "2024-01-15T09:30:00.000Z" +} diff --git a/src/authorization/interfaces/create-organization-role-options.interface.ts b/src/authorization/interfaces/create-organization-role-options.interface.ts new file mode 100644 index 000000000..c938f3eff --- /dev/null +++ b/src/authorization/interfaces/create-organization-role-options.interface.ts @@ -0,0 +1,12 @@ +export interface CreateOrganizationRoleOptions { + organizationId: string; + slug: string; + name: string; + description?: string; +} + +export interface SerializedCreateOrganizationRoleOptions { + slug: string; + name: string; + description?: string; +} diff --git a/src/authorization/interfaces/index.ts b/src/authorization/interfaces/index.ts index 9750d53bc..d05e18438 100644 --- a/src/authorization/interfaces/index.ts +++ b/src/authorization/interfaces/index.ts @@ -4,3 +4,7 @@ export * from './update-environment-role-options.interface'; export * from './list-environment-roles-options.interface'; export * from './set-environment-role-permissions-options.interface'; export * from './add-environment-role-permission-options.interface'; +export * from './organization-role.interface'; +export * from './create-organization-role-options.interface'; +export * from './update-organization-role-options.interface'; +export * from './list-organization-roles-options.interface'; diff --git a/src/authorization/interfaces/list-organization-roles-options.interface.ts b/src/authorization/interfaces/list-organization-roles-options.interface.ts new file mode 100644 index 000000000..cf1d1f58a --- /dev/null +++ b/src/authorization/interfaces/list-organization-roles-options.interface.ts @@ -0,0 +1,4 @@ +export interface ListOrganizationRolesOptions { + organizationId: string; + expand?: 'permissions'; +} diff --git a/src/authorization/interfaces/organization-role.interface.ts b/src/authorization/interfaces/organization-role.interface.ts new file mode 100644 index 000000000..56b52290e --- /dev/null +++ b/src/authorization/interfaces/organization-role.interface.ts @@ -0,0 +1,33 @@ +export interface OrganizationRole { + object: 'role'; + id: string; + name: string; + slug: string; + description: string | null; + permissions: string[]; + type: 'OrganizationRole'; + createdAt: string; + updatedAt: string; +} + +export interface OrganizationRoleResponse { + object: 'role'; + id: string; + name: string; + slug: string; + description: string | null; + permissions: string[]; + type: 'OrganizationRole'; + created_at: string; + updated_at: string; +} + +export interface OrganizationRoleList { + object: 'list'; + data: OrganizationRole[]; +} + +export interface OrganizationRoleListResponse { + object: 'list'; + data: OrganizationRoleResponse[]; +} diff --git a/src/authorization/interfaces/update-organization-role-options.interface.ts b/src/authorization/interfaces/update-organization-role-options.interface.ts new file mode 100644 index 000000000..a2fd4a314 --- /dev/null +++ b/src/authorization/interfaces/update-organization-role-options.interface.ts @@ -0,0 +1,9 @@ +export interface UpdateOrganizationRoleOptions { + name?: string; + description?: string | null; +} + +export interface SerializedUpdateOrganizationRoleOptions { + name?: string; + description?: string | null; +} diff --git a/src/authorization/serializers/create-organization-role-options.serializer.ts b/src/authorization/serializers/create-organization-role-options.serializer.ts new file mode 100644 index 000000000..f97bcebe0 --- /dev/null +++ b/src/authorization/serializers/create-organization-role-options.serializer.ts @@ -0,0 +1,12 @@ +import { + CreateOrganizationRoleOptions, + SerializedCreateOrganizationRoleOptions, +} from '../interfaces/create-organization-role-options.interface'; + +export const serializeCreateOrganizationRoleOptions = ( + options: CreateOrganizationRoleOptions, +): SerializedCreateOrganizationRoleOptions => ({ + slug: options.slug, + name: options.name, + description: options.description, +}); diff --git a/src/authorization/serializers/index.ts b/src/authorization/serializers/index.ts index 8aad90ac3..5e0f4c741 100644 --- a/src/authorization/serializers/index.ts +++ b/src/authorization/serializers/index.ts @@ -1,3 +1,6 @@ export * from './environment-role.serializer'; export * from './create-environment-role-options.serializer'; export * from './update-environment-role-options.serializer'; +export * from './organization-role.serializer'; +export * from './create-organization-role-options.serializer'; +export * from './update-organization-role-options.serializer'; diff --git a/src/authorization/serializers/organization-role.serializer.ts b/src/authorization/serializers/organization-role.serializer.ts new file mode 100644 index 000000000..061f8da49 --- /dev/null +++ b/src/authorization/serializers/organization-role.serializer.ts @@ -0,0 +1,18 @@ +import { + OrganizationRole, + OrganizationRoleResponse, +} from '../interfaces/organization-role.interface'; + +export const deserializeOrganizationRole = ( + role: OrganizationRoleResponse, +): OrganizationRole => ({ + object: role.object, + id: role.id, + name: role.name, + slug: role.slug, + description: role.description, + permissions: role.permissions, + type: role.type, + createdAt: role.created_at, + updatedAt: role.updated_at, +}); diff --git a/src/authorization/serializers/update-organization-role-options.serializer.ts b/src/authorization/serializers/update-organization-role-options.serializer.ts new file mode 100644 index 000000000..7bfc5571d --- /dev/null +++ b/src/authorization/serializers/update-organization-role-options.serializer.ts @@ -0,0 +1,11 @@ +import { + UpdateOrganizationRoleOptions, + SerializedUpdateOrganizationRoleOptions, +} from '../interfaces/update-organization-role-options.interface'; + +export const serializeUpdateOrganizationRoleOptions = ( + options: UpdateOrganizationRoleOptions, +): SerializedUpdateOrganizationRoleOptions => ({ + name: options.name, + description: options.description, +}); From e9ca1dd6f82f840398bdfd10e2114f1e511b1c1e Mon Sep 17 00:00:00 2001 From: Colin Barber Date: Thu, 29 Jan 2026 16:35:15 -0400 Subject: [PATCH 2/6] More specific types, cleaning up interfaces --- src/authorization/authorization.spec.ts | 30 +++++++++++-------- src/authorization/authorization.ts | 28 +++++++++-------- .../fixtures/list-organization-roles.json | 11 +++++++ ...ate-organization-role-options.interface.ts | 1 - ...st-organization-roles-options.interface.ts | 1 - .../interfaces/organization-role.interface.ts | 26 +++------------- .../organization-role.serializer.ts | 20 +++++++++---- 7 files changed, 63 insertions(+), 54 deletions(-) diff --git a/src/authorization/authorization.spec.ts b/src/authorization/authorization.spec.ts index 8aa69d7e5..4491f7d1a 100644 --- a/src/authorization/authorization.spec.ts +++ b/src/authorization/authorization.spec.ts @@ -246,12 +246,14 @@ describe('Authorization', () => { it('creates an organization role', async () => { fetchOnce(organizationRoleFixture, { status: 201 }); - const role = await workos.authorization.createOrganizationRole({ - organizationId: testOrgId, - slug: 'org-admin', - name: 'Org Admin', - description: 'Organization administrator', - }); + const role = await workos.authorization.createOrganizationRole( + testOrgId, + { + slug: 'org-admin', + name: 'Org Admin', + description: 'Organization administrator', + }, + ); expect(fetchURL()).toContain( `/authorization/organizations/${testOrgId}/roles`, @@ -272,20 +274,23 @@ describe('Authorization', () => { }); describe('listOrganizationRoles', () => { - it('returns organization roles', async () => { + it('returns both environment and organization roles', async () => { fetchOnce(listOrganizationRolesFixture); - const { data, object } = await workos.authorization.listOrganizationRoles( - { organizationId: testOrgId }, - ); + const { data, object } = + await workos.authorization.listOrganizationRoles(testOrgId); expect(fetchURL()).toContain( `/authorization/organizations/${testOrgId}/roles`, ); expect(object).toEqual('list'); - expect(data).toHaveLength(2); + expect(data).toHaveLength(3); expect(data).toEqual( expect.arrayContaining([ + expect.objectContaining({ + slug: 'admin', + type: 'EnvironmentRole', + }), expect.objectContaining({ slug: 'org-admin', type: 'OrganizationRole', @@ -301,8 +306,7 @@ describe('Authorization', () => { it('passes expand parameter', async () => { fetchOnce(listOrganizationRolesFixture); - await workos.authorization.listOrganizationRoles({ - organizationId: testOrgId, + await workos.authorization.listOrganizationRoles(testOrgId, { expand: 'permissions', }); diff --git a/src/authorization/authorization.ts b/src/authorization/authorization.ts index 86b445a69..83bd24110 100644 --- a/src/authorization/authorization.ts +++ b/src/authorization/authorization.ts @@ -1,4 +1,10 @@ import { WorkOS } from '../workos'; +import { + Role, + RoleList, + OrganizationRoleResponse, + ListOrganizationRolesResponse, +} from '../roles/interfaces'; import { EnvironmentRole, EnvironmentRoleResponse, @@ -10,9 +16,6 @@ import { SetEnvironmentRolePermissionsOptions, AddEnvironmentRolePermissionOptions, OrganizationRole, - OrganizationRoleResponse, - OrganizationRoleList, - OrganizationRoleListResponse, CreateOrganizationRoleOptions, UpdateOrganizationRoleOptions, ListOrganizationRolesOptions, @@ -21,6 +24,7 @@ import { deserializeEnvironmentRole, serializeCreateEnvironmentRoleOptions, serializeUpdateEnvironmentRoleOptions, + deserializeRole, deserializeOrganizationRole, serializeCreateOrganizationRoleOptions, serializeUpdateOrganizationRoleOptions, @@ -97,9 +101,9 @@ export class Authorization { // === Organization Roles === async createOrganizationRole( + organizationId: string, options: CreateOrganizationRoleOptions, ): Promise { - const { organizationId, ...payload } = options; const { data } = await this.workos.post( `/authorization/organizations/${organizationId}/roles`, serializeCreateOrganizationRoleOptions(options), @@ -108,27 +112,27 @@ export class Authorization { } async listOrganizationRoles( - options: ListOrganizationRolesOptions, - ): Promise { - const { organizationId, ...query } = options; - const { data } = await this.workos.get( + organizationId: string, + options?: ListOrganizationRolesOptions, + ): Promise { + const { data } = await this.workos.get( `/authorization/organizations/${organizationId}/roles`, - { query }, + { query: options }, ); return { object: 'list', - data: data.data.map(deserializeOrganizationRole), + data: data.data.map(deserializeRole), }; } async getOrganizationRole( organizationId: string, slug: string, - ): Promise { + ): Promise { const { data } = await this.workos.get( `/authorization/organizations/${organizationId}/roles/${slug}`, ); - return deserializeOrganizationRole(data); + return deserializeRole(data); } async updateOrganizationRole( diff --git a/src/authorization/fixtures/list-organization-roles.json b/src/authorization/fixtures/list-organization-roles.json index 939259ea4..0533606d2 100644 --- a/src/authorization/fixtures/list-organization-roles.json +++ b/src/authorization/fixtures/list-organization-roles.json @@ -1,6 +1,17 @@ { "object": "list", "data": [ + { + "object": "role", + "id": "role_01HXYZ123ABC456DEF789ENV", + "name": "Admin", + "slug": "admin", + "description": "Environment-level admin role", + "permissions": ["users:read", "users:write"], + "type": "EnvironmentRole", + "created_at": "2024-01-15T08:00:00.000Z", + "updated_at": "2024-01-15T08:00:00.000Z" + }, { "object": "role", "id": "role_01HXYZ123ABC456DEF789ORG", diff --git a/src/authorization/interfaces/create-organization-role-options.interface.ts b/src/authorization/interfaces/create-organization-role-options.interface.ts index c938f3eff..09b397e69 100644 --- a/src/authorization/interfaces/create-organization-role-options.interface.ts +++ b/src/authorization/interfaces/create-organization-role-options.interface.ts @@ -1,5 +1,4 @@ export interface CreateOrganizationRoleOptions { - organizationId: string; slug: string; name: string; description?: string; diff --git a/src/authorization/interfaces/list-organization-roles-options.interface.ts b/src/authorization/interfaces/list-organization-roles-options.interface.ts index cf1d1f58a..6a6686c92 100644 --- a/src/authorization/interfaces/list-organization-roles-options.interface.ts +++ b/src/authorization/interfaces/list-organization-roles-options.interface.ts @@ -1,4 +1,3 @@ export interface ListOrganizationRolesOptions { - organizationId: string; expand?: 'permissions'; } diff --git a/src/authorization/interfaces/organization-role.interface.ts b/src/authorization/interfaces/organization-role.interface.ts index 56b52290e..71a37a331 100644 --- a/src/authorization/interfaces/organization-role.interface.ts +++ b/src/authorization/interfaces/organization-role.interface.ts @@ -1,3 +1,7 @@ +/** + * A role scoped to a specific organization. + * Distinct from EnvironmentRole which applies environment-wide. + */ export interface OrganizationRole { object: 'role'; id: string; @@ -9,25 +13,3 @@ export interface OrganizationRole { createdAt: string; updatedAt: string; } - -export interface OrganizationRoleResponse { - object: 'role'; - id: string; - name: string; - slug: string; - description: string | null; - permissions: string[]; - type: 'OrganizationRole'; - created_at: string; - updated_at: string; -} - -export interface OrganizationRoleList { - object: 'list'; - data: OrganizationRole[]; -} - -export interface OrganizationRoleListResponse { - object: 'list'; - data: OrganizationRoleResponse[]; -} diff --git a/src/authorization/serializers/organization-role.serializer.ts b/src/authorization/serializers/organization-role.serializer.ts index 061f8da49..3e20278d8 100644 --- a/src/authorization/serializers/organization-role.serializer.ts +++ b/src/authorization/serializers/organization-role.serializer.ts @@ -1,7 +1,17 @@ -import { - OrganizationRole, - OrganizationRoleResponse, -} from '../interfaces/organization-role.interface'; +import { Role, OrganizationRoleResponse } from '../../roles/interfaces'; +import { OrganizationRole } from '../interfaces'; + +export const deserializeRole = (role: OrganizationRoleResponse): Role => ({ + object: role.object, + id: role.id, + name: role.name, + slug: role.slug, + description: role.description, + permissions: role.permissions, + type: role.type, + createdAt: role.created_at, + updatedAt: role.updated_at, +}); export const deserializeOrganizationRole = ( role: OrganizationRoleResponse, @@ -12,7 +22,7 @@ export const deserializeOrganizationRole = ( slug: role.slug, description: role.description, permissions: role.permissions, - type: role.type, + type: 'OrganizationRole', createdAt: role.created_at, updatedAt: role.updated_at, }); From caf0f593ec7532282772e54de7602e715ee03db7 Mon Sep 17 00:00:00 2001 From: Colin Barber Date: Fri, 30 Jan 2026 09:37:49 -0400 Subject: [PATCH 3/6] Remove comments --- src/authorization/authorization.spec.ts | 2 -- src/authorization/authorization.ts | 4 ---- src/authorization/interfaces/organization-role.interface.ts | 4 ---- 3 files changed, 10 deletions(-) diff --git a/src/authorization/authorization.spec.ts b/src/authorization/authorization.spec.ts index 4491f7d1a..e4d67c976 100644 --- a/src/authorization/authorization.spec.ts +++ b/src/authorization/authorization.spec.ts @@ -240,8 +240,6 @@ describe('Authorization', () => { }); }); - // === Organization Roles === - describe('createOrganizationRole', () => { it('creates an organization role', async () => { fetchOnce(organizationRoleFixture, { status: 201 }); diff --git a/src/authorization/authorization.ts b/src/authorization/authorization.ts index 83bd24110..b774ddc66 100644 --- a/src/authorization/authorization.ts +++ b/src/authorization/authorization.ts @@ -33,8 +33,6 @@ import { export class Authorization { constructor(private readonly workos: WorkOS) {} - // === Environment Roles === - async createEnvironmentRole( options: CreateEnvironmentRoleOptions, ): Promise { @@ -98,8 +96,6 @@ export class Authorization { return deserializeEnvironmentRole(data); } - // === Organization Roles === - async createOrganizationRole( organizationId: string, options: CreateOrganizationRoleOptions, diff --git a/src/authorization/interfaces/organization-role.interface.ts b/src/authorization/interfaces/organization-role.interface.ts index 71a37a331..d17f850f4 100644 --- a/src/authorization/interfaces/organization-role.interface.ts +++ b/src/authorization/interfaces/organization-role.interface.ts @@ -1,7 +1,3 @@ -/** - * A role scoped to a specific organization. - * Distinct from EnvironmentRole which applies environment-wide. - */ export interface OrganizationRole { object: 'role'; id: string; From dd82bf17b46b1215907eca5655a2c1e9b51577c6 Mon Sep 17 00:00:00 2001 From: Colin Barber Date: Mon, 2 Feb 2026 14:28:39 -0400 Subject: [PATCH 4/6] Options objects for consistency --- src/authorization/authorization.spec.ts | 6 +++--- src/authorization/authorization.ts | 15 +++++++++------ ...anization-role-permission-options.interface.ts | 3 +++ src/authorization/interfaces/index.ts | 3 +++ ...anization-role-permission-options.interface.ts | 3 +++ ...nization-role-permissions-options.interface.ts | 3 +++ 6 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 src/authorization/interfaces/add-organization-role-permission-options.interface.ts create mode 100644 src/authorization/interfaces/remove-organization-role-permission-options.interface.ts create mode 100644 src/authorization/interfaces/set-organization-role-permissions-options.interface.ts diff --git a/src/authorization/authorization.spec.ts b/src/authorization/authorization.spec.ts index e4d67c976..32716a6f6 100644 --- a/src/authorization/authorization.spec.ts +++ b/src/authorization/authorization.spec.ts @@ -389,7 +389,7 @@ describe('Authorization', () => { const role = await workos.authorization.setOrganizationRolePermissions( testOrgId, 'org-admin', - ['org:read', 'org:write'], + { permissions: ['org:read', 'org:write'] }, ); expect(fetchURL()).toContain( @@ -415,7 +415,7 @@ describe('Authorization', () => { const role = await workos.authorization.addOrganizationRolePermission( testOrgId, 'org-admin', - 'billing:read', + { permissionSlug: 'billing:read' }, ); expect(fetchURL()).toContain( @@ -437,7 +437,7 @@ describe('Authorization', () => { await workos.authorization.removeOrganizationRolePermission( testOrgId, 'org-admin', - 'members:invite', + { permissionSlug: 'members:invite' }, ); expect(fetchURL()).toContain( diff --git a/src/authorization/authorization.ts b/src/authorization/authorization.ts index b774ddc66..b5450466e 100644 --- a/src/authorization/authorization.ts +++ b/src/authorization/authorization.ts @@ -19,6 +19,9 @@ import { CreateOrganizationRoleOptions, UpdateOrganizationRoleOptions, ListOrganizationRolesOptions, + SetOrganizationRolePermissionsOptions, + AddOrganizationRolePermissionOptions, + RemoveOrganizationRolePermissionOptions, } from './interfaces'; import { deserializeEnvironmentRole, @@ -155,11 +158,11 @@ export class Authorization { async setOrganizationRolePermissions( organizationId: string, slug: string, - permissions: string[], + options: SetOrganizationRolePermissionsOptions, ): Promise { const { data } = await this.workos.put( `/authorization/organizations/${organizationId}/roles/${slug}/permissions`, - { permissions }, + { permissions: options.permissions }, ); return deserializeOrganizationRole(data); } @@ -167,11 +170,11 @@ export class Authorization { async addOrganizationRolePermission( organizationId: string, slug: string, - permissionSlug: string, + options: AddOrganizationRolePermissionOptions, ): Promise { const { data } = await this.workos.post( `/authorization/organizations/${organizationId}/roles/${slug}/permissions`, - { slug: permissionSlug }, + { slug: options.permissionSlug }, ); return deserializeOrganizationRole(data); } @@ -179,10 +182,10 @@ export class Authorization { async removeOrganizationRolePermission( organizationId: string, slug: string, - permissionSlug: string, + options: RemoveOrganizationRolePermissionOptions, ): Promise { await this.workos.delete( - `/authorization/organizations/${organizationId}/roles/${slug}/permissions/${permissionSlug}`, + `/authorization/organizations/${organizationId}/roles/${slug}/permissions/${options.permissionSlug}`, ); } } diff --git a/src/authorization/interfaces/add-organization-role-permission-options.interface.ts b/src/authorization/interfaces/add-organization-role-permission-options.interface.ts new file mode 100644 index 000000000..1fc26296c --- /dev/null +++ b/src/authorization/interfaces/add-organization-role-permission-options.interface.ts @@ -0,0 +1,3 @@ +export interface AddOrganizationRolePermissionOptions { + permissionSlug: string; +} diff --git a/src/authorization/interfaces/index.ts b/src/authorization/interfaces/index.ts index d05e18438..2ce47d3cb 100644 --- a/src/authorization/interfaces/index.ts +++ b/src/authorization/interfaces/index.ts @@ -8,3 +8,6 @@ export * from './organization-role.interface'; export * from './create-organization-role-options.interface'; export * from './update-organization-role-options.interface'; export * from './list-organization-roles-options.interface'; +export * from './set-organization-role-permissions-options.interface'; +export * from './add-organization-role-permission-options.interface'; +export * from './remove-organization-role-permission-options.interface'; diff --git a/src/authorization/interfaces/remove-organization-role-permission-options.interface.ts b/src/authorization/interfaces/remove-organization-role-permission-options.interface.ts new file mode 100644 index 000000000..80068249f --- /dev/null +++ b/src/authorization/interfaces/remove-organization-role-permission-options.interface.ts @@ -0,0 +1,3 @@ +export interface RemoveOrganizationRolePermissionOptions { + permissionSlug: string; +} diff --git a/src/authorization/interfaces/set-organization-role-permissions-options.interface.ts b/src/authorization/interfaces/set-organization-role-permissions-options.interface.ts new file mode 100644 index 000000000..09c563c2a --- /dev/null +++ b/src/authorization/interfaces/set-organization-role-permissions-options.interface.ts @@ -0,0 +1,3 @@ +export interface SetOrganizationRolePermissionsOptions { + permissions: string[]; +} From dd74cd1c92d12dca3bfec50304a7cc3a0a9170b6 Mon Sep 17 00:00:00 2001 From: Colin Barber Date: Mon, 2 Feb 2026 14:37:08 -0400 Subject: [PATCH 5/6] Union Role type --- src/roles/interfaces/role.interface.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/roles/interfaces/role.interface.ts b/src/roles/interfaces/role.interface.ts index 642311ec0..1cf8ed5e6 100644 --- a/src/roles/interfaces/role.interface.ts +++ b/src/roles/interfaces/role.interface.ts @@ -1,3 +1,8 @@ +import { + EnvironmentRole, + OrganizationRole, +} from '../../authorization/interfaces'; + export interface RoleResponse { slug: string; } @@ -35,17 +40,7 @@ export interface OrganizationRoleResponse { updated_at: string; } -export interface Role { - object: 'role'; - id: string; - name: string; - slug: string; - description: string | null; - permissions: string[]; - type: 'EnvironmentRole' | 'OrganizationRole'; - createdAt: string; - updatedAt: string; -} +export type Role = EnvironmentRole | OrganizationRole; export interface RoleList { object: 'list'; From 34f5e08fa2b4b01ca4bff10c04aad48530a42120 Mon Sep 17 00:00:00 2001 From: Colin Barber Date: Thu, 5 Feb 2026 10:02:45 -0400 Subject: [PATCH 6/6] feat: Add permissions support (#1456) ## Description - Adds Permission support ## Documentation Does this require changes to the WorkOS Docs? E.g. the [API Reference](https://workos.com/docs/reference) or code snippets need updates. ``` [X] Yes ``` If yes, link a related docs PR and add a docs maintainer as a reviewer. Their approval is required. --- src/authorization/authorization.spec.ts | 194 +++++++++++++++--- src/authorization/authorization.ts | 72 ++++++- .../fixtures/list-permissions.json | 29 +++ src/authorization/fixtures/permission.json | 10 + .../create-permission-options.interface.ts | 11 + src/authorization/interfaces/index.ts | 6 +- ...ist-environment-roles-options.interface.ts | 3 - ...st-organization-roles-options.interface.ts | 3 - .../list-permissions-options.interface.ts | 3 + .../interfaces/permission.interface.ts | 39 ++++ .../update-permission-options.interface.ts | 9 + .../create-permission-options.serializer.ts | 12 ++ src/authorization/serializers/index.ts | 3 + .../serializers/permission.serializer.ts | 17 ++ .../update-permission-options.serializer.ts | 11 + 15 files changed, 379 insertions(+), 43 deletions(-) create mode 100644 src/authorization/fixtures/list-permissions.json create mode 100644 src/authorization/fixtures/permission.json create mode 100644 src/authorization/interfaces/create-permission-options.interface.ts delete mode 100644 src/authorization/interfaces/list-environment-roles-options.interface.ts delete mode 100644 src/authorization/interfaces/list-organization-roles-options.interface.ts create mode 100644 src/authorization/interfaces/list-permissions-options.interface.ts create mode 100644 src/authorization/interfaces/permission.interface.ts create mode 100644 src/authorization/interfaces/update-permission-options.interface.ts create mode 100644 src/authorization/serializers/create-permission-options.serializer.ts create mode 100644 src/authorization/serializers/permission.serializer.ts create mode 100644 src/authorization/serializers/update-permission-options.serializer.ts diff --git a/src/authorization/authorization.spec.ts b/src/authorization/authorization.spec.ts index 32716a6f6..dae0e3e30 100644 --- a/src/authorization/authorization.spec.ts +++ b/src/authorization/authorization.spec.ts @@ -10,6 +10,8 @@ import environmentRoleFixture from './fixtures/environment-role.json'; import listEnvironmentRolesFixture from './fixtures/list-environment-roles.json'; import organizationRoleFixture from './fixtures/organization-role.json'; import listOrganizationRolesFixture from './fixtures/list-organization-roles.json'; +import permissionFixture from './fixtures/permission.json'; +import listPermissionsFixture from './fixtures/list-permissions.json'; const workos = new WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU'); const testOrgId = 'org_01HXYZ123ABC456DEF789ABC'; @@ -98,18 +100,6 @@ describe('Authorization', () => { ]), ); }); - - it('passes expand parameter', async () => { - fetchOnce(listEnvironmentRolesFixture); - - await workos.authorization.listEnvironmentRoles({ - expand: 'permissions', - }); - - expect(fetchSearchParams()).toEqual({ - expand: 'permissions', - }); - }); }); describe('getEnvironmentRole', () => { @@ -300,18 +290,6 @@ describe('Authorization', () => { ]), ); }); - - it('passes expand parameter', async () => { - fetchOnce(listOrganizationRolesFixture); - - await workos.authorization.listOrganizationRoles(testOrgId, { - expand: 'permissions', - }); - - expect(fetchSearchParams()).toEqual({ - expand: 'permissions', - }); - }); }); describe('getOrganizationRole', () => { @@ -445,4 +423,172 @@ describe('Authorization', () => { ); }); }); + + describe('createPermission', () => { + it('creates a permission', async () => { + fetchOnce(permissionFixture, { status: 201 }); + + const permission = await workos.authorization.createPermission({ + slug: 'users:read', + name: 'Read Users', + description: 'Allows reading user data', + }); + + expect(fetchURL()).toContain('/authorization/permissions'); + expect(fetchBody()).toEqual({ + slug: 'users:read', + name: 'Read Users', + description: 'Allows reading user data', + }); + expect(permission).toMatchObject({ + object: 'permission', + id: 'perm_01HXYZ123ABC456DEF789GHI', + slug: 'users:read', + name: 'Read Users', + description: 'Allows reading user data', + system: false, + }); + }); + + it('creates a permission without description', async () => { + fetchOnce({ ...permissionFixture, description: null }, { status: 201 }); + + const permission = await workos.authorization.createPermission({ + slug: 'users:read', + name: 'Read Users', + }); + + expect(fetchBody()).toEqual({ + slug: 'users:read', + name: 'Read Users', + }); + expect(permission.description).toBeNull(); + }); + }); + + describe('listPermissions', () => { + it('returns permissions', async () => { + fetchOnce(listPermissionsFixture); + + const { data, object, listMetadata } = + await workos.authorization.listPermissions(); + + expect(fetchURL()).toContain('/authorization/permissions'); + expect(object).toEqual('list'); + expect(data).toHaveLength(2); + expect(data).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + object: 'permission', + id: 'perm_01HXYZ123ABC456DEF789GHI', + slug: 'users:read', + name: 'Read Users', + }), + expect.objectContaining({ + object: 'permission', + id: 'perm_01HXYZ123ABC456DEF789GHJ', + slug: 'users:write', + name: 'Write Users', + }), + ]), + ); + expect(listMetadata).toEqual({ + before: null, + after: 'perm_01HXYZ123ABC456DEF789GHJ', + }); + }); + + it('passes pagination parameters', async () => { + fetchOnce(listPermissionsFixture); + + await workos.authorization.listPermissions({ + limit: 10, + after: 'perm_01HXYZ123ABC456DEF789GHI', + order: 'desc', + }); + + expect(fetchSearchParams()).toEqual({ + limit: '10', + after: 'perm_01HXYZ123ABC456DEF789GHI', + order: 'desc', + }); + }); + }); + + describe('getPermission', () => { + it('gets a permission by slug', async () => { + fetchOnce(permissionFixture); + + const permission = await workos.authorization.getPermission('users:read'); + + expect(fetchURL()).toContain('/authorization/permissions/users:read'); + expect(permission).toMatchObject({ + object: 'permission', + id: 'perm_01HXYZ123ABC456DEF789GHI', + slug: 'users:read', + name: 'Read Users', + description: 'Allows reading user data', + system: false, + }); + }); + }); + + describe('updatePermission', () => { + it('updates a permission', async () => { + const updatedPermissionFixture = { + ...permissionFixture, + name: 'Read All Users', + description: 'Updated description', + }; + fetchOnce(updatedPermissionFixture); + + const permission = await workos.authorization.updatePermission( + 'users:read', + { + name: 'Read All Users', + description: 'Updated description', + }, + ); + + expect(fetchURL()).toContain('/authorization/permissions/users:read'); + expect(fetchBody()).toEqual({ + name: 'Read All Users', + description: 'Updated description', + }); + expect(permission).toMatchObject({ + name: 'Read All Users', + description: 'Updated description', + }); + }); + + it('clears description when set to null', async () => { + const updatedPermissionFixture = { + ...permissionFixture, + description: null, + }; + fetchOnce(updatedPermissionFixture); + + const permission = await workos.authorization.updatePermission( + 'users:read', + { + description: null, + }, + ); + + expect(fetchBody()).toEqual({ + description: null, + }); + expect(permission.description).toBeNull(); + }); + }); + + describe('deletePermission', () => { + it('deletes a permission', async () => { + fetchOnce({}, { status: 204 }); + + await workos.authorization.deletePermission('users:read'); + + expect(fetchURL()).toContain('/authorization/permissions/users:read'); + }); + }); }); diff --git a/src/authorization/authorization.ts b/src/authorization/authorization.ts index b5450466e..2cd92fa31 100644 --- a/src/authorization/authorization.ts +++ b/src/authorization/authorization.ts @@ -12,16 +12,21 @@ import { EnvironmentRoleListResponse, CreateEnvironmentRoleOptions, UpdateEnvironmentRoleOptions, - ListEnvironmentRolesOptions, SetEnvironmentRolePermissionsOptions, AddEnvironmentRolePermissionOptions, OrganizationRole, CreateOrganizationRoleOptions, UpdateOrganizationRoleOptions, - ListOrganizationRolesOptions, SetOrganizationRolePermissionsOptions, AddOrganizationRolePermissionOptions, RemoveOrganizationRolePermissionOptions, + Permission, + PermissionResponse, + PermissionList, + PermissionListResponse, + CreatePermissionOptions, + UpdatePermissionOptions, + ListPermissionsOptions, } from './interfaces'; import { deserializeEnvironmentRole, @@ -31,6 +36,9 @@ import { deserializeOrganizationRole, serializeCreateOrganizationRoleOptions, serializeUpdateOrganizationRoleOptions, + deserializePermission, + serializeCreatePermissionOptions, + serializeUpdatePermissionOptions, } from './serializers'; export class Authorization { @@ -46,12 +54,9 @@ export class Authorization { return deserializeEnvironmentRole(data); } - async listEnvironmentRoles( - options?: ListEnvironmentRolesOptions, - ): Promise { + async listEnvironmentRoles(): Promise { const { data } = await this.workos.get( '/authorization/roles', - { query: options }, ); return { object: 'list', @@ -110,13 +115,9 @@ export class Authorization { return deserializeOrganizationRole(data); } - async listOrganizationRoles( - organizationId: string, - options?: ListOrganizationRolesOptions, - ): Promise { + async listOrganizationRoles(organizationId: string): Promise { const { data } = await this.workos.get( `/authorization/organizations/${organizationId}/roles`, - { query: options }, ); return { object: 'list', @@ -188,4 +189,53 @@ export class Authorization { `/authorization/organizations/${organizationId}/roles/${slug}/permissions/${options.permissionSlug}`, ); } + + async createPermission( + options: CreatePermissionOptions, + ): Promise { + const { data } = await this.workos.post( + '/authorization/permissions', + serializeCreatePermissionOptions(options), + ); + return deserializePermission(data); + } + + async listPermissions( + options?: ListPermissionsOptions, + ): Promise { + const { data } = await this.workos.get( + '/authorization/permissions', + { query: options }, + ); + return { + object: 'list', + data: data.data.map(deserializePermission), + listMetadata: { + before: data.list_metadata.before, + after: data.list_metadata.after, + }, + }; + } + + async getPermission(slug: string): Promise { + const { data } = await this.workos.get( + `/authorization/permissions/${slug}`, + ); + return deserializePermission(data); + } + + async updatePermission( + slug: string, + options: UpdatePermissionOptions, + ): Promise { + const { data } = await this.workos.patch( + `/authorization/permissions/${slug}`, + serializeUpdatePermissionOptions(options), + ); + return deserializePermission(data); + } + + async deletePermission(slug: string): Promise { + await this.workos.delete(`/authorization/permissions/${slug}`); + } } diff --git a/src/authorization/fixtures/list-permissions.json b/src/authorization/fixtures/list-permissions.json new file mode 100644 index 000000000..c9f4bc8a2 --- /dev/null +++ b/src/authorization/fixtures/list-permissions.json @@ -0,0 +1,29 @@ +{ + "object": "list", + "data": [ + { + "object": "permission", + "id": "perm_01HXYZ123ABC456DEF789GHI", + "slug": "users:read", + "name": "Read Users", + "description": "Allows reading user data", + "system": false, + "created_at": "2024-01-15T08:00:00.000Z", + "updated_at": "2024-01-15T08:00:00.000Z" + }, + { + "object": "permission", + "id": "perm_01HXYZ123ABC456DEF789GHJ", + "slug": "users:write", + "name": "Write Users", + "description": null, + "system": true, + "created_at": "2024-01-15T09:00:00.000Z", + "updated_at": "2024-01-15T09:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": "perm_01HXYZ123ABC456DEF789GHJ" + } +} diff --git a/src/authorization/fixtures/permission.json b/src/authorization/fixtures/permission.json new file mode 100644 index 000000000..d8759fba1 --- /dev/null +++ b/src/authorization/fixtures/permission.json @@ -0,0 +1,10 @@ +{ + "object": "permission", + "id": "perm_01HXYZ123ABC456DEF789GHI", + "slug": "users:read", + "name": "Read Users", + "description": "Allows reading user data", + "system": false, + "created_at": "2024-01-15T08:00:00.000Z", + "updated_at": "2024-01-15T08:00:00.000Z" +} diff --git a/src/authorization/interfaces/create-permission-options.interface.ts b/src/authorization/interfaces/create-permission-options.interface.ts new file mode 100644 index 000000000..d69437fb5 --- /dev/null +++ b/src/authorization/interfaces/create-permission-options.interface.ts @@ -0,0 +1,11 @@ +export interface CreatePermissionOptions { + slug: string; + name: string; + description?: string; +} + +export interface SerializedCreatePermissionOptions { + slug: string; + name: string; + description?: string; +} diff --git a/src/authorization/interfaces/index.ts b/src/authorization/interfaces/index.ts index 2ce47d3cb..e605c9351 100644 --- a/src/authorization/interfaces/index.ts +++ b/src/authorization/interfaces/index.ts @@ -1,13 +1,15 @@ export * from './environment-role.interface'; export * from './create-environment-role-options.interface'; export * from './update-environment-role-options.interface'; -export * from './list-environment-roles-options.interface'; export * from './set-environment-role-permissions-options.interface'; export * from './add-environment-role-permission-options.interface'; export * from './organization-role.interface'; export * from './create-organization-role-options.interface'; export * from './update-organization-role-options.interface'; -export * from './list-organization-roles-options.interface'; export * from './set-organization-role-permissions-options.interface'; export * from './add-organization-role-permission-options.interface'; export * from './remove-organization-role-permission-options.interface'; +export * from './permission.interface'; +export * from './create-permission-options.interface'; +export * from './update-permission-options.interface'; +export * from './list-permissions-options.interface'; diff --git a/src/authorization/interfaces/list-environment-roles-options.interface.ts b/src/authorization/interfaces/list-environment-roles-options.interface.ts deleted file mode 100644 index ea95542f5..000000000 --- a/src/authorization/interfaces/list-environment-roles-options.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ListEnvironmentRolesOptions { - expand?: 'permissions'; -} diff --git a/src/authorization/interfaces/list-organization-roles-options.interface.ts b/src/authorization/interfaces/list-organization-roles-options.interface.ts deleted file mode 100644 index 6a6686c92..000000000 --- a/src/authorization/interfaces/list-organization-roles-options.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ListOrganizationRolesOptions { - expand?: 'permissions'; -} diff --git a/src/authorization/interfaces/list-permissions-options.interface.ts b/src/authorization/interfaces/list-permissions-options.interface.ts new file mode 100644 index 000000000..05628c604 --- /dev/null +++ b/src/authorization/interfaces/list-permissions-options.interface.ts @@ -0,0 +1,3 @@ +import { PaginationOptions } from '../../common/interfaces'; + +export type ListPermissionsOptions = PaginationOptions; diff --git a/src/authorization/interfaces/permission.interface.ts b/src/authorization/interfaces/permission.interface.ts new file mode 100644 index 000000000..a70c14804 --- /dev/null +++ b/src/authorization/interfaces/permission.interface.ts @@ -0,0 +1,39 @@ +export interface Permission { + object: 'permission'; + id: string; + slug: string; + name: string; + description: string | null; + system: boolean; + createdAt: string; + updatedAt: string; +} + +export interface PermissionResponse { + object: 'permission'; + id: string; + slug: string; + name: string; + description: string | null; + system: boolean; + created_at: string; + updated_at: string; +} + +export interface PermissionList { + object: 'list'; + data: Permission[]; + listMetadata: { + before: string | null; + after: string | null; + }; +} + +export interface PermissionListResponse { + object: 'list'; + data: PermissionResponse[]; + list_metadata: { + before: string | null; + after: string | null; + }; +} diff --git a/src/authorization/interfaces/update-permission-options.interface.ts b/src/authorization/interfaces/update-permission-options.interface.ts new file mode 100644 index 000000000..600645607 --- /dev/null +++ b/src/authorization/interfaces/update-permission-options.interface.ts @@ -0,0 +1,9 @@ +export interface UpdatePermissionOptions { + name?: string; + description?: string | null; +} + +export interface SerializedUpdatePermissionOptions { + name?: string; + description?: string | null; +} diff --git a/src/authorization/serializers/create-permission-options.serializer.ts b/src/authorization/serializers/create-permission-options.serializer.ts new file mode 100644 index 000000000..f3f0081ee --- /dev/null +++ b/src/authorization/serializers/create-permission-options.serializer.ts @@ -0,0 +1,12 @@ +import { + CreatePermissionOptions, + SerializedCreatePermissionOptions, +} from '../interfaces/create-permission-options.interface'; + +export const serializeCreatePermissionOptions = ( + options: CreatePermissionOptions, +): SerializedCreatePermissionOptions => ({ + slug: options.slug, + name: options.name, + description: options.description, +}); diff --git a/src/authorization/serializers/index.ts b/src/authorization/serializers/index.ts index 5e0f4c741..bbaf011f3 100644 --- a/src/authorization/serializers/index.ts +++ b/src/authorization/serializers/index.ts @@ -4,3 +4,6 @@ export * from './update-environment-role-options.serializer'; export * from './organization-role.serializer'; export * from './create-organization-role-options.serializer'; export * from './update-organization-role-options.serializer'; +export * from './permission.serializer'; +export * from './create-permission-options.serializer'; +export * from './update-permission-options.serializer'; diff --git a/src/authorization/serializers/permission.serializer.ts b/src/authorization/serializers/permission.serializer.ts new file mode 100644 index 000000000..a8b698f31 --- /dev/null +++ b/src/authorization/serializers/permission.serializer.ts @@ -0,0 +1,17 @@ +import { + Permission, + PermissionResponse, +} from '../interfaces/permission.interface'; + +export const deserializePermission = ( + permission: PermissionResponse, +): Permission => ({ + object: permission.object, + id: permission.id, + slug: permission.slug, + name: permission.name, + description: permission.description, + system: permission.system, + createdAt: permission.created_at, + updatedAt: permission.updated_at, +}); diff --git a/src/authorization/serializers/update-permission-options.serializer.ts b/src/authorization/serializers/update-permission-options.serializer.ts new file mode 100644 index 000000000..4ac4e67d0 --- /dev/null +++ b/src/authorization/serializers/update-permission-options.serializer.ts @@ -0,0 +1,11 @@ +import { + UpdatePermissionOptions, + SerializedUpdatePermissionOptions, +} from '../interfaces/update-permission-options.interface'; + +export const serializeUpdatePermissionOptions = ( + options: UpdatePermissionOptions, +): SerializedUpdatePermissionOptions => ({ + name: options.name, + description: options.description, +});