Skip to content

Commit

Permalink
fix: allow async policy actions at types level
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed May 24, 2024
1 parent 2a2a85c commit fa3ef8c
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 2 deletions.
3 changes: 1 addition & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,8 @@ export type NarrowAbilitiesForAUser<
*/
export type AuthorizerResponse =
| boolean
| Promise<boolean>
| AuthorizationResponse
| Promise<AuthorizationResponse>
| Promise<boolean | AuthorizationResponse>

/**
* The callback function that authorizes an ability. It should always
Expand Down
94 changes: 94 additions & 0 deletions tests/bouncer/policies.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,50 @@ test.group('Bouncer | policies | types', () => {
bouncer.with(StaffPolicy).execute('resolvePermissions')
})

test('infer async policy methods', async () => {
class User {
declare id: number
declare email: string
}

class PostPolicy extends BasePolicy {
resolvePermissions() {}

async view(_: User) {
if (_) {
return AuthorizationResponse.deny('Denied')
}
return true
}

async viewAll(_: User) {
return false
}

async create(_: User) {
return AuthorizationResponse.deny('Denied')
}
}

const bouncer = new Bouncer(new User())

/**
* Both policy references should work, because we cannot infer
* in advance if all the methods of a given policy works
* with a specific user type or not.
*/
await bouncer.with(PostPolicy).execute('view')
await bouncer.with(PostPolicy).execute('viewAll')
await bouncer.with(PostPolicy).execute('create')

/**
* The resolvePermission method does not accept the user
* and neither returns AuthorizerResponse
*/
// @ts-expect-error
await bouncer.with(PostPolicy).execute('resolvePermissions')
})

test('infer policy methods of a pre-registered policy', async () => {
class User {
declare id: number
Expand Down Expand Up @@ -269,6 +313,56 @@ test.group('Bouncer | policies | types', () => {
bouncer.with('StaffPolicy').execute('resolvePermissions')
})

test('infer async policy methods of a pre-registered policy', async () => {
class User {
declare id: number
declare email: string
}

class PostPolicy extends BasePolicy {
resolvePermissions() {}

async view(_: User) {
if (_) {
return AuthorizationResponse.deny('Denied')
}
return true
}

async viewAll(_: User) {
return false
}

async create(_: User) {
return AuthorizationResponse.deny('Denied')
}
}

const bouncer = new Bouncer(new User(), undefined, {
PostPolicy: async () => {
return {
default: PostPolicy,
}
},
})

/**
* Both policy references should work, because we cannot infer
* in advance if all the methods of a given policy works
* with a specific user type or not.
*/
await bouncer.with('PostPolicy').execute('view')
await bouncer.with('PostPolicy').execute('viewAll')
await bouncer.with('PostPolicy').execute('create')

/**
* The resolvePermission method does not accept the user
* and neither returns AuthorizerResponse
*/
// @ts-expect-error
await bouncer.with('PostPolicy').execute('resolvePermissions')
})

test('infer policy method arguments', async () => {
class User {
declare id: number
Expand Down

0 comments on commit fa3ef8c

Please sign in to comment.