@codeleap/permissions 5.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +25 -0
- package/package.json.bak +25 -0
- package/src/Permission.ts +125 -0
- package/src/PermissionsManager.ts +128 -0
- package/src/globals.ts +10 -0
- package/src/index.ts +4 -0
- package/src/types.ts +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codeleap/permissions",
|
|
3
|
+
"version": "5.0.7",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
8
|
+
"type": "git",
|
|
9
|
+
"directory": "packages/permissions"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@codeleap/config": "5.0.7",
|
|
13
|
+
"@codeleap/store": "5.0.7",
|
|
14
|
+
"@codeleap/types": "5.0.7",
|
|
15
|
+
"ts-node-dev": "1.1.8"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "echo 'No build needed'"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@codeleap/store": "5.0.7",
|
|
22
|
+
"@codeleap/types": "5.0.7",
|
|
23
|
+
"typescript": "5.5.2"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/package.json.bak
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codeleap/permissions",
|
|
3
|
+
"version": "5.0.7",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
8
|
+
"type": "git",
|
|
9
|
+
"directory": "packages/permissions"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@codeleap/config": "workspace:*",
|
|
13
|
+
"@codeleap/store": "workspace:*",
|
|
14
|
+
"@codeleap/types": "workspace:*",
|
|
15
|
+
"ts-node-dev": "1.1.8"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "echo 'No build needed'"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@codeleap/store": "workspace:*",
|
|
22
|
+
"@codeleap/types": "workspace:*",
|
|
23
|
+
"typescript": "5.5.2"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { GlobalState, globalState } from '@codeleap/store'
|
|
2
|
+
import { PermissionOptions } from './types'
|
|
3
|
+
import { PermissionConfig, PermissionStatus } from './globals'
|
|
4
|
+
import { TypeGuards } from '@codeleap/types'
|
|
5
|
+
|
|
6
|
+
export class Permission {
|
|
7
|
+
/** The name of the permission. */
|
|
8
|
+
public name: string
|
|
9
|
+
|
|
10
|
+
private state: GlobalState<PermissionStatus>
|
|
11
|
+
|
|
12
|
+
private checkStatus: () => Promise<PermissionStatus>
|
|
13
|
+
|
|
14
|
+
private requestStatus: () => Promise<PermissionStatus>
|
|
15
|
+
|
|
16
|
+
static logsEnabled: boolean = false
|
|
17
|
+
|
|
18
|
+
static is(status: PermissionStatus) {
|
|
19
|
+
return {
|
|
20
|
+
value: status,
|
|
21
|
+
isGranted: status === 'granted',
|
|
22
|
+
isLimited: status === 'limited',
|
|
23
|
+
isDenied: status === 'denied',
|
|
24
|
+
isBlocked: status === 'blocked',
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Configuration object associated with the permission. */
|
|
29
|
+
public config: PermissionConfig
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets the current permission status.
|
|
33
|
+
* @returns The current permission status.
|
|
34
|
+
*/
|
|
35
|
+
get value() {
|
|
36
|
+
return this.state.get()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get isGranted() {
|
|
40
|
+
return Permission.is(this.value).isGranted
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get isLimited() {
|
|
44
|
+
return Permission.is(this.value).isLimited
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get isDenied() {
|
|
48
|
+
return Permission.is(this.value).isDenied
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get isBlocked() {
|
|
52
|
+
return Permission.is(this.value).isBlocked
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
constructor(options: PermissionOptions<PermissionConfig>) {
|
|
56
|
+
const { name, config, check, request } = options
|
|
57
|
+
|
|
58
|
+
this.state = globalState(null as PermissionStatus, { persistKey: 'permissions-' + name })
|
|
59
|
+
|
|
60
|
+
this.name = name
|
|
61
|
+
this.config = config
|
|
62
|
+
this.checkStatus = check
|
|
63
|
+
this.requestStatus = request
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private log(msg: string, obj?: any) {
|
|
67
|
+
if (!Permission.logsEnabled) return
|
|
68
|
+
console.log(`[Permissions] ${this.name} -> ${msg}`, obj)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Updates the permission status.
|
|
73
|
+
* @param newStatus - The new permission status.
|
|
74
|
+
*/
|
|
75
|
+
set(newStatus: PermissionStatus) {
|
|
76
|
+
this.state.set(newStatus)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* React hook for consuming the permission state.
|
|
81
|
+
* @returns The current permission status state.
|
|
82
|
+
*/
|
|
83
|
+
use() {
|
|
84
|
+
return this.state.use()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Checks the current permission status and updates the state if it has changed.
|
|
89
|
+
* @returns The checked permission status.
|
|
90
|
+
*/
|
|
91
|
+
async check() {
|
|
92
|
+
let status = await this.checkStatus()
|
|
93
|
+
|
|
94
|
+
if (status === 'denied' && this.value === 'blocked') {
|
|
95
|
+
status = this.value
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const update = status != this.value
|
|
99
|
+
|
|
100
|
+
if (update && TypeGuards.isString(status)) {
|
|
101
|
+
this.set(status as PermissionStatus)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.log('check', { status, update })
|
|
105
|
+
|
|
106
|
+
return status
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Requests the permission and updates the state if it has changed.
|
|
111
|
+
* @returns The requested permission status.
|
|
112
|
+
*/
|
|
113
|
+
async request() {
|
|
114
|
+
const status = await this.requestStatus()
|
|
115
|
+
const update = status != this.value
|
|
116
|
+
|
|
117
|
+
if (update && TypeGuards.isString(status)) {
|
|
118
|
+
this.set(status as PermissionStatus)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.log('request', { status, update })
|
|
122
|
+
|
|
123
|
+
return status
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Permission } from './Permission'
|
|
2
|
+
import { PermissionOptions } from './types'
|
|
3
|
+
import { PermissionStatus, PermissionConfig } from './globals'
|
|
4
|
+
|
|
5
|
+
export class PermissionsManager<P extends string> {
|
|
6
|
+
private requester: (permission: Permission) => Promise<PermissionStatus>
|
|
7
|
+
|
|
8
|
+
permissions: Record<P, Permission> = {} as Record<P, Permission>
|
|
9
|
+
|
|
10
|
+
private get keys() {
|
|
11
|
+
return Object.keys(this.permissions) as P[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves the current status values of all permissions.
|
|
16
|
+
* @returns An object mapping permission names to their statuses.
|
|
17
|
+
*/
|
|
18
|
+
get values() {
|
|
19
|
+
const values = {} as Record<P, PermissionStatus>
|
|
20
|
+
|
|
21
|
+
this.forEach(permission => {
|
|
22
|
+
values[permission.name] = permission.value
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return values
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private async forEach(callbackFn: (permission: Permission) => void) {
|
|
29
|
+
for (const permissionName in this.permissions) {
|
|
30
|
+
const permission = this.permissions[permissionName]
|
|
31
|
+
callbackFn(permission)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
requester: (permission: Permission) => Promise<PermissionStatus>,
|
|
37
|
+
permissions: Record<P, Omit<PermissionOptions<PermissionConfig>, 'name'>>
|
|
38
|
+
) {
|
|
39
|
+
for (const permission in permissions) {
|
|
40
|
+
const permissionConfig = permissions[permission]
|
|
41
|
+
|
|
42
|
+
const permissionClass = new Permission({
|
|
43
|
+
...permissionConfig,
|
|
44
|
+
name: permission,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
this.permissions[permission as unknown as P] = permissionClass
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.requester = requester
|
|
51
|
+
|
|
52
|
+
this.checkAll()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private log(msg: string, obj?: any) {
|
|
56
|
+
if (!Permission.logsEnabled) return
|
|
57
|
+
console.log(`[Permissions] -> ${msg}`, obj)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* React hook for consuming the permission state.
|
|
62
|
+
* @returns The current permission status state.
|
|
63
|
+
*/
|
|
64
|
+
use(permissionName: P) {
|
|
65
|
+
return this.permissions[permissionName].use()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Requests a specific permission.
|
|
70
|
+
* @param {P} permissionName - The name of the permission to request.
|
|
71
|
+
* @returns The updated permission status.
|
|
72
|
+
*/
|
|
73
|
+
async request(permissionName: P) {
|
|
74
|
+
const permission = this.permissions[permissionName]
|
|
75
|
+
const status = await this.requester(permission)
|
|
76
|
+
return Permission.is(status)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Checks the status of a specific permission.
|
|
81
|
+
* @param {P} permissionName - The name of the permission to check.
|
|
82
|
+
* @returns The current permission status.
|
|
83
|
+
*/
|
|
84
|
+
async check(permissionName: P) {
|
|
85
|
+
const permission = this.permissions[permissionName]
|
|
86
|
+
const status = await permission.check()
|
|
87
|
+
return Permission.is(status)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Requests multiple permissions at once.
|
|
92
|
+
* @param {P[]} permissionsNames - An array of permission names to request.
|
|
93
|
+
* @returns A record of updated permission statuses.
|
|
94
|
+
*/
|
|
95
|
+
async requestMany<K extends P>(permissionsNames: K[]): Promise<Record<K, ReturnType<typeof Permission.is>>> {
|
|
96
|
+
const status = {} as Record<K, ReturnType<typeof Permission.is>>
|
|
97
|
+
|
|
98
|
+
for (const permissionName of permissionsNames) {
|
|
99
|
+
status[permissionName] = await this.request(permissionName)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return status
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Checks the status of multiple permissions at once.
|
|
107
|
+
* @param {P[]} permissionsNames - An array of permission names to check.
|
|
108
|
+
* @returns A record of current permission statuses.
|
|
109
|
+
*/
|
|
110
|
+
async checkMany<K extends P>(permissionsNames: K[]): Promise<Record<K, ReturnType<typeof Permission.is>>> {
|
|
111
|
+
const status = {} as Record<K, ReturnType<typeof Permission.is>>
|
|
112
|
+
|
|
113
|
+
for (const permissionName of permissionsNames) {
|
|
114
|
+
status[permissionName] = await this.check(permissionName)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return status
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Checks the status of all managed permissions.
|
|
122
|
+
* @returns A record of all current permission statuses.
|
|
123
|
+
*/
|
|
124
|
+
async checkAll() {
|
|
125
|
+
this.log('checkAll')
|
|
126
|
+
return await this.checkMany(this.keys)
|
|
127
|
+
}
|
|
128
|
+
}
|
package/src/globals.ts
ADDED
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AnyRecord } from '@codeleap/types'
|
|
2
|
+
import { PermissionStatus } from './globals'
|
|
3
|
+
|
|
4
|
+
export type PermissionOptions<Config extends AnyRecord> = {
|
|
5
|
+
name: string
|
|
6
|
+
config: Config
|
|
7
|
+
check: () => Promise<PermissionStatus>
|
|
8
|
+
request: () => Promise<PermissionStatus>
|
|
9
|
+
}
|