react-native-permission-handler 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/engines/expo.d.mts +1 -1
- package/dist/engines/expo.d.ts +1 -1
- package/dist/engines/rnp.d.mts +1 -1
- package/dist/engines/rnp.d.ts +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +165 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +165 -43
- package/dist/index.mjs.map +1 -1
- package/dist/{types-QXyq8VnD.d.mts → types-DwqbbLGD.d.mts} +6 -0
- package/dist/{types-QXyq8VnD.d.ts → types-DwqbbLGD.d.ts} +6 -0
- package/package.json +1 -1
- package/src/core/debug-logger.test.ts +67 -0
- package/src/core/debug-logger.ts +29 -0
- package/src/core/with-timeout.test.ts +82 -0
- package/src/core/with-timeout.ts +34 -0
- package/src/hooks/use-multiple-permissions.ts +71 -29
- package/src/hooks/use-permission-handler.ts +60 -14
- package/src/types.ts +6 -0
package/dist/index.mjs
CHANGED
|
@@ -94,6 +94,55 @@ function transition(state, event) {
|
|
|
94
94
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
95
95
|
import { AppState } from "react-native";
|
|
96
96
|
|
|
97
|
+
// src/core/debug-logger.ts
|
|
98
|
+
var PREFIX = "[permission-handler]";
|
|
99
|
+
var NOOP_LOGGER = {
|
|
100
|
+
transition: () => {
|
|
101
|
+
},
|
|
102
|
+
info: () => {
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
function createDebugLogger(debug, permission) {
|
|
106
|
+
if (!debug) return NOOP_LOGGER;
|
|
107
|
+
const log = typeof debug === "function" ? debug : (msg) => console.log(msg);
|
|
108
|
+
return {
|
|
109
|
+
transition(from, to, event) {
|
|
110
|
+
log(`${PREFIX} ${permission}: ${from} \u2192 ${to}${event ? ` (${event})` : ""}`);
|
|
111
|
+
},
|
|
112
|
+
info(msg) {
|
|
113
|
+
log(`${PREFIX} ${permission}: ${msg}`);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/core/with-timeout.ts
|
|
119
|
+
var PermissionTimeoutError = class extends Error {
|
|
120
|
+
constructor(permission, timeoutMs) {
|
|
121
|
+
super(`Permission request for "${permission}" timed out after ${timeoutMs}ms`);
|
|
122
|
+
this.name = "PermissionTimeoutError";
|
|
123
|
+
this.permission = permission;
|
|
124
|
+
this.timeoutMs = timeoutMs;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
function withTimeout(promise, timeoutMs, permission) {
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
const timer = setTimeout(
|
|
130
|
+
() => reject(new PermissionTimeoutError(permission, timeoutMs)),
|
|
131
|
+
timeoutMs
|
|
132
|
+
);
|
|
133
|
+
promise.then(
|
|
134
|
+
(val) => {
|
|
135
|
+
clearTimeout(timer);
|
|
136
|
+
resolve(val);
|
|
137
|
+
},
|
|
138
|
+
(err) => {
|
|
139
|
+
clearTimeout(timer);
|
|
140
|
+
reject(err);
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
97
146
|
// src/engines/rnp-fallback.ts
|
|
98
147
|
var cachedFallback = null;
|
|
99
148
|
function getRNPFallbackEngine() {
|
|
@@ -126,47 +175,83 @@ function usePermissionHandler(config) {
|
|
|
126
175
|
const isRequesting = useRef(false);
|
|
127
176
|
const waitingForSettings = useRef(false);
|
|
128
177
|
const appStateRef = useRef(AppState.currentState);
|
|
129
|
-
const {
|
|
178
|
+
const {
|
|
179
|
+
permission,
|
|
180
|
+
autoCheck = true,
|
|
181
|
+
requestTimeout,
|
|
182
|
+
onTimeout,
|
|
183
|
+
debug,
|
|
184
|
+
onGrant,
|
|
185
|
+
onDeny,
|
|
186
|
+
onBlock,
|
|
187
|
+
onSettingsReturn
|
|
188
|
+
} = config;
|
|
189
|
+
const logger = createDebugLogger(debug, permission);
|
|
130
190
|
const checkPermission = useCallback(async () => {
|
|
131
|
-
setFlowState((s) =>
|
|
191
|
+
setFlowState((s) => {
|
|
192
|
+
const next = transition(s, { type: "CHECK" });
|
|
193
|
+
logger.transition(s, next, "CHECK");
|
|
194
|
+
return next;
|
|
195
|
+
});
|
|
132
196
|
try {
|
|
133
197
|
const status = await engine.check(permission);
|
|
134
198
|
setNativeStatus(status);
|
|
135
199
|
setFlowState((s) => {
|
|
136
200
|
const next = transition(s, { type: "CHECK_RESULT", status });
|
|
201
|
+
logger.transition(s, next, `CHECK_RESULT:${status}`);
|
|
137
202
|
if (next === "granted" && s !== "granted") onGrant?.();
|
|
138
203
|
return next;
|
|
139
204
|
});
|
|
140
205
|
} catch {
|
|
141
206
|
setFlowState("idle");
|
|
142
207
|
}
|
|
143
|
-
}, [engine, permission, onGrant]);
|
|
208
|
+
}, [engine, permission, logger, onGrant]);
|
|
144
209
|
const requestPermission = useCallback(async () => {
|
|
145
210
|
if (isRequesting.current) return;
|
|
146
211
|
isRequesting.current = true;
|
|
147
|
-
setFlowState((s) =>
|
|
212
|
+
setFlowState((s) => {
|
|
213
|
+
const next = transition(s, { type: "PRE_PROMPT_CONFIRM" });
|
|
214
|
+
logger.transition(s, next, "PRE_PROMPT_CONFIRM");
|
|
215
|
+
return next;
|
|
216
|
+
});
|
|
148
217
|
try {
|
|
149
|
-
const
|
|
218
|
+
const requestPromise = engine.request(permission);
|
|
219
|
+
const status = requestTimeout ? await withTimeout(requestPromise, requestTimeout, permission) : await requestPromise;
|
|
150
220
|
setNativeStatus(status);
|
|
151
221
|
setFlowState((s) => {
|
|
152
222
|
const next = transition(s, { type: "REQUEST_RESULT", status });
|
|
223
|
+
logger.transition(s, next, `REQUEST_RESULT:${status}`);
|
|
153
224
|
if (next === "granted") onGrant?.();
|
|
154
225
|
if (next === "denied") onDeny?.();
|
|
155
226
|
if (next === "blockedPrompt") onBlock?.();
|
|
156
227
|
return next;
|
|
157
228
|
});
|
|
158
|
-
} catch {
|
|
159
|
-
|
|
229
|
+
} catch (err) {
|
|
230
|
+
if (err instanceof PermissionTimeoutError) {
|
|
231
|
+
logger.info(`request timed out after ${requestTimeout}ms`);
|
|
232
|
+
onTimeout?.();
|
|
233
|
+
setFlowState("blockedPrompt");
|
|
234
|
+
} else {
|
|
235
|
+
setFlowState("denied");
|
|
236
|
+
}
|
|
160
237
|
} finally {
|
|
161
238
|
isRequesting.current = false;
|
|
162
239
|
}
|
|
163
|
-
}, [engine, permission, onGrant, onDeny, onBlock]);
|
|
240
|
+
}, [engine, permission, requestTimeout, onTimeout, logger, onGrant, onDeny, onBlock]);
|
|
164
241
|
const dismiss = useCallback(() => {
|
|
165
|
-
setFlowState((s) =>
|
|
242
|
+
setFlowState((s) => {
|
|
243
|
+
const next = transition(s, { type: "PRE_PROMPT_DISMISS" });
|
|
244
|
+
logger.transition(s, next, "PRE_PROMPT_DISMISS");
|
|
245
|
+
return next;
|
|
246
|
+
});
|
|
166
247
|
onDeny?.();
|
|
167
|
-
}, [onDeny]);
|
|
248
|
+
}, [logger, onDeny]);
|
|
168
249
|
const goToSettings = useCallback(async () => {
|
|
169
|
-
setFlowState((s) =>
|
|
250
|
+
setFlowState((s) => {
|
|
251
|
+
const next = transition(s, { type: "OPEN_SETTINGS" });
|
|
252
|
+
logger.transition(s, next, "OPEN_SETTINGS");
|
|
253
|
+
return next;
|
|
254
|
+
});
|
|
170
255
|
waitingForSettings.current = true;
|
|
171
256
|
try {
|
|
172
257
|
await engine.openSettings();
|
|
@@ -174,14 +259,19 @@ function usePermissionHandler(config) {
|
|
|
174
259
|
waitingForSettings.current = false;
|
|
175
260
|
setFlowState("blockedPrompt");
|
|
176
261
|
}
|
|
177
|
-
}, [engine]);
|
|
262
|
+
}, [engine, logger]);
|
|
178
263
|
const recheckAfterSettings = useCallback(async () => {
|
|
179
|
-
setFlowState((s) =>
|
|
264
|
+
setFlowState((s) => {
|
|
265
|
+
const next = transition(s, { type: "SETTINGS_RETURN" });
|
|
266
|
+
logger.transition(s, next, "SETTINGS_RETURN");
|
|
267
|
+
return next;
|
|
268
|
+
});
|
|
180
269
|
try {
|
|
181
270
|
const status = await engine.check(permission);
|
|
182
271
|
setNativeStatus(status);
|
|
183
272
|
setFlowState((s) => {
|
|
184
273
|
const next = transition(s, { type: "RECHECK_RESULT", status });
|
|
274
|
+
logger.transition(s, next, `RECHECK_RESULT:${status}`);
|
|
185
275
|
if (next === "granted") onGrant?.();
|
|
186
276
|
onSettingsReturn?.(next === "granted");
|
|
187
277
|
return next;
|
|
@@ -189,7 +279,7 @@ function usePermissionHandler(config) {
|
|
|
189
279
|
} catch {
|
|
190
280
|
setFlowState("blockedPrompt");
|
|
191
281
|
}
|
|
192
|
-
}, [engine, permission, onGrant, onSettingsReturn]);
|
|
282
|
+
}, [engine, permission, logger, onGrant, onSettingsReturn]);
|
|
193
283
|
useEffect(() => {
|
|
194
284
|
if (autoCheck) {
|
|
195
285
|
checkPermission();
|
|
@@ -245,7 +335,16 @@ function statusToFlowState(status) {
|
|
|
245
335
|
}
|
|
246
336
|
function useMultiplePermissions(config) {
|
|
247
337
|
const engine = resolveEngine(config.engine);
|
|
248
|
-
const {
|
|
338
|
+
const {
|
|
339
|
+
permissions,
|
|
340
|
+
strategy,
|
|
341
|
+
autoCheck = true,
|
|
342
|
+
requestTimeout,
|
|
343
|
+
onTimeout,
|
|
344
|
+
debug,
|
|
345
|
+
onAllGranted
|
|
346
|
+
} = config;
|
|
347
|
+
const logger = createDebugLogger(debug, "multi");
|
|
249
348
|
const [statuses, setStatuses] = useState2(() => {
|
|
250
349
|
const initial = {};
|
|
251
350
|
for (const entry of permissions) {
|
|
@@ -259,13 +358,16 @@ function useMultiplePermissions(config) {
|
|
|
259
358
|
if (isRunning.current) return;
|
|
260
359
|
isRunning.current = true;
|
|
261
360
|
const update = (key, state) => {
|
|
262
|
-
setStatuses((prev) =>
|
|
361
|
+
setStatuses((prev) => {
|
|
362
|
+
logger.transition(prev[key] ?? "idle", state, key);
|
|
363
|
+
return { ...prev, [key]: state };
|
|
364
|
+
});
|
|
263
365
|
};
|
|
264
366
|
try {
|
|
265
367
|
if (strategy === "sequential") {
|
|
266
|
-
await runSequential(permissions, engine, update);
|
|
368
|
+
await runSequential(permissions, engine, update, requestTimeout, onTimeout);
|
|
267
369
|
} else {
|
|
268
|
-
await runParallel(permissions, engine, update);
|
|
370
|
+
await runParallel(permissions, engine, update, requestTimeout, onTimeout);
|
|
269
371
|
}
|
|
270
372
|
let allDone = true;
|
|
271
373
|
for (const entry of permissions) {
|
|
@@ -281,7 +383,7 @@ function useMultiplePermissions(config) {
|
|
|
281
383
|
} finally {
|
|
282
384
|
isRunning.current = false;
|
|
283
385
|
}
|
|
284
|
-
}, [permissions, strategy, engine, onAllGranted]);
|
|
386
|
+
}, [permissions, strategy, engine, requestTimeout, onTimeout, logger, onAllGranted]);
|
|
285
387
|
useEffect2(() => {
|
|
286
388
|
if (!autoCheck) return;
|
|
287
389
|
let cancelled = false;
|
|
@@ -304,7 +406,7 @@ function useMultiplePermissions(config) {
|
|
|
304
406
|
request: requestAll
|
|
305
407
|
};
|
|
306
408
|
}
|
|
307
|
-
async function runSequential(permissions, engine, updateStatus) {
|
|
409
|
+
async function runSequential(permissions, engine, updateStatus, requestTimeout, onTimeout) {
|
|
308
410
|
for (const entry of permissions) {
|
|
309
411
|
const key = permissionKey(entry);
|
|
310
412
|
updateStatus(key, "checking");
|
|
@@ -324,22 +426,32 @@ async function runSequential(permissions, engine, updateStatus) {
|
|
|
324
426
|
break;
|
|
325
427
|
}
|
|
326
428
|
updateStatus(key, "requesting");
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
429
|
+
try {
|
|
430
|
+
const requestPromise = engine.request(entry.permission);
|
|
431
|
+
const requestStatus = requestTimeout ? await withTimeout(requestPromise, requestTimeout, entry.permission) : await requestPromise;
|
|
432
|
+
if (isGrantedStatus(requestStatus)) {
|
|
433
|
+
updateStatus(key, "granted");
|
|
434
|
+
entry.onGrant?.();
|
|
435
|
+
} else if (requestStatus === "blocked") {
|
|
436
|
+
updateStatus(key, "blockedPrompt");
|
|
437
|
+
entry.onBlock?.();
|
|
438
|
+
break;
|
|
439
|
+
} else {
|
|
440
|
+
updateStatus(key, "denied");
|
|
441
|
+
entry.onDeny?.();
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
} catch (err) {
|
|
445
|
+
if (err instanceof PermissionTimeoutError) {
|
|
446
|
+
onTimeout?.();
|
|
447
|
+
updateStatus(key, "blockedPrompt");
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
throw err;
|
|
339
451
|
}
|
|
340
452
|
}
|
|
341
453
|
}
|
|
342
|
-
async function runParallel(permissions, engine, updateStatus) {
|
|
454
|
+
async function runParallel(permissions, engine, updateStatus, requestTimeout, onTimeout) {
|
|
343
455
|
const checkResults = await Promise.all(
|
|
344
456
|
permissions.map(async (entry) => {
|
|
345
457
|
const key = permissionKey(entry);
|
|
@@ -366,16 +478,26 @@ async function runParallel(permissions, engine, updateStatus) {
|
|
|
366
478
|
continue;
|
|
367
479
|
}
|
|
368
480
|
updateStatus(key, "requesting");
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
481
|
+
try {
|
|
482
|
+
const requestPromise = engine.request(entry.permission);
|
|
483
|
+
const requestStatus = requestTimeout ? await withTimeout(requestPromise, requestTimeout, entry.permission) : await requestPromise;
|
|
484
|
+
if (isGrantedStatus(requestStatus)) {
|
|
485
|
+
updateStatus(key, "granted");
|
|
486
|
+
entry.onGrant?.();
|
|
487
|
+
} else if (requestStatus === "blocked") {
|
|
488
|
+
updateStatus(key, "blockedPrompt");
|
|
489
|
+
entry.onBlock?.();
|
|
490
|
+
} else {
|
|
491
|
+
updateStatus(key, "denied");
|
|
492
|
+
entry.onDeny?.();
|
|
493
|
+
}
|
|
494
|
+
} catch (err) {
|
|
495
|
+
if (err instanceof PermissionTimeoutError) {
|
|
496
|
+
onTimeout?.();
|
|
497
|
+
updateStatus(key, "blockedPrompt");
|
|
498
|
+
} else {
|
|
499
|
+
throw err;
|
|
500
|
+
}
|
|
379
501
|
}
|
|
380
502
|
}
|
|
381
503
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engines/resolve.ts","../src/core/state-machine.ts","../src/hooks/use-permission-handler.ts","../src/engines/rnp-fallback.ts","../src/engines/use-engine.ts","../src/hooks/use-multiple-permissions.ts","../src/components/default-blocked-prompt.tsx","../src/components/default-pre-prompt.tsx","../src/components/permission-gate.tsx"],"sourcesContent":["import type { PermissionEngine } from \"../types\";\n\nlet defaultEngine: PermissionEngine | null = null;\n\nexport function setDefaultEngine(engine: PermissionEngine): void {\n defaultEngine = engine;\n}\n\nexport function getDefaultEngine(): PermissionEngine | null {\n return defaultEngine;\n}\n","import type { PermissionFlowEvent, PermissionFlowState } from \"../types\";\n\nexport function transition(\n state: PermissionFlowState,\n event: PermissionFlowEvent,\n): PermissionFlowState {\n switch (state) {\n case \"idle\":\n if (event.type === \"CHECK\") return \"checking\";\n return state;\n\n case \"checking\":\n if (event.type === \"CHECK_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"denied\":\n return \"prePrompt\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"unavailable\":\n return \"unavailable\";\n default:\n return state;\n }\n }\n return state;\n\n case \"prePrompt\":\n if (event.type === \"PRE_PROMPT_CONFIRM\") return \"requesting\";\n if (event.type === \"PRE_PROMPT_DISMISS\") return \"denied\";\n return state;\n\n case \"requesting\":\n if (event.type === \"REQUEST_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"denied\":\n return \"denied\";\n case \"blocked\":\n return \"blockedPrompt\";\n default:\n return state;\n }\n }\n return state;\n\n case \"blockedPrompt\":\n if (event.type === \"OPEN_SETTINGS\") return \"openingSettings\";\n return state;\n\n case \"openingSettings\":\n if (event.type === \"SETTINGS_RETURN\") return \"recheckingAfterSettings\";\n return state;\n\n case \"recheckingAfterSettings\":\n if (event.type === \"RECHECK_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"denied\":\n return \"blockedPrompt\";\n default:\n return state;\n }\n }\n return state;\n\n case \"granted\":\n case \"denied\":\n case \"unavailable\":\n if (event.type === \"CHECK\") return \"checking\";\n return state;\n\n case \"blocked\":\n return state;\n\n default:\n return state;\n }\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { AppState } from \"react-native\";\nimport { transition } from \"../core/state-machine\";\nimport { resolveEngine } from \"../engines/use-engine\";\nimport type {\n PermissionFlowState,\n PermissionHandlerConfig,\n PermissionHandlerResult,\n PermissionStatus,\n} from \"../types\";\n\nexport function usePermissionHandler(config: PermissionHandlerConfig): PermissionHandlerResult {\n const engine = resolveEngine(config.engine);\n const [flowState, setFlowState] = useState<PermissionFlowState>(\"idle\");\n const [nativeStatus, setNativeStatus] = useState<PermissionStatus | null>(null);\n const isRequesting = useRef(false);\n const waitingForSettings = useRef(false);\n const appStateRef = useRef(AppState.currentState);\n\n const { permission, autoCheck = true, onGrant, onDeny, onBlock, onSettingsReturn } = config;\n\n const checkPermission = useCallback(async () => {\n setFlowState((s) => transition(s, { type: \"CHECK\" }));\n try {\n const status = await engine.check(permission);\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"CHECK_RESULT\", status });\n if (next === \"granted\" && s !== \"granted\") onGrant?.();\n return next;\n });\n } catch {\n setFlowState(\"idle\");\n }\n }, [engine, permission, onGrant]);\n\n const requestPermission = useCallback(async () => {\n if (isRequesting.current) return;\n isRequesting.current = true;\n\n setFlowState((s) => transition(s, { type: \"PRE_PROMPT_CONFIRM\" }));\n try {\n const status = await engine.request(permission);\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"REQUEST_RESULT\", status });\n if (next === \"granted\") onGrant?.();\n if (next === \"denied\") onDeny?.();\n if (next === \"blockedPrompt\") onBlock?.();\n return next;\n });\n } catch {\n setFlowState(\"denied\");\n } finally {\n isRequesting.current = false;\n }\n }, [engine, permission, onGrant, onDeny, onBlock]);\n\n const dismiss = useCallback(() => {\n setFlowState((s) => transition(s, { type: \"PRE_PROMPT_DISMISS\" }));\n onDeny?.();\n }, [onDeny]);\n\n const goToSettings = useCallback(async () => {\n setFlowState((s) => transition(s, { type: \"OPEN_SETTINGS\" }));\n waitingForSettings.current = true;\n try {\n await engine.openSettings();\n } catch {\n waitingForSettings.current = false;\n setFlowState(\"blockedPrompt\");\n }\n }, [engine]);\n\n const recheckAfterSettings = useCallback(async () => {\n setFlowState((s) => transition(s, { type: \"SETTINGS_RETURN\" }));\n try {\n const status = await engine.check(permission);\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"RECHECK_RESULT\", status });\n if (next === \"granted\") onGrant?.();\n onSettingsReturn?.(next === \"granted\");\n return next;\n });\n } catch {\n setFlowState(\"blockedPrompt\");\n }\n }, [engine, permission, onGrant, onSettingsReturn]);\n\n // Auto-check on mount\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional mount-only effect\n useEffect(() => {\n if (autoCheck) {\n checkPermission();\n }\n }, []);\n\n // AppState listener for settings return\n useEffect(() => {\n const subscription = AppState.addEventListener(\"change\", (nextAppState) => {\n if (\n appStateRef.current.match(/inactive|background/) &&\n nextAppState === \"active\" &&\n waitingForSettings.current\n ) {\n waitingForSettings.current = false;\n recheckAfterSettings();\n }\n appStateRef.current = nextAppState;\n });\n return () => subscription.remove();\n }, [recheckAfterSettings]);\n\n return {\n state: flowState,\n nativeStatus,\n isGranted: flowState === \"granted\",\n isDenied: flowState === \"denied\",\n isBlocked:\n flowState === \"blocked\" || flowState === \"blockedPrompt\" || flowState === \"openingSettings\",\n isChecking: flowState === \"checking\" || flowState === \"recheckingAfterSettings\",\n isUnavailable: flowState === \"unavailable\",\n request: requestPermission,\n check: checkPermission,\n dismiss,\n openSettings: goToSettings,\n };\n}\n","import type { PermissionEngine } from \"../types\";\n\nlet cachedFallback: PermissionEngine | null = null;\n\nexport function getRNPFallbackEngine(): PermissionEngine {\n if (cachedFallback) return cachedFallback;\n\n try {\n // Dynamic require to avoid hard dependency — only resolves if\n // react-native-permissions is installed by the consumer.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require(\"./rnp\") as { createRNPEngine: () => PermissionEngine };\n const { createRNPEngine } = mod;\n cachedFallback = createRNPEngine();\n return cachedFallback;\n } catch {\n throw new Error(\n \"react-native-permission-handler: No permission engine configured. \" +\n \"Either pass an `engine` in your hook config, call setDefaultEngine(), \" +\n \"or install react-native-permissions as a peer dependency.\",\n );\n }\n}\n","import type { PermissionEngine } from \"../types\";\nimport { getDefaultEngine } from \"./resolve\";\nimport { getRNPFallbackEngine } from \"./rnp-fallback\";\n\nexport function resolveEngine(configEngine?: PermissionEngine): PermissionEngine {\n if (configEngine) return configEngine;\n const global = getDefaultEngine();\n if (global) return global;\n return getRNPFallbackEngine();\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { resolveEngine } from \"../engines/use-engine\";\nimport type {\n MultiPermissionEntry,\n MultiplePermissionsConfig,\n MultiplePermissionsResult,\n PermissionEngine,\n PermissionFlowState,\n PermissionStatus,\n} from \"../types\";\n\nfunction permissionKey(entry: MultiPermissionEntry): string {\n return String(entry.permission);\n}\n\nfunction isGrantedStatus(status: PermissionStatus): boolean {\n return status === \"granted\" || status === \"limited\";\n}\n\nfunction statusToFlowState(status: PermissionStatus): PermissionFlowState {\n switch (status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"unavailable\":\n return \"unavailable\";\n case \"denied\":\n return \"prePrompt\";\n default:\n return \"idle\";\n }\n}\n\nexport function useMultiplePermissions(\n config: MultiplePermissionsConfig,\n): MultiplePermissionsResult {\n const engine = resolveEngine(config.engine);\n const { permissions, strategy, autoCheck = true, onAllGranted } = config;\n const [statuses, setStatuses] = useState<Record<string, PermissionFlowState>>(() => {\n const initial: Record<string, PermissionFlowState> = {};\n for (const entry of permissions) {\n initial[permissionKey(entry)] = \"idle\";\n }\n return initial;\n });\n const isRunning = useRef(false);\n\n const allGranted = permissions.every((entry) => statuses[permissionKey(entry)] === \"granted\");\n\n const requestAll = useCallback(async () => {\n if (isRunning.current) return;\n isRunning.current = true;\n\n const update = (key: string, state: PermissionFlowState) => {\n setStatuses((prev) => ({ ...prev, [key]: state }));\n };\n\n try {\n if (strategy === \"sequential\") {\n await runSequential(permissions, engine, update);\n } else {\n await runParallel(permissions, engine, update);\n }\n\n // Final check: are all granted?\n let allDone = true;\n for (const entry of permissions) {\n const finalStatus = await engine.check(entry.permission);\n if (!isGrantedStatus(finalStatus)) {\n allDone = false;\n break;\n }\n }\n if (allDone) {\n onAllGranted?.();\n }\n } finally {\n isRunning.current = false;\n }\n }, [permissions, strategy, engine, onAllGranted]);\n\n // Auto-check on mount\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional mount-only effect\n useEffect(() => {\n if (!autoCheck) return;\n\n let cancelled = false;\n async function checkAll() {\n for (const entry of permissions) {\n const key = permissionKey(entry);\n const status = await engine.check(entry.permission);\n if (cancelled) return;\n setStatuses((prev) => ({ ...prev, [key]: statusToFlowState(status) }));\n }\n }\n checkAll();\n return () => {\n cancelled = true;\n };\n }, []);\n\n return {\n statuses,\n allGranted,\n request: requestAll,\n };\n}\n\nasync function runSequential(\n permissions: MultiPermissionEntry[],\n engine: PermissionEngine,\n updateStatus: (key: string, state: PermissionFlowState) => void,\n): Promise<void> {\n for (const entry of permissions) {\n const key = permissionKey(entry);\n\n updateStatus(key, \"checking\");\n const checkStatus = await engine.check(entry.permission);\n\n if (isGrantedStatus(checkStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n continue;\n }\n\n if (checkStatus === \"unavailable\") {\n updateStatus(key, \"unavailable\");\n continue;\n }\n\n if (checkStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n break;\n }\n\n // Denied — request it\n updateStatus(key, \"requesting\");\n const requestStatus = await engine.request(entry.permission);\n\n if (isGrantedStatus(requestStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (requestStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n break;\n } else {\n updateStatus(key, \"denied\");\n entry.onDeny?.();\n break;\n }\n }\n}\n\nasync function runParallel(\n permissions: MultiPermissionEntry[],\n engine: PermissionEngine,\n updateStatus: (key: string, state: PermissionFlowState) => void,\n): Promise<void> {\n // Check all in parallel\n const checkResults = await Promise.all(\n permissions.map(async (entry) => {\n const key = permissionKey(entry);\n updateStatus(key, \"checking\");\n const status = await engine.check(entry.permission);\n return { entry, key, status };\n }),\n );\n\n // Update granted/unavailable immediately\n for (const { entry, key, status } of checkResults) {\n if (isGrantedStatus(status)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (status === \"unavailable\") {\n updateStatus(key, \"unavailable\");\n }\n }\n\n // Request denied/blocked ones sequentially (system dialogs are sequential)\n const needsAction = checkResults.filter(\n ({ status }) => status === \"denied\" || status === \"blocked\",\n );\n\n for (const { entry, key, status } of needsAction) {\n if (status === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n continue;\n }\n\n updateStatus(key, \"requesting\");\n const requestStatus = await engine.request(entry.permission);\n\n if (isGrantedStatus(requestStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (requestStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n } else {\n updateStatus(key, \"denied\");\n entry.onDeny?.();\n }\n }\n}\n","import React from \"react\";\nimport { Modal, StyleSheet, Text, TouchableOpacity, View } from \"react-native\";\nimport type { BlockedPromptConfig } from \"../types\";\n\nexport interface DefaultBlockedPromptProps extends BlockedPromptConfig {\n visible: boolean;\n onOpenSettings: () => void;\n}\n\nexport function DefaultBlockedPrompt({\n visible,\n title,\n message,\n settingsLabel = \"Open Settings\",\n onOpenSettings,\n}: DefaultBlockedPromptProps) {\n return (\n <Modal visible={visible} transparent animationType=\"fade\">\n <View style={styles.overlay}>\n <View style={styles.modal}>\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.message}>{message}</Text>\n <TouchableOpacity\n style={styles.settingsButton}\n onPress={onOpenSettings}\n accessibilityRole=\"button\"\n >\n <Text style={styles.settingsText}>{settingsLabel}</Text>\n </TouchableOpacity>\n </View>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n flex: 1,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n justifyContent: \"center\",\n alignItems: \"center\",\n },\n modal: {\n backgroundColor: \"white\",\n borderRadius: 16,\n padding: 24,\n width: \"85%\",\n alignItems: \"center\",\n },\n title: {\n fontSize: 20,\n fontWeight: \"600\",\n marginBottom: 12,\n textAlign: \"center\",\n },\n message: {\n fontSize: 15,\n color: \"#666\",\n textAlign: \"center\",\n marginBottom: 24,\n lineHeight: 22,\n },\n settingsButton: {\n backgroundColor: \"#007AFF\",\n borderRadius: 12,\n paddingVertical: 14,\n paddingHorizontal: 32,\n width: \"100%\",\n alignItems: \"center\",\n },\n settingsText: {\n color: \"white\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n});\n","import React from \"react\";\nimport { Modal, StyleSheet, Text, TouchableOpacity, View } from \"react-native\";\nimport type { PrePromptConfig } from \"../types\";\n\nexport interface DefaultPrePromptProps extends PrePromptConfig {\n visible: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\nexport function DefaultPrePrompt({\n visible,\n title,\n message,\n confirmLabel = \"Continue\",\n cancelLabel = \"Not Now\",\n onConfirm,\n onCancel,\n}: DefaultPrePromptProps) {\n return (\n <Modal visible={visible} transparent animationType=\"fade\">\n <View style={styles.overlay}>\n <View style={styles.modal}>\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.message}>{message}</Text>\n <TouchableOpacity\n style={styles.confirmButton}\n onPress={onConfirm}\n accessibilityRole=\"button\"\n >\n <Text style={styles.confirmText}>{confirmLabel}</Text>\n </TouchableOpacity>\n <TouchableOpacity onPress={onCancel} accessibilityRole=\"button\">\n <Text style={styles.cancelText}>{cancelLabel}</Text>\n </TouchableOpacity>\n </View>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n flex: 1,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n justifyContent: \"center\",\n alignItems: \"center\",\n },\n modal: {\n backgroundColor: \"white\",\n borderRadius: 16,\n padding: 24,\n width: \"85%\",\n alignItems: \"center\",\n },\n title: {\n fontSize: 20,\n fontWeight: \"600\",\n marginBottom: 12,\n textAlign: \"center\",\n },\n message: {\n fontSize: 15,\n color: \"#666\",\n textAlign: \"center\",\n marginBottom: 24,\n lineHeight: 22,\n },\n confirmButton: {\n backgroundColor: \"#007AFF\",\n borderRadius: 12,\n paddingVertical: 14,\n paddingHorizontal: 32,\n width: \"100%\",\n alignItems: \"center\",\n marginBottom: 12,\n },\n confirmText: {\n color: \"white\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n cancelText: {\n color: \"#007AFF\",\n fontSize: 15,\n },\n});\n","import React from \"react\";\nimport type { ReactNode } from \"react\";\nimport { usePermissionHandler } from \"../hooks/use-permission-handler\";\nimport type {\n BlockedPromptConfig,\n PermissionCallbacks,\n PermissionEngine,\n PrePromptConfig,\n} from \"../types\";\nimport { DefaultBlockedPrompt } from \"./default-blocked-prompt\";\nimport { DefaultPrePrompt } from \"./default-pre-prompt\";\n\nexport interface PermissionGateProps extends PermissionCallbacks {\n permission: string;\n engine?: PermissionEngine;\n prePrompt: PrePromptConfig;\n blockedPrompt: BlockedPromptConfig;\n children: ReactNode;\n fallback?: ReactNode;\n renderPrePrompt?: (props: {\n config: PrePromptConfig;\n onConfirm: () => void;\n onCancel: () => void;\n }) => ReactNode;\n renderBlockedPrompt?: (props: {\n config: BlockedPromptConfig;\n onOpenSettings: () => void;\n }) => ReactNode;\n}\n\nexport function PermissionGate({\n permission,\n engine,\n prePrompt,\n blockedPrompt,\n children,\n fallback = null,\n renderPrePrompt,\n renderBlockedPrompt,\n onGrant,\n onDeny,\n onBlock,\n onSettingsReturn,\n}: PermissionGateProps) {\n const handler = usePermissionHandler({\n permission,\n engine,\n prePrompt,\n blockedPrompt,\n onGrant,\n onDeny,\n onBlock,\n onSettingsReturn,\n });\n\n if (handler.isGranted) {\n return <>{children}</>;\n }\n\n if (handler.isChecking || handler.isUnavailable) {\n return <>{fallback}</>;\n }\n\n if (handler.state === \"prePrompt\") {\n if (renderPrePrompt) {\n return (\n <>\n {renderPrePrompt({\n config: prePrompt,\n onConfirm: handler.request,\n onCancel: handler.dismiss,\n })}\n </>\n );\n }\n return (\n <DefaultPrePrompt\n visible\n title={prePrompt.title}\n message={prePrompt.message}\n confirmLabel={prePrompt.confirmLabel}\n cancelLabel={prePrompt.cancelLabel}\n onConfirm={handler.request}\n onCancel={handler.dismiss}\n />\n );\n }\n\n if (handler.state === \"blockedPrompt\") {\n if (renderBlockedPrompt) {\n return (\n <>\n {renderBlockedPrompt({\n config: blockedPrompt,\n onOpenSettings: handler.openSettings,\n })}\n </>\n );\n }\n return (\n <DefaultBlockedPrompt\n visible\n title={blockedPrompt.title}\n message={blockedPrompt.message}\n settingsLabel={blockedPrompt.settingsLabel}\n onOpenSettings={handler.openSettings}\n />\n );\n }\n\n return <>{fallback}</>;\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","Modal","StyleSheet","Text","TouchableOpacity","View","jsx","jsxs","styles","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/engines/resolve.ts","../src/core/state-machine.ts","../src/hooks/use-permission-handler.ts","../src/core/debug-logger.ts","../src/core/with-timeout.ts","../src/engines/rnp-fallback.ts","../src/engines/use-engine.ts","../src/hooks/use-multiple-permissions.ts","../src/components/default-blocked-prompt.tsx","../src/components/default-pre-prompt.tsx","../src/components/permission-gate.tsx"],"sourcesContent":["import type { PermissionEngine } from \"../types\";\n\nlet defaultEngine: PermissionEngine | null = null;\n\nexport function setDefaultEngine(engine: PermissionEngine): void {\n defaultEngine = engine;\n}\n\nexport function getDefaultEngine(): PermissionEngine | null {\n return defaultEngine;\n}\n","import type { PermissionFlowEvent, PermissionFlowState } from \"../types\";\n\nexport function transition(\n state: PermissionFlowState,\n event: PermissionFlowEvent,\n): PermissionFlowState {\n switch (state) {\n case \"idle\":\n if (event.type === \"CHECK\") return \"checking\";\n return state;\n\n case \"checking\":\n if (event.type === \"CHECK_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"denied\":\n return \"prePrompt\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"unavailable\":\n return \"unavailable\";\n default:\n return state;\n }\n }\n return state;\n\n case \"prePrompt\":\n if (event.type === \"PRE_PROMPT_CONFIRM\") return \"requesting\";\n if (event.type === \"PRE_PROMPT_DISMISS\") return \"denied\";\n return state;\n\n case \"requesting\":\n if (event.type === \"REQUEST_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"denied\":\n return \"denied\";\n case \"blocked\":\n return \"blockedPrompt\";\n default:\n return state;\n }\n }\n return state;\n\n case \"blockedPrompt\":\n if (event.type === \"OPEN_SETTINGS\") return \"openingSettings\";\n return state;\n\n case \"openingSettings\":\n if (event.type === \"SETTINGS_RETURN\") return \"recheckingAfterSettings\";\n return state;\n\n case \"recheckingAfterSettings\":\n if (event.type === \"RECHECK_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"denied\":\n return \"blockedPrompt\";\n default:\n return state;\n }\n }\n return state;\n\n case \"granted\":\n case \"denied\":\n case \"unavailable\":\n if (event.type === \"CHECK\") return \"checking\";\n return state;\n\n case \"blocked\":\n return state;\n\n default:\n return state;\n }\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { AppState } from \"react-native\";\nimport { createDebugLogger } from \"../core/debug-logger\";\nimport { transition } from \"../core/state-machine\";\nimport { PermissionTimeoutError, withTimeout } from \"../core/with-timeout\";\nimport { resolveEngine } from \"../engines/use-engine\";\nimport type {\n PermissionFlowState,\n PermissionHandlerConfig,\n PermissionHandlerResult,\n PermissionStatus,\n} from \"../types\";\n\nexport function usePermissionHandler(config: PermissionHandlerConfig): PermissionHandlerResult {\n const engine = resolveEngine(config.engine);\n const [flowState, setFlowState] = useState<PermissionFlowState>(\"idle\");\n const [nativeStatus, setNativeStatus] = useState<PermissionStatus | null>(null);\n const isRequesting = useRef(false);\n const waitingForSettings = useRef(false);\n const appStateRef = useRef(AppState.currentState);\n\n const {\n permission,\n autoCheck = true,\n requestTimeout,\n onTimeout,\n debug,\n onGrant,\n onDeny,\n onBlock,\n onSettingsReturn,\n } = config;\n\n const logger = createDebugLogger(debug, permission);\n\n const checkPermission = useCallback(async () => {\n setFlowState((s) => {\n const next = transition(s, { type: \"CHECK\" });\n logger.transition(s, next, \"CHECK\");\n return next;\n });\n try {\n const status = await engine.check(permission);\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"CHECK_RESULT\", status });\n logger.transition(s, next, `CHECK_RESULT:${status}`);\n if (next === \"granted\" && s !== \"granted\") onGrant?.();\n return next;\n });\n } catch {\n setFlowState(\"idle\");\n }\n }, [engine, permission, logger, onGrant]);\n\n const requestPermission = useCallback(async () => {\n if (isRequesting.current) return;\n isRequesting.current = true;\n\n setFlowState((s) => {\n const next = transition(s, { type: \"PRE_PROMPT_CONFIRM\" });\n logger.transition(s, next, \"PRE_PROMPT_CONFIRM\");\n return next;\n });\n try {\n const requestPromise = engine.request(permission);\n const status = requestTimeout\n ? await withTimeout(requestPromise, requestTimeout, permission)\n : await requestPromise;\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"REQUEST_RESULT\", status });\n logger.transition(s, next, `REQUEST_RESULT:${status}`);\n if (next === \"granted\") onGrant?.();\n if (next === \"denied\") onDeny?.();\n if (next === \"blockedPrompt\") onBlock?.();\n return next;\n });\n } catch (err) {\n if (err instanceof PermissionTimeoutError) {\n logger.info(`request timed out after ${requestTimeout}ms`);\n onTimeout?.();\n setFlowState(\"blockedPrompt\");\n } else {\n setFlowState(\"denied\");\n }\n } finally {\n isRequesting.current = false;\n }\n }, [engine, permission, requestTimeout, onTimeout, logger, onGrant, onDeny, onBlock]);\n\n const dismiss = useCallback(() => {\n setFlowState((s) => {\n const next = transition(s, { type: \"PRE_PROMPT_DISMISS\" });\n logger.transition(s, next, \"PRE_PROMPT_DISMISS\");\n return next;\n });\n onDeny?.();\n }, [logger, onDeny]);\n\n const goToSettings = useCallback(async () => {\n setFlowState((s) => {\n const next = transition(s, { type: \"OPEN_SETTINGS\" });\n logger.transition(s, next, \"OPEN_SETTINGS\");\n return next;\n });\n waitingForSettings.current = true;\n try {\n await engine.openSettings();\n } catch {\n waitingForSettings.current = false;\n setFlowState(\"blockedPrompt\");\n }\n }, [engine, logger]);\n\n const recheckAfterSettings = useCallback(async () => {\n setFlowState((s) => {\n const next = transition(s, { type: \"SETTINGS_RETURN\" });\n logger.transition(s, next, \"SETTINGS_RETURN\");\n return next;\n });\n try {\n const status = await engine.check(permission);\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"RECHECK_RESULT\", status });\n logger.transition(s, next, `RECHECK_RESULT:${status}`);\n if (next === \"granted\") onGrant?.();\n onSettingsReturn?.(next === \"granted\");\n return next;\n });\n } catch {\n setFlowState(\"blockedPrompt\");\n }\n }, [engine, permission, logger, onGrant, onSettingsReturn]);\n\n // Auto-check on mount\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional mount-only effect\n useEffect(() => {\n if (autoCheck) {\n checkPermission();\n }\n }, []);\n\n // AppState listener for settings return\n useEffect(() => {\n const subscription = AppState.addEventListener(\"change\", (nextAppState) => {\n if (\n appStateRef.current.match(/inactive|background/) &&\n nextAppState === \"active\" &&\n waitingForSettings.current\n ) {\n waitingForSettings.current = false;\n recheckAfterSettings();\n }\n appStateRef.current = nextAppState;\n });\n return () => subscription.remove();\n }, [recheckAfterSettings]);\n\n return {\n state: flowState,\n nativeStatus,\n isGranted: flowState === \"granted\",\n isDenied: flowState === \"denied\",\n isBlocked:\n flowState === \"blocked\" || flowState === \"blockedPrompt\" || flowState === \"openingSettings\",\n isChecking: flowState === \"checking\" || flowState === \"recheckingAfterSettings\",\n isUnavailable: flowState === \"unavailable\",\n request: requestPermission,\n check: checkPermission,\n dismiss,\n openSettings: goToSettings,\n };\n}\n","const PREFIX = \"[permission-handler]\";\n\ninterface DebugLogger {\n transition(from: string, to: string, event?: string): void;\n info(msg: string): void;\n}\n\nconst NOOP_LOGGER: DebugLogger = {\n transition: () => {},\n info: () => {},\n};\n\nexport function createDebugLogger(\n debug: boolean | ((msg: string) => void) | undefined,\n permission: string,\n): DebugLogger {\n if (!debug) return NOOP_LOGGER;\n\n const log = typeof debug === \"function\" ? debug : (msg: string) => console.log(msg);\n\n return {\n transition(from: string, to: string, event?: string) {\n log(`${PREFIX} ${permission}: ${from} → ${to}${event ? ` (${event})` : \"\"}`);\n },\n info(msg: string) {\n log(`${PREFIX} ${permission}: ${msg}`);\n },\n };\n}\n","export class PermissionTimeoutError extends Error {\n readonly permission: string;\n readonly timeoutMs: number;\n\n constructor(permission: string, timeoutMs: number) {\n super(`Permission request for \"${permission}\" timed out after ${timeoutMs}ms`);\n this.name = \"PermissionTimeoutError\";\n this.permission = permission;\n this.timeoutMs = timeoutMs;\n }\n}\n\nexport function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n permission: string,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new PermissionTimeoutError(permission, timeoutMs)),\n timeoutMs,\n );\n promise.then(\n (val) => {\n clearTimeout(timer);\n resolve(val);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n","import type { PermissionEngine } from \"../types\";\n\nlet cachedFallback: PermissionEngine | null = null;\n\nexport function getRNPFallbackEngine(): PermissionEngine {\n if (cachedFallback) return cachedFallback;\n\n try {\n // Dynamic require to avoid hard dependency — only resolves if\n // react-native-permissions is installed by the consumer.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require(\"./rnp\") as { createRNPEngine: () => PermissionEngine };\n const { createRNPEngine } = mod;\n cachedFallback = createRNPEngine();\n return cachedFallback;\n } catch {\n throw new Error(\n \"react-native-permission-handler: No permission engine configured. \" +\n \"Either pass an `engine` in your hook config, call setDefaultEngine(), \" +\n \"or install react-native-permissions as a peer dependency.\",\n );\n }\n}\n","import type { PermissionEngine } from \"../types\";\nimport { getDefaultEngine } from \"./resolve\";\nimport { getRNPFallbackEngine } from \"./rnp-fallback\";\n\nexport function resolveEngine(configEngine?: PermissionEngine): PermissionEngine {\n if (configEngine) return configEngine;\n const global = getDefaultEngine();\n if (global) return global;\n return getRNPFallbackEngine();\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createDebugLogger } from \"../core/debug-logger\";\nimport { PermissionTimeoutError, withTimeout } from \"../core/with-timeout\";\nimport { resolveEngine } from \"../engines/use-engine\";\nimport type {\n MultiPermissionEntry,\n MultiplePermissionsConfig,\n MultiplePermissionsResult,\n PermissionEngine,\n PermissionFlowState,\n PermissionStatus,\n} from \"../types\";\n\nfunction permissionKey(entry: MultiPermissionEntry): string {\n return String(entry.permission);\n}\n\nfunction isGrantedStatus(status: PermissionStatus): boolean {\n return status === \"granted\" || status === \"limited\";\n}\n\nfunction statusToFlowState(status: PermissionStatus): PermissionFlowState {\n switch (status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"unavailable\":\n return \"unavailable\";\n case \"denied\":\n return \"prePrompt\";\n default:\n return \"idle\";\n }\n}\n\nexport function useMultiplePermissions(\n config: MultiplePermissionsConfig,\n): MultiplePermissionsResult {\n const engine = resolveEngine(config.engine);\n const {\n permissions,\n strategy,\n autoCheck = true,\n requestTimeout,\n onTimeout,\n debug,\n onAllGranted,\n } = config;\n const logger = createDebugLogger(debug, \"multi\");\n const [statuses, setStatuses] = useState<Record<string, PermissionFlowState>>(() => {\n const initial: Record<string, PermissionFlowState> = {};\n for (const entry of permissions) {\n initial[permissionKey(entry)] = \"idle\";\n }\n return initial;\n });\n const isRunning = useRef(false);\n\n const allGranted = permissions.every((entry) => statuses[permissionKey(entry)] === \"granted\");\n\n const requestAll = useCallback(async () => {\n if (isRunning.current) return;\n isRunning.current = true;\n\n const update = (key: string, state: PermissionFlowState) => {\n setStatuses((prev) => {\n logger.transition(prev[key] ?? \"idle\", state, key);\n return { ...prev, [key]: state };\n });\n };\n\n try {\n if (strategy === \"sequential\") {\n await runSequential(permissions, engine, update, requestTimeout, onTimeout);\n } else {\n await runParallel(permissions, engine, update, requestTimeout, onTimeout);\n }\n\n // Final check: are all granted?\n let allDone = true;\n for (const entry of permissions) {\n const finalStatus = await engine.check(entry.permission);\n if (!isGrantedStatus(finalStatus)) {\n allDone = false;\n break;\n }\n }\n if (allDone) {\n onAllGranted?.();\n }\n } finally {\n isRunning.current = false;\n }\n }, [permissions, strategy, engine, requestTimeout, onTimeout, logger, onAllGranted]);\n\n // Auto-check on mount\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional mount-only effect\n useEffect(() => {\n if (!autoCheck) return;\n\n let cancelled = false;\n async function checkAll() {\n for (const entry of permissions) {\n const key = permissionKey(entry);\n const status = await engine.check(entry.permission);\n if (cancelled) return;\n setStatuses((prev) => ({ ...prev, [key]: statusToFlowState(status) }));\n }\n }\n checkAll();\n return () => {\n cancelled = true;\n };\n }, []);\n\n return {\n statuses,\n allGranted,\n request: requestAll,\n };\n}\n\nasync function runSequential(\n permissions: MultiPermissionEntry[],\n engine: PermissionEngine,\n updateStatus: (key: string, state: PermissionFlowState) => void,\n requestTimeout?: number,\n onTimeout?: () => void,\n): Promise<void> {\n for (const entry of permissions) {\n const key = permissionKey(entry);\n\n updateStatus(key, \"checking\");\n const checkStatus = await engine.check(entry.permission);\n\n if (isGrantedStatus(checkStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n continue;\n }\n\n if (checkStatus === \"unavailable\") {\n updateStatus(key, \"unavailable\");\n continue;\n }\n\n if (checkStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n break;\n }\n\n // Denied — request it\n updateStatus(key, \"requesting\");\n try {\n const requestPromise = engine.request(entry.permission);\n const requestStatus = requestTimeout\n ? await withTimeout(requestPromise, requestTimeout, entry.permission)\n : await requestPromise;\n\n if (isGrantedStatus(requestStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (requestStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n break;\n } else {\n updateStatus(key, \"denied\");\n entry.onDeny?.();\n break;\n }\n } catch (err) {\n if (err instanceof PermissionTimeoutError) {\n onTimeout?.();\n updateStatus(key, \"blockedPrompt\");\n break;\n }\n throw err;\n }\n }\n}\n\nasync function runParallel(\n permissions: MultiPermissionEntry[],\n engine: PermissionEngine,\n updateStatus: (key: string, state: PermissionFlowState) => void,\n requestTimeout?: number,\n onTimeout?: () => void,\n): Promise<void> {\n // Check all in parallel\n const checkResults = await Promise.all(\n permissions.map(async (entry) => {\n const key = permissionKey(entry);\n updateStatus(key, \"checking\");\n const status = await engine.check(entry.permission);\n return { entry, key, status };\n }),\n );\n\n // Update granted/unavailable immediately\n for (const { entry, key, status } of checkResults) {\n if (isGrantedStatus(status)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (status === \"unavailable\") {\n updateStatus(key, \"unavailable\");\n }\n }\n\n // Request denied/blocked ones sequentially (system dialogs are sequential)\n const needsAction = checkResults.filter(\n ({ status }) => status === \"denied\" || status === \"blocked\",\n );\n\n for (const { entry, key, status } of needsAction) {\n if (status === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n continue;\n }\n\n updateStatus(key, \"requesting\");\n try {\n const requestPromise = engine.request(entry.permission);\n const requestStatus = requestTimeout\n ? await withTimeout(requestPromise, requestTimeout, entry.permission)\n : await requestPromise;\n\n if (isGrantedStatus(requestStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (requestStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n } else {\n updateStatus(key, \"denied\");\n entry.onDeny?.();\n }\n } catch (err) {\n if (err instanceof PermissionTimeoutError) {\n onTimeout?.();\n updateStatus(key, \"blockedPrompt\");\n } else {\n throw err;\n }\n }\n }\n}\n","import React from \"react\";\nimport { Modal, StyleSheet, Text, TouchableOpacity, View } from \"react-native\";\nimport type { BlockedPromptConfig } from \"../types\";\n\nexport interface DefaultBlockedPromptProps extends BlockedPromptConfig {\n visible: boolean;\n onOpenSettings: () => void;\n}\n\nexport function DefaultBlockedPrompt({\n visible,\n title,\n message,\n settingsLabel = \"Open Settings\",\n onOpenSettings,\n}: DefaultBlockedPromptProps) {\n return (\n <Modal visible={visible} transparent animationType=\"fade\">\n <View style={styles.overlay}>\n <View style={styles.modal}>\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.message}>{message}</Text>\n <TouchableOpacity\n style={styles.settingsButton}\n onPress={onOpenSettings}\n accessibilityRole=\"button\"\n >\n <Text style={styles.settingsText}>{settingsLabel}</Text>\n </TouchableOpacity>\n </View>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n flex: 1,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n justifyContent: \"center\",\n alignItems: \"center\",\n },\n modal: {\n backgroundColor: \"white\",\n borderRadius: 16,\n padding: 24,\n width: \"85%\",\n alignItems: \"center\",\n },\n title: {\n fontSize: 20,\n fontWeight: \"600\",\n marginBottom: 12,\n textAlign: \"center\",\n },\n message: {\n fontSize: 15,\n color: \"#666\",\n textAlign: \"center\",\n marginBottom: 24,\n lineHeight: 22,\n },\n settingsButton: {\n backgroundColor: \"#007AFF\",\n borderRadius: 12,\n paddingVertical: 14,\n paddingHorizontal: 32,\n width: \"100%\",\n alignItems: \"center\",\n },\n settingsText: {\n color: \"white\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n});\n","import React from \"react\";\nimport { Modal, StyleSheet, Text, TouchableOpacity, View } from \"react-native\";\nimport type { PrePromptConfig } from \"../types\";\n\nexport interface DefaultPrePromptProps extends PrePromptConfig {\n visible: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\nexport function DefaultPrePrompt({\n visible,\n title,\n message,\n confirmLabel = \"Continue\",\n cancelLabel = \"Not Now\",\n onConfirm,\n onCancel,\n}: DefaultPrePromptProps) {\n return (\n <Modal visible={visible} transparent animationType=\"fade\">\n <View style={styles.overlay}>\n <View style={styles.modal}>\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.message}>{message}</Text>\n <TouchableOpacity\n style={styles.confirmButton}\n onPress={onConfirm}\n accessibilityRole=\"button\"\n >\n <Text style={styles.confirmText}>{confirmLabel}</Text>\n </TouchableOpacity>\n <TouchableOpacity onPress={onCancel} accessibilityRole=\"button\">\n <Text style={styles.cancelText}>{cancelLabel}</Text>\n </TouchableOpacity>\n </View>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n flex: 1,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n justifyContent: \"center\",\n alignItems: \"center\",\n },\n modal: {\n backgroundColor: \"white\",\n borderRadius: 16,\n padding: 24,\n width: \"85%\",\n alignItems: \"center\",\n },\n title: {\n fontSize: 20,\n fontWeight: \"600\",\n marginBottom: 12,\n textAlign: \"center\",\n },\n message: {\n fontSize: 15,\n color: \"#666\",\n textAlign: \"center\",\n marginBottom: 24,\n lineHeight: 22,\n },\n confirmButton: {\n backgroundColor: \"#007AFF\",\n borderRadius: 12,\n paddingVertical: 14,\n paddingHorizontal: 32,\n width: \"100%\",\n alignItems: \"center\",\n marginBottom: 12,\n },\n confirmText: {\n color: \"white\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n cancelText: {\n color: \"#007AFF\",\n fontSize: 15,\n },\n});\n","import React from \"react\";\nimport type { ReactNode } from \"react\";\nimport { usePermissionHandler } from \"../hooks/use-permission-handler\";\nimport type {\n BlockedPromptConfig,\n PermissionCallbacks,\n PermissionEngine,\n PrePromptConfig,\n} from \"../types\";\nimport { DefaultBlockedPrompt } from \"./default-blocked-prompt\";\nimport { DefaultPrePrompt } from \"./default-pre-prompt\";\n\nexport interface PermissionGateProps extends PermissionCallbacks {\n permission: string;\n engine?: PermissionEngine;\n prePrompt: PrePromptConfig;\n blockedPrompt: BlockedPromptConfig;\n children: ReactNode;\n fallback?: ReactNode;\n renderPrePrompt?: (props: {\n config: PrePromptConfig;\n onConfirm: () => void;\n onCancel: () => void;\n }) => ReactNode;\n renderBlockedPrompt?: (props: {\n config: BlockedPromptConfig;\n onOpenSettings: () => void;\n }) => ReactNode;\n}\n\nexport function PermissionGate({\n permission,\n engine,\n prePrompt,\n blockedPrompt,\n children,\n fallback = null,\n renderPrePrompt,\n renderBlockedPrompt,\n onGrant,\n onDeny,\n onBlock,\n onSettingsReturn,\n}: PermissionGateProps) {\n const handler = usePermissionHandler({\n permission,\n engine,\n prePrompt,\n blockedPrompt,\n onGrant,\n onDeny,\n onBlock,\n onSettingsReturn,\n });\n\n if (handler.isGranted) {\n return <>{children}</>;\n }\n\n if (handler.isChecking || handler.isUnavailable) {\n return <>{fallback}</>;\n }\n\n if (handler.state === \"prePrompt\") {\n if (renderPrePrompt) {\n return (\n <>\n {renderPrePrompt({\n config: prePrompt,\n onConfirm: handler.request,\n onCancel: handler.dismiss,\n })}\n </>\n );\n }\n return (\n <DefaultPrePrompt\n visible\n title={prePrompt.title}\n message={prePrompt.message}\n confirmLabel={prePrompt.confirmLabel}\n cancelLabel={prePrompt.cancelLabel}\n onConfirm={handler.request}\n onCancel={handler.dismiss}\n />\n );\n }\n\n if (handler.state === \"blockedPrompt\") {\n if (renderBlockedPrompt) {\n return (\n <>\n {renderBlockedPrompt({\n config: blockedPrompt,\n onOpenSettings: handler.openSettings,\n })}\n </>\n );\n }\n return (\n <DefaultBlockedPrompt\n visible\n title={blockedPrompt.title}\n message={blockedPrompt.message}\n settingsLabel={blockedPrompt.settingsLabel}\n onOpenSettings={handler.openSettings}\n />\n );\n }\n\n return <>{fallback}</>;\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","Modal","StyleSheet","Text","TouchableOpacity","View","jsx","jsxs","styles","jsx"]}
|
|
@@ -75,6 +75,9 @@ interface PermissionHandlerConfig extends PermissionCallbacks {
|
|
|
75
75
|
blockedPrompt: BlockedPromptConfig;
|
|
76
76
|
autoCheck?: boolean;
|
|
77
77
|
recheckOnForeground?: boolean;
|
|
78
|
+
requestTimeout?: number;
|
|
79
|
+
onTimeout?: () => void;
|
|
80
|
+
debug?: boolean | ((msg: string) => void);
|
|
78
81
|
}
|
|
79
82
|
/**
|
|
80
83
|
* Return type of usePermissionHandler.
|
|
@@ -108,6 +111,9 @@ interface MultiplePermissionsConfig {
|
|
|
108
111
|
strategy: "sequential" | "parallel";
|
|
109
112
|
engine?: PermissionEngine;
|
|
110
113
|
autoCheck?: boolean;
|
|
114
|
+
requestTimeout?: number;
|
|
115
|
+
onTimeout?: () => void;
|
|
116
|
+
debug?: boolean | ((msg: string) => void);
|
|
111
117
|
onAllGranted?: () => void;
|
|
112
118
|
}
|
|
113
119
|
/**
|
|
@@ -75,6 +75,9 @@ interface PermissionHandlerConfig extends PermissionCallbacks {
|
|
|
75
75
|
blockedPrompt: BlockedPromptConfig;
|
|
76
76
|
autoCheck?: boolean;
|
|
77
77
|
recheckOnForeground?: boolean;
|
|
78
|
+
requestTimeout?: number;
|
|
79
|
+
onTimeout?: () => void;
|
|
80
|
+
debug?: boolean | ((msg: string) => void);
|
|
78
81
|
}
|
|
79
82
|
/**
|
|
80
83
|
* Return type of usePermissionHandler.
|
|
@@ -108,6 +111,9 @@ interface MultiplePermissionsConfig {
|
|
|
108
111
|
strategy: "sequential" | "parallel";
|
|
109
112
|
engine?: PermissionEngine;
|
|
110
113
|
autoCheck?: boolean;
|
|
114
|
+
requestTimeout?: number;
|
|
115
|
+
onTimeout?: () => void;
|
|
116
|
+
debug?: boolean | ((msg: string) => void);
|
|
111
117
|
onAllGranted?: () => void;
|
|
112
118
|
}
|
|
113
119
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-permission-handler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Smart permission UX flows for React Native — pre-prompts, blocked handling, settings redirect & foreground re-check. Pluggable engine: works with react-native-permissions, Expo, or your own.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createDebugLogger } from "./debug-logger";
|
|
3
|
+
|
|
4
|
+
describe("createDebugLogger", () => {
|
|
5
|
+
let consoleSpy: ReturnType<typeof vi.spyOn>;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
consoleSpy.mockRestore();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("logs transitions when enabled", () => {
|
|
16
|
+
const logger = createDebugLogger(true, "camera");
|
|
17
|
+
logger.transition("idle", "checking", "CHECK");
|
|
18
|
+
|
|
19
|
+
expect(consoleSpy).toHaveBeenCalledWith("[permission-handler] camera: idle → checking (CHECK)");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("does not log when disabled", () => {
|
|
23
|
+
const logger = createDebugLogger(false, "camera");
|
|
24
|
+
logger.transition("idle", "checking", "CHECK");
|
|
25
|
+
logger.info("test");
|
|
26
|
+
|
|
27
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("does not log when undefined", () => {
|
|
31
|
+
const logger = createDebugLogger(undefined, "camera");
|
|
32
|
+
logger.transition("idle", "checking");
|
|
33
|
+
logger.info("test");
|
|
34
|
+
|
|
35
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("omits event when not provided", () => {
|
|
39
|
+
const logger = createDebugLogger(true, "camera");
|
|
40
|
+
logger.transition("idle", "checking");
|
|
41
|
+
|
|
42
|
+
expect(consoleSpy).toHaveBeenCalledWith("[permission-handler] camera: idle → checking");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("logs info messages", () => {
|
|
46
|
+
const logger = createDebugLogger(true, "camera");
|
|
47
|
+
logger.info("request timed out");
|
|
48
|
+
|
|
49
|
+
expect(consoleSpy).toHaveBeenCalledWith("[permission-handler] camera: request timed out");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("uses custom logger function when provided", () => {
|
|
53
|
+
const customLog = vi.fn();
|
|
54
|
+
const logger = createDebugLogger(customLog, "mic");
|
|
55
|
+
logger.transition("idle", "checking", "CHECK");
|
|
56
|
+
|
|
57
|
+
expect(customLog).toHaveBeenCalledWith("[permission-handler] mic: idle → checking (CHECK)");
|
|
58
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("includes permission name in all messages", () => {
|
|
62
|
+
const logger = createDebugLogger(true, "notifications");
|
|
63
|
+
logger.transition("prePrompt", "requesting", "PRE_PROMPT_CONFIRM");
|
|
64
|
+
|
|
65
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("notifications"));
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const PREFIX = "[permission-handler]";
|
|
2
|
+
|
|
3
|
+
interface DebugLogger {
|
|
4
|
+
transition(from: string, to: string, event?: string): void;
|
|
5
|
+
info(msg: string): void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const NOOP_LOGGER: DebugLogger = {
|
|
9
|
+
transition: () => {},
|
|
10
|
+
info: () => {},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function createDebugLogger(
|
|
14
|
+
debug: boolean | ((msg: string) => void) | undefined,
|
|
15
|
+
permission: string,
|
|
16
|
+
): DebugLogger {
|
|
17
|
+
if (!debug) return NOOP_LOGGER;
|
|
18
|
+
|
|
19
|
+
const log = typeof debug === "function" ? debug : (msg: string) => console.log(msg);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
transition(from: string, to: string, event?: string) {
|
|
23
|
+
log(`${PREFIX} ${permission}: ${from} → ${to}${event ? ` (${event})` : ""}`);
|
|
24
|
+
},
|
|
25
|
+
info(msg: string) {
|
|
26
|
+
log(`${PREFIX} ${permission}: ${msg}`);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|