@ankhorage/permissions 0.2.3 → 0.2.4

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +3 -3
  3. package/dist/expo/client.js +16 -13
  4. package/dist/expo/client.js.map +1 -1
  5. package/dist/expo/client.testSupport.d.ts +54 -0
  6. package/dist/expo/client.testSupport.d.ts.map +1 -0
  7. package/dist/expo/client.testSupport.js +183 -0
  8. package/dist/expo/client.testSupport.js.map +1 -0
  9. package/dist/expo/manifest.d.ts.map +1 -1
  10. package/dist/expo/manifest.js.map +1 -1
  11. package/dist/expo/permissionResponse.js +4 -4
  12. package/dist/expo/permissionResponse.js.map +1 -1
  13. package/dist/react/index.d.ts.map +1 -1
  14. package/dist/react/index.js +16 -11
  15. package/dist/react/index.js.map +1 -1
  16. package/dist/state/permissionState.d.ts.map +1 -1
  17. package/dist/state/permissionState.js.map +1 -1
  18. package/dist/testing/index.d.ts.map +1 -1
  19. package/dist/testing/index.js +27 -17
  20. package/dist/testing/index.js.map +1 -1
  21. package/dist/web/index.d.ts +1 -2
  22. package/dist/web/index.d.ts.map +1 -1
  23. package/dist/web/index.js +2 -76
  24. package/dist/web/index.js.map +1 -1
  25. package/dist/web/permissionStates.d.ts +10 -0
  26. package/dist/web/permissionStates.d.ts.map +1 -0
  27. package/dist/web/permissionStates.js +64 -0
  28. package/dist/web/permissionStates.js.map +1 -0
  29. package/package.json +10 -11
  30. package/src/expo/client.notifications.test.ts +106 -0
  31. package/src/expo/client.test.ts +110 -535
  32. package/src/expo/client.testSupport.ts +188 -0
  33. package/src/expo/client.ts +17 -13
  34. package/src/expo/manifest.test.ts +48 -50
  35. package/src/expo/manifest.ts +1 -5
  36. package/src/expo/permissionResponse.ts +4 -4
  37. package/src/manager/createPermissionManager.test.ts +48 -50
  38. package/src/react/index.tsx +21 -13
  39. package/src/registry/permissions.test.ts +4 -3
  40. package/src/state/permissionState.ts +1 -6
  41. package/src/testing/index.ts +36 -25
  42. package/src/web/index.test.ts +149 -151
  43. package/src/web/index.ts +9 -102
  44. package/src/web/permissionStates.ts +83 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @ankhorage/permissions
2
2
 
3
+ ## 0.2.4
4
+
5
+ ### Patch Changes
6
+
7
+ - f4b561b: Adopt the current Devtools policy and keep permission clients compatible with strict React and security linting.
8
+
3
9
  ## 0.2.3
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # PERMISSIONS
5
5
 
6
- ![license: MIT](././paradox/badges/license.svg) ![npm: v0.2.2](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![docs: paradox](././paradox/badges/docs.svg)
6
+ ![license: MIT](././paradox/badges/license.svg) ![npm: v0.2.3](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![docs: paradox](././paradox/badges/docs.svg)
7
7
 
8
8
  Cross-platform permission registry and runtime helpers for Expo, React Native, and React Native Web apps, with unified request/check APIs for camera, media, location, notifications, microphone, and other web/native capabilities.
9
9
 
@@ -132,7 +132,7 @@ Fake clients make permission flows testable without native devices, browser
132
132
  prompts, simulators, or network access.
133
133
 
134
134
  Module: `src/testing/index.ts`
135
- Source: `src/testing/index.ts:55:1`
135
+ Source: `src/testing/index.ts:61:1`
136
136
  Related symbols: `FakePermissionClient`, `FakePermissionClientOptions`
137
137
 
138
138
  </details>
@@ -192,7 +192,7 @@ Unsupported web APIs resolve to `status: 'unavailable'`. The adapter does not
192
192
  import DOM types and does not assume it is running in a browser.
193
193
 
194
194
  Module: `src/web/index.ts`
195
- Source: `src/web/index.ts:78:1`
195
+ Source: `src/web/index.ts:80:1`
196
196
  Related symbols: `PermissionClient`, `WebPermissionClientOptions`
197
197
 
198
198
  </details>
@@ -7,15 +7,15 @@ import { microphoneAdapter } from './adapters/microphone';
7
7
  import { notificationsAdapter } from './adapters/notifications';
8
8
  import { EXPO_PERMISSION_SUPPORT } from './manifest';
9
9
  const OPEN_SETTINGS_ERROR_MESSAGE = 'Unable to open application settings.';
10
- const adapters = {
11
- [Permission.Camera]: cameraAdapter,
12
- [Permission.MediaLibrary]: mediaLibraryAdapter,
13
- [Permission.MediaLibraryWrite]: mediaLibraryAdapter,
14
- [Permission.Microphone]: microphoneAdapter,
15
- [Permission.LocationForeground]: locationAdapter,
16
- [Permission.LocationBackground]: locationAdapter,
17
- [Permission.Notifications]: notificationsAdapter,
18
- };
10
+ const adapters = new Map([
11
+ [Permission.Camera, cameraAdapter],
12
+ [Permission.MediaLibrary, mediaLibraryAdapter],
13
+ [Permission.MediaLibraryWrite, mediaLibraryAdapter],
14
+ [Permission.Microphone, microphoneAdapter],
15
+ [Permission.LocationForeground, locationAdapter],
16
+ [Permission.LocationBackground, locationAdapter],
17
+ [Permission.Notifications, notificationsAdapter],
18
+ ]);
19
19
  /***
20
20
  * Creates a permission client backed by Expo SDK modules.
21
21
  *
@@ -33,28 +33,28 @@ const adapters = {
33
33
  export function createPermissionClient() {
34
34
  return {
35
35
  async getStatus(permission) {
36
- const metadata = EXPO_PERMISSION_SUPPORT[permission];
36
+ const metadata = getPermissionSupport(permission);
37
37
  if (metadata.support === 'unsupported' || metadata.support === 'notImplemented') {
38
38
  return createUnavailableSupportState(permission);
39
39
  }
40
40
  if (metadata.support === 'notRequired') {
41
41
  return createNotRequiredState(permission);
42
42
  }
43
- const adapter = adapters[permission];
43
+ const adapter = adapters.get(permission);
44
44
  if (!adapter) {
45
45
  throw new Error(`No adapter registered for permission: ${permission}`);
46
46
  }
47
47
  return adapter.getStatus(permission);
48
48
  },
49
49
  async request(permission) {
50
- const metadata = EXPO_PERMISSION_SUPPORT[permission];
50
+ const metadata = getPermissionSupport(permission);
51
51
  if (metadata.support === 'unsupported' || metadata.support === 'notImplemented') {
52
52
  return createUnavailableSupportState(permission);
53
53
  }
54
54
  if (metadata.support === 'notRequired') {
55
55
  return createNotRequiredState(permission);
56
56
  }
57
- const adapter = adapters[permission];
57
+ const adapter = adapters.get(permission);
58
58
  if (!adapter) {
59
59
  throw new Error(`No adapter registered for permission: ${permission}`);
60
60
  }
@@ -73,6 +73,9 @@ export function createPermissionClient() {
73
73
  },
74
74
  };
75
75
  }
76
+ function getPermissionSupport(permission) {
77
+ return Reflect.get(EXPO_PERMISSION_SUPPORT, permission);
78
+ }
76
79
  function createUnavailableSupportState(permission) {
77
80
  return createPermissionState({
78
81
  permission,
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/expo/client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PermissionClient } from '../client/types';\nimport { Permission } from '../registry/permissions';\nimport { createPermissionState, type PermissionState } from '../state/permissionState';\nimport { cameraAdapter } from './adapters/camera';\nimport { locationAdapter } from './adapters/location';\nimport { mediaLibraryAdapter } from './adapters/mediaLibrary';\nimport { microphoneAdapter } from './adapters/microphone';\nimport { notificationsAdapter } from './adapters/notifications';\nimport { EXPO_PERMISSION_SUPPORT } from './manifest';\n\nconst OPEN_SETTINGS_ERROR_MESSAGE = 'Unable to open application settings.';\n\nexport interface ExpoPermissionAdapter {\n getStatus(permission: Permission): Promise<PermissionState>;\n request(permission: Permission): Promise<PermissionState>;\n}\n\nconst adapters: Partial<Record<Permission, ExpoPermissionAdapter>> = {\n [Permission.Camera]: cameraAdapter,\n [Permission.MediaLibrary]: mediaLibraryAdapter,\n [Permission.MediaLibraryWrite]: mediaLibraryAdapter,\n [Permission.Microphone]: microphoneAdapter,\n [Permission.LocationForeground]: locationAdapter,\n [Permission.LocationBackground]: locationAdapter,\n [Permission.Notifications]: notificationsAdapter,\n};\n\n/***\n * Creates a permission client backed by Expo SDK modules.\n *\n * Denials that Expo cannot request again are normalized to `blocked`. Limited\n * media-library access and provisional or ephemeral iOS notification access\n * are normalized to usable `limited` states, where `granted` remains true.\n * The client requires `expo-linking` for settings recovery and rejects with a\n * stable error when the operating-system settings page cannot be opened.\n *\n * Expo modules are loaded only when a client operation uses them. The package\n * root and Expo manifest metadata remain free of native module imports.\n *\n * @readme\n */\nexport function createPermissionClient(): PermissionClient {\n return {\n async getStatus(permission: Permission): Promise<PermissionState> {\n const metadata = EXPO_PERMISSION_SUPPORT[permission];\n if (metadata.support === 'unsupported' || metadata.support === 'notImplemented') {\n return createUnavailableSupportState(permission);\n }\n\n if (metadata.support === 'notRequired') {\n return createNotRequiredState(permission);\n }\n\n const adapter = adapters[permission];\n if (!adapter) {\n throw new Error(`No adapter registered for permission: ${permission}`);\n }\n\n return adapter.getStatus(permission);\n },\n\n async request(permission: Permission): Promise<PermissionState> {\n const metadata = EXPO_PERMISSION_SUPPORT[permission];\n if (metadata.support === 'unsupported' || metadata.support === 'notImplemented') {\n return createUnavailableSupportState(permission);\n }\n\n if (metadata.support === 'notRequired') {\n return createNotRequiredState(permission);\n }\n\n const adapter = adapters[permission];\n if (!adapter) {\n throw new Error(`No adapter registered for permission: ${permission}`);\n }\n\n return adapter.request(permission);\n },\n\n async openSettings(): Promise<void> {\n try {\n const linking = await import('expo-linking');\n\n await linking.openSettings();\n } catch (error) {\n throw new Error(OPEN_SETTINGS_ERROR_MESSAGE, {\n cause: error,\n });\n }\n },\n };\n}\n\nfunction createUnavailableSupportState(permission: Permission): PermissionState {\n return createPermissionState({\n permission,\n status: 'unavailable',\n reason: `Permission ${permission} is not implemented or supported on Expo.`,\n });\n}\n\nfunction createNotRequiredState(permission: Permission): PermissionState {\n return createPermissionState({\n permission,\n status: 'granted',\n });\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/expo/client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PermissionClient } from '../client/types';\nimport { Permission } from '../registry/permissions';\nimport { createPermissionState, type PermissionState } from '../state/permissionState';\nimport { cameraAdapter } from './adapters/camera';\nimport { locationAdapter } from './adapters/location';\nimport { mediaLibraryAdapter } from './adapters/mediaLibrary';\nimport { microphoneAdapter } from './adapters/microphone';\nimport { notificationsAdapter } from './adapters/notifications';\nimport { EXPO_PERMISSION_SUPPORT } from './manifest';\n\nconst OPEN_SETTINGS_ERROR_MESSAGE = 'Unable to open application settings.';\n\nexport interface ExpoPermissionAdapter {\n getStatus(permission: Permission): Promise<PermissionState>;\n request(permission: Permission): Promise<PermissionState>;\n}\n\nconst adapters = new Map<Permission, ExpoPermissionAdapter>([\n [Permission.Camera, cameraAdapter],\n [Permission.MediaLibrary, mediaLibraryAdapter],\n [Permission.MediaLibraryWrite, mediaLibraryAdapter],\n [Permission.Microphone, microphoneAdapter],\n [Permission.LocationForeground, locationAdapter],\n [Permission.LocationBackground, locationAdapter],\n [Permission.Notifications, notificationsAdapter],\n]);\n\n/***\n * Creates a permission client backed by Expo SDK modules.\n *\n * Denials that Expo cannot request again are normalized to `blocked`. Limited\n * media-library access and provisional or ephemeral iOS notification access\n * are normalized to usable `limited` states, where `granted` remains true.\n * The client requires `expo-linking` for settings recovery and rejects with a\n * stable error when the operating-system settings page cannot be opened.\n *\n * Expo modules are loaded only when a client operation uses them. The package\n * root and Expo manifest metadata remain free of native module imports.\n *\n * @readme\n */\nexport function createPermissionClient(): PermissionClient {\n return {\n async getStatus(permission: Permission): Promise<PermissionState> {\n const metadata = getPermissionSupport(permission);\n if (metadata.support === 'unsupported' || metadata.support === 'notImplemented') {\n return createUnavailableSupportState(permission);\n }\n\n if (metadata.support === 'notRequired') {\n return createNotRequiredState(permission);\n }\n\n const adapter = adapters.get(permission);\n if (!adapter) {\n throw new Error(`No adapter registered for permission: ${permission}`);\n }\n\n return adapter.getStatus(permission);\n },\n\n async request(permission: Permission): Promise<PermissionState> {\n const metadata = getPermissionSupport(permission);\n if (metadata.support === 'unsupported' || metadata.support === 'notImplemented') {\n return createUnavailableSupportState(permission);\n }\n\n if (metadata.support === 'notRequired') {\n return createNotRequiredState(permission);\n }\n\n const adapter = adapters.get(permission);\n if (!adapter) {\n throw new Error(`No adapter registered for permission: ${permission}`);\n }\n\n return adapter.request(permission);\n },\n\n async openSettings(): Promise<void> {\n try {\n const linking = await import('expo-linking');\n\n await linking.openSettings();\n } catch (error) {\n throw new Error(OPEN_SETTINGS_ERROR_MESSAGE, {\n cause: error,\n });\n }\n },\n };\n}\n\nfunction getPermissionSupport(permission: Permission) {\n return Reflect.get(EXPO_PERMISSION_SUPPORT, permission);\n}\n\nfunction createUnavailableSupportState(permission: Permission): PermissionState {\n return createPermissionState({\n permission,\n status: 'unavailable',\n reason: `Permission ${permission} is not implemented or supported on Expo.`,\n });\n}\n\nfunction createNotRequiredState(permission: Permission): PermissionState {\n return createPermissionState({\n permission,\n status: 'granted',\n });\n}\n"]}
@@ -0,0 +1,54 @@
1
+ export interface MockPermissionResponse {
2
+ readonly status: string;
3
+ readonly canAskAgain?: boolean;
4
+ readonly accessPrivileges?: 'all' | 'limited' | 'none';
5
+ readonly ios?: {
6
+ readonly status?: number;
7
+ };
8
+ }
9
+ type CameraMockMode = 'topLevel' | 'cameraNamespace' | 'missingExports';
10
+ type AudioMockMode = 'topLevel' | 'audioModule' | 'missingExports';
11
+ export declare function permissionResponse(status: string, canAskAgain?: boolean): MockPermissionResponse;
12
+ export declare const cameraMock: {
13
+ mode: CameraMockMode;
14
+ getResponse: MockPermissionResponse;
15
+ requestResponse: MockPermissionResponse;
16
+ getError: string | undefined;
17
+ requestError: string | undefined;
18
+ };
19
+ export declare const audioMock: {
20
+ mode: AudioMockMode;
21
+ getResponse: MockPermissionResponse;
22
+ requestResponse: MockPermissionResponse;
23
+ getError: string | undefined;
24
+ requestError: string | undefined;
25
+ };
26
+ export declare const mediaLibraryMock: {
27
+ getResponse: MockPermissionResponse;
28
+ requestResponse: MockPermissionResponse;
29
+ getError: string | undefined;
30
+ requestError: string | undefined;
31
+ getCalls: boolean[];
32
+ requestCalls: boolean[];
33
+ };
34
+ export declare const locationMock: {
35
+ foregroundGetResponse: MockPermissionResponse;
36
+ foregroundRequestResponse: MockPermissionResponse;
37
+ backgroundGetResponse: MockPermissionResponse;
38
+ backgroundRequestResponse: MockPermissionResponse;
39
+ getCalls: string[];
40
+ requestCalls: string[];
41
+ };
42
+ export declare const notificationsMock: {
43
+ getResponse: MockPermissionResponse;
44
+ requestResponse: MockPermissionResponse;
45
+ getError: string | undefined;
46
+ requestError: string | undefined;
47
+ };
48
+ export declare const linkingMock: {
49
+ calls: number;
50
+ error: Error | undefined;
51
+ };
52
+ export declare function resetExpoMocks(): void;
53
+ export {};
54
+ //# sourceMappingURL=client.testSupport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.testSupport.d.ts","sourceRoot":"","sources":["../../src/expo/client.testSupport.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,KAAK,cAAc,GAAG,UAAU,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AACxE,KAAK,aAAa,GAAG,UAAU,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEnE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,UAAO,GAAG,sBAAsB,CAE7F;AAED,eAAO,MAAM,UAAU;UACD,cAAc;;;cAGX,MAAM,GAAG,SAAS;kBACd,MAAM,GAAG,SAAS;CAC9C,CAAC;AACF,eAAO,MAAM,SAAS;UACA,aAAa;;;cAGV,MAAM,GAAG,SAAS;kBACd,MAAM,GAAG,SAAS;CAC9C,CAAC;AACF,eAAO,MAAM,gBAAgB;;;cAGJ,MAAM,GAAG,SAAS;kBACd,MAAM,GAAG,SAAS;cAC7B,OAAO,EAAE;kBACL,OAAO,EAAE;CAC9B,CAAC;AACF,eAAO,MAAM,YAAY;;;;;cAKP,MAAM,EAAE;kBACJ,MAAM,EAAE;CAC7B,CAAC;AACF,eAAO,MAAM,iBAAiB;;;cAGL,MAAM,GAAG,SAAS;kBACd,MAAM,GAAG,SAAS;CAC9C,CAAC;AACF,eAAO,MAAM,WAAW;;WAAmC,KAAK,GAAG,SAAS;CAAE,CAAC;AAsG/E,wBAAgB,cAAc,IAAI,IAAI,CAkBrC"}
@@ -0,0 +1,183 @@
1
+ import { mock } from 'bun:test';
2
+ export function permissionResponse(status, canAskAgain = true) {
3
+ return { status, canAskAgain };
4
+ }
5
+ export const cameraMock = {
6
+ mode: 'topLevel',
7
+ getResponse: permissionResponse('granted'),
8
+ requestResponse: permissionResponse('granted'),
9
+ getError: undefined,
10
+ requestError: undefined,
11
+ };
12
+ export const audioMock = {
13
+ mode: 'topLevel',
14
+ getResponse: permissionResponse('granted'),
15
+ requestResponse: permissionResponse('granted'),
16
+ getError: undefined,
17
+ requestError: undefined,
18
+ };
19
+ export const mediaLibraryMock = {
20
+ getResponse: permissionResponse('granted'),
21
+ requestResponse: permissionResponse('granted'),
22
+ getError: undefined,
23
+ requestError: undefined,
24
+ getCalls: [],
25
+ requestCalls: [],
26
+ };
27
+ export const locationMock = {
28
+ foregroundGetResponse: permissionResponse('granted'),
29
+ foregroundRequestResponse: permissionResponse('granted'),
30
+ backgroundGetResponse: permissionResponse('granted'),
31
+ backgroundRequestResponse: permissionResponse('granted'),
32
+ getCalls: [],
33
+ requestCalls: [],
34
+ };
35
+ export const notificationsMock = {
36
+ getResponse: permissionResponse('granted'),
37
+ requestResponse: permissionResponse('granted'),
38
+ getError: undefined,
39
+ requestError: undefined,
40
+ };
41
+ export const linkingMock = { calls: 0, error: undefined };
42
+ void mock.module('expo-camera', () => ({
43
+ get getCameraPermissionsAsync() {
44
+ if (cameraMock.mode !== 'topLevel')
45
+ return undefined;
46
+ return () => {
47
+ if (cameraMock.getError !== undefined)
48
+ throw new Error(cameraMock.getError);
49
+ return Promise.resolve(cameraMock.getResponse);
50
+ };
51
+ },
52
+ get requestCameraPermissionsAsync() {
53
+ if (cameraMock.mode !== 'topLevel')
54
+ return undefined;
55
+ return () => {
56
+ if (cameraMock.requestError !== undefined)
57
+ throw new Error(cameraMock.requestError);
58
+ return Promise.resolve(cameraMock.requestResponse);
59
+ };
60
+ },
61
+ get Camera() {
62
+ if (cameraMock.mode !== 'cameraNamespace')
63
+ return undefined;
64
+ return {
65
+ getCameraPermissionsAsync: () => Promise.resolve(cameraMock.getResponse),
66
+ requestCameraPermissionsAsync: () => Promise.resolve(cameraMock.requestResponse),
67
+ };
68
+ },
69
+ }));
70
+ void mock.module('expo-audio', () => ({
71
+ get getRecordingPermissionsAsync() {
72
+ if (audioMock.mode !== 'topLevel')
73
+ return undefined;
74
+ return () => {
75
+ if (audioMock.getError !== undefined)
76
+ throw new Error(audioMock.getError);
77
+ return Promise.resolve(audioMock.getResponse);
78
+ };
79
+ },
80
+ get requestRecordingPermissionsAsync() {
81
+ if (audioMock.mode !== 'topLevel')
82
+ return undefined;
83
+ return () => {
84
+ if (audioMock.requestError !== undefined)
85
+ throw new Error(audioMock.requestError);
86
+ return Promise.resolve(audioMock.requestResponse);
87
+ };
88
+ },
89
+ get AudioModule() {
90
+ if (audioMock.mode !== 'audioModule')
91
+ return undefined;
92
+ return {
93
+ getRecordingPermissionsAsync: () => Promise.resolve(audioMock.getResponse),
94
+ requestRecordingPermissionsAsync: () => Promise.resolve(audioMock.requestResponse),
95
+ };
96
+ },
97
+ }));
98
+ void mock.module('expo-media-library', () => ({
99
+ getPermissionsAsync: (writeOnly) => {
100
+ mediaLibraryMock.getCalls.push(writeOnly === true);
101
+ if (mediaLibraryMock.getError !== undefined)
102
+ throw new Error(mediaLibraryMock.getError);
103
+ return Promise.resolve(mediaLibraryMock.getResponse);
104
+ },
105
+ requestPermissionsAsync: (writeOnly) => {
106
+ mediaLibraryMock.requestCalls.push(writeOnly === true);
107
+ if (mediaLibraryMock.requestError !== undefined)
108
+ throw new Error(mediaLibraryMock.requestError);
109
+ return Promise.resolve(mediaLibraryMock.requestResponse);
110
+ },
111
+ }));
112
+ void mock.module('expo-location', () => ({
113
+ getForegroundPermissionsAsync: () => {
114
+ locationMock.getCalls.push('foreground');
115
+ return Promise.resolve(locationMock.foregroundGetResponse);
116
+ },
117
+ requestForegroundPermissionsAsync: () => {
118
+ locationMock.requestCalls.push('foreground');
119
+ return Promise.resolve(locationMock.foregroundRequestResponse);
120
+ },
121
+ getBackgroundPermissionsAsync: () => {
122
+ locationMock.getCalls.push('background');
123
+ return Promise.resolve(locationMock.backgroundGetResponse);
124
+ },
125
+ requestBackgroundPermissionsAsync: () => {
126
+ locationMock.requestCalls.push('background');
127
+ return Promise.resolve(locationMock.backgroundRequestResponse);
128
+ },
129
+ }));
130
+ void mock.module('expo-notifications', () => ({
131
+ getPermissionsAsync: () => {
132
+ if (notificationsMock.getError !== undefined)
133
+ throw new Error(notificationsMock.getError);
134
+ return Promise.resolve(notificationsMock.getResponse);
135
+ },
136
+ requestPermissionsAsync: () => {
137
+ if (notificationsMock.requestError !== undefined)
138
+ throw new Error(notificationsMock.requestError);
139
+ return Promise.resolve(notificationsMock.requestResponse);
140
+ },
141
+ }));
142
+ void mock.module('expo-linking', () => ({
143
+ openSettings: () => {
144
+ linkingMock.calls += 1;
145
+ if (linkingMock.error !== undefined)
146
+ throw linkingMock.error;
147
+ return Promise.resolve();
148
+ },
149
+ }));
150
+ export function resetExpoMocks() {
151
+ cameraMock.mode = 'topLevel';
152
+ cameraMock.getResponse = permissionResponse('granted');
153
+ cameraMock.requestResponse = permissionResponse('granted');
154
+ cameraMock.getError = undefined;
155
+ cameraMock.requestError = undefined;
156
+ audioMock.mode = 'topLevel';
157
+ audioMock.getResponse = permissionResponse('granted');
158
+ audioMock.requestResponse = permissionResponse('granted');
159
+ audioMock.getError = undefined;
160
+ audioMock.requestError = undefined;
161
+ resetCollectionMocks();
162
+ notificationsMock.getResponse = permissionResponse('granted');
163
+ notificationsMock.requestResponse = permissionResponse('granted');
164
+ notificationsMock.getError = undefined;
165
+ notificationsMock.requestError = undefined;
166
+ linkingMock.calls = 0;
167
+ linkingMock.error = undefined;
168
+ }
169
+ function resetCollectionMocks() {
170
+ mediaLibraryMock.getResponse = permissionResponse('granted');
171
+ mediaLibraryMock.requestResponse = permissionResponse('granted');
172
+ mediaLibraryMock.getError = undefined;
173
+ mediaLibraryMock.requestError = undefined;
174
+ mediaLibraryMock.getCalls.length = 0;
175
+ mediaLibraryMock.requestCalls.length = 0;
176
+ locationMock.foregroundGetResponse = permissionResponse('granted');
177
+ locationMock.foregroundRequestResponse = permissionResponse('granted');
178
+ locationMock.backgroundGetResponse = permissionResponse('granted');
179
+ locationMock.backgroundRequestResponse = permissionResponse('granted');
180
+ locationMock.getCalls.length = 0;
181
+ locationMock.requestCalls.length = 0;
182
+ }
183
+ //# sourceMappingURL=client.testSupport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.testSupport.js","sourceRoot":"","sources":["../../src/expo/client.testSupport.ts"],"names":[],"mappings":"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","sourcesContent":["import { mock } from 'bun:test';\n\nexport interface MockPermissionResponse {\n readonly status: string;\n readonly canAskAgain?: boolean;\n readonly accessPrivileges?: 'all' | 'limited' | 'none';\n readonly ios?: { readonly status?: number };\n}\n\ntype CameraMockMode = 'topLevel' | 'cameraNamespace' | 'missingExports';\ntype AudioMockMode = 'topLevel' | 'audioModule' | 'missingExports';\n\nexport function permissionResponse(status: string, canAskAgain = true): MockPermissionResponse {\n return { status, canAskAgain };\n}\n\nexport const cameraMock = {\n mode: 'topLevel' as CameraMockMode,\n getResponse: permissionResponse('granted'),\n requestResponse: permissionResponse('granted'),\n getError: undefined as string | undefined,\n requestError: undefined as string | undefined,\n};\nexport const audioMock = {\n mode: 'topLevel' as AudioMockMode,\n getResponse: permissionResponse('granted'),\n requestResponse: permissionResponse('granted'),\n getError: undefined as string | undefined,\n requestError: undefined as string | undefined,\n};\nexport const mediaLibraryMock = {\n getResponse: permissionResponse('granted'),\n requestResponse: permissionResponse('granted'),\n getError: undefined as string | undefined,\n requestError: undefined as string | undefined,\n getCalls: [] as boolean[],\n requestCalls: [] as boolean[],\n};\nexport const locationMock = {\n foregroundGetResponse: permissionResponse('granted'),\n foregroundRequestResponse: permissionResponse('granted'),\n backgroundGetResponse: permissionResponse('granted'),\n backgroundRequestResponse: permissionResponse('granted'),\n getCalls: [] as string[],\n requestCalls: [] as string[],\n};\nexport const notificationsMock = {\n getResponse: permissionResponse('granted'),\n requestResponse: permissionResponse('granted'),\n getError: undefined as string | undefined,\n requestError: undefined as string | undefined,\n};\nexport const linkingMock = { calls: 0, error: undefined as Error | undefined };\n\nvoid mock.module('expo-camera', () => ({\n get getCameraPermissionsAsync() {\n if (cameraMock.mode !== 'topLevel') return undefined;\n return () => {\n if (cameraMock.getError !== undefined) throw new Error(cameraMock.getError);\n return Promise.resolve(cameraMock.getResponse);\n };\n },\n get requestCameraPermissionsAsync() {\n if (cameraMock.mode !== 'topLevel') return undefined;\n return () => {\n if (cameraMock.requestError !== undefined) throw new Error(cameraMock.requestError);\n return Promise.resolve(cameraMock.requestResponse);\n };\n },\n get Camera() {\n if (cameraMock.mode !== 'cameraNamespace') return undefined;\n return {\n getCameraPermissionsAsync: () => Promise.resolve(cameraMock.getResponse),\n requestCameraPermissionsAsync: () => Promise.resolve(cameraMock.requestResponse),\n };\n },\n}));\n\nvoid mock.module('expo-audio', () => ({\n get getRecordingPermissionsAsync() {\n if (audioMock.mode !== 'topLevel') return undefined;\n return () => {\n if (audioMock.getError !== undefined) throw new Error(audioMock.getError);\n return Promise.resolve(audioMock.getResponse);\n };\n },\n get requestRecordingPermissionsAsync() {\n if (audioMock.mode !== 'topLevel') return undefined;\n return () => {\n if (audioMock.requestError !== undefined) throw new Error(audioMock.requestError);\n return Promise.resolve(audioMock.requestResponse);\n };\n },\n get AudioModule() {\n if (audioMock.mode !== 'audioModule') return undefined;\n return {\n getRecordingPermissionsAsync: () => Promise.resolve(audioMock.getResponse),\n requestRecordingPermissionsAsync: () => Promise.resolve(audioMock.requestResponse),\n };\n },\n}));\n\nvoid mock.module('expo-media-library', () => ({\n getPermissionsAsync: (writeOnly?: boolean) => {\n mediaLibraryMock.getCalls.push(writeOnly === true);\n if (mediaLibraryMock.getError !== undefined) throw new Error(mediaLibraryMock.getError);\n return Promise.resolve(mediaLibraryMock.getResponse);\n },\n requestPermissionsAsync: (writeOnly?: boolean) => {\n mediaLibraryMock.requestCalls.push(writeOnly === true);\n if (mediaLibraryMock.requestError !== undefined) throw new Error(mediaLibraryMock.requestError);\n return Promise.resolve(mediaLibraryMock.requestResponse);\n },\n}));\n\nvoid mock.module('expo-location', () => ({\n getForegroundPermissionsAsync: () => {\n locationMock.getCalls.push('foreground');\n return Promise.resolve(locationMock.foregroundGetResponse);\n },\n requestForegroundPermissionsAsync: () => {\n locationMock.requestCalls.push('foreground');\n return Promise.resolve(locationMock.foregroundRequestResponse);\n },\n getBackgroundPermissionsAsync: () => {\n locationMock.getCalls.push('background');\n return Promise.resolve(locationMock.backgroundGetResponse);\n },\n requestBackgroundPermissionsAsync: () => {\n locationMock.requestCalls.push('background');\n return Promise.resolve(locationMock.backgroundRequestResponse);\n },\n}));\n\nvoid mock.module('expo-notifications', () => ({\n getPermissionsAsync: () => {\n if (notificationsMock.getError !== undefined) throw new Error(notificationsMock.getError);\n return Promise.resolve(notificationsMock.getResponse);\n },\n requestPermissionsAsync: () => {\n if (notificationsMock.requestError !== undefined)\n throw new Error(notificationsMock.requestError);\n return Promise.resolve(notificationsMock.requestResponse);\n },\n}));\n\nvoid mock.module('expo-linking', () => ({\n openSettings: () => {\n linkingMock.calls += 1;\n if (linkingMock.error !== undefined) throw linkingMock.error;\n return Promise.resolve();\n },\n}));\n\nexport function resetExpoMocks(): void {\n cameraMock.mode = 'topLevel';\n cameraMock.getResponse = permissionResponse('granted');\n cameraMock.requestResponse = permissionResponse('granted');\n cameraMock.getError = undefined;\n cameraMock.requestError = undefined;\n audioMock.mode = 'topLevel';\n audioMock.getResponse = permissionResponse('granted');\n audioMock.requestResponse = permissionResponse('granted');\n audioMock.getError = undefined;\n audioMock.requestError = undefined;\n resetCollectionMocks();\n notificationsMock.getResponse = permissionResponse('granted');\n notificationsMock.requestResponse = permissionResponse('granted');\n notificationsMock.getError = undefined;\n notificationsMock.requestError = undefined;\n linkingMock.calls = 0;\n linkingMock.error = undefined;\n}\n\nfunction resetCollectionMocks(): void {\n mediaLibraryMock.getResponse = permissionResponse('granted');\n mediaLibraryMock.requestResponse = permissionResponse('granted');\n mediaLibraryMock.getError = undefined;\n mediaLibraryMock.requestError = undefined;\n mediaLibraryMock.getCalls.length = 0;\n mediaLibraryMock.requestCalls.length = 0;\n locationMock.foregroundGetResponse = permissionResponse('granted');\n locationMock.foregroundRequestResponse = permissionResponse('granted');\n locationMock.backgroundGetResponse = permissionResponse('granted');\n locationMock.backgroundRequestResponse = permissionResponse('granted');\n locationMock.getCalls.length = 0;\n locationMock.requestCalls.length = 0;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/expo/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,MAAM,iBAAiB,GACzB,WAAW,GACX,aAAa,GACb,SAAS,GACT,gBAAgB,GAChB,aAAa,CAAC;AAElB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED;;;GAGG;AACH,eAAO,MAAM,wCAAwC,2BAA4B,CAAC;AAElF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAyCxF,CAAC"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/expo/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAC3B,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE7E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED;;;GAGG;AACH,eAAO,MAAM,wCAAwC,2BAA4B,CAAC;AAElF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAyCxF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/expo/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAerD;;;GAGG;AACH,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,cAAc,CAAU,CAAC;AAElF,MAAM,CAAC,MAAM,uBAAuB,GAAyD;IAC3F,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;QACnB,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,aAAa,CAAC;QACjC,WAAW,EAAE,CAAC,kBAAkB,CAAC;KAClC;IACD,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QACvB,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,YAAY,CAAC;QAChC,WAAW,EAAE,CAAC,sBAAsB,EAAE,oBAAoB,CAAC;KAC5D;IACD,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE;QACzB,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,oBAAoB,CAAC;QACxC,WAAW,EAAE,CAAC,wBAAwB,CAAC;KACxC;IACD,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE;QAC9B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,oBAAoB,CAAC;QACxC,WAAW,EAAE,CAAC,wBAAwB,CAAC;KACxC;IACD,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE;QAC/B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,eAAe,CAAC;QACnC,WAAW,EAAE,CAAC,6BAA6B,CAAC;KAC7C;IACD,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE;QAC/B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,eAAe,CAAC;QACnC,WAAW,EAAE,CAAC,sCAAsC,CAAC;KACtD;IACD,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;QAC1B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,oBAAoB,CAAC;QACxC,WAAW,EAAE,CAAC,yBAAyB,CAAC;KACzC;IACD,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QACtB,OAAO,EAAE,aAAa;QACtB,gBAAgB,EAAE,EAAE;QACpB,WAAW,EAAE,EAAE;KAChB;CACF,CAAC","sourcesContent":["import { Permission } from '../registry/permissions';\n\nexport type PermissionSupport =\n | 'supported'\n | 'notRequired'\n | 'limited'\n | 'notImplemented'\n | 'unsupported';\n\nexport interface ExpoPermissionMetadata {\n readonly support: PermissionSupport;\n readonly requiredPackages: readonly string[];\n readonly configHints: readonly string[];\n}\n\n/***\n * Expo packages required by the permission client independently of a specific\n * permission capability.\n */\nexport const EXPO_PERMISSION_CLIENT_REQUIRED_PACKAGES = ['expo-linking'] as const;\n\nexport const EXPO_PERMISSION_SUPPORT: Readonly<Record<Permission, ExpoPermissionMetadata>> = {\n [Permission.Camera]: {\n support: 'supported',\n requiredPackages: ['expo-camera'],\n configHints: ['cameraPermission'],\n },\n [Permission.Microphone]: {\n support: 'supported',\n requiredPackages: ['expo-audio'],\n configHints: ['microphonePermission', 'recordAudioAndroid'],\n },\n [Permission.MediaLibrary]: {\n support: 'supported',\n requiredPackages: ['expo-media-library'],\n configHints: ['mediaLibraryPermission'],\n },\n [Permission.MediaLibraryWrite]: {\n support: 'supported',\n requiredPackages: ['expo-media-library'],\n configHints: ['mediaLibraryPermission'],\n },\n [Permission.LocationForeground]: {\n support: 'supported',\n requiredPackages: ['expo-location'],\n configHints: ['locationWhenInUsePermission'],\n },\n [Permission.LocationBackground]: {\n support: 'supported',\n requiredPackages: ['expo-location'],\n configHints: ['locationAlwaysAndWhenInUsePermission'],\n },\n [Permission.Notifications]: {\n support: 'supported',\n requiredPackages: ['expo-notifications'],\n configHints: ['notificationsPermission'],\n },\n [Permission.Clipboard]: {\n support: 'notRequired',\n requiredPackages: [],\n configHints: [],\n },\n};\n"]}
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/expo/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAWrD;;;GAGG;AACH,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,cAAc,CAAU,CAAC;AAElF,MAAM,CAAC,MAAM,uBAAuB,GAAyD;IAC3F,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;QACnB,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,aAAa,CAAC;QACjC,WAAW,EAAE,CAAC,kBAAkB,CAAC;KAClC;IACD,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QACvB,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,YAAY,CAAC;QAChC,WAAW,EAAE,CAAC,sBAAsB,EAAE,oBAAoB,CAAC;KAC5D;IACD,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE;QACzB,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,oBAAoB,CAAC;QACxC,WAAW,EAAE,CAAC,wBAAwB,CAAC;KACxC;IACD,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE;QAC9B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,oBAAoB,CAAC;QACxC,WAAW,EAAE,CAAC,wBAAwB,CAAC;KACxC;IACD,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE;QAC/B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,eAAe,CAAC;QACnC,WAAW,EAAE,CAAC,6BAA6B,CAAC;KAC7C;IACD,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE;QAC/B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,eAAe,CAAC;QACnC,WAAW,EAAE,CAAC,sCAAsC,CAAC;KACtD;IACD,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;QAC1B,OAAO,EAAE,WAAW;QACpB,gBAAgB,EAAE,CAAC,oBAAoB,CAAC;QACxC,WAAW,EAAE,CAAC,yBAAyB,CAAC;KACzC;IACD,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QACtB,OAAO,EAAE,aAAa;QACtB,gBAAgB,EAAE,EAAE;QACpB,WAAW,EAAE,EAAE;KAChB;CACF,CAAC","sourcesContent":["import { Permission } from '../registry/permissions';\n\nexport type PermissionSupport =\n 'supported' | 'notRequired' | 'limited' | 'notImplemented' | 'unsupported';\n\nexport interface ExpoPermissionMetadata {\n readonly support: PermissionSupport;\n readonly requiredPackages: readonly string[];\n readonly configHints: readonly string[];\n}\n\n/***\n * Expo packages required by the permission client independently of a specific\n * permission capability.\n */\nexport const EXPO_PERMISSION_CLIENT_REQUIRED_PACKAGES = ['expo-linking'] as const;\n\nexport const EXPO_PERMISSION_SUPPORT: Readonly<Record<Permission, ExpoPermissionMetadata>> = {\n [Permission.Camera]: {\n support: 'supported',\n requiredPackages: ['expo-camera'],\n configHints: ['cameraPermission'],\n },\n [Permission.Microphone]: {\n support: 'supported',\n requiredPackages: ['expo-audio'],\n configHints: ['microphonePermission', 'recordAudioAndroid'],\n },\n [Permission.MediaLibrary]: {\n support: 'supported',\n requiredPackages: ['expo-media-library'],\n configHints: ['mediaLibraryPermission'],\n },\n [Permission.MediaLibraryWrite]: {\n support: 'supported',\n requiredPackages: ['expo-media-library'],\n configHints: ['mediaLibraryPermission'],\n },\n [Permission.LocationForeground]: {\n support: 'supported',\n requiredPackages: ['expo-location'],\n configHints: ['locationWhenInUsePermission'],\n },\n [Permission.LocationBackground]: {\n support: 'supported',\n requiredPackages: ['expo-location'],\n configHints: ['locationAlwaysAndWhenInUsePermission'],\n },\n [Permission.Notifications]: {\n support: 'supported',\n requiredPackages: ['expo-notifications'],\n configHints: ['notificationsPermission'],\n },\n [Permission.Clipboard]: {\n support: 'notRequired',\n requiredPackages: [],\n configHints: [],\n },\n};\n"]}
@@ -12,15 +12,15 @@ export function createExpoUnavailableState(permission, error) {
12
12
  }
13
13
  export function findExpoPermissionMethod(source, methodName, containerNames = []) {
14
14
  if (hasExpoPermissionMethod(source, methodName)) {
15
- return source[methodName];
15
+ return Reflect.get(source, methodName);
16
16
  }
17
17
  if (!isRecord(source)) {
18
18
  return undefined;
19
19
  }
20
20
  for (const containerName of containerNames) {
21
- const container = source[containerName];
21
+ const container = Reflect.get(source, containerName);
22
22
  if (hasExpoPermissionMethod(container, methodName)) {
23
- return container[methodName];
23
+ return Reflect.get(container, methodName);
24
24
  }
25
25
  }
26
26
  return undefined;
@@ -46,7 +46,7 @@ function createNormalizedExpoPermissionState(permission, response, status, reaso
46
46
  });
47
47
  }
48
48
  function hasExpoPermissionMethod(value, methodName) {
49
- return isRecord(value) && typeof value[methodName] === 'function';
49
+ return isRecord(value) && typeof Reflect.get(value, methodName) === 'function';
50
50
  }
51
51
  function isRecord(value) {
52
52
  return typeof value === 'object' && value !== null;
@@ -1 +1 @@
1
- {"version":3,"file":"permissionResponse.js","sourceRoot":"","sources":["../../src/expo/permissionResponse.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,kBAAkB,GAGnB,MAAM,0BAA0B,CAAC;AASlC,MAAM,UAAU,yBAAyB,CACvC,UAAsB,EACtB,QAAgC;IAEhC,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAEjF,OAAO,mCAAmC,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAAsB,EACtB,KAAc;IAEd,OAAO,qBAAqB,CAAC;QAC3B,UAAU;QACV,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,6BAA6B,CAAC,KAAK,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,MAAe,EACf,UAAkB,EAClB,iBAAoC,EAAE;IAEtC,IAAI,uBAAuB,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QAExC,IAAI,uBAAuB,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;YACnD,OAAO,SAAS,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,6BAA6B,CAAC,KAAc;IACnD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,mCAAmC,CAAC;AAC7C,CAAC;AAED,SAAS,mCAAmC,CAC1C,UAAsB,EACtB,QAAgC,EAChC,MAAwB,EACxB,MAAe;IAEf,MAAM,gBAAgB,GACpB,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAE7E,OAAO,qBAAqB,CAAC;QAC3B,UAAU;QACV,MAAM,EAAE,gBAAgB;QACxB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,MAAM,EACJ,gBAAgB,KAAK,SAAS;YAC5B,CAAC,CAAC,2DAA2D;YAC7D,CAAC,CAAC,MAAM;KACb,CAAC,CAAC;AACL,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAc,EACd,UAAkB;IAElB,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,UAAU,CAAC;AACpE,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC","sourcesContent":["import type { Permission } from '../registry/permissions';\nimport {\n createPermissionState,\n isPermissionStatus,\n type PermissionState,\n type PermissionStatus,\n} from '../state/permissionState';\n\nexport interface ExpoPermissionResponse {\n readonly status: string;\n readonly canAskAgain?: boolean;\n}\n\nexport type ExpoPermissionMethod = () => Promise<ExpoPermissionResponse>;\n\nexport function createExpoPermissionState(\n permission: Permission,\n response: ExpoPermissionResponse,\n): PermissionState {\n const status = isPermissionStatus(response.status) ? response.status : 'unknown';\n\n return createNormalizedExpoPermissionState(permission, response, status);\n}\n\nexport function createExpoUnavailableState(\n permission: Permission,\n error: unknown,\n): PermissionState {\n return createPermissionState({\n permission,\n status: 'unavailable',\n reason: getExpoPermissionErrorMessage(error),\n });\n}\n\nexport function findExpoPermissionMethod(\n source: unknown,\n methodName: string,\n containerNames: readonly string[] = [],\n): ExpoPermissionMethod | undefined {\n if (hasExpoPermissionMethod(source, methodName)) {\n return source[methodName];\n }\n\n if (!isRecord(source)) {\n return undefined;\n }\n\n for (const containerName of containerNames) {\n const container = source[containerName];\n\n if (hasExpoPermissionMethod(container, methodName)) {\n return container[methodName];\n }\n }\n\n return undefined;\n}\n\nfunction getExpoPermissionErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message.length > 0) {\n return error.message;\n }\n\n if (typeof error === 'string' && error.length > 0) {\n return error;\n }\n\n return 'Expo permission operation failed.';\n}\n\nfunction createNormalizedExpoPermissionState(\n permission: Permission,\n response: ExpoPermissionResponse,\n status: PermissionStatus,\n reason?: string,\n): PermissionState {\n const normalizedStatus =\n status === 'denied' && response.canAskAgain === false ? 'blocked' : status;\n\n return createPermissionState({\n permission,\n status: normalizedStatus,\n canAskAgain: response.canAskAgain,\n reason:\n normalizedStatus === 'blocked'\n ? 'Permission is blocked. Open system settings to change it.'\n : reason,\n });\n}\n\nfunction hasExpoPermissionMethod(\n value: unknown,\n methodName: string,\n): value is Record<string, ExpoPermissionMethod> {\n return isRecord(value) && typeof value[methodName] === 'function';\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"]}
1
+ {"version":3,"file":"permissionResponse.js","sourceRoot":"","sources":["../../src/expo/permissionResponse.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,kBAAkB,GAGnB,MAAM,0BAA0B,CAAC;AASlC,MAAM,UAAU,yBAAyB,CACvC,UAAsB,EACtB,QAAgC;IAEhC,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAEjF,OAAO,mCAAmC,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAAsB,EACtB,KAAc;IAEd,OAAO,qBAAqB,CAAC;QAC3B,UAAU;QACV,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,6BAA6B,CAAC,KAAK,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,MAAe,EACf,UAAkB,EAClB,iBAAoC,EAAE;IAEtC,IAAI,uBAAuB,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;QAChD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QAErD,IAAI,uBAAuB,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;YACnD,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,6BAA6B,CAAC,KAAc;IACnD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,mCAAmC,CAAC;AAC7C,CAAC;AAED,SAAS,mCAAmC,CAC1C,UAAsB,EACtB,QAAgC,EAChC,MAAwB,EACxB,MAAe;IAEf,MAAM,gBAAgB,GACpB,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAE7E,OAAO,qBAAqB,CAAC;QAC3B,UAAU;QACV,MAAM,EAAE,gBAAgB;QACxB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,MAAM,EACJ,gBAAgB,KAAK,SAAS;YAC5B,CAAC,CAAC,2DAA2D;YAC7D,CAAC,CAAC,MAAM;KACb,CAAC,CAAC;AACL,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAc,EACd,UAAkB;IAElB,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,UAAU,CAAC;AACjF,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC","sourcesContent":["import type { Permission } from '../registry/permissions';\nimport {\n createPermissionState,\n isPermissionStatus,\n type PermissionState,\n type PermissionStatus,\n} from '../state/permissionState';\n\nexport interface ExpoPermissionResponse {\n readonly status: string;\n readonly canAskAgain?: boolean;\n}\n\nexport type ExpoPermissionMethod = () => Promise<ExpoPermissionResponse>;\n\nexport function createExpoPermissionState(\n permission: Permission,\n response: ExpoPermissionResponse,\n): PermissionState {\n const status = isPermissionStatus(response.status) ? response.status : 'unknown';\n\n return createNormalizedExpoPermissionState(permission, response, status);\n}\n\nexport function createExpoUnavailableState(\n permission: Permission,\n error: unknown,\n): PermissionState {\n return createPermissionState({\n permission,\n status: 'unavailable',\n reason: getExpoPermissionErrorMessage(error),\n });\n}\n\nexport function findExpoPermissionMethod(\n source: unknown,\n methodName: string,\n containerNames: readonly string[] = [],\n): ExpoPermissionMethod | undefined {\n if (hasExpoPermissionMethod(source, methodName)) {\n return Reflect.get(source, methodName);\n }\n\n if (!isRecord(source)) {\n return undefined;\n }\n\n for (const containerName of containerNames) {\n const container = Reflect.get(source, containerName);\n\n if (hasExpoPermissionMethod(container, methodName)) {\n return Reflect.get(container, methodName);\n }\n }\n\n return undefined;\n}\n\nfunction getExpoPermissionErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message.length > 0) {\n return error.message;\n }\n\n if (typeof error === 'string' && error.length > 0) {\n return error;\n }\n\n return 'Expo permission operation failed.';\n}\n\nfunction createNormalizedExpoPermissionState(\n permission: Permission,\n response: ExpoPermissionResponse,\n status: PermissionStatus,\n reason?: string,\n): PermissionState {\n const normalizedStatus =\n status === 'denied' && response.canAskAgain === false ? 'blocked' : status;\n\n return createPermissionState({\n permission,\n status: normalizedStatus,\n canAskAgain: response.canAskAgain,\n reason:\n normalizedStatus === 'blocked'\n ? 'Permission is blocked. Open system settings to change it.'\n : reason,\n });\n}\n\nfunction hasExpoPermissionMethod(\n value: unknown,\n methodName: string,\n): value is Record<string, ExpoPermissionMethod> {\n return isRecord(value) && typeof Reflect.get(value, methodName) === 'function';\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAIlC;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,YAAY,CAAC,EAAE,eAAe,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,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;IACzB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,OAAO,GACR,EAAE,wBAAwB,GAAG,SAAS,CActC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAQlD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,oBAAyB,GACjC,oBAAoB,CAkDtB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAIlC;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,YAAY,CAAC,EAAE,eAAe,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,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;IACzB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,OAAO,GACR,EAAE,wBAAwB,GAAG,SAAS,CActC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAQlD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,oBAAyB,GACjC,oBAAoB,CAgDtB"}
@@ -36,13 +36,7 @@ export function usePermissions() {
36
36
  */
37
37
  export function usePermission(permission, options = {}) {
38
38
  const manager = usePermissions();
39
- const [state, setState] = useState(() => (options.initialState === undefined
40
- ? undefined
41
- : normalizePermissionState(permission, options.initialState)) ??
42
- createPermissionState({
43
- permission,
44
- status: 'unknown',
45
- }));
39
+ const [state, setState] = useState(() => createInitialPermissionState(permission, options.initialState));
46
40
  const refresh = useCallback(async () => {
47
41
  const nextState = await manager.getStatus(permission);
48
42
  setState(nextState);
@@ -54,10 +48,17 @@ export function usePermission(permission, options = {}) {
54
48
  return nextState;
55
49
  }, [manager, permission]);
56
50
  useEffect(() => {
57
- if (options.refreshOnMount === true) {
58
- void refresh();
59
- }
60
- }, [options.refreshOnMount, refresh]);
51
+ if (options.refreshOnMount !== true)
52
+ return;
53
+ let active = true;
54
+ void manager.getStatus(permission).then((nextState) => {
55
+ if (active)
56
+ setState(nextState);
57
+ });
58
+ return () => {
59
+ active = false;
60
+ };
61
+ }, [manager, options.refreshOnMount, permission]);
61
62
  const openSettings = manager.openSettings === undefined
62
63
  ? undefined
63
64
  : () => manager.openSettings?.() ?? Promise.resolve();
@@ -74,4 +75,8 @@ export function usePermission(permission, options = {}) {
74
75
  openSettings,
75
76
  };
76
77
  }
78
+ function createInitialPermissionState(permission, initialState) {
79
+ return ((initialState === undefined ? undefined : normalizePermissionState(permission, initialState)) ??
80
+ createPermissionState({ permission, status: 'unknown' }));
81
+ }
77
82
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n createElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nimport type { PermissionClient } from '../client/types';\nimport {\n createPermissionManager,\n type PermissionManager,\n} from '../manager/createPermissionManager';\nimport type { Permission } from '../registry/permissions';\nimport {\n createPermissionState,\n normalizePermissionState,\n type PermissionState,\n type PermissionStatus,\n} from '../state/permissionState';\n\nconst PermissionsContext = createContext<PermissionManager | undefined>(undefined);\n\n/***\n * Props accepted by `PermissionsProvider`.\n */\nexport interface PermissionsProviderProps {\n readonly children: ReactNode;\n readonly client?: PermissionClient;\n readonly manager?: PermissionManager;\n}\n\n/***\n * Options for `usePermission`.\n */\nexport interface UsePermissionOptions {\n readonly initialState?: PermissionState;\n readonly refreshOnMount?: boolean;\n}\n\n/***\n * Result returned by `usePermission`.\n */\nexport interface PermissionHookResult {\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 readonly state: PermissionState;\n readonly refresh: () => Promise<PermissionState>;\n readonly request: () => Promise<PermissionState>;\n readonly openSettings?: () => Promise<void>;\n}\n\n/***\n * Provides a permission manager to React hooks.\n *\n * @readme\n * React helpers are framework-neutral. They depend on React only and do not\n * import browser, Expo, or React Native permission APIs.\n */\nexport function PermissionsProvider({\n children,\n client,\n manager,\n}: PermissionsProviderProps): ReactNode {\n const resolvedManager = useMemo(() => {\n if (manager !== undefined) {\n return manager;\n }\n\n if (client !== undefined) {\n return createPermissionManager(client);\n }\n\n throw new Error('PermissionsProvider requires a client or manager.');\n }, [client, manager]);\n\n return createElement(PermissionsContext.Provider, { value: resolvedManager }, children);\n}\n\n/***\n * Reads the current permission manager from context.\n */\nexport function usePermissions(): PermissionManager {\n const manager = useContext(PermissionsContext);\n\n if (manager === undefined) {\n throw new Error('usePermissions must be used within PermissionsProvider.');\n }\n\n return manager;\n}\n\n/***\n * Tracks a single permission and exposes explicit refresh/request actions.\n */\nexport function usePermission(\n permission: Permission,\n options: UsePermissionOptions = {},\n): PermissionHookResult {\n const manager = usePermissions();\n const [state, setState] = useState<PermissionState>(\n () =>\n (options.initialState === undefined\n ? undefined\n : normalizePermissionState(permission, options.initialState)) ??\n createPermissionState({\n permission,\n status: 'unknown',\n }),\n );\n\n const refresh = useCallback(async () => {\n const nextState = await manager.getStatus(permission);\n setState(nextState);\n\n return nextState;\n }, [manager, permission]);\n\n const request = useCallback(async () => {\n const nextState = await manager.request(permission);\n setState(nextState);\n\n return nextState;\n }, [manager, permission]);\n\n useEffect(() => {\n if (options.refreshOnMount === true) {\n void refresh();\n }\n }, [options.refreshOnMount, refresh]);\n\n const openSettings =\n manager.openSettings === undefined\n ? undefined\n : () => manager.openSettings?.() ?? Promise.resolve();\n\n return {\n permission: state.permission,\n status: state.status,\n canAskAgain: state.canAskAgain,\n granted: state.granted,\n requestedAt: state.requestedAt,\n reason: state.reason,\n state,\n refresh,\n request,\n openSettings,\n };\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n createElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nimport type { PermissionClient } from '../client/types';\nimport {\n createPermissionManager,\n type PermissionManager,\n} from '../manager/createPermissionManager';\nimport type { Permission } from '../registry/permissions';\nimport {\n createPermissionState,\n normalizePermissionState,\n type PermissionState,\n type PermissionStatus,\n} from '../state/permissionState';\n\nconst PermissionsContext = createContext<PermissionManager | undefined>(undefined);\n\n/***\n * Props accepted by `PermissionsProvider`.\n */\nexport interface PermissionsProviderProps {\n readonly children: ReactNode;\n readonly client?: PermissionClient;\n readonly manager?: PermissionManager;\n}\n\n/***\n * Options for `usePermission`.\n */\nexport interface UsePermissionOptions {\n readonly initialState?: PermissionState;\n readonly refreshOnMount?: boolean;\n}\n\n/***\n * Result returned by `usePermission`.\n */\nexport interface PermissionHookResult {\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 readonly state: PermissionState;\n readonly refresh: () => Promise<PermissionState>;\n readonly request: () => Promise<PermissionState>;\n readonly openSettings?: () => Promise<void>;\n}\n\n/***\n * Provides a permission manager to React hooks.\n *\n * @readme\n * React helpers are framework-neutral. They depend on React only and do not\n * import browser, Expo, or React Native permission APIs.\n */\nexport function PermissionsProvider({\n children,\n client,\n manager,\n}: PermissionsProviderProps): ReactNode {\n const resolvedManager = useMemo(() => {\n if (manager !== undefined) {\n return manager;\n }\n\n if (client !== undefined) {\n return createPermissionManager(client);\n }\n\n throw new Error('PermissionsProvider requires a client or manager.');\n }, [client, manager]);\n\n return createElement(PermissionsContext.Provider, { value: resolvedManager }, children);\n}\n\n/***\n * Reads the current permission manager from context.\n */\nexport function usePermissions(): PermissionManager {\n const manager = useContext(PermissionsContext);\n\n if (manager === undefined) {\n throw new Error('usePermissions must be used within PermissionsProvider.');\n }\n\n return manager;\n}\n\n/***\n * Tracks a single permission and exposes explicit refresh/request actions.\n */\nexport function usePermission(\n permission: Permission,\n options: UsePermissionOptions = {},\n): PermissionHookResult {\n const manager = usePermissions();\n const [state, setState] = useState<PermissionState>(() =>\n createInitialPermissionState(permission, options.initialState),\n );\n\n const refresh = useCallback(async () => {\n const nextState = await manager.getStatus(permission);\n setState(nextState);\n\n return nextState;\n }, [manager, permission]);\n\n const request = useCallback(async () => {\n const nextState = await manager.request(permission);\n setState(nextState);\n\n return nextState;\n }, [manager, permission]);\n\n useEffect(() => {\n if (options.refreshOnMount !== true) return;\n let active = true;\n void manager.getStatus(permission).then((nextState) => {\n if (active) setState(nextState);\n });\n return () => {\n active = false;\n };\n }, [manager, options.refreshOnMount, permission]);\n\n const openSettings =\n manager.openSettings === undefined\n ? undefined\n : () => manager.openSettings?.() ?? Promise.resolve();\n\n return {\n permission: state.permission,\n status: state.status,\n canAskAgain: state.canAskAgain,\n granted: state.granted,\n requestedAt: state.requestedAt,\n reason: state.reason,\n state,\n refresh,\n request,\n openSettings,\n };\n}\n\nfunction createInitialPermissionState(\n permission: Permission,\n initialState: PermissionState | undefined,\n): PermissionState {\n return (\n (initialState === undefined ? undefined : normalizePermissionState(permission, initialState)) ??\n createPermissionState({ permission, status: 'unknown' })\n );\n}\n"]}
@@ -1 +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;;;;GAIG;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"}
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,GAC1B,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE3E;;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;;;;GAIG;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"}
@@ -1 +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;;;;GAIG;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,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QACjE,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 * Limited access is usable partial authorization, so both `granted` and\n * `limited` states set `granted` to true.\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' || input.status === 'limited',\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"]}
1
+ {"version":3,"file":"permissionState.js","sourceRoot":"","sources":["../../src/state/permissionState.ts"],"names":[],"mappings":"AAWA;;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;;;;GAIG;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,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QACjE,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' | 'granted' | 'denied' | 'blocked' | 'limited' | '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 * Limited access is usable partial authorization, so both `granted` and\n * `limited` states set `granted` to true.\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' || input.status === 'limited',\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"]}