@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 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
+ }
@@ -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
@@ -0,0 +1,10 @@
1
+
2
+ export interface PermissionConfig {
3
+
4
+ }
5
+
6
+ export interface Status {
7
+
8
+ }
9
+
10
+ export type PermissionStatus = keyof Status | null
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './PermissionsManager'
2
+ export * from './Permission'
3
+ export * from './types'
4
+ export * from './globals'
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
+ }