expo-permissions-store 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createApi.d.ts","sourceRoot":"","sources":["../src/createApi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,cAAc,EACf,MAAM,SAAS,CAAC;AAIjB,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,iBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuElE;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { PermissionsApi } from "./createApi";
2
+ /**
3
+ * Sets up a listener to invalidate permission cache when app returns to foreground
4
+ * This handles the case where users change permissions in device settings
5
+ */
6
+ export declare function setupForegroundListener(api: PermissionsApi): () => void;
7
+ //# sourceMappingURL=foreground.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foreground.d.ts","sourceRoot":"","sources":["../src/foreground.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,IAAI,CAYvE"}
package/dist/index.cjs ADDED
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ALL_PERMISSIONS: () => ALL_PERMISSIONS,
24
+ DEFAULT_CONFIG: () => DEFAULT_CONFIG,
25
+ createPermissionsApi: () => createPermissionsApi,
26
+ permissionsApi: () => permissionsApi,
27
+ setupForegroundListener: () => setupForegroundListener,
28
+ store: () => store,
29
+ useGetPermissionQuery: () => useGetPermissionQuery,
30
+ useLazyGetPermissionQuery: () => useLazyGetPermissionQuery,
31
+ usePrefetch: () => usePrefetch,
32
+ useRequestPermissionMutation: () => useRequestPermissionMutation
33
+ });
34
+ module.exports = __toCommonJS(index_exports);
35
+
36
+ // src/types.ts
37
+ var ALL_PERMISSIONS = [
38
+ "camera",
39
+ "microphone",
40
+ "mediaLibrary",
41
+ "locationForeground",
42
+ "locationBackground",
43
+ "notifications",
44
+ "contacts",
45
+ "calendar",
46
+ "tracking"
47
+ ];
48
+ var DEFAULT_CONFIG = {
49
+ permissions: ALL_PERMISSIONS,
50
+ recheckOnForeground: true,
51
+ autoCheckOnMount: false,
52
+ cacheTime: Infinity
53
+ };
54
+
55
+ // src/createApi.ts
56
+ var import_react = require("@reduxjs/toolkit/query/react");
57
+
58
+ // src/permissions/handlers.ts
59
+ function normalizeResponse(response) {
60
+ const status = response.status;
61
+ return {
62
+ status: status === "granted" || status === "denied" || status === "limited" ? status : "undetermined",
63
+ canAskAgain: response.canAskAgain ?? true,
64
+ expires: response.expires ?? "never"
65
+ };
66
+ }
67
+ async function tryImport(moduleName) {
68
+ try {
69
+ return await import(moduleName);
70
+ } catch {
71
+ return null;
72
+ }
73
+ }
74
+ async function getPermission(type) {
75
+ switch (type) {
76
+ case "camera": {
77
+ const Camera = await tryImport("expo-camera");
78
+ if (!Camera) throw new Error("expo-camera is not installed");
79
+ const response = await Camera.Camera.getCameraPermissionsAsync();
80
+ return normalizeResponse(response);
81
+ }
82
+ case "microphone": {
83
+ const Camera = await tryImport("expo-camera");
84
+ if (!Camera) throw new Error("expo-camera is not installed");
85
+ const response = await Camera.Camera.getMicrophonePermissionsAsync();
86
+ return normalizeResponse(response);
87
+ }
88
+ case "mediaLibrary": {
89
+ const MediaLibrary = await tryImport(
90
+ "expo-media-library"
91
+ );
92
+ if (!MediaLibrary) throw new Error("expo-media-library is not installed");
93
+ const response = await MediaLibrary.getPermissionsAsync();
94
+ return normalizeResponse(response);
95
+ }
96
+ case "locationForeground": {
97
+ const Location = await tryImport("expo-location");
98
+ if (!Location) throw new Error("expo-location is not installed");
99
+ const response = await Location.getForegroundPermissionsAsync();
100
+ return normalizeResponse(response);
101
+ }
102
+ case "locationBackground": {
103
+ const Location = await tryImport("expo-location");
104
+ if (!Location) throw new Error("expo-location is not installed");
105
+ const response = await Location.getBackgroundPermissionsAsync();
106
+ return normalizeResponse(response);
107
+ }
108
+ case "notifications": {
109
+ const Notifications = await tryImport(
110
+ "expo-notifications"
111
+ );
112
+ if (!Notifications)
113
+ throw new Error("expo-notifications is not installed");
114
+ const response = await Notifications.getPermissionsAsync();
115
+ return normalizeResponse(response);
116
+ }
117
+ case "contacts": {
118
+ const Contacts = await tryImport("expo-contacts");
119
+ if (!Contacts) throw new Error("expo-contacts is not installed");
120
+ const response = await Contacts.getPermissionsAsync();
121
+ return normalizeResponse(response);
122
+ }
123
+ case "calendar": {
124
+ const Calendar = await tryImport("expo-calendar");
125
+ if (!Calendar) throw new Error("expo-calendar is not installed");
126
+ const response = await Calendar.getCalendarPermissionsAsync();
127
+ return normalizeResponse(response);
128
+ }
129
+ case "tracking": {
130
+ const Tracking = await tryImport("expo-tracking-transparency");
131
+ if (!Tracking)
132
+ throw new Error("expo-tracking-transparency is not installed");
133
+ const response = await Tracking.getTrackingPermissionsAsync();
134
+ return normalizeResponse(response);
135
+ }
136
+ default: {
137
+ const _exhaustive = type;
138
+ throw new Error(`Unknown permission type: ${_exhaustive}`);
139
+ }
140
+ }
141
+ }
142
+ async function requestPermission(type) {
143
+ switch (type) {
144
+ case "camera": {
145
+ const Camera = await tryImport("expo-camera");
146
+ if (!Camera) throw new Error("expo-camera is not installed");
147
+ const response = await Camera.Camera.requestCameraPermissionsAsync();
148
+ return normalizeResponse(response);
149
+ }
150
+ case "microphone": {
151
+ const Camera = await tryImport("expo-camera");
152
+ if (!Camera) throw new Error("expo-camera is not installed");
153
+ const response = await Camera.Camera.requestMicrophonePermissionsAsync();
154
+ return normalizeResponse(response);
155
+ }
156
+ case "mediaLibrary": {
157
+ const MediaLibrary = await tryImport(
158
+ "expo-media-library"
159
+ );
160
+ if (!MediaLibrary) throw new Error("expo-media-library is not installed");
161
+ const response = await MediaLibrary.requestPermissionsAsync();
162
+ return normalizeResponse(response);
163
+ }
164
+ case "locationForeground": {
165
+ const Location = await tryImport("expo-location");
166
+ if (!Location) throw new Error("expo-location is not installed");
167
+ const response = await Location.requestForegroundPermissionsAsync();
168
+ return normalizeResponse(response);
169
+ }
170
+ case "locationBackground": {
171
+ const Location = await tryImport("expo-location");
172
+ if (!Location) throw new Error("expo-location is not installed");
173
+ const response = await Location.requestBackgroundPermissionsAsync();
174
+ return normalizeResponse(response);
175
+ }
176
+ case "notifications": {
177
+ const Notifications = await tryImport(
178
+ "expo-notifications"
179
+ );
180
+ if (!Notifications)
181
+ throw new Error("expo-notifications is not installed");
182
+ const response = await Notifications.requestPermissionsAsync();
183
+ return normalizeResponse(response);
184
+ }
185
+ case "contacts": {
186
+ const Contacts = await tryImport("expo-contacts");
187
+ if (!Contacts) throw new Error("expo-contacts is not installed");
188
+ const response = await Contacts.requestPermissionsAsync();
189
+ return normalizeResponse(response);
190
+ }
191
+ case "calendar": {
192
+ const Calendar = await tryImport("expo-calendar");
193
+ if (!Calendar) throw new Error("expo-calendar is not installed");
194
+ const response = await Calendar.requestCalendarPermissionsAsync();
195
+ return normalizeResponse(response);
196
+ }
197
+ case "tracking": {
198
+ const Tracking = await tryImport("expo-tracking-transparency");
199
+ if (!Tracking)
200
+ throw new Error("expo-tracking-transparency is not installed");
201
+ const response = await Tracking.requestTrackingPermissionsAsync();
202
+ return normalizeResponse(response);
203
+ }
204
+ default: {
205
+ const _exhaustive = type;
206
+ throw new Error(`Unknown permission type: ${_exhaustive}`);
207
+ }
208
+ }
209
+ }
210
+
211
+ // src/createApi.ts
212
+ function createPermissionsApi(config = {}) {
213
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
214
+ const api = (0, import_react.createApi)({
215
+ reducerPath: "permissionsApi",
216
+ baseQuery: (0, import_react.fakeBaseQuery)(),
217
+ tagTypes: ["Permission"],
218
+ endpoints: (builder) => ({
219
+ getPermission: builder.query({
220
+ queryFn: async (permissionType) => {
221
+ if (!mergedConfig.permissions.includes(permissionType)) {
222
+ return {
223
+ error: {
224
+ status: "CUSTOM_ERROR",
225
+ error: `Permission "${permissionType}" is not configured`
226
+ }
227
+ };
228
+ }
229
+ try {
230
+ const data = await getPermission(permissionType);
231
+ return { data };
232
+ } catch (error) {
233
+ return {
234
+ error: {
235
+ status: "CUSTOM_ERROR",
236
+ error: error instanceof Error ? error.message : "Unknown error"
237
+ }
238
+ };
239
+ }
240
+ },
241
+ providesTags: (_, __, permissionType) => [
242
+ { type: "Permission", id: permissionType }
243
+ ],
244
+ keepUnusedDataFor: mergedConfig.cacheTime
245
+ }),
246
+ requestPermission: builder.mutation({
247
+ queryFn: async (permissionType) => {
248
+ if (!mergedConfig.permissions.includes(permissionType)) {
249
+ return {
250
+ error: {
251
+ status: "CUSTOM_ERROR",
252
+ error: `Permission "${permissionType}" is not configured`
253
+ }
254
+ };
255
+ }
256
+ try {
257
+ const data = await requestPermission(permissionType);
258
+ return { data };
259
+ } catch (error) {
260
+ return {
261
+ error: {
262
+ status: "CUSTOM_ERROR",
263
+ error: error instanceof Error ? error.message : "Unknown error"
264
+ }
265
+ };
266
+ }
267
+ },
268
+ invalidatesTags: (_, __, permissionType) => [
269
+ { type: "Permission", id: permissionType }
270
+ ]
271
+ })
272
+ })
273
+ });
274
+ return {
275
+ ...api,
276
+ config: mergedConfig
277
+ };
278
+ }
279
+
280
+ // src/api.ts
281
+ var permissionsApi = createPermissionsApi();
282
+ var {
283
+ useGetPermissionQuery,
284
+ useLazyGetPermissionQuery,
285
+ useRequestPermissionMutation,
286
+ usePrefetch
287
+ } = permissionsApi;
288
+
289
+ // src/store.ts
290
+ var import_toolkit = require("@reduxjs/toolkit");
291
+ var store = (0, import_toolkit.configureStore)({
292
+ reducer: {
293
+ [permissionsApi.reducerPath]: permissionsApi.reducer
294
+ },
295
+ middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(permissionsApi.middleware)
296
+ });
297
+
298
+ // src/foreground.ts
299
+ var import_react_native = require("react-native");
300
+ function setupForegroundListener(api) {
301
+ let previousState = import_react_native.AppState.currentState;
302
+ const subscription = import_react_native.AppState.addEventListener("change", (nextState) => {
303
+ if (previousState !== "active" && nextState === "active") {
304
+ api.util.invalidateTags(["Permission"]);
305
+ }
306
+ previousState = nextState;
307
+ });
308
+ return () => subscription.remove();
309
+ }
310
+ // Annotate the CommonJS export names for ESM import in node:
311
+ 0 && (module.exports = {
312
+ ALL_PERMISSIONS,
313
+ DEFAULT_CONFIG,
314
+ createPermissionsApi,
315
+ permissionsApi,
316
+ setupForegroundListener,
317
+ store,
318
+ useGetPermissionQuery,
319
+ useLazyGetPermissionQuery,
320
+ usePrefetch,
321
+ useRequestPermissionMutation
322
+ });
@@ -0,0 +1,7 @@
1
+ export type { PermissionType, PermissionStatus, PermissionState, PermissionsConfig, } from "./types";
2
+ export { ALL_PERMISSIONS, DEFAULT_CONFIG } from "./types";
3
+ export { createPermissionsApi, type PermissionsApi } from "./createApi";
4
+ export { permissionsApi, useGetPermissionQuery, useLazyGetPermissionQuery, useRequestPermissionMutation, usePrefetch, } from "./api";
5
+ export { store, type RootState, type AppDispatch } from "./store";
6
+ export { setupForegroundListener } from "./foreground";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG1D,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAGxE,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,WAAW,GACZ,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,KAAK,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAGlE,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,286 @@
1
+ // src/types.ts
2
+ var ALL_PERMISSIONS = [
3
+ "camera",
4
+ "microphone",
5
+ "mediaLibrary",
6
+ "locationForeground",
7
+ "locationBackground",
8
+ "notifications",
9
+ "contacts",
10
+ "calendar",
11
+ "tracking"
12
+ ];
13
+ var DEFAULT_CONFIG = {
14
+ permissions: ALL_PERMISSIONS,
15
+ recheckOnForeground: true,
16
+ autoCheckOnMount: false,
17
+ cacheTime: Infinity
18
+ };
19
+
20
+ // src/createApi.ts
21
+ import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react";
22
+
23
+ // src/permissions/handlers.ts
24
+ function normalizeResponse(response) {
25
+ const status = response.status;
26
+ return {
27
+ status: status === "granted" || status === "denied" || status === "limited" ? status : "undetermined",
28
+ canAskAgain: response.canAskAgain ?? true,
29
+ expires: response.expires ?? "never"
30
+ };
31
+ }
32
+ async function tryImport(moduleName) {
33
+ try {
34
+ return await import(moduleName);
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
39
+ async function getPermission(type) {
40
+ switch (type) {
41
+ case "camera": {
42
+ const Camera = await tryImport("expo-camera");
43
+ if (!Camera) throw new Error("expo-camera is not installed");
44
+ const response = await Camera.Camera.getCameraPermissionsAsync();
45
+ return normalizeResponse(response);
46
+ }
47
+ case "microphone": {
48
+ const Camera = await tryImport("expo-camera");
49
+ if (!Camera) throw new Error("expo-camera is not installed");
50
+ const response = await Camera.Camera.getMicrophonePermissionsAsync();
51
+ return normalizeResponse(response);
52
+ }
53
+ case "mediaLibrary": {
54
+ const MediaLibrary = await tryImport(
55
+ "expo-media-library"
56
+ );
57
+ if (!MediaLibrary) throw new Error("expo-media-library is not installed");
58
+ const response = await MediaLibrary.getPermissionsAsync();
59
+ return normalizeResponse(response);
60
+ }
61
+ case "locationForeground": {
62
+ const Location = await tryImport("expo-location");
63
+ if (!Location) throw new Error("expo-location is not installed");
64
+ const response = await Location.getForegroundPermissionsAsync();
65
+ return normalizeResponse(response);
66
+ }
67
+ case "locationBackground": {
68
+ const Location = await tryImport("expo-location");
69
+ if (!Location) throw new Error("expo-location is not installed");
70
+ const response = await Location.getBackgroundPermissionsAsync();
71
+ return normalizeResponse(response);
72
+ }
73
+ case "notifications": {
74
+ const Notifications = await tryImport(
75
+ "expo-notifications"
76
+ );
77
+ if (!Notifications)
78
+ throw new Error("expo-notifications is not installed");
79
+ const response = await Notifications.getPermissionsAsync();
80
+ return normalizeResponse(response);
81
+ }
82
+ case "contacts": {
83
+ const Contacts = await tryImport("expo-contacts");
84
+ if (!Contacts) throw new Error("expo-contacts is not installed");
85
+ const response = await Contacts.getPermissionsAsync();
86
+ return normalizeResponse(response);
87
+ }
88
+ case "calendar": {
89
+ const Calendar = await tryImport("expo-calendar");
90
+ if (!Calendar) throw new Error("expo-calendar is not installed");
91
+ const response = await Calendar.getCalendarPermissionsAsync();
92
+ return normalizeResponse(response);
93
+ }
94
+ case "tracking": {
95
+ const Tracking = await tryImport("expo-tracking-transparency");
96
+ if (!Tracking)
97
+ throw new Error("expo-tracking-transparency is not installed");
98
+ const response = await Tracking.getTrackingPermissionsAsync();
99
+ return normalizeResponse(response);
100
+ }
101
+ default: {
102
+ const _exhaustive = type;
103
+ throw new Error(`Unknown permission type: ${_exhaustive}`);
104
+ }
105
+ }
106
+ }
107
+ async function requestPermission(type) {
108
+ switch (type) {
109
+ case "camera": {
110
+ const Camera = await tryImport("expo-camera");
111
+ if (!Camera) throw new Error("expo-camera is not installed");
112
+ const response = await Camera.Camera.requestCameraPermissionsAsync();
113
+ return normalizeResponse(response);
114
+ }
115
+ case "microphone": {
116
+ const Camera = await tryImport("expo-camera");
117
+ if (!Camera) throw new Error("expo-camera is not installed");
118
+ const response = await Camera.Camera.requestMicrophonePermissionsAsync();
119
+ return normalizeResponse(response);
120
+ }
121
+ case "mediaLibrary": {
122
+ const MediaLibrary = await tryImport(
123
+ "expo-media-library"
124
+ );
125
+ if (!MediaLibrary) throw new Error("expo-media-library is not installed");
126
+ const response = await MediaLibrary.requestPermissionsAsync();
127
+ return normalizeResponse(response);
128
+ }
129
+ case "locationForeground": {
130
+ const Location = await tryImport("expo-location");
131
+ if (!Location) throw new Error("expo-location is not installed");
132
+ const response = await Location.requestForegroundPermissionsAsync();
133
+ return normalizeResponse(response);
134
+ }
135
+ case "locationBackground": {
136
+ const Location = await tryImport("expo-location");
137
+ if (!Location) throw new Error("expo-location is not installed");
138
+ const response = await Location.requestBackgroundPermissionsAsync();
139
+ return normalizeResponse(response);
140
+ }
141
+ case "notifications": {
142
+ const Notifications = await tryImport(
143
+ "expo-notifications"
144
+ );
145
+ if (!Notifications)
146
+ throw new Error("expo-notifications is not installed");
147
+ const response = await Notifications.requestPermissionsAsync();
148
+ return normalizeResponse(response);
149
+ }
150
+ case "contacts": {
151
+ const Contacts = await tryImport("expo-contacts");
152
+ if (!Contacts) throw new Error("expo-contacts is not installed");
153
+ const response = await Contacts.requestPermissionsAsync();
154
+ return normalizeResponse(response);
155
+ }
156
+ case "calendar": {
157
+ const Calendar = await tryImport("expo-calendar");
158
+ if (!Calendar) throw new Error("expo-calendar is not installed");
159
+ const response = await Calendar.requestCalendarPermissionsAsync();
160
+ return normalizeResponse(response);
161
+ }
162
+ case "tracking": {
163
+ const Tracking = await tryImport("expo-tracking-transparency");
164
+ if (!Tracking)
165
+ throw new Error("expo-tracking-transparency is not installed");
166
+ const response = await Tracking.requestTrackingPermissionsAsync();
167
+ return normalizeResponse(response);
168
+ }
169
+ default: {
170
+ const _exhaustive = type;
171
+ throw new Error(`Unknown permission type: ${_exhaustive}`);
172
+ }
173
+ }
174
+ }
175
+
176
+ // src/createApi.ts
177
+ function createPermissionsApi(config = {}) {
178
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
179
+ const api = createApi({
180
+ reducerPath: "permissionsApi",
181
+ baseQuery: fakeBaseQuery(),
182
+ tagTypes: ["Permission"],
183
+ endpoints: (builder) => ({
184
+ getPermission: builder.query({
185
+ queryFn: async (permissionType) => {
186
+ if (!mergedConfig.permissions.includes(permissionType)) {
187
+ return {
188
+ error: {
189
+ status: "CUSTOM_ERROR",
190
+ error: `Permission "${permissionType}" is not configured`
191
+ }
192
+ };
193
+ }
194
+ try {
195
+ const data = await getPermission(permissionType);
196
+ return { data };
197
+ } catch (error) {
198
+ return {
199
+ error: {
200
+ status: "CUSTOM_ERROR",
201
+ error: error instanceof Error ? error.message : "Unknown error"
202
+ }
203
+ };
204
+ }
205
+ },
206
+ providesTags: (_, __, permissionType) => [
207
+ { type: "Permission", id: permissionType }
208
+ ],
209
+ keepUnusedDataFor: mergedConfig.cacheTime
210
+ }),
211
+ requestPermission: builder.mutation({
212
+ queryFn: async (permissionType) => {
213
+ if (!mergedConfig.permissions.includes(permissionType)) {
214
+ return {
215
+ error: {
216
+ status: "CUSTOM_ERROR",
217
+ error: `Permission "${permissionType}" is not configured`
218
+ }
219
+ };
220
+ }
221
+ try {
222
+ const data = await requestPermission(permissionType);
223
+ return { data };
224
+ } catch (error) {
225
+ return {
226
+ error: {
227
+ status: "CUSTOM_ERROR",
228
+ error: error instanceof Error ? error.message : "Unknown error"
229
+ }
230
+ };
231
+ }
232
+ },
233
+ invalidatesTags: (_, __, permissionType) => [
234
+ { type: "Permission", id: permissionType }
235
+ ]
236
+ })
237
+ })
238
+ });
239
+ return {
240
+ ...api,
241
+ config: mergedConfig
242
+ };
243
+ }
244
+
245
+ // src/api.ts
246
+ var permissionsApi = createPermissionsApi();
247
+ var {
248
+ useGetPermissionQuery,
249
+ useLazyGetPermissionQuery,
250
+ useRequestPermissionMutation,
251
+ usePrefetch
252
+ } = permissionsApi;
253
+
254
+ // src/store.ts
255
+ import { configureStore } from "@reduxjs/toolkit";
256
+ var store = configureStore({
257
+ reducer: {
258
+ [permissionsApi.reducerPath]: permissionsApi.reducer
259
+ },
260
+ middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(permissionsApi.middleware)
261
+ });
262
+
263
+ // src/foreground.ts
264
+ import { AppState } from "react-native";
265
+ function setupForegroundListener(api) {
266
+ let previousState = AppState.currentState;
267
+ const subscription = AppState.addEventListener("change", (nextState) => {
268
+ if (previousState !== "active" && nextState === "active") {
269
+ api.util.invalidateTags(["Permission"]);
270
+ }
271
+ previousState = nextState;
272
+ });
273
+ return () => subscription.remove();
274
+ }
275
+ export {
276
+ ALL_PERMISSIONS,
277
+ DEFAULT_CONFIG,
278
+ createPermissionsApi,
279
+ permissionsApi,
280
+ setupForegroundListener,
281
+ store,
282
+ useGetPermissionQuery,
283
+ useLazyGetPermissionQuery,
284
+ usePrefetch,
285
+ useRequestPermissionMutation
286
+ };
@@ -0,0 +1,4 @@
1
+ import type { PermissionState, PermissionType } from "../types";
2
+ export declare function getPermission(type: PermissionType): Promise<PermissionState>;
3
+ export declare function requestPermission(type: PermissionType): Promise<PermissionState>;
4
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/permissions/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA6BhE,wBAAsB,aAAa,CACjC,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,eAAe,CAAC,CAsF1B;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,eAAe,CAAC,CAsF1B"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Pre-configured store with permissions API
3
+ * Use this for quick setup without integrating into an existing store
4
+ */
5
+ export declare const store: import("@reduxjs/toolkit").EnhancedStore<{
6
+ permissionsApi: import("@reduxjs/toolkit/query").CombinedState<{
7
+ getPermission: import("@reduxjs/toolkit/query").QueryDefinition<import("./types").PermissionType, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Permission", import("./types").PermissionState, "permissionsApi", unknown>;
8
+ requestPermission: import("@reduxjs/toolkit/query").MutationDefinition<import("./types").PermissionType, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Permission", import("./types").PermissionState, "permissionsApi", unknown>;
9
+ }, "Permission", "permissionsApi">;
10
+ }, import("redux").UnknownAction, import("@reduxjs/toolkit").Tuple<[import("redux").StoreEnhancer<{
11
+ dispatch: import("redux-thunk").ThunkDispatch<{
12
+ permissionsApi: import("@reduxjs/toolkit/query").CombinedState<{
13
+ getPermission: import("@reduxjs/toolkit/query").QueryDefinition<import("./types").PermissionType, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Permission", import("./types").PermissionState, "permissionsApi", unknown>;
14
+ requestPermission: import("@reduxjs/toolkit/query").MutationDefinition<import("./types").PermissionType, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Permission", import("./types").PermissionState, "permissionsApi", unknown>;
15
+ }, "Permission", "permissionsApi">;
16
+ }, undefined, import("redux").UnknownAction>;
17
+ }>, import("redux").StoreEnhancer]>>;
18
+ export type RootState = ReturnType<typeof store.getState>;
19
+ export type AppDispatch = typeof store.dispatch;
20
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,KAAK;;;;;;;;;;;;oCAMhB,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC1D,MAAM,MAAM,WAAW,GAAG,OAAO,KAAK,CAAC,QAAQ,CAAC"}