@ankhorage/permissions 0.1.0
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/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/client/types.d.ts +19 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/manager/createPermissionManager.d.ts +31 -0
- package/dist/manager/createPermissionManager.d.ts.map +1 -0
- package/dist/manager/createPermissionManager.js +39 -0
- package/dist/manager/createPermissionManager.js.map +1 -0
- package/dist/metadata/index.d.ts +8 -0
- package/dist/metadata/index.d.ts.map +1 -0
- package/dist/metadata/index.js +8 -0
- package/dist/metadata/index.js.map +1 -0
- package/dist/react/index.d.ts +66 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +91 -0
- package/dist/react/index.js.map +1 -0
- package/dist/registry/permissions.d.ts +52 -0
- package/dist/registry/permissions.d.ts.map +1 -0
- package/dist/registry/permissions.js +108 -0
- package/dist/registry/permissions.js.map +1 -0
- package/dist/state/permissionState.d.ts +43 -0
- package/dist/state/permissionState.d.ts.map +1 -0
- package/dist/state/permissionState.js +44 -0
- package/dist/state/permissionState.js.map +1 -0
- package/dist/testing/index.d.ts +49 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +95 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/web/index.d.ts +60 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +234 -0
- package/dist/web/index.js.map +1 -0
- package/package.json +114 -0
- package/src/client/types.ts +19 -0
- package/src/index.ts +31 -0
- package/src/manager/createPermissionManager.test.ts +67 -0
- package/src/manager/createPermissionManager.ts +54 -0
- package/src/metadata/index.ts +7 -0
- package/src/react/index.test.ts +11 -0
- package/src/react/index.tsx +170 -0
- package/src/registry/permissions.test.ts +37 -0
- package/src/registry/permissions.ts +128 -0
- package/src/state/permissionState.test.ts +54 -0
- package/src/state/permissionState.ts +86 -0
- package/src/testing/index.test.ts +57 -0
- package/src/testing/index.ts +168 -0
- package/src/web/index.test.ts +205 -0
- package/src/web/index.ts +390 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Common runtime permissions supported by the registry.
|
|
3
|
+
*
|
|
4
|
+
* @readme
|
|
5
|
+
* The registry is intentionally platform-neutral. Adapters translate each
|
|
6
|
+
* permission into whatever a browser, React Native app, Expo app, or test
|
|
7
|
+
* environment can actually check or request.
|
|
8
|
+
*/
|
|
9
|
+
export var Permission;
|
|
10
|
+
(function (Permission) {
|
|
11
|
+
Permission["Camera"] = "camera";
|
|
12
|
+
Permission["Microphone"] = "microphone";
|
|
13
|
+
Permission["MediaLibrary"] = "mediaLibrary";
|
|
14
|
+
Permission["MediaLibraryWrite"] = "mediaLibraryWrite";
|
|
15
|
+
Permission["LocationForeground"] = "locationForeground";
|
|
16
|
+
Permission["LocationBackground"] = "locationBackground";
|
|
17
|
+
Permission["Notifications"] = "notifications";
|
|
18
|
+
Permission["Clipboard"] = "clipboard";
|
|
19
|
+
})(Permission || (Permission = {}));
|
|
20
|
+
/***
|
|
21
|
+
* Stable ordered list of known permissions.
|
|
22
|
+
*/
|
|
23
|
+
export const PERMISSIONS = [
|
|
24
|
+
Permission.Camera,
|
|
25
|
+
Permission.Microphone,
|
|
26
|
+
Permission.MediaLibrary,
|
|
27
|
+
Permission.MediaLibraryWrite,
|
|
28
|
+
Permission.LocationForeground,
|
|
29
|
+
Permission.LocationBackground,
|
|
30
|
+
Permission.Notifications,
|
|
31
|
+
Permission.Clipboard,
|
|
32
|
+
];
|
|
33
|
+
const PERMISSION_SET = new Set(PERMISSIONS);
|
|
34
|
+
/***
|
|
35
|
+
* Metadata for known permissions.
|
|
36
|
+
*/
|
|
37
|
+
export const PERMISSION_REGISTRY = {
|
|
38
|
+
[Permission.Camera]: {
|
|
39
|
+
permission: Permission.Camera,
|
|
40
|
+
label: 'Camera',
|
|
41
|
+
description: 'Access to a device camera for capture or scanning workflows.',
|
|
42
|
+
environments: ['web', 'native', 'test'],
|
|
43
|
+
},
|
|
44
|
+
[Permission.Microphone]: {
|
|
45
|
+
permission: Permission.Microphone,
|
|
46
|
+
label: 'Microphone',
|
|
47
|
+
description: 'Access to a device microphone for audio recording or calls.',
|
|
48
|
+
environments: ['web', 'native', 'test'],
|
|
49
|
+
},
|
|
50
|
+
[Permission.MediaLibrary]: {
|
|
51
|
+
permission: Permission.MediaLibrary,
|
|
52
|
+
label: 'Media library',
|
|
53
|
+
description: 'Read access to photos, videos, or other local media assets.',
|
|
54
|
+
environments: ['native', 'test'],
|
|
55
|
+
},
|
|
56
|
+
[Permission.MediaLibraryWrite]: {
|
|
57
|
+
permission: Permission.MediaLibraryWrite,
|
|
58
|
+
label: 'Media library write',
|
|
59
|
+
description: 'Write access for saving media to a local library.',
|
|
60
|
+
environments: ['native', 'test'],
|
|
61
|
+
},
|
|
62
|
+
[Permission.LocationForeground]: {
|
|
63
|
+
permission: Permission.LocationForeground,
|
|
64
|
+
label: 'Foreground location',
|
|
65
|
+
description: 'Location access while the app or page is actively in use.',
|
|
66
|
+
environments: ['web', 'native', 'test'],
|
|
67
|
+
},
|
|
68
|
+
[Permission.LocationBackground]: {
|
|
69
|
+
permission: Permission.LocationBackground,
|
|
70
|
+
label: 'Background location',
|
|
71
|
+
description: 'Location access while the app is not actively in use.',
|
|
72
|
+
environments: ['native', 'test'],
|
|
73
|
+
},
|
|
74
|
+
[Permission.Notifications]: {
|
|
75
|
+
permission: Permission.Notifications,
|
|
76
|
+
label: 'Notifications',
|
|
77
|
+
description: 'Permission to show user-visible notifications.',
|
|
78
|
+
environments: ['web', 'native', 'test'],
|
|
79
|
+
},
|
|
80
|
+
[Permission.Clipboard]: {
|
|
81
|
+
permission: Permission.Clipboard,
|
|
82
|
+
label: 'Clipboard',
|
|
83
|
+
description: 'Read or write access to clipboard contents.',
|
|
84
|
+
environments: ['web', 'native', 'test'],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
/***
|
|
88
|
+
* Returns true when a string is a registered permission identifier.
|
|
89
|
+
*/
|
|
90
|
+
export function isPermission(value) {
|
|
91
|
+
return PERMISSION_SET.has(value);
|
|
92
|
+
}
|
|
93
|
+
/***
|
|
94
|
+
* Throws for programmer errors where an invalid permission reaches runtime.
|
|
95
|
+
*/
|
|
96
|
+
export function assertKnownPermission(permission) {
|
|
97
|
+
if (!isPermission(permission)) {
|
|
98
|
+
throw new TypeError(`Unknown permission: ${permission}`);
|
|
99
|
+
}
|
|
100
|
+
return permission;
|
|
101
|
+
}
|
|
102
|
+
/***
|
|
103
|
+
* Reads registry metadata for a known permission.
|
|
104
|
+
*/
|
|
105
|
+
export function getPermissionDefinition(permission) {
|
|
106
|
+
return PERMISSION_REGISTRY[assertKnownPermission(permission)];
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/registry/permissions.ts"],"names":[],"mappings":"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","sourcesContent":["/***\n * Common runtime permissions supported by the registry.\n *\n * @readme\n * The registry is intentionally platform-neutral. Adapters translate each\n * permission into whatever a browser, React Native app, Expo app, or test\n * environment can actually check or request.\n */\nexport enum Permission {\n Camera = 'camera',\n Microphone = 'microphone',\n MediaLibrary = 'mediaLibrary',\n MediaLibraryWrite = 'mediaLibraryWrite',\n LocationForeground = 'locationForeground',\n LocationBackground = 'locationBackground',\n Notifications = 'notifications',\n Clipboard = 'clipboard',\n}\n\n/***\n * Broad environment categories where a permission can be meaningful.\n */\nexport type PermissionEnvironment = 'web' | 'native' | 'test';\n\n/***\n * Describes a known permission without coupling the registry to a platform SDK.\n */\nexport interface PermissionDefinition {\n readonly permission: Permission;\n readonly label: string;\n readonly description: string;\n readonly environments: readonly PermissionEnvironment[];\n}\n\n/***\n * Stable ordered list of known permissions.\n */\nexport const PERMISSIONS = [\n Permission.Camera,\n Permission.Microphone,\n Permission.MediaLibrary,\n Permission.MediaLibraryWrite,\n Permission.LocationForeground,\n Permission.LocationBackground,\n Permission.Notifications,\n Permission.Clipboard,\n] as const;\n\nconst PERMISSION_SET = new Set<string>(PERMISSIONS);\n\n/***\n * Metadata for known permissions.\n */\nexport const PERMISSION_REGISTRY: Readonly<Record<Permission, PermissionDefinition>> = {\n [Permission.Camera]: {\n permission: Permission.Camera,\n label: 'Camera',\n description: 'Access to a device camera for capture or scanning workflows.',\n environments: ['web', 'native', 'test'],\n },\n [Permission.Microphone]: {\n permission: Permission.Microphone,\n label: 'Microphone',\n description: 'Access to a device microphone for audio recording or calls.',\n environments: ['web', 'native', 'test'],\n },\n [Permission.MediaLibrary]: {\n permission: Permission.MediaLibrary,\n label: 'Media library',\n description: 'Read access to photos, videos, or other local media assets.',\n environments: ['native', 'test'],\n },\n [Permission.MediaLibraryWrite]: {\n permission: Permission.MediaLibraryWrite,\n label: 'Media library write',\n description: 'Write access for saving media to a local library.',\n environments: ['native', 'test'],\n },\n [Permission.LocationForeground]: {\n permission: Permission.LocationForeground,\n label: 'Foreground location',\n description: 'Location access while the app or page is actively in use.',\n environments: ['web', 'native', 'test'],\n },\n [Permission.LocationBackground]: {\n permission: Permission.LocationBackground,\n label: 'Background location',\n description: 'Location access while the app is not actively in use.',\n environments: ['native', 'test'],\n },\n [Permission.Notifications]: {\n permission: Permission.Notifications,\n label: 'Notifications',\n description: 'Permission to show user-visible notifications.',\n environments: ['web', 'native', 'test'],\n },\n [Permission.Clipboard]: {\n permission: Permission.Clipboard,\n label: 'Clipboard',\n description: 'Read or write access to clipboard contents.',\n environments: ['web', 'native', 'test'],\n },\n};\n\n/***\n * Returns true when a string is a registered permission identifier.\n */\nexport function isPermission(value: string): value is Permission {\n return PERMISSION_SET.has(value);\n}\n\n/***\n * Throws for programmer errors where an invalid permission reaches runtime.\n */\nexport function assertKnownPermission(permission: string): Permission {\n if (!isPermission(permission)) {\n throw new TypeError(`Unknown permission: ${permission}`);\n }\n\n return permission;\n}\n\n/***\n * Reads registry metadata for a known permission.\n */\nexport function getPermissionDefinition(permission: Permission): PermissionDefinition {\n return PERMISSION_REGISTRY[assertKnownPermission(permission)];\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Permission } from '../registry/permissions';
|
|
2
|
+
/***
|
|
3
|
+
* Normalized permission statuses shared by adapters and UI code.
|
|
4
|
+
*
|
|
5
|
+
* Denial is normal control flow. Unexpected adapter failures may still throw,
|
|
6
|
+
* but user denial should be represented as a permission state.
|
|
7
|
+
*/
|
|
8
|
+
export type PermissionStatus = 'unknown' | 'granted' | 'denied' | 'blocked' | 'limited' | 'unavailable';
|
|
9
|
+
/***
|
|
10
|
+
* Stable ordered list of normalized statuses.
|
|
11
|
+
*/
|
|
12
|
+
export declare const PERMISSION_STATUSES: readonly ["unknown", "granted", "denied", "blocked", "limited", "unavailable"];
|
|
13
|
+
/***
|
|
14
|
+
* Normalized result returned by permission clients and managers.
|
|
15
|
+
*/
|
|
16
|
+
export interface PermissionState {
|
|
17
|
+
readonly permission: Permission;
|
|
18
|
+
readonly status: PermissionStatus;
|
|
19
|
+
readonly canAskAgain?: boolean;
|
|
20
|
+
readonly granted: boolean;
|
|
21
|
+
readonly requestedAt?: Date;
|
|
22
|
+
readonly reason?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface CreatePermissionStateInput {
|
|
25
|
+
readonly permission: Permission;
|
|
26
|
+
readonly status: PermissionStatus;
|
|
27
|
+
readonly canAskAgain?: boolean;
|
|
28
|
+
readonly requestedAt?: Date;
|
|
29
|
+
readonly reason?: string;
|
|
30
|
+
}
|
|
31
|
+
/***
|
|
32
|
+
* Returns true when a string is one of the normalized statuses.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isPermissionStatus(value: string): value is PermissionStatus;
|
|
35
|
+
/***
|
|
36
|
+
* Creates a normalized state and derives the `granted` convenience flag.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createPermissionState(input: CreatePermissionStateInput): PermissionState;
|
|
39
|
+
/***
|
|
40
|
+
* Normalizes an adapter result to the requested permission and status shape.
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizePermissionState(permission: Permission, state: PermissionState): PermissionState;
|
|
43
|
+
//# sourceMappingURL=permissionState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionState.d.ts","sourceRoot":"","sources":["../../src/state/permissionState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,QAAQ,GACR,SAAS,GACT,SAAS,GACT,aAAa,CAAC;AAElB;;GAEG;AACH,eAAO,MAAM,mBAAmB,gFAOgB,CAAC;AAIjD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,gBAAgB,CAE3E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,eAAe,CASxF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,eAAe,GACrB,eAAe,CAQjB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Stable ordered list of normalized statuses.
|
|
3
|
+
*/
|
|
4
|
+
export const PERMISSION_STATUSES = [
|
|
5
|
+
'unknown',
|
|
6
|
+
'granted',
|
|
7
|
+
'denied',
|
|
8
|
+
'blocked',
|
|
9
|
+
'limited',
|
|
10
|
+
'unavailable',
|
|
11
|
+
];
|
|
12
|
+
const PERMISSION_STATUS_SET = new Set(PERMISSION_STATUSES);
|
|
13
|
+
/***
|
|
14
|
+
* Returns true when a string is one of the normalized statuses.
|
|
15
|
+
*/
|
|
16
|
+
export function isPermissionStatus(value) {
|
|
17
|
+
return PERMISSION_STATUS_SET.has(value);
|
|
18
|
+
}
|
|
19
|
+
/***
|
|
20
|
+
* Creates a normalized state and derives the `granted` convenience flag.
|
|
21
|
+
*/
|
|
22
|
+
export function createPermissionState(input) {
|
|
23
|
+
return {
|
|
24
|
+
permission: input.permission,
|
|
25
|
+
status: input.status,
|
|
26
|
+
canAskAgain: input.canAskAgain,
|
|
27
|
+
granted: input.status === 'granted',
|
|
28
|
+
requestedAt: input.requestedAt,
|
|
29
|
+
reason: input.reason,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/***
|
|
33
|
+
* Normalizes an adapter result to the requested permission and status shape.
|
|
34
|
+
*/
|
|
35
|
+
export function normalizePermissionState(permission, state) {
|
|
36
|
+
return createPermissionState({
|
|
37
|
+
permission,
|
|
38
|
+
status: state.status,
|
|
39
|
+
canAskAgain: state.canAskAgain,
|
|
40
|
+
requestedAt: state.requestedAt,
|
|
41
|
+
reason: state.reason,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=permissionState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionState.js","sourceRoot":"","sources":["../../src/state/permissionState.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,SAAS;IACT,aAAa;CACiC,CAAC;AAEjD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAS,mBAAmB,CAAC,CAAC;AAsBnE;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,OAAO,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAiC;IACrE,OAAO;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,KAAK,CAAC,MAAM,KAAK,SAAS;QACnC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,UAAsB,EACtB,KAAsB;IAEtB,OAAO,qBAAqB,CAAC;QAC3B,UAAU;QACV,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { Permission } from '../registry/permissions';\n\n/***\n * Normalized permission statuses shared by adapters and UI code.\n *\n * Denial is normal control flow. Unexpected adapter failures may still throw,\n * but user denial should be represented as a permission state.\n */\nexport type PermissionStatus =\n | 'unknown'\n | 'granted'\n | 'denied'\n | 'blocked'\n | 'limited'\n | 'unavailable';\n\n/***\n * Stable ordered list of normalized statuses.\n */\nexport const PERMISSION_STATUSES = [\n 'unknown',\n 'granted',\n 'denied',\n 'blocked',\n 'limited',\n 'unavailable',\n] as const satisfies readonly PermissionStatus[];\n\nconst PERMISSION_STATUS_SET = new Set<string>(PERMISSION_STATUSES);\n\n/***\n * Normalized result returned by permission clients and managers.\n */\nexport interface PermissionState {\n readonly permission: Permission;\n readonly status: PermissionStatus;\n readonly canAskAgain?: boolean;\n readonly granted: boolean;\n readonly requestedAt?: Date;\n readonly reason?: string;\n}\n\nexport interface CreatePermissionStateInput {\n readonly permission: Permission;\n readonly status: PermissionStatus;\n readonly canAskAgain?: boolean;\n readonly requestedAt?: Date;\n readonly reason?: string;\n}\n\n/***\n * Returns true when a string is one of the normalized statuses.\n */\nexport function isPermissionStatus(value: string): value is PermissionStatus {\n return PERMISSION_STATUS_SET.has(value);\n}\n\n/***\n * Creates a normalized state and derives the `granted` convenience flag.\n */\nexport function createPermissionState(input: CreatePermissionStateInput): PermissionState {\n return {\n permission: input.permission,\n status: input.status,\n canAskAgain: input.canAskAgain,\n granted: input.status === 'granted',\n requestedAt: input.requestedAt,\n reason: input.reason,\n };\n}\n\n/***\n * Normalizes an adapter result to the requested permission and status shape.\n */\nexport function normalizePermissionState(\n permission: Permission,\n state: PermissionState,\n): PermissionState {\n return createPermissionState({\n permission,\n status: state.status,\n canAskAgain: state.canAskAgain,\n requestedAt: state.requestedAt,\n reason: state.reason,\n });\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PermissionClient } from '../client/types';
|
|
2
|
+
import type { Permission } from '../registry/permissions';
|
|
3
|
+
import { type PermissionState, type PermissionStatus } from '../state/permissionState';
|
|
4
|
+
/***
|
|
5
|
+
* Seed format accepted by the fake client.
|
|
6
|
+
*/
|
|
7
|
+
export type FakePermissionStateSeed = PermissionState | {
|
|
8
|
+
readonly permission: Permission;
|
|
9
|
+
readonly status: PermissionStatus;
|
|
10
|
+
readonly canAskAgain?: boolean;
|
|
11
|
+
readonly reason?: string;
|
|
12
|
+
};
|
|
13
|
+
/***
|
|
14
|
+
* Options for deterministic fake clients.
|
|
15
|
+
*/
|
|
16
|
+
export interface FakePermissionClientOptions {
|
|
17
|
+
readonly initialStates?: readonly FakePermissionStateSeed[];
|
|
18
|
+
readonly requestStates?: readonly FakePermissionStateSeed[];
|
|
19
|
+
readonly now?: () => Date;
|
|
20
|
+
readonly openSettings?: () => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
/***
|
|
23
|
+
* Test client that stores permission states in memory.
|
|
24
|
+
*/
|
|
25
|
+
export interface FakePermissionClient extends PermissionClient {
|
|
26
|
+
setState(state: FakePermissionStateSeed): void;
|
|
27
|
+
setStatus(permission: Permission, status: PermissionStatus, options?: {
|
|
28
|
+
readonly canAskAgain?: boolean;
|
|
29
|
+
readonly reason?: string;
|
|
30
|
+
}): void;
|
|
31
|
+
getSnapshot(): readonly PermissionState[];
|
|
32
|
+
}
|
|
33
|
+
/***
|
|
34
|
+
* Creates a deterministic in-memory client for tests and examples.
|
|
35
|
+
*
|
|
36
|
+
* @readme
|
|
37
|
+
* Fake clients make permission flows testable without native devices, browser
|
|
38
|
+
* prompts, simulators, or network access.
|
|
39
|
+
*
|
|
40
|
+
* @usage
|
|
41
|
+
* ```ts
|
|
42
|
+
* const client = createFakePermissionClient({
|
|
43
|
+
* initialStates: [{ permission: Permission.Camera, status: 'denied' }],
|
|
44
|
+
* });
|
|
45
|
+
* await client.request(Permission.Camera);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function createFakePermissionClient(options?: FakePermissionClientOptions): FakePermissionClient;
|
|
49
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAC/B,eAAe,GACf;IACE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAC5D,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAC5D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC/C,SAAS,CACP,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC1B,GACA,IAAI,CAAC;IACR,WAAW,IAAI,SAAS,eAAe,EAAE,CAAC;CAC3C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,2BAAgC,GACxC,oBAAoB,CA4EtB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { assertKnownPermission, PERMISSIONS } from '../registry/permissions';
|
|
2
|
+
import { createPermissionState, } from '../state/permissionState';
|
|
3
|
+
/***
|
|
4
|
+
* Creates a deterministic in-memory client for tests and examples.
|
|
5
|
+
*
|
|
6
|
+
* @readme
|
|
7
|
+
* Fake clients make permission flows testable without native devices, browser
|
|
8
|
+
* prompts, simulators, or network access.
|
|
9
|
+
*
|
|
10
|
+
* @usage
|
|
11
|
+
* ```ts
|
|
12
|
+
* const client = createFakePermissionClient({
|
|
13
|
+
* initialStates: [{ permission: Permission.Camera, status: 'denied' }],
|
|
14
|
+
* });
|
|
15
|
+
* await client.request(Permission.Camera);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function createFakePermissionClient(options = {}) {
|
|
19
|
+
const now = options.now ?? (() => new Date());
|
|
20
|
+
const states = new Map();
|
|
21
|
+
const requestStates = new Map();
|
|
22
|
+
for (const permission of PERMISSIONS) {
|
|
23
|
+
states.set(permission, createPermissionState({
|
|
24
|
+
permission,
|
|
25
|
+
status: 'unknown',
|
|
26
|
+
canAskAgain: true,
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
for (const state of options.initialStates ?? []) {
|
|
30
|
+
states.set(state.permission, normalizeSeed(state));
|
|
31
|
+
}
|
|
32
|
+
for (const state of options.requestStates ?? []) {
|
|
33
|
+
requestStates.set(state.permission, normalizeSeed(state));
|
|
34
|
+
}
|
|
35
|
+
const client = {
|
|
36
|
+
getStatus(permission) {
|
|
37
|
+
return Promise.resolve(getStoredState(states, assertKnownPermission(permission)));
|
|
38
|
+
},
|
|
39
|
+
request(permission) {
|
|
40
|
+
const knownPermission = assertKnownPermission(permission);
|
|
41
|
+
const requestState = requestStates.get(knownPermission) ?? getStoredState(states, knownPermission);
|
|
42
|
+
const nextState = createPermissionState({
|
|
43
|
+
permission: knownPermission,
|
|
44
|
+
status: requestState.status,
|
|
45
|
+
canAskAgain: requestState.canAskAgain,
|
|
46
|
+
requestedAt: now(),
|
|
47
|
+
reason: requestState.reason,
|
|
48
|
+
});
|
|
49
|
+
states.set(knownPermission, nextState);
|
|
50
|
+
return Promise.resolve(nextState);
|
|
51
|
+
},
|
|
52
|
+
openSettings: options.openSettings,
|
|
53
|
+
setState(state) {
|
|
54
|
+
const normalizedState = normalizeSeed(state);
|
|
55
|
+
states.set(normalizedState.permission, normalizedState);
|
|
56
|
+
},
|
|
57
|
+
setStatus(permission, status, statusOptions = {}) {
|
|
58
|
+
const knownPermission = assertKnownPermission(permission);
|
|
59
|
+
states.set(knownPermission, createPermissionState({
|
|
60
|
+
permission: knownPermission,
|
|
61
|
+
status,
|
|
62
|
+
canAskAgain: statusOptions.canAskAgain,
|
|
63
|
+
reason: statusOptions.reason,
|
|
64
|
+
}));
|
|
65
|
+
},
|
|
66
|
+
getSnapshot() {
|
|
67
|
+
return PERMISSIONS.map((permission) => getStoredState(states, permission));
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
if (options.openSettings === undefined) {
|
|
71
|
+
delete client.openSettings;
|
|
72
|
+
}
|
|
73
|
+
return client;
|
|
74
|
+
}
|
|
75
|
+
function normalizeSeed(seed) {
|
|
76
|
+
return createPermissionState({
|
|
77
|
+
permission: assertKnownPermission(seed.permission),
|
|
78
|
+
status: seed.status,
|
|
79
|
+
canAskAgain: seed.canAskAgain,
|
|
80
|
+
requestedAt: 'requestedAt' in seed ? seed.requestedAt : undefined,
|
|
81
|
+
reason: seed.reason,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function getStoredState(states, permission) {
|
|
85
|
+
const state = states.get(permission);
|
|
86
|
+
if (state === undefined) {
|
|
87
|
+
return createPermissionState({
|
|
88
|
+
permission,
|
|
89
|
+
status: 'unknown',
|
|
90
|
+
canAskAgain: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return state;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PermissionClient } from '../client/types';\nimport type { Permission } from '../registry/permissions';\nimport { assertKnownPermission, PERMISSIONS } from '../registry/permissions';\nimport {\n createPermissionState,\n type PermissionState,\n type PermissionStatus,\n} from '../state/permissionState';\n\n/***\n * Seed format accepted by the fake client.\n */\nexport type FakePermissionStateSeed =\n | PermissionState\n | {\n readonly permission: Permission;\n readonly status: PermissionStatus;\n readonly canAskAgain?: boolean;\n readonly reason?: string;\n };\n\n/***\n * Options for deterministic fake clients.\n */\nexport interface FakePermissionClientOptions {\n readonly initialStates?: readonly FakePermissionStateSeed[];\n readonly requestStates?: readonly FakePermissionStateSeed[];\n readonly now?: () => Date;\n readonly openSettings?: () => Promise<void>;\n}\n\n/***\n * Test client that stores permission states in memory.\n */\nexport interface FakePermissionClient extends PermissionClient {\n setState(state: FakePermissionStateSeed): void;\n setStatus(\n permission: Permission,\n status: PermissionStatus,\n options?: {\n readonly canAskAgain?: boolean;\n readonly reason?: string;\n },\n ): void;\n getSnapshot(): readonly PermissionState[];\n}\n\n/***\n * Creates a deterministic in-memory client for tests and examples.\n *\n * @readme\n * Fake clients make permission flows testable without native devices, browser\n * prompts, simulators, or network access.\n *\n * @usage\n * ```ts\n * const client = createFakePermissionClient({\n * initialStates: [{ permission: Permission.Camera, status: 'denied' }],\n * });\n * await client.request(Permission.Camera);\n * ```\n */\nexport function createFakePermissionClient(\n options: FakePermissionClientOptions = {},\n): FakePermissionClient {\n const now = options.now ?? (() => new Date());\n const states = new Map<Permission, PermissionState>();\n const requestStates = new Map<Permission, PermissionState>();\n\n for (const permission of PERMISSIONS) {\n states.set(\n permission,\n createPermissionState({\n permission,\n status: 'unknown',\n canAskAgain: true,\n }),\n );\n }\n\n for (const state of options.initialStates ?? []) {\n states.set(state.permission, normalizeSeed(state));\n }\n\n for (const state of options.requestStates ?? []) {\n requestStates.set(state.permission, normalizeSeed(state));\n }\n\n const client: FakePermissionClient = {\n getStatus(permission) {\n return Promise.resolve(getStoredState(states, assertKnownPermission(permission)));\n },\n\n request(permission) {\n const knownPermission = assertKnownPermission(permission);\n const requestState =\n requestStates.get(knownPermission) ?? getStoredState(states, knownPermission);\n const nextState = createPermissionState({\n permission: knownPermission,\n status: requestState.status,\n canAskAgain: requestState.canAskAgain,\n requestedAt: now(),\n reason: requestState.reason,\n });\n\n states.set(knownPermission, nextState);\n\n return Promise.resolve(nextState);\n },\n\n openSettings: options.openSettings,\n\n setState(state) {\n const normalizedState = normalizeSeed(state);\n states.set(normalizedState.permission, normalizedState);\n },\n\n setStatus(permission, status, statusOptions = {}) {\n const knownPermission = assertKnownPermission(permission);\n states.set(\n knownPermission,\n createPermissionState({\n permission: knownPermission,\n status,\n canAskAgain: statusOptions.canAskAgain,\n reason: statusOptions.reason,\n }),\n );\n },\n\n getSnapshot() {\n return PERMISSIONS.map((permission) => getStoredState(states, permission));\n },\n };\n\n if (options.openSettings === undefined) {\n delete client.openSettings;\n }\n\n return client;\n}\n\nfunction normalizeSeed(seed: FakePermissionStateSeed): PermissionState {\n return createPermissionState({\n permission: assertKnownPermission(seed.permission),\n status: seed.status,\n canAskAgain: seed.canAskAgain,\n requestedAt: 'requestedAt' in seed ? seed.requestedAt : undefined,\n reason: seed.reason,\n });\n}\n\nfunction getStoredState(\n states: ReadonlyMap<Permission, PermissionState>,\n permission: Permission,\n): PermissionState {\n const state = states.get(permission);\n\n if (state === undefined) {\n return createPermissionState({\n permission,\n status: 'unknown',\n canAskAgain: true,\n });\n }\n\n return state;\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { PermissionClient } from '../client/types';
|
|
2
|
+
type BrowserPermissionName = 'camera' | 'microphone' | 'geolocation' | 'notifications';
|
|
3
|
+
type BrowserPermissionState = 'granted' | 'denied' | 'prompt';
|
|
4
|
+
type NotificationPermissionState = 'default' | 'denied' | 'granted';
|
|
5
|
+
interface BrowserPermissionStatus {
|
|
6
|
+
readonly state: BrowserPermissionState;
|
|
7
|
+
}
|
|
8
|
+
interface BrowserPermissions {
|
|
9
|
+
query(descriptor: {
|
|
10
|
+
readonly name: BrowserPermissionName;
|
|
11
|
+
}): Promise<BrowserPermissionStatus>;
|
|
12
|
+
}
|
|
13
|
+
interface MediaStreamTrackLike {
|
|
14
|
+
stop(): void;
|
|
15
|
+
}
|
|
16
|
+
interface MediaStreamLike {
|
|
17
|
+
getTracks(): readonly MediaStreamTrackLike[];
|
|
18
|
+
}
|
|
19
|
+
interface MediaDevicesLike {
|
|
20
|
+
getUserMedia(constraints: {
|
|
21
|
+
readonly audio?: boolean;
|
|
22
|
+
readonly video?: boolean;
|
|
23
|
+
}): Promise<MediaStreamLike>;
|
|
24
|
+
}
|
|
25
|
+
interface GeolocationLike {
|
|
26
|
+
getCurrentPosition(success: () => void, error: () => void, options?: {
|
|
27
|
+
readonly maximumAge?: number;
|
|
28
|
+
readonly timeout?: number;
|
|
29
|
+
}): void;
|
|
30
|
+
}
|
|
31
|
+
interface NavigatorLike {
|
|
32
|
+
readonly permissions?: BrowserPermissions;
|
|
33
|
+
readonly mediaDevices?: MediaDevicesLike;
|
|
34
|
+
readonly geolocation?: GeolocationLike;
|
|
35
|
+
}
|
|
36
|
+
interface NotificationLike {
|
|
37
|
+
readonly permission: NotificationPermissionState;
|
|
38
|
+
requestPermission(): Promise<NotificationPermissionState> | NotificationPermissionState;
|
|
39
|
+
}
|
|
40
|
+
interface WebGlobalLike {
|
|
41
|
+
readonly isSecureContext?: boolean;
|
|
42
|
+
readonly navigator?: NavigatorLike;
|
|
43
|
+
readonly Notification?: NotificationLike;
|
|
44
|
+
}
|
|
45
|
+
/***
|
|
46
|
+
* Options for the browser permission adapter.
|
|
47
|
+
*/
|
|
48
|
+
export interface WebPermissionClientOptions {
|
|
49
|
+
readonly global?: WebGlobalLike;
|
|
50
|
+
}
|
|
51
|
+
/***
|
|
52
|
+
* Creates a browser permission client using guarded structural globals.
|
|
53
|
+
*
|
|
54
|
+
* @readme
|
|
55
|
+
* Unsupported web APIs resolve to `status: 'unavailable'`. The adapter does not
|
|
56
|
+
* import DOM types and does not assume it is running in a browser.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createWebPermissionClient(options?: WebPermissionClientOptions): PermissionClient;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAQxD,KAAK,qBAAqB,GAAG,QAAQ,GAAG,YAAY,GAAG,aAAa,GAAG,eAAe,CAAC;AACvF,KAAK,sBAAsB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC9D,KAAK,2BAA2B,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpE,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAC;CACxC;AAED,UAAU,kBAAkB;IAC1B,KAAK,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAA;KAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC/F;AAED,UAAU,oBAAoB;IAC5B,IAAI,IAAI,IAAI,CAAC;CACd;AAED,UAAU,eAAe;IACvB,SAAS,IAAI,SAAS,oBAAoB,EAAE,CAAC;CAC9C;AAED,UAAU,gBAAgB;IACxB,YAAY,CAAC,WAAW,EAAE;QACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KAC1B,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC9B;AAED,UAAU,eAAe;IACvB,kBAAkB,CAChB,OAAO,EAAE,MAAM,IAAI,EACnB,KAAK,EAAE,MAAM,IAAI,EACjB,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,GACA,IAAI,CAAC;CACT;AAED,UAAU,aAAa;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IAC1C,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACzC,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC;CACxC;AAED,UAAU,gBAAgB;IACxB,QAAQ,CAAC,UAAU,EAAE,2BAA2B,CAAC;IACjD,iBAAiB,IAAI,OAAO,CAAC,2BAA2B,CAAC,GAAG,2BAA2B,CAAC;CACzF;AAED,UAAU,aAAa;IACrB,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,0BAA+B,GACvC,gBAAgB,CAiDlB"}
|