From 023f1ce089eefcc8dcbc4c74bf3c7f5755c92987 Mon Sep 17 00:00:00 2001 From: Kyzgor Date: Thu, 25 Jun 2026 15:29:36 +0000 Subject: [PATCH] fix: add missing extends field to Role and ResourceRole types The Permit API and OpenAPI spec define extends (Array) on the role schemas, but it is missing from the generated TypeScript types, so consumers cannot type-safely set or read role inheritance. Add extends?: Array to RoleCreate/Read/Update and ResourceRoleCreate/Read/Update, matching the generator's emitted style and field position so a future regeneration is a no-op. Add a unit test pinning the field on all six types; it fails to compile if any addition is reverted. The canonical fix (regenerate the client) is currently blocked: the pinned generator 6.2.1 cannot read the now-OpenAPI-3.1 spec and regenerates an all-any client (see #130). --- src/openapi/types/resource-role-create.ts | 6 ++++ src/openapi/types/resource-role-read.ts | 6 ++++ src/openapi/types/resource-role-update.ts | 6 ++++ src/openapi/types/role-create.ts | 6 ++++ src/openapi/types/role-read.ts | 6 ++++ src/openapi/types/role-update.ts | 6 ++++ src/tests/unit/role-extends.spec.ts | 36 +++++++++++++++++++++++ 7 files changed, 72 insertions(+) create mode 100644 src/tests/unit/role-extends.spec.ts diff --git a/src/openapi/types/resource-role-create.ts b/src/openapi/types/resource-role-create.ts index a66bbad..1257d6a 100644 --- a/src/openapi/types/resource-role-create.ts +++ b/src/openapi/types/resource-role-create.ts @@ -52,6 +52,12 @@ export interface ResourceRoleCreate { * @memberof ResourceRoleCreate */ attributes?: object; + /** + * list of role keys that define what roles this role extends. In other words: this role will automatically inherit all the permissions of the given roles in this list. + * @type {Array} + * @memberof ResourceRoleCreate + */ + extends?: Array; /** * * @type {GrantedTo1} diff --git a/src/openapi/types/resource-role-read.ts b/src/openapi/types/resource-role-read.ts index f175f30..506459e 100644 --- a/src/openapi/types/resource-role-read.ts +++ b/src/openapi/types/resource-role-read.ts @@ -46,6 +46,12 @@ export interface ResourceRoleRead { * @memberof ResourceRoleRead */ attributes?: object; + /** + * list of role keys that define what roles this role extends. In other words: this role will automatically inherit all the permissions of the given roles in this list. + * @type {Array} + * @memberof ResourceRoleRead + */ + extends?: Array; /** * * @type {GrantedTo2} diff --git a/src/openapi/types/resource-role-update.ts b/src/openapi/types/resource-role-update.ts index 421c7aa..230be01 100644 --- a/src/openapi/types/resource-role-update.ts +++ b/src/openapi/types/resource-role-update.ts @@ -46,6 +46,12 @@ export interface ResourceRoleUpdate { * @memberof ResourceRoleUpdate */ attributes?: object; + /** + * list of role keys that define what roles this role extends. In other words: this role will automatically inherit all the permissions of the given roles in this list. + * @type {Array} + * @memberof ResourceRoleUpdate + */ + extends?: Array; /** * * @type {GrantedTo1} diff --git a/src/openapi/types/role-create.ts b/src/openapi/types/role-create.ts index 2e5fbc7..0f9bbca 100644 --- a/src/openapi/types/role-create.ts +++ b/src/openapi/types/role-create.ts @@ -52,6 +52,12 @@ export interface RoleCreate { * @memberof RoleCreate */ attributes?: object; + /** + * list of role keys that define what roles this role extends. In other words: this role will automatically inherit all the permissions of the given roles in this list. + * @type {Array} + * @memberof RoleCreate + */ + extends?: Array; /** * * @type {GrantedTo1} diff --git a/src/openapi/types/role-read.ts b/src/openapi/types/role-read.ts index dd47e7c..26863df 100644 --- a/src/openapi/types/role-read.ts +++ b/src/openapi/types/role-read.ts @@ -46,6 +46,12 @@ export interface RoleRead { * @memberof RoleRead */ attributes?: object; + /** + * list of role keys that define what roles this role extends. In other words: this role will automatically inherit all the permissions of the given roles in this list. + * @type {Array} + * @memberof RoleRead + */ + extends?: Array; /** * * @type {GrantedTo} diff --git a/src/openapi/types/role-update.ts b/src/openapi/types/role-update.ts index eea11de..23ca51d 100644 --- a/src/openapi/types/role-update.ts +++ b/src/openapi/types/role-update.ts @@ -46,6 +46,12 @@ export interface RoleUpdate { * @memberof RoleUpdate */ attributes?: object; + /** + * list of role keys that define what roles this role extends. In other words: this role will automatically inherit all the permissions of the given roles in this list. + * @type {Array} + * @memberof RoleUpdate + */ + extends?: Array; /** * * @type {GrantedTo1} diff --git a/src/tests/unit/role-extends.spec.ts b/src/tests/unit/role-extends.spec.ts new file mode 100644 index 0000000..7faabac --- /dev/null +++ b/src/tests/unit/role-extends.spec.ts @@ -0,0 +1,36 @@ +import test from 'ava'; + +import { + ResourceRoleCreate, + ResourceRoleRead, + ResourceRoleUpdate, + RoleCreate, + RoleRead, + RoleUpdate, +} from '../../openapi/types'; + +// Compile-time guard for the `extends` role-inheritance field on the six generated role types. +// Removing `extends?: Array` from any of them makes this file fail to compile under +// `yarn build` (build:types -> tsc): TS2322 on the create/update object literals (excess property) +// and TS2339 on the read member access. The runtime assertions below exist only so the test:unit +// ava glob exercises the file; the substantive check is that it type-checks. +const roleCreate: RoleCreate = { key: 'editor', name: 'Editor', extends: ['viewer'] }; +const roleUpdate: RoleUpdate = { extends: ['viewer'] }; +const roleReadExtends: Array | undefined = ({} as RoleRead).extends; + +const resourceRoleCreate: ResourceRoleCreate = { + key: 'editor', + name: 'Editor', + extends: ['viewer'], +}; +const resourceRoleUpdate: ResourceRoleUpdate = { extends: ['viewer'] }; +const resourceRoleReadExtends: Array | undefined = ({} as ResourceRoleRead).extends; + +test('Role and ResourceRole types expose the `extends` inheritance field', (t) => { + t.deepEqual(roleCreate.extends, ['viewer']); + t.deepEqual(roleUpdate.extends, ['viewer']); + t.is(roleReadExtends, undefined); + t.deepEqual(resourceRoleCreate.extends, ['viewer']); + t.deepEqual(resourceRoleUpdate.extends, ['viewer']); + t.is(resourceRoleReadExtends, undefined); +});