@buoy-gg/permissions 7.0.44

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 (62) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +29 -0
  3. package/lib/commonjs/components/PermissionsBody.js +1 -0
  4. package/lib/commonjs/components/PermissionsChip.js +1 -0
  5. package/lib/commonjs/components/PermissionsToolView.js +1 -0
  6. package/lib/commonjs/engine/adapters/android.js +1 -0
  7. package/lib/commonjs/engine/adapters/expo.js +3 -0
  8. package/lib/commonjs/engine/adapters/rnPermissions.js +1 -0
  9. package/lib/commonjs/engine/adapters/wrap.js +1 -0
  10. package/lib/commonjs/engine/appSettings.js +1 -0
  11. package/lib/commonjs/engine/install.js +1 -0
  12. package/lib/commonjs/engine/install.web.js +1 -0
  13. package/lib/commonjs/engine/model.js +1 -0
  14. package/lib/commonjs/engine/persistence.js +1 -0
  15. package/lib/commonjs/engine/prompt.js +3 -0
  16. package/lib/commonjs/engine/readSavedSync.js +1 -0
  17. package/lib/commonjs/engine/readSavedSync.web.js +1 -0
  18. package/lib/commonjs/engine/store.js +1 -0
  19. package/lib/commonjs/index.js +1 -0
  20. package/lib/commonjs/package.json +1 -0
  21. package/lib/commonjs/preset.js +1 -0
  22. package/lib/commonjs/sync/permissionsSyncAdapter.js +1 -0
  23. package/lib/module/components/PermissionsBody.js +1 -0
  24. package/lib/module/components/PermissionsChip.js +1 -0
  25. package/lib/module/components/PermissionsToolView.js +1 -0
  26. package/lib/module/engine/adapters/android.js +1 -0
  27. package/lib/module/engine/adapters/expo.js +3 -0
  28. package/lib/module/engine/adapters/rnPermissions.js +1 -0
  29. package/lib/module/engine/adapters/wrap.js +1 -0
  30. package/lib/module/engine/appSettings.js +1 -0
  31. package/lib/module/engine/install.js +1 -0
  32. package/lib/module/engine/install.web.js +1 -0
  33. package/lib/module/engine/model.js +1 -0
  34. package/lib/module/engine/persistence.js +1 -0
  35. package/lib/module/engine/prompt.js +3 -0
  36. package/lib/module/engine/readSavedSync.js +1 -0
  37. package/lib/module/engine/readSavedSync.web.js +1 -0
  38. package/lib/module/engine/store.js +1 -0
  39. package/lib/module/index.js +1 -0
  40. package/lib/module/preset.js +1 -0
  41. package/lib/module/sync/permissionsSyncAdapter.js +1 -0
  42. package/lib/typescript/components/PermissionsBody.d.ts +2 -0
  43. package/lib/typescript/components/PermissionsChip.d.ts +7 -0
  44. package/lib/typescript/components/PermissionsToolView.d.ts +10 -0
  45. package/lib/typescript/engine/adapters/android.d.ts +13 -0
  46. package/lib/typescript/engine/adapters/expo.d.ts +60 -0
  47. package/lib/typescript/engine/adapters/rnPermissions.d.ts +16 -0
  48. package/lib/typescript/engine/adapters/wrap.d.ts +25 -0
  49. package/lib/typescript/engine/appSettings.d.ts +32 -0
  50. package/lib/typescript/engine/install.d.ts +3 -0
  51. package/lib/typescript/engine/install.web.d.ts +7 -0
  52. package/lib/typescript/engine/model.d.ts +115 -0
  53. package/lib/typescript/engine/persistence.d.ts +36 -0
  54. package/lib/typescript/engine/prompt.d.ts +26 -0
  55. package/lib/typescript/engine/readSavedSync.d.ts +9 -0
  56. package/lib/typescript/engine/readSavedSync.web.d.ts +4 -0
  57. package/lib/typescript/engine/store.d.ts +140 -0
  58. package/lib/typescript/index.d.ts +13 -0
  59. package/lib/typescript/preset.d.ts +45 -0
  60. package/lib/typescript/sync/permissionsSyncAdapter.d.ts +19 -0
  61. package/lib/web/index.mjs +1 -0
  62. package/package.json +110 -0
package/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ PROPRIETARY SOFTWARE LICENSE
2
+
3
+ Copyright (c) 2024-present Buoy. All rights reserved.
4
+
5
+ This software and its source code are proprietary and confidential.
6
+
7
+ NOTICE: This is NOT open source software. This software is licensed,
8
+ not sold, and is protected by copyright laws and international treaties.
9
+
10
+ TERMS AND CONDITIONS:
11
+
12
+ 1. LICENSE GRANT
13
+ Subject to the terms of this Agreement and payment of applicable fees,
14
+ Buoy grants you a limited, non-exclusive, non-transferable license
15
+ to use the compiled software packages in your applications.
16
+
17
+ 2. RESTRICTIONS
18
+ You may NOT:
19
+ - Copy, modify, or distribute the source code
20
+ - Reverse engineer, decompile, or disassemble the software
21
+ - Remove or alter any proprietary notices or labels
22
+ - Sublicense, rent, lease, or lend the software
23
+ - Use the software to create competing products
24
+ - Share access credentials with unauthorized parties
25
+
26
+ 3. OWNERSHIP
27
+ React Buoy retains all right, title, and interest in the software,
28
+ including all intellectual property rights. This license does not
29
+ grant you any rights to trademarks or service marks.
30
+
31
+ 4. TERMINATION
32
+ This license is effective until terminated. Your rights under this
33
+ license will terminate automatically without notice if you fail to
34
+ comply with any of its terms. Upon termination, you must cease all
35
+ use and destroy all copies of the software.
36
+
37
+ 5. DISCLAIMER OF WARRANTIES
38
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
39
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
41
+
42
+ 6. LIMITATION OF LIABILITY
43
+ IN NO EVENT SHALL BUOY BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
44
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN
45
+ CONNECTION WITH THIS LICENSE OR THE USE OF THE SOFTWARE.
46
+
47
+ 7. GOVERNING LAW
48
+ This Agreement shall be governed by and construed in accordance with
49
+ the laws of the United States, without regard to its conflict of
50
+ law provisions.
51
+
52
+ For licensing inquiries and subscription information:
53
+ - Website: https://buoy.gg
54
+ - Email: AustinLovesWorking@gmail.com
55
+
56
+ Unauthorized reproduction or distribution of this software, or any
57
+ portion of it, may result in severe civil and criminal penalties,
58
+ and will be prosecuted to the maximum extent possible under the law.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ <div align="center">
2
+
3
+ # @buoy-gg/permissions
4
+
5
+ Make your React Native app see any permission state (not asked, allowed, limited, denied or blocked) for location, camera, notifications, photos and more. You can test the prompt, the refusal screen and the trip to Settings without changing the device's settings or reinstalling the app.
6
+
7
+ <a href="https://buoy.gg/buoy/latest/docs/tools/permissions"><b>Permissions guide</b></a> &nbsp;·&nbsp; <a href="https://buoy.gg">buoy.gg</a> &nbsp;·&nbsp; <a href="https://github.com/Buoy-gg/buoy">All tools</a>
8
+
9
+ [![npm version](https://img.shields.io/npm/v/@buoy-gg/permissions?style=flat-square&labelColor=10302a&color=2a9d78)](https://www.npmjs.com/package/@buoy-gg/permissions) [![npm downloads](https://img.shields.io/npm/dm/@buoy-gg/permissions?style=flat-square&labelColor=10302a&color=2a9d78&label=downloads%2Fmonth)](https://www.npmjs.com/package/@buoy-gg/permissions)
10
+
11
+ </div>
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @buoy-gg/core @buoy-gg/permissions
17
+ ```
18
+
19
+ The tool appears in `FloatingDevTools` on its own. It works with Expo modules (expo-location, expo-camera, expo-notifications, expo-image-picker, expo-media-library, expo-contacts and others), React Native's `PermissionsAndroid` and react-native-permissions, with no extra setup. If your app checks a permission while its modules load, import the package first in your entry file so a saved override applies before that check:
20
+
21
+ ```js
22
+ import "@buoy-gg/permissions";
23
+ ```
24
+
25
+ The [Permissions guide](https://buoy.gg/buoy/latest/docs/tools/permissions) lists the states each platform supports and what the override can and can't change. New to Buoy? Start with the [Quick start](https://buoy.gg/buoy/latest/docs/quick-start).
26
+
27
+ ---
28
+
29
+ <sub>Part of <a href="https://buoy.gg">Buoy</a>, developer tools that live inside your app. Proprietary software. © Buoy LLC. <a href="https://buoy.gg/terms">Terms</a></sub>
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PermissionsBody=PermissionsBody;var _react=require("react");var _sharedUi=require("@buoy-gg/shared-ui");var _expo=require("../engine/adapters/expo");var _install=require("../engine/install");var _store=require("../engine/store");var _permissionsSyncAdapter=require("../sync/permissionsSyncAdapter");var _PermissionsToolView=require("./PermissionsToolView");var _jsxRuntime=require("react/jsx-runtime");const actions=_permissionsSyncAdapter.permissionsSyncAdapter.actions;async function runAction(e,r){const s=actions[e];if(!s)throw new Error(`Unknown permissions action: ${e}`);return s(r)}function reload(){void(0,_sharedUi.reloadApp)("auto","buoy permissions").catch(()=>{})}function PermissionsBody(){(0,_react.useEffect)(()=>{(0,_install.installPermissions)();void(0,_expo.refreshExpoRealStates)()},[]);const e=(0,_react.useSyncExternalStore)(_store.subscribePermissions,_store.getPermissionsSnapshot,_store.getPermissionsSnapshot);return(0,_jsxRuntime.jsx)(_PermissionsToolView.PermissionsToolView,{snapshot:e,onAction:runAction,onReload:reload})}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PERMISSIONS_CHIP_ID=void 0;exports.PermissionsChip=PermissionsChip;exports.openPermissionsChip=openPermissionsChip;exports.watchPermissionsChip=watchPermissionsChip;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _model=require("../engine/model");var _store=require("../engine/store");var _jsxRuntime=require("react/jsx-runtime");const PERMISSIONS_CHIP_ID=exports.PERMISSIONS_CHIP_ID="permissions-chip";const UNDO_MS=8e3;const registration={id:PERMISSIONS_CHIP_ID,render:e=>(0,_jsxRuntime.jsx)(PermissionsChip,{...e})};const isChipOpen=()=>(0,_sharedUi.getFloatingTools)().some(e=>e.id===PERMISSIONS_CHIP_ID);function openPermissionsChip(){(0,_sharedUi.openFloatingTool)(registration)}let undo=null;const undoListeners=new Set;let syncChip=()=>{};function setUndo(e){if(undo)clearTimeout(undo.timer);undo=e;for(const t of Array.from(undoListeners))t();syncChip()}function subscribeUndo(e){undoListeners.add(e);return()=>{undoListeners.delete(e)}}const getUndo=()=>undo;function resetWithUndo(){setUndo({overrides:(0,_store.getOverrides)(),timer:setTimeout(()=>setUndo(null),UNDO_MS)});(0,_store.resetPermissions)()}function undoReset(){const e=undo;if(!e)return;setUndo(null);(0,_store.restoreOverrides)(e.overrides)}let watching=false;function watchPermissionsChip(){if(watching)return;watching=true;let e=false;syncChip=()=>{const t=((0,_store.anyOverride)()||undo!==null)&&(0,_store.getSettings)().showChip;if(t&&!e)(0,_sharedUi.openFloatingTool)(registration);else if(!t&&isChipOpen())(0,_sharedUi.dismissFloatingTool)(PERMISSIONS_CHIP_ID);e=t};(0,_store.subscribePermissions)(syncChip);syncChip()}function PermissionsChip({id:e,revealToken:t}){const s=(0,_react.useSyncExternalStore)(_store.subscribePermissions,_store.getPermissionsSnapshot,_store.getPermissionsSnapshot);const n=(0,_react.useSyncExternalStore)(subscribeUndo,getUndo,getUndo);(0,_react.useEffect)(()=>{if(n&&s.overriddenCount>0)setUndo(null)},[n,s.overriddenCount]);const o=s.permissions.filter(l=>l.override!==null);const i=o.length===1?o[0]:null;const r=i?`${i.label}: ${i.once&&i.override==="granted"?"Allowed Once":(0,_model.stateLabel)(i.id,s.platform,i.override)}`:`${o.length} permissions simulated`;if(n&&o.length===0){return(0,_jsxRuntime.jsx)(_sharedUi.FloatingTool,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:"Move or hide the permissions strip",handleAdornment:(0,_jsxRuntime.jsx)(_sharedUi.PermissionsIcon,{size:12}),children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.row,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,numberOfLines:1,testID:"permissions-chip-summary",children:"Real permissions"}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"permissions-chip-undo",accessibilityRole:"button",accessibilityLabel:"Undo, put the simulated permissions back",onPress:undoReset,style:styles.undo,hitSlop:{top:8,bottom:8,left:8,right:8},children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.undoText,children:"Undo"})})]})})}return(0,_jsxRuntime.jsx)(_sharedUi.FloatingTool,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:`Move or hide the permissions strip. ${r}`,handleAdornment:(0,_jsxRuntime.jsx)(_sharedUi.PermissionsIcon,{size:12}),children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.row,children:[(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:"permissions-chip-open",accessibilityRole:"button",accessibilityLabel:`${r}. Open Permissions`,onPress:()=>{(0,_sharedUi.openBuoyTool)("permissions")},style:styles.open,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.dot}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,numberOfLines:1,testID:"permissions-chip-summary",children:r})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.separator}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"permissions-chip-reset",accessibilityRole:"button",accessibilityLabel:"Use real permissions",onPress:resetWithUndo,style:styles.button,hitSlop:{top:8,bottom:8,left:4,right:8},children:(0,_jsxRuntime.jsx)(_sharedUi.X,{size:16,color:_sharedUi.night.color.textSecondary})})]})})}const styles=_reactNative.StyleSheet.create({row:{flexDirection:"row",alignItems:"center",gap:10,paddingLeft:12,paddingRight:4,minHeight:40,minWidth:200},open:{flexDirection:"row",alignItems:"center",gap:8,flexShrink:1},dot:{width:7,height:7,borderRadius:4,backgroundColor:_sharedUi.night.color.accent},title:{color:_sharedUi.night.color.text,fontSize:14,fontWeight:"600",flexShrink:1},button:{width:32,height:32,alignItems:"center",justifyContent:"center",borderRadius:16},undo:{paddingHorizontal:12,paddingVertical:6},undoText:{color:_sharedUi.night.color.accent,fontSize:14,fontWeight:"600"},separator:{width:_reactNative.StyleSheet.hairlineWidth,height:20,backgroundColor:_sharedUi.night.color.separator}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PermissionsToolView=PermissionsToolView;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _model=require("../engine/model");var _jsxRuntime=require("react/jsx-runtime");const STALE_AFTER_MS=1500;const realNow=()=>{const e=globalThis.__buoyRealNow;return typeof e==="function"?e():Date.now()};function valueLabel(e,i){if(!e.effective)return"Not Checked";if(e.once&&e.effective==="granted")return"Allowed Once";return(0,_model.stateLabel)(e.id,i,e.effective)}function PermissionsToolView({snapshot:e,onAction:i,onReload:l}){const o=(0,_sharedUi.useSafeAreaInsets)({minBottom:16});const[a,c]=(0,_react.useState)(null);const[s,h]=(0,_react.useState)({name:"list"});const t=(r,m)=>{c(null);i(r,m).catch(f=>{c(f instanceof Error?f.message:String(f))})};const n=s.name==="detail"?e?.permissions.find(r=>r.id===s.id):void 0;const x=()=>h(s.name==="detail"&&s.from==="other"?{name:"other"}:{name:"list"});const d=s.name==="other"?"Other Permissions":n?n.label:null;const T=(0,_sharedUi.useToolScreenHeader)(d?{title:d,onBack:x,searchable:false}:null,[d,s.name,s.name==="detail"?s.from:null]);if(!e){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.waiting,testID:"permissions-waiting",children:(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{centered:true,children:"Waiting for the app\u2026"})})}const{platform:p,permissions:y}=e;const j=y.filter(r=>r.calls>0||r.override!==null);const g=y.filter(r=>!(r.calls>0||r.override!==null));const b=(r,m)=>h({name:"detail",id:r,from:m});let u;if(s.name==="detail"&&n){u=(0,_jsxRuntime.jsx)(DetailScreen,{row:n,platform:p,log:e.log,run:t,onPicked:x})}else if(s.name==="other"){u=(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(PermissionList,{rows:g,platform:p,onOpen:r=>b(r,"other")}),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Your app can ask for these but hasn't yet."})]})}else{u=(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[j.length>0?(0,_jsxRuntime.jsx)(PermissionList,{rows:j,platform:p,onOpen:r=>b(r,"list"),onReload:l}):(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{padded:true,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.empty,testID:"permissions-empty",children:"Your app hasn't checked any permissions yet. Open a screen that uses location, the camera or notifications and it will show up here."})}),g.length>0?(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:"permissions-other",accessibilityRole:"button",accessibilityLabel:`Other Permissions, ${g.length}`,activeOpacity:.6,onPress:()=>h({name:"other"}),style:styles.row,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Other Permissions"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowRight,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowValue,children:g.length}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:16,color:_sharedUi.night.color.textTertiary})]})]})}):null,e.overriddenCount>0?(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"permissions-reset",accessibilityRole:"button",accessibilityLabel:"Use Real Permissions",activeOpacity:.6,onPress:()=>t("resetAll"),style:styles.row,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.destructive,children:"Use Real Permissions"})})}):null]})}return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.fill,contentContainerStyle:[styles.content,{paddingBottom:o.bottom}],testID:"permissions-scroll",children:[!T&&s.name!=="list"?(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:"permissions-back",accessibilityRole:"button",accessibilityLabel:"Back",onPress:x,style:styles.inlineBack,children:[(0,_jsxRuntime.jsx)(_sharedUi.ChevronLeft,{size:18,color:_sharedUi.night.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.inlineBackText,children:s.name==="detail"&&s.from==="other"?"Other Permissions":"Permissions"}),d?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.inlineTitle,children:d}):null]}):null,a?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"danger",centered:true,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"permissions-error",children:a})}):null,u]})}function PermissionList({rows:e,platform:i,onOpen:l,onReload:o}){const[,a]=(0,_react.useReducer)(t=>t+1,0);const c=realNow();const s=e.filter(t=>t.stale&&t.changedAt!==null&&c-t.changedAt<STALE_AFTER_MS).map(t=>STALE_AFTER_MS-(c-t.changedAt));const h=s.length>0?Math.min(...s):null;(0,_react.useEffect)(()=>{if(h===null)return;const t=setTimeout(a,h+50);return()=>clearTimeout(t)},[h]);return(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsx)(_sharedUi.NightRows,{children:e.map(t=>{const n=t.stale&&t.changedAt!==null&&c-t.changedAt>=STALE_AFTER_MS;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(PermissionRowView,{row:t,platform:i,onPress:()=>l(t.id)}),n?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stale,testID:`permissions-stale-${t.id}`,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.staleText,children:"The app hasn't checked again since this changed."}),o?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:`permissions-reload-${t.id}`,accessibilityRole:"button",accessibilityLabel:"Reload App",onPress:o,hitSlop:{top:8,bottom:8,left:8,right:8},children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.staleAction,children:"Reload App"})}):null]}):null]},t.id)})})})}function PermissionRowView({row:e,platform:i,onPress:l}){const o=e.override!==null;const a=valueLabel(e,i);const c=e.real?(0,_model.stateLabel)(e.id,i,e.real):"Not Checked";return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:`permissions-row-${e.id}`,accessibilityRole:"button",accessibilityLabel:`${e.label}: ${a}${o?`, simulated. Phone: ${c}`:""}`,activeOpacity:.6,onPress:l,style:styles.row,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowLeft,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:e.label}),o?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.rowSub,testID:`permissions-phone-${e.id}`,children:["Phone: ",c]}):null]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowRight,children:[o?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.dot}):null,(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.rowValue,o?styles.rowValueSimulated:null],testID:`permissions-value-${e.id}`,numberOfLines:1,children:a}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:16,color:_sharedUi.night.color.textTertiary})]})]})}function OptionRow({title:e,detail:i,selected:l,testID:o,onPress:a}){return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:o,accessibilityRole:"button",accessibilityLabel:`${e}. ${i}`,accessibilityState:{selected:l},activeOpacity:.6,onPress:a,style:styles.option,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.optionText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionDetail,children:i})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.check,children:l?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:18,color:_sharedUi.night.color.accent}):null})]})}const VERBS={check:"Checked",request:"Asked",settings:"Opened Settings",gated:"Needed it"};function DetailScreen({row:e,platform:i,log:l,run:o,onPicked:a}){const c=e.real?(0,_model.stateLabel)(e.id,i,e.real):null;const s=n=>{if(n===null)o("clearOverride",{permission:e.id});else o("setOverride",{permission:e.id,state:n});a()};const h=l.filter(n=>n.permission===e.id).slice(0,8);const t=e.canRequestReal&&e.real==="undetermined";return(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"What the app sees"}),(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_sharedUi.NightRows,{children:[(0,_jsxRuntime.jsx)(OptionRow,{title:"Phone's Setting",detail:c?`Use what the phone says: ${c}.`:"Use what the phone says.",selected:e.override===null,testID:`permissions-state-${e.id}-real`,onPress:()=>s(null)},"real"),e.states.map(n=>(0,_jsxRuntime.jsx)(OptionRow,{title:(0,_model.stateLabel)(e.id,i,n),detail:(0,_model.stateDescription)(e.id,i,n),selected:e.override===n,testID:`permissions-state-${e.id}-${n}`,onPress:()=>s(n)},n))]})})]}),t?(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:`permissions-request-real-${e.id}`,accessibilityRole:"button",accessibilityLabel:`Show the real system prompt for ${e.label}`,activeOpacity:.6,onPress:()=>o("requestReal",{permission:e.id}),style:styles.row,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.action,children:"Show Real Prompt"})})}),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:e.warning??"Asks the phone for real, so calls that need this permission work."})]}):e.warning?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"warning",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:`permissions-warning-${e.id}`,children:e.warning})}):null,h.length>0?(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Recent"}),(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsx)(_sharedUi.NightRows,{children:h.map(n=>(0,_jsxRuntime.jsx)(RecentRow,{entry:n,platform:i},n.id))})}),e.sources.length>0?(0,_jsxRuntime.jsxs)(_sharedUi.NightFootnote,{children:["Read through ",e.sources.join(", ")]}):null]}):null]})}function clockTime(e){const i=new Date(e);const l=o=>String(o).padStart(2,"0");return`${l(i.getHours())}:${l(i.getMinutes())}:${l(i.getSeconds())}`}function RecentRow({entry:e,platform:i}){const l=e.error?"Failed":e.returned&&e.permission?e.answer==="once"&&e.returned==="granted"?"Allowed Once":(0,_model.stateLabel)(e.permission,i,e.returned):"";return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.recentRow,testID:`permissions-log-${e.id}`,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.recentTime,children:clockTime(e.at)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.recentVerb,numberOfLines:1,children:VERBS[e.kind]}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.recentResult,e.error?styles.recentFailed:null],numberOfLines:1,children:l})]})}const styles=_reactNative.StyleSheet.create({fill:{flex:1},content:{paddingHorizontal:_sharedUi.night.gutter,paddingTop:12,gap:_sharedUi.night.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},empty:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body,lineHeight:20},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:10},rowLeft:{flexShrink:1,gap:2},rowTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row},rowSub:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption},rowRight:{flexDirection:"row",alignItems:"center",gap:6,flexShrink:1},rowValue:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.row},rowValueSimulated:{color:_sharedUi.night.color.accent},dot:{width:7,height:7,borderRadius:4,backgroundColor:_sharedUi.night.color.accent},stale:{flexDirection:"row",alignItems:"center",flexWrap:"wrap",columnGap:10,rowGap:4,paddingHorizontal:_sharedUi.night.rowPadH,paddingBottom:12,marginTop:-4},staleText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,flexShrink:1},staleAction:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},destructive:{color:_sharedUi.night.color.danger,fontSize:_sharedUi.night.font.row},action:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.row},option:{flexDirection:"row",alignItems:"center",gap:12,paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:11,minHeight:50},optionText:{flex:1,gap:2},optionDetail:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,lineHeight:17},check:{width:20,alignItems:"center"},inlineBack:{flexDirection:"row",alignItems:"center",gap:4,marginBottom:-8},inlineBackText:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.row},inlineTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600",marginLeft:"auto"},recentRow:{flexDirection:"row",alignItems:"center",gap:12,paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:10},recentTime:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,fontVariant:["tabular-nums"]},recentVerb:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,flex:1},recentResult:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body},recentFailed:{color:_sharedUi.night.color.danger}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.androidPermissionId=androidPermissionId;exports.installAndroidAdapter=installAndroidAdapter;var _model=require("../model");var _store=require("../store");var _wrap=require("./wrap");const SOURCE="PermissionsAndroid";const ANDROID_TO_ID={ACCESS_FINE_LOCATION:"location",ACCESS_COARSE_LOCATION:"location",ACCESS_BACKGROUND_LOCATION:"locationBackground",CAMERA:"camera",RECORD_AUDIO:"microphone",POST_NOTIFICATIONS:"notifications",READ_MEDIA_IMAGES:"photos",READ_MEDIA_VIDEO:"photos",READ_MEDIA_VISUAL_USER_SELECTED:"photos",READ_EXTERNAL_STORAGE:"photos",WRITE_EXTERNAL_STORAGE:"photos",READ_CONTACTS:"contacts",WRITE_CONTACTS:"contacts",READ_CALENDAR:"calendar",WRITE_CALENDAR:"calendar",ACTIVITY_RECOGNITION:"motion",BLUETOOTH_SCAN:"bluetooth",BLUETOOTH_CONNECT:"bluetooth",BLUETOOTH_ADVERTISE:"bluetooth"};function androidPermissionId(e){const t=e.replace(/^android\.permission\./,"");return ANDROID_TO_ID[t]??`android:${e}`}function resultFor(e,t){if((0,_model.toAndroidCheck)(e,t))return"granted";if(e==="blocked"||e==="restricted")return"never_ask_again";return"denied"}function stateFromResult(e){if(e==="granted"||e===true)return"granted";if(e==="never_ask_again")return"blocked";if(e==="denied")return"denied";return null}function installAndroidAdapter(e){if(!e)return false;(0,_wrap.wrapMethod)(e,"check",t=>async(...s)=>{const d=String(s[0]);const r=androidPermissionId(d);const i=await t(...s);const n=i===true?"granted":null;(0,_store.noteReal)(r,n,SOURCE);const a=(0,_store.getOverride)(r);if(a===null){(0,_store.recordCall)({source:SOURCE,method:"check",permission:r,kind:"check",real:n,returned:n,overridden:false});return i}(0,_store.recordCall)({source:SOURCE,method:"check",permission:r,kind:"check",real:n,returned:a,overridden:true});return(0,_model.toAndroidCheck)(a,d)});(0,_wrap.wrapMethod)(e,"request",t=>async(...s)=>{const d=String(s[0]);const r=androidPermissionId(d);if((0,_store.getOverride)(r)===null){const a=await t(...s);const o=stateFromResult(a);(0,_store.noteReal)(r,o,SOURCE);(0,_store.recordCall)({source:SOURCE,method:"request",permission:r,kind:"request",real:o,returned:o,overridden:false});return a}const{state:i,answer:n}=await(0,_store.resolveRequest)(r);(0,_store.recordCall)({source:SOURCE,method:"request",permission:r,kind:"request",real:null,returned:i,overridden:true,answer:n});return resultFor(i,d)});(0,_wrap.wrapMethod)(e,"requestMultiple",t=>async(...s)=>{const d=Array.isArray(s[0])?s[0].map(String):[];const r=d.filter(o=>(0,_store.getOverride)(androidPermissionId(o))!==null);const i=d.filter(o=>!r.includes(o));const n={};if(i.length>0){const o=await t(i,...s.slice(1));for(const c of i){n[c]=o?.[c];const u=androidPermissionId(c);const l=stateFromResult(o?.[c]);(0,_store.noteReal)(u,l,SOURCE);(0,_store.recordCall)({source:SOURCE,method:"requestMultiple",permission:u,kind:"request",real:l,returned:l,overridden:false})}}const a=new Map;for(const o of r){const c=androidPermissionId(o);if(!a.has(c)){const u=await(0,_store.resolveRequest)(c);a.set(c,u);(0,_store.recordCall)({source:SOURCE,method:"requestMultiple",permission:c,kind:"request",real:null,returned:u.state,overridden:true,answer:u.answer})}n[o]=resultFor(a.get(c).state,o)}return n});for(const[t,s]of Object.entries(ANDROID_TO_ID)){if(t==="ACCESS_COARSE_LOCATION"||t.startsWith("WRITE_")||t==="READ_MEDIA_VIDEO")continue;(0,_store.registerRealRequester)(s,async()=>{const d=e.request;const r=d?.__buoyPermissionsOriginal;if(!r)return null;const i=await r.call(e,`android.permission.${t}`);const n=stateFromResult(i);(0,_store.recordCall)({source:SOURCE,method:"request (system)",permission:s,kind:"request",real:n,returned:n,overridden:false});return n})}(0,_store.registerLibrary)(SOURCE,[]);return true}
@@ -0,0 +1,3 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.EXPO_MODULES=void 0;exports.coarsenPosition=coarsenPosition;exports.installExpoAdapter=installExpoAdapter;exports.refreshExpoRealStates=refreshExpoRealStates;var _model=require("../model");var _store=require("../store");var _wrap=require("./wrap");const LOCATION_DENIED={ios:{code:"ERR_DENIED_FOREGROUND_LOCATION_PERMISSION",reason:"Location permission is required to do this operation"},android:{code:"ERR_LOCATION_UNAUTHORIZED",reason:"Not authorized to use location services"}};const BACKGROUND_DENIED={ios:{code:"ERR_DENIED_BACKGROUND_LOCATION_PERMISSION",reason:"Background location permission is required to do this operation"},android:{code:"ERR_LOCATION_BACKGROUND_UNAUTHORIZED",reason:"Not authorized to use background location services"}};const EXPO_MODULES=exports.EXPO_MODULES=[{module:"ExpoLocation",library:"expo-location",permissions:[{get:"getForegroundPermissionsAsync",request:"requestForegroundPermissionsAsync",permission:"location",flavor:"location"},{get:"getBackgroundPermissionsAsync",request:"requestBackgroundPermissionsAsync",permission:"locationBackground",flavor:"locationBackground"},{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"location",flavor:"location"}],gated:[{method:"getCurrentPositionAsync",permission:"location",...LOCATION_DENIED},{method:"getLastKnownPositionAsync",permission:"location",...LOCATION_DENIED},{method:"watchPositionImplAsync",permission:"location",...LOCATION_DENIED},{method:"startGeofencingAsync",permission:"locationBackground",...BACKGROUND_DENIED},{method:"startLocationUpdatesAsync",permission:"locationBackground",...BACKGROUND_DENIED}]},{module:"ExpoMaps",library:"expo-maps",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"location",flavor:"plain"}]},{module:"ExpoCamera",library:"expo-camera",permissions:[{get:"getCameraPermissionsAsync",request:"requestCameraPermissionsAsync",permission:"camera",flavor:"plain"},{get:"getMicrophonePermissionsAsync",request:"requestMicrophonePermissionsAsync",permission:"microphone",flavor:"plain"}]},{module:"ExpoNotificationPermissionsModule",library:"expo-notifications",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"notifications",flavor:"notifications",defaultArgs:s=>s==="ios"?[{allowAlert:true,allowBadge:true,allowSound:true}]:[void 0]}]},{module:"ExpoMediaLibrary",library:"expo-media-library",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"photos",flavor:"privileges",defaultArgs:()=>[false]}],gated:["getAssetsAsync","getAlbumsAsync","getAssetInfoAsync","createAssetAsync","saveToLibraryAsync"].map(s=>({method:s,permission:"photos",ios:{code:"ERR_MEDIA_LIBRARY_PERMISSIONS",reason:"Media Library permission is required to do this operation"}}))},{module:"ExponentImagePicker",library:"expo-image-picker",permissions:[{get:"getCameraPermissionsAsync",request:"requestCameraPermissionsAsync",permission:"camera",flavor:"plain"},{get:"getMediaLibraryPermissionsAsync",request:"requestMediaLibraryPermissionsAsync",permission:"photos",flavor:"privileges",defaultArgs:()=>[false]}],gated:[{method:"launchCameraAsync",permission:"camera",ios:{code:"ERR_MISSING_CAMERA_PERMISSION",reason:"Missing camera or camera roll permission"},android:{code:"ERR_USER_REJECTED_PERMISSIONS",reason:"User rejected permissions"}}]},{module:"ExpoContacts",library:"expo-contacts",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"contacts",flavor:"privileges"}]},{module:"ExpoCalendar",library:"expo-calendar",permissions:[{get:"getCalendarPermissionsAsync",request:"requestCalendarPermissionsAsync",permission:"calendar",flavor:"plain"},{get:"getRemindersPermissionsAsync",request:"requestRemindersPermissionsAsync",permission:"reminders",flavor:"plain"}]},{module:"CalendarNext",library:"expo-calendar",permissions:[{get:"getCalendarPermissions",request:"requestCalendarPermissions",permission:"calendar",flavor:"plain"},{get:"getRemindersPermissions",request:"requestRemindersPermissions",permission:"reminders",flavor:"plain"}]},{module:"ExpoTrackingTransparency",library:"expo-tracking-transparency",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"tracking",flavor:"plain"}]},{module:"ExpoAudio",library:"expo-audio",permissions:[{get:"getRecordingPermissionsAsync",request:"requestRecordingPermissionsAsync",permission:"microphone",flavor:"plain"}]},{module:"ExponentPedometer",library:"expo-sensors",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"motion",flavor:"plain"}]}];function expoModules(){const s=globalThis.expo?.modules;return s&&typeof s==="object"?s:null}function names(s){try{return new Set(Object.keys(s))}catch{return new Set}}const refused=s=>s==="denied"||s==="blocked"||s==="restricted"||s==="undetermined";function expoMessage(s,o,e,r){return r==="ios"?`Calling the '${o}' function has failed
2
+ \u2192 Caused by: ${e}`:`Call to function '${s}.${o}' has been rejected.
3
+ \u2192 Caused by: ${e}`}function getterArgs(s,o=[]){if(s.flavor!=="privileges")return[];return o.length>0?o.slice(0,1):[false]}function wrapPermission(s,o,e){const r=o.library;(0,_wrap.wrapMethod)(s,e.get,n=>async(...a)=>{const i=(0,_store.getPlatform)();let t;let c;try{t=await n(...a)}catch(d){c=d}const l=(0,_model.fromExpo)(t,i);(0,_store.noteReal)(e.permission,l,r);const u=(0,_store.getOverride)(e.permission);if(u===null){(0,_store.recordCall)({source:r,method:e.get,permission:e.permission,kind:"check",real:l,returned:l,overridden:false,error:c?String(c?.message??c):void 0});if(c)throw c;return t}const m=(0,_model.toExpo)(u,i,e.flavor,t);(0,_store.recordCall)({source:r,method:e.get,permission:e.permission,kind:"check",real:l,returned:u,overridden:true});return m});(0,_wrap.wrapMethod)(s,e.request,n=>async(...a)=>{const i=(0,_store.getPlatform)();if((0,_store.getOverride)(e.permission)===null){try{const d=await n(...a);const p=(0,_model.fromExpo)(d,i);(0,_store.noteReal)(e.permission,p,r);(0,_store.recordCall)({source:r,method:e.request,permission:e.permission,kind:"request",real:p,returned:p,overridden:false});return d}catch(d){(0,_store.recordCall)({source:r,method:e.request,permission:e.permission,kind:"request",real:null,returned:null,overridden:false,error:String(d?.message??d)});throw d}}let t;const c=s[e.get];try{const d=c.__buoyPermissionsOriginal;t=d?await d.apply(s,getterArgs(e,a)):void 0}catch{t=void 0}const l=(0,_model.fromExpo)(t,i);(0,_store.noteReal)(e.permission,l,r);const{state:u,answer:m}=await(0,_store.resolveRequest)(e.permission);(0,_store.recordCall)({source:r,method:e.request,permission:e.permission,kind:"request",real:l,returned:u,overridden:true,answer:m});return(0,_model.toExpo)(u,i,e.flavor,t)})}const POSITION_METHODS=new Set(["getCurrentPositionAsync","getLastKnownPositionAsync"]);function coarsenPosition(s){const o=s;if(!o?.coords||typeof o.coords.latitude!=="number"||typeof o.coords.longitude!=="number")return s;const e=r=>Math.round(r/.02)*.02;return{...o,coords:{...o.coords,latitude:Number(e(o.coords.latitude).toFixed(4)),longitude:Number(e(o.coords.longitude).toFixed(4)),accuracy:Math.max(o.coords.accuracy??0,3e3),altitude:null,altitudeAccuracy:null,heading:null,speed:null}}}function wrapGated(s,o,e){(0,_wrap.wrapMethod)(s,e.method,r=>(...n)=>{const a=(0,_store.getPlatform)();const i=a==="ios"?e.ios:e.android;const t=(0,_store.getOverride)(e.permission);const c=(0,_store.getSettings)().enforce;if(i&&c&&t!==null&&refused(t)){const l=expoMessage(o.module,e.method,i.reason,a);(0,_store.recordCall)({source:o.library,method:e.method,permission:e.permission,kind:"gated",real:null,returned:t,overridden:true,error:i.code});return Promise.reject((0,_wrap.codedError)(i.code,l))}if(c&&t==="limited"&&POSITION_METHODS.has(e.method)){return Promise.resolve(r(...n)).then(l=>coarsenPosition(l))}return r(...n)})}function registerRealRequest(s,o,e){(0,_store.registerRealRequester)(e.permission,async()=>{const r=s[e.request];const n=r?.__buoyPermissionsOriginal??r;if(typeof n!=="function")return null;const a=await n.apply(s,e.defaultArgs?.((0,_store.getPlatform)())??[]);const i=(0,_model.fromExpo)(a,(0,_store.getPlatform)());(0,_store.recordCall)({source:o.library,method:`${e.request} (system)`,permission:e.permission,kind:"request",real:i,returned:i,overridden:false});return i})}function installExpoAdapter(){const s=expoModules();if(!s)return[];const o=names(s);const e=[];for(const r of EXPO_MODULES){if(!o.has(r.module))continue;let n;try{n=s[r.module]}catch{n=void 0}if(!n||typeof n!=="object")continue;const a=[];for(const i of r.permissions){if(typeof n[i.get]!=="function")continue;wrapPermission(n,r,i);registerRealRequest(n,r,i);a.push(i.permission)}for(const i of r.gated??[])wrapGated(n,r,i);if(a.length>0){(0,_store.registerLibrary)(r.library,a);e.push(r.library)}}return e}async function refreshExpoRealStates(){const s=expoModules();if(!s)return;const o=names(s);const e=(0,_store.getPlatform)();const r=[];for(const n of EXPO_MODULES){if(!o.has(n.module))continue;const a=s[n.module];if(!a)continue;const i=new Set;for(const t of n.permissions){if(i.has(t.permission))continue;const c=a[t.get];const l=c?.__buoyPermissionsOriginal??c;if(typeof l!=="function")continue;i.add(t.permission);r.push(Promise.resolve().then(()=>l.apply(a,getterArgs(t))).then(u=>(0,_store.noteReal)(t.permission,(0,_model.fromExpo)(u,e),n.library)).catch(()=>{}))}}await Promise.all(r)}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.installRnPermissionsAdapter=installRnPermissionsAdapter;exports.rnpPermissionId=rnpPermissionId;var _model=require("../model");var _store=require("../store");var _android=require("./android");var _wrap=require("./wrap");const SOURCE="react-native-permissions";const IOS_TO_ID={APP_TRACKING_TRANSPARENCY:"tracking",BLUETOOTH:"bluetooth",CALENDARS:"calendar",CALENDARS_WRITE_ONLY:"calendar",CAMERA:"camera",CONTACTS:"contacts",LOCATION_ALWAYS:"locationBackground",LOCATION_WHEN_IN_USE:"location",MICROPHONE:"microphone",MOTION:"motion",PHOTO_LIBRARY:"photos",PHOTO_LIBRARY_ADD_ONLY:"photos",REMINDERS:"reminders"};function rnpPermissionId(l){if(l.startsWith("ios.permission.")){return IOS_TO_ID[l.slice("ios.permission.".length)]??null}if(l.startsWith("android.permission."))return(0,_android.androidPermissionId)(l);return null}function notificationSettings(l){const s=l==="granted";const f=l==="limited";return{alert:s,badge:s,sound:s,lockScreen:s,notificationCenter:s||f,carPlay:false,criticalAlert:false,provisional:f,providesAppSettings:false}}function installRnPermissionsAdapter(l){if(!l)return false;const s=(0,_store.getPlatform)();const f=async(i,r,c,o)=>{const e=rnpPermissionId(c);const a=await i(...o);if(!e)return a;const u=(0,_model.fromRnp)(a,s);(0,_store.noteReal)(e,u,SOURCE);const n=(0,_store.getOverride)(e);(0,_store.recordCall)({source:SOURCE,method:r,permission:e,kind:"check",real:u,returned:n??u,overridden:n!==null});return n===null?a:(0,_model.toRnp)(n,s)};const R=async(i,r,c,o)=>{const e=rnpPermissionId(c);if(!e||(0,_store.getOverride)(e)===null){const n=await i(...o);if(e){const t=(0,_model.fromRnp)(n,s);(0,_store.noteReal)(e,t,SOURCE);(0,_store.recordCall)({source:SOURCE,method:r,permission:e,kind:"request",real:t,returned:t,overridden:false})}return n}const{state:a,answer:u}=await(0,_store.resolveRequest)(e);(0,_store.recordCall)({source:SOURCE,method:r,permission:e,kind:"request",real:null,returned:a,overridden:true,answer:u});return(0,_model.toRnp)(a,s)};(0,_wrap.wrapMethod)(l,"check",i=>(...r)=>f(i,"check",String(r[0]),r));(0,_wrap.wrapMethod)(l,"request",i=>(...r)=>R(i,"request",String(r[0]),r));(0,_wrap.wrapMethod)(l,"checkMultiple",i=>async(...r)=>{const c=Array.isArray(r[0])?r[0].map(String):[];const o=await i(...r)??{};const e={...o};for(const a of c){const u=rnpPermissionId(a);if(!u)continue;const n=(0,_model.fromRnp)(o[a],s);(0,_store.noteReal)(u,n,SOURCE);const t=(0,_store.getOverride)(u);(0,_store.recordCall)({source:SOURCE,method:"checkMultiple",permission:u,kind:"check",real:n,returned:t??n,overridden:t!==null});if(t!==null)e[a]=(0,_model.toRnp)(t,s)}return e});(0,_wrap.wrapMethod)(l,"requestMultiple",i=>async(...r)=>{const c=Array.isArray(r[0])?r[0].map(String):[];const o=n=>{const t=rnpPermissionId(n);return t!==null&&(0,_store.getOverride)(t)!==null};const e=c.filter(n=>!o(n));const a={};if(e.length>0){const n=await i(e,...r.slice(1))??{};for(const t of e){a[t]=n[t];const d=rnpPermissionId(t);if(!d)continue;const p=(0,_model.fromRnp)(n[t],s);(0,_store.noteReal)(d,p,SOURCE);(0,_store.recordCall)({source:SOURCE,method:"requestMultiple",permission:d,kind:"request",real:p,returned:p,overridden:false})}}const u=new Map;for(const n of c.filter(o)){const t=rnpPermissionId(n);if(!u.has(t)){const{state:d,answer:p}=await(0,_store.resolveRequest)(t);u.set(t,d);(0,_store.recordCall)({source:SOURCE,method:"requestMultiple",permission:t,kind:"request",real:null,returned:d,overridden:true,answer:p})}a[n]=(0,_model.toRnp)(u.get(t),s)}return a});(0,_wrap.wrapMethod)(l,"checkNotifications",i=>async(...r)=>{const c=await i(...r);const o=(0,_model.fromRnp)(c?.status,s);(0,_store.noteReal)("notifications",o,SOURCE);const e=(0,_store.getOverride)("notifications");(0,_store.recordCall)({source:SOURCE,method:"checkNotifications",permission:"notifications",kind:"check",real:o,returned:e??o,overridden:e!==null});if(e===null)return c;return{status:(0,_model.toRnp)(e,s),settings:{...c?.settings??{},...notificationSettings(e)}}});(0,_wrap.wrapMethod)(l,"requestNotifications",i=>async(...r)=>{if((0,_store.getOverride)("notifications")===null){const e=await i(...r);const a=(0,_model.fromRnp)(e?.status,s);(0,_store.noteReal)("notifications",a,SOURCE);(0,_store.recordCall)({source:SOURCE,method:"requestNotifications",permission:"notifications",kind:"request",real:a,returned:a,overridden:false});return e}const{state:c,answer:o}=await(0,_store.resolveRequest)("notifications");(0,_store.recordCall)({source:SOURCE,method:"requestNotifications",permission:"notifications",kind:"request",real:null,returned:c,overridden:true,answer:o});return{status:(0,_model.toRnp)(c,s),settings:notificationSettings(c)}});const m=i=>r=>async(...c)=>{const o=(0,_store.getOverride)("location");if(o===null)return r(...c);(0,_store.recordCall)({source:SOURCE,method:i,permission:"location",kind:i.startsWith("request")?"request":"check",real:null,returned:o,overridden:true});return o==="limited"?"reduced":"full"};(0,_wrap.wrapMethod)(l,"checkLocationAccuracy",m("checkLocationAccuracy"));(0,_wrap.wrapMethod)(l,"requestLocationAccuracy",m("requestLocationAccuracy"));(0,_store.registerLibrary)(SOURCE,[]);return true}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.codedError=codedError;exports.originalOf=originalOf;exports.wrapMethod=wrapMethod;const ORIGINAL="__buoyPermissionsOriginal";function originalOf(r,o){const n=r[o];if(typeof n!=="function")return null;return n[ORIGINAL]??n}function wrapMethod(r,o,n){const e=originalOf(r,o);if(!e)return false;const c=(...i)=>e.apply(r,i);const t=n(c);t[ORIGINAL]=e;try{r[o]=t}catch{return false}return r[o]===t}function codedError(r,o){const n=new Error(o);n.code=r;return n}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.configureAppSettings=configureAppSettings;exports.installRnpSettingsIntercept=installRnpSettingsIntercept;exports.installSettingsIntercept=installSettingsIntercept;exports.notifyAppOfChange=notifyAppOfChange;exports.openSettingsStandIn=openSettingsStandIn;exports.settingsTarget=settingsTarget;exports.simulateLeaveApp=simulateLeaveApp;exports.simulateReturnToApp=simulateReturnToApp;var _sharedUi=require("@buoy-gg/shared-ui");var _model=require("./model");var _store=require("./store");var _wrap=require("./adapters/wrap");let emitter=null;let alert=null;function configureAppSettings(e){emitter=e.emitter;alert=e.alert}function emitAppState(e){try{emitter?.emit("appStateDidChange",{app_state:e,[_sharedUi.BUOY_SYNTHETIC_MARK]:true})}catch{}}function simulateLeaveApp(){if((0,_store.getPlatform)()==="ios")emitAppState("inactive");emitAppState("background")}function simulateReturnToApp(){emitAppState("active")}let notifyTimer=null;let standInOpen=false;function notifyAppOfChange(){if(!emitter||standInOpen)return;if(notifyTimer)clearTimeout(notifyTimer);notifyTimer=setTimeout(()=>{notifyTimer=null;simulateLeaveApp();setTimeout(simulateReturnToApp,60)},120)}function settingsTarget(){const{log:e,permissions:r}=(0,_store.getPermissionsSnapshot)();const n=t=>t==="denied"||t==="blocked"||t==="restricted";const i=e.filter(t=>t.permission&&t.overridden&&(0,_store.getOverride)(t.permission)!==null);const s=i.find(t=>n((0,_store.getOverride)(t.permission)));if(s)return s.permission;const a=r.find(t=>t.override!==null&&n(t.override));if(a)return a.id;if(i[0])return i[0].permission;const u=r.find(t=>t.override!==null);return u?.id??null}function settingsChoices(e){const r=(0,_store.getPlatform)();return(0,_model.supportedStates)(e,r).filter(n=>(n!=="undetermined"||r==="ios"&&e==="location")&&n!=="restricted"&&!(r==="android"&&n==="blocked"))}function openSettingsStandIn(e,r){const n=(0,_store.getPlatform)();const i=(0,_model.permissionInfo)(e);const s=(0,_store.getOverride)(e);(0,_store.recordCall)({source:r,method:"openSettings",permission:e,kind:"settings",real:null,returned:s,overridden:true});simulateLeaveApp();standInOpen=true;return new Promise(a=>{let u=false;const t=()=>{if(u)return;u=true;standInOpen=false;simulateReturnToApp();a()};if(!alert){t();return}const p=settingsChoices(e);const l=n==="android"?p.filter(o=>o!==s).slice(0,2):p;const c=l.map(o=>({text:`${o===s?"\u2713 ":""}${(0,_model.settingsLabel)(e,n,o)}`,onPress:()=>{try{(0,_store.setOverride)(e,o)}catch{}t()}}));c.push({text:"Back to App",onPress:t,style:"cancel"});alert.alert(i.label,"Buoy's stand-in for Settings. Pick what the app gets when it comes back.",c,{cancelable:true,onDismiss:t})})}function shouldIntercept(){return(0,_store.getSettings)().interceptSettings&&(0,_store.anyOverride)()&&settingsTarget()!==null}function isAppSettingsUrl(e){return typeof e==="string"&&/^app-settings:/i.test(e)}function installSettingsIntercept(e){if(!e)return;(0,_wrap.wrapMethod)(e,"openSettings",r=>(...n)=>{if(!shouldIntercept())return r(...n);return openSettingsStandIn(settingsTarget(),"Linking")});(0,_wrap.wrapMethod)(e,"openURL",r=>(...n)=>{if(!isAppSettingsUrl(n[0])||!shouldIntercept())return r(...n);return openSettingsStandIn(settingsTarget(),"Linking")})}function installRnpSettingsIntercept(e){if(!e)return;(0,_wrap.wrapMethod)(e,"openSettings",r=>(...n)=>{const i=n[0];if(i!==void 0&&i!=="application"&&i!=="notifications"||!shouldIntercept()){return r(...n)}const s=i==="notifications"&&(0,_store.getOverride)("notifications")!==null?"notifications":settingsTarget();return openSettingsStandIn(s,"react-native-permissions")})}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.installPermissions=installPermissions;var _reactNative=_interopRequireWildcard(require("react-native"));var ReactNative=_reactNative;var _android=require("./adapters/android");var _expo=require("./adapters/expo");var _rnPermissions=require("./adapters/rnPermissions");var _appSettings=require("./appSettings");var _prompt=require("./prompt");var _store=require("./store");function _interopRequireWildcard(r,t){if("function"==typeof WeakMap)var n=new WeakMap,a=new WeakMap;return(_interopRequireWildcard=function(e,i){if(!i&&e&&e.__esModule)return e;var o,p,l={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return l;if(o=i?a:n){if(o.has(e))return o.get(e);o.set(e,l)}for(const s in e)"default"!==s&&{}.hasOwnProperty.call(e,s)&&((p=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,s))&&(p.get||p.set)?o(l,s,p):l[s]=e[s]);return l})(r,t)}const INSTALLED="__buoyPermissionsInstalled";function readHost(){const r=globalThis.expo?.modules;const t=i=>{try{return r?.[i]}catch{return void 0}};const n=t("ExpoDevice");const a=t("ExpoApplication");const e=i=>typeof i==="string"&&i?i:null;return{isSimulator:typeof n?.isDevice==="boolean"?!n.isDevice:null,deviceName:e(n?.deviceName),bundleId:e(a?.applicationId)}}function rnPermissionsModule(){try{const r=_reactNative.TurboModuleRegistry?.get;const t=typeof r==="function"?r("RNPermissions"):null;return t&&typeof t==="object"?t:null}catch{return null}}function installPermissions(){const r=globalThis;if(r[INSTALLED])return false;r[INSTALLED]=true;const t=_reactNative.Platform.OS==="android"?"android":"ios";(0,_store.configurePermissions)({platform:t,host:readHost()});(0,_store.bootPermissions)();(0,_appSettings.configureAppSettings)({emitter:_reactNative.DeviceEventEmitter??null,alert:_reactNative.Alert??null});(0,_store.setPrompter)((0,_prompt.createAlertPrompter)(_reactNative.Alert));(0,_expo.installExpoAdapter)();if(t==="android"){(0,_android.installAndroidAdapter)(ReactNative.PermissionsAndroid)}const n=rnPermissionsModule();if(n){(0,_rnPermissions.installRnPermissionsAdapter)(n);(0,_appSettings.installRnpSettingsIntercept)(n)}(0,_appSettings.installSettingsIntercept)(_reactNative.Linking);(0,_store.onPermissionChange)(({from:a})=>{if(a==="tool"&&(0,_store.getSettings)().notifyApp)(0,_appSettings.notifyAppOfChange)()});setTimeout(()=>{void(0,_expo.refreshExpoRealStates)()},1500);return true}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.installPermissions=installPermissions;function installPermissions(){return false}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.REQUEST_ANSWERS=exports.PERMISSION_STATES=exports.KNOWN_PERMISSION_IDS=void 0;exports.canPrompt=canPrompt;exports.fromExpo=fromExpo;exports.fromRnp=fromRnp;exports.isPermissionId=isPermissionId;exports.isSupported=isSupported;exports.normalizeState=normalizeState;exports.permissionInfo=permissionInfo;exports.promptChoices=promptChoices;exports.settingsLabel=settingsLabel;exports.stateAfterRequest=stateAfterRequest;exports.stateDescription=stateDescription;exports.stateLabel=stateLabel;exports.supportedStates=supportedStates;exports.toAndroidCheck=toAndroidCheck;exports.toAndroidRequestResult=toAndroidRequestResult;exports.toExpo=toExpo;exports.toRnp=toRnp;const PERMISSION_STATES=exports.PERMISSION_STATES=["undetermined","granted","limited","denied","blocked","restricted"];const REQUEST_ANSWERS=exports.REQUEST_ANSWERS=["ask","allow","limited","deny"];const CATALOG={location:{id:"location",label:"Location",limited:{ios:"Approximate",android:"Approximate"},purpose:"use your location"},locationBackground:{id:"locationBackground",label:"Background Location",purpose:"use your location in the background"},camera:{id:"camera",label:"Camera",purpose:"access your camera"},microphone:{id:"microphone",label:"Microphone",purpose:"access your microphone"},notifications:{id:"notifications",label:"Notifications",limited:{ios:"Provisional"},purpose:"send you notifications"},photos:{id:"photos",label:"Photos",limited:{ios:"Selected Photos",android:"Selected Photos"},purpose:"access your photos"},contacts:{id:"contacts",label:"Contacts",limited:{ios:"Selected Contacts"},purpose:"access your contacts"},calendar:{id:"calendar",label:"Calendar",purpose:"access your calendar"},reminders:{id:"reminders",label:"Reminders",only:"ios",purpose:"access your reminders"},tracking:{id:"tracking",label:"Tracking",only:"ios",purpose:"track your activity across other companies' apps and websites"},motion:{id:"motion",label:"Motion & Fitness",purpose:"access your motion and fitness activity"},bluetooth:{id:"bluetooth",label:"Bluetooth",purpose:"use Bluetooth"}};const KNOWN_PERMISSION_IDS=exports.KNOWN_PERMISSION_IDS=Object.keys(CATALOG);function isPermissionId(e){return typeof e==="string"&&(e in CATALOG||e.startsWith("android:")&&e.length>8)}function permissionInfo(e){const i=CATALOG[e];if(i)return i;const n=e.slice("android:".length).replace(/^android\.permission\./,"");return{id:e,label:n.toLowerCase().split("_").map(o=>o.charAt(0).toUpperCase()+o.slice(1)).join(" "),only:"android",purpose:`use ${n.toLowerCase().replace(/_/g," ")}`}}function supportedStates(e,i){const n=permissionInfo(e);const o=["undetermined","granted"];if(n.limited?.[i])o.push("limited");o.push("denied");if(i==="android")o.push("blocked");if(i==="ios"&&e!=="notifications")o.push("restricted");return o}function isSupported(e,i,n){return supportedStates(e,i).includes(n)}function normalizeState(e,i,n){if(isSupported(e,i,n))return n;if(n==="blocked")return"denied";if(n==="restricted")return i==="android"?"blocked":"denied";if(n==="limited")return"granted";return n}function canPrompt(e,i){if(i==="undetermined")return true;return e==="android"&&i==="denied"}function stateAfterRequest(e,i,n,o){if(!canPrompt(i,n))return n;if(o==="allow"||o==="once")return"granted";if(o==="limited")return isSupported(e,i,"limited")?"limited":"granted";if(i==="android")return n==="denied"?"blocked":"denied";return"denied"}function offersOnce(e,i){if(i==="ios")return e==="location";return e==="camera"||e==="microphone"}function promptChoices(e,i){const n=permissionInfo(e);const o=n.limited?.[i];const t=i==="ios";const r=[];if(t&&offersOnce(e,i))r.push({answer:"once",label:"Allow Once"});if(e==="location"||e==="locationBackground"){r.push({answer:"allow",label:t?"Allow While Using App":"While using the app"})}else{r.push({answer:"allow",label:"Allow"})}if(!t&&offersOnce(e,i))r.push({answer:"once",label:"Only this time"});if(o){const d=e==="location"?t?"Allow With Approximate Location":"Approximate location":e==="photos"?t?"Limit Access\u2026":"Select photos":e==="contacts"?"Select Contacts\u2026":`Allow ${o}`;r.push({answer:"limited",label:d})}r.push({answer:"deny",label:t?"Don\u2019t Allow":"Don\u2019t allow"});return r}function settingsLabel(e,i,n){if(i==="ios"){if(e==="location"||e==="locationBackground"){if(n==="undetermined")return"Ask Next Time";if(n==="granted")return e==="locationBackground"?"Always":"While Using the App";if(n==="limited")return"While Using the App, Approximate";if(n==="denied")return"Never"}if(e==="photos"||e==="contacts"){if(n==="granted")return"Full Access";if(n==="limited")return"Limited Access";if(n==="denied")return"None"}if(e==="notifications"){if(n==="granted")return"Allow Notifications";if(n==="limited")return"Deliver Quietly";if(n==="denied")return"Off"}if(n==="granted")return"Allow";if(n==="denied")return"Don\u2019t Allow"}else{if(e==="location"&&n==="granted")return"Allow only while using the app";if(e==="location"&&n==="limited")return"While using the app, approximate";if(e==="photos"&&n==="granted")return"Allow all";if(e==="photos"&&n==="limited")return"Allow limited access";if(n==="granted")return"Allow";if(n==="denied")return"Don\u2019t allow"}return stateLabel(e,i,n)}function stateDescription(e,i,n){switch(n){case"undetermined":return"Never asked. The next request shows a prompt.";case"granted":return"Full access.";case"limited":if(e==="location")return"Allowed, with an approximate position.";if(e==="photos")return"Allowed for the photos the person picked.";if(e==="contacts")return"Allowed for the contacts the person picked.";if(e==="notifications")return"Delivered quietly to Notification Center, without asking.";return"Partial access.";case"denied":return i==="ios"?"The person said no. The app can't ask again, only send them to Settings.":"The person said no once. The app can ask one more time.";case"blocked":return"The person said no for good. Only Settings can change it.";case"restricted":return"Turned off by Screen Time or device management. The person can't change it."}}function fromExpo(e,i){if(!e||typeof e!=="object")return null;const n=e;const o=typeof n.ios?.status==="number"?n.ios.status:void 0;if(o===3||o===4)return"limited";if(n.status==="granted"){if(n.accessPrivileges==="limited")return"limited";if(n.ios?.accuracy==="reduced")return"limited";if(n.android?.accuracy==="coarse")return"limited";return"granted"}if(n.status==="denied"){if(i==="android"&&n.canAskAgain===false)return"blocked";return"denied"}if(n.status==="undetermined")return"undetermined";return null}function fromRnp(e,i){switch(e){case"granted":return"granted";case"limited":return"limited";case"blocked":return i==="ios"?"denied":"blocked";case"denied":return i==="ios"?"undetermined":"denied";default:return null}}const NOTIFICATION_SETTING_KEYS=["allowsAlert","allowsBadge","allowsSound","allowsDisplayInNotificationCenter","allowsDisplayOnLockScreen","allowsDisplayInCarPlay","allowsCriticalAlerts","allowsAnnouncements"];function toExpo(e,i,n,o){const t=o&&typeof o==="object"?o:{};const r=e==="granted"||e==="limited";const d=r?"granted":e==="undetermined"?"undetermined":"denied";const u=e==="undetermined"||i==="android"&&e==="denied";const s={...t,status:d,granted:r,canAskAgain:u,expires:"never"};if(n==="privileges"){s.accessPrivileges=e==="granted"?"all":e==="limited"?"limited":"none"}if(n==="location"||n==="locationBackground"){const l=n==="locationBackground";if(i==="ios"){const c=r?l?"always":"whenInUse":"none";s.ios={...t.ios??{},scope:c,accuracy:e==="limited"?"reduced":"full"};if("scope"in t)s.scope=c}else{const c=e==="granted"?"fine":e==="limited"?"coarse":"none";s.android={...t.android??{},accuracy:c};if("scope"in t)s.scope=c}}if(n==="notifications"){if(i==="ios"){const l=e==="granted"?2:e==="limited"?3:e==="undetermined"?0:1;if(e==="limited"){s.status="undetermined";s.granted=false;s.canAskAgain=true}const c={...t.ios??{},status:l};for(const a of NOTIFICATION_SETTING_KEYS){c[a]=e==="undetermined"?null:e==="granted"?true:e==="limited"?a==="allowsDisplayInNotificationCenter":false}c.alertStyle=e==="granted"?1:0;s.ios=c}else{s.android={...t.android??{},importance:r?3:0}}}return s}function toRnp(e,i){switch(e){case"granted":return"granted";case"limited":return"limited";case"undetermined":return"denied";case"denied":return i==="ios"?"blocked":"denied";case"blocked":case"restricted":return"blocked"}}function toAndroidRequestResult(e){if(e==="granted"||e==="limited")return"granted";if(e==="blocked"||e==="restricted")return"never_ask_again";return"denied"}function toAndroidCheck(e,i){if(e==="granted")return true;if(e!=="limited")return false;return/ACCESS_COARSE_LOCATION|READ_MEDIA_VISUAL_USER_SELECTED/.test(i)}function stateLabel(e,i,n){switch(n){case"undetermined":return"Not Asked";case"granted":return"Allowed";case"limited":return permissionInfo(e).limited?.[i]??"Limited";case"denied":return"Denied";case"blocked":return"Blocked";case"restricted":return"Restricted"}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PERMISSIONS_STORAGE_KEY=exports.DEFAULT_SETTINGS=void 0;exports.parseSaved=parseSaved;exports.parseSettings=parseSettings;exports.readSavedAsync=readSavedAsync;Object.defineProperty(exports,"readSavedSync",{enumerable:true,get:function(){return _readSavedSync.readSavedSync}});exports.writeSaved=writeSaved;var _sharedUi=require("@buoy-gg/shared-ui");var _model=require("./model");var _readSavedSync=require("./readSavedSync");const DEFAULT_SETTINGS=exports.DEFAULT_SETTINGS={requestAnswer:"ask",persist:true,showChip:true,notifyApp:true,enforce:true,interceptSettings:true};const PERMISSIONS_STORAGE_KEY=exports.PERMISSIONS_STORAGE_KEY=_sharedUi.devToolsStorageKeys.permissions.state();function bool(t,e){return typeof t==="boolean"?t:e}function parseSettings(t){const e=t&&typeof t==="object"?t:{};return{requestAnswer:_model.REQUEST_ANSWERS.includes(e.requestAnswer)?e.requestAnswer:DEFAULT_SETTINGS.requestAnswer,persist:bool(e.persist,DEFAULT_SETTINGS.persist),showChip:bool(e.showChip,DEFAULT_SETTINGS.showChip),notifyApp:bool(e.notifyApp,DEFAULT_SETTINGS.notifyApp),enforce:bool(e.enforce,DEFAULT_SETTINGS.enforce),interceptSettings:bool(e.interceptSettings,DEFAULT_SETTINGS.interceptSettings)}}function parseSaved(t){if(!t)return null;try{const e=JSON.parse(t);if(!e||e.v!==1)return null;const r={};for(const[s,n]of Object.entries(e.overrides??{})){if((0,_model.isPermissionId)(s)&&_model.PERMISSION_STATES.includes(n)){r[s]=n}}return{v:1,overrides:r,settings:parseSettings(e.settings)}}catch{return null}}async function readSavedAsync(){try{return parseSaved(await _sharedUi.persistentStorage.getItem(PERMISSIONS_STORAGE_KEY))}catch{return null}}let writes=Promise.resolve();function writeSaved(t){const e=JSON.stringify(t);writes=writes.then(()=>_sharedUi.persistentStorage.setItem(PERMISSIONS_STORAGE_KEY,e)).catch(()=>{});return writes.then(()=>{})}
@@ -0,0 +1,3 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.createAlertPrompter=createAlertPrompter;exports.readPurposeString=readPurposeString;var _model=require("./model");var _store=require("./store");let config;function readConfig(){if(config!==void 0)return config;config=null;try{const o=require("expo-constants");config=(o?.default??o)?.expoConfig??null}catch{}return config}function readAppName(){const o=readConfig()?.name;return typeof o==="string"&&o?o:"This app"}const PURPOSE_SOURCES={location:{plist:["NSLocationWhenInUseUsageDescription"],plugins:[["expo-location","locationWhenInUsePermission"]]},locationBackground:{plist:["NSLocationAlwaysAndWhenInUseUsageDescription"],plugins:[["expo-location","locationAlwaysAndWhenInUsePermission"]]},camera:{plist:["NSCameraUsageDescription"],plugins:[["expo-camera","cameraPermission"],["expo-image-picker","cameraPermission"]]},microphone:{plist:["NSMicrophoneUsageDescription"],plugins:[["expo-audio","microphonePermission"],["expo-camera","microphonePermission"],["expo-image-picker","microphonePermission"]]},photos:{plist:["NSPhotoLibraryUsageDescription"],plugins:[["expo-image-picker","photosPermission"],["expo-media-library","photosPermission"]]},contacts:{plist:["NSContactsUsageDescription"],plugins:[["expo-contacts","contactsPermission"]]},calendar:{plist:["NSCalendarsFullAccessUsageDescription","NSCalendarsUsageDescription"],plugins:[["expo-calendar","calendarPermission"]]},reminders:{plist:["NSRemindersFullAccessUsageDescription","NSRemindersUsageDescription"],plugins:[["expo-calendar","remindersPermission"]]},tracking:{plist:["NSUserTrackingUsageDescription"],plugins:[["expo-tracking-transparency","userTrackingPermission"]]},motion:{plist:["NSMotionUsageDescription"],plugins:[["expo-sensors","motionPermission"]]},bluetooth:{plist:["NSBluetoothAlwaysUsageDescription"],plugins:[]}};function readPurposeString(o){const s=PURPOSE_SOURCES[o];const t=readConfig();if(!s||!t)return null;const c=readAppName();const a=e=>typeof e==="string"&&e.trim()?e.replace(/\$\(PRODUCT_NAME\)/g,c).trim():null;for(const e of s.plist){const i=a(t.ios?.infoPlist?.[e]);if(i)return i}for(const[e,i]of s.plugins){for(const n of t.plugins??[]){if(Array.isArray(n)&&n[0]===e&&n[1]&&typeof n[1]==="object"){const p=a(n[1][i]);if(p)return p}}}return null}const BUOY_NOTE="Test prompt from Buoy. Your phone's settings won't change.";let queue=Promise.resolve();function createAlertPrompter(o){return s=>{const t=()=>new Promise(a=>{const e=(0,_store.getPlatform)();const i=(0,_model.permissionInfo)(s);const n=readAppName();const p=e==="ios"?`Allow \u201C${n}\u201D to ${i.purpose}?`:`Allow ${n} to ${i.purpose}?`;const g=(0,_model.promptChoices)(s,e);let l=false;const u=r=>{if(l)return;l=true;a(r)};const m=e==="ios"?readPurposeString(s):null;o.alert(p,m?`${m}
2
+
3
+ ${BUOY_NOTE}`:BUOY_NOTE,g.map(r=>({text:r.label,style:r.answer==="deny"?"cancel":"default",onPress:()=>u(r.answer)})),{cancelable:e==="android",onDismiss:()=>u("deny")})});const c=queue.then(t,t);queue=c.catch(()=>{});return c}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.readSavedSync=readSavedSync;var _persistence=require("./persistence");function fsNames(e){const n=encodeURIComponent(e.replace(/~/g,"~0").replace(/\//g,"~1"));return n===e?[e]:[n,e]}function readSavedSync(){try{const e=require("expo-file-system");if(typeof e?.File!=="function"||!e.Paths?.document)return void 0;const n=new e.File(e.Paths.document,"react-buoy");if(typeof n.textSync!=="function")return void 0;for(const r of fsNames(_persistence.PERMISSIONS_STORAGE_KEY)){const t=new e.File(e.Paths.document,"react-buoy",`${r}.json`);if(t.exists)return(0,_persistence.parseSaved)(t.textSync())}return null}catch{return void 0}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.readSavedSync=readSavedSync;function readSavedSync(){return void 0}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.__resetPermissionsForTests=__resetPermissionsForTests;exports.anyOverride=anyOverride;exports.bootPermissions=bootPermissions;exports.canRequestReal=canRequestReal;exports.clearOverride=clearOverride;exports.clearPermissionLog=clearPermissionLog;exports.configurePermissions=configurePermissions;exports.getOverride=getOverride;exports.getOverrides=getOverrides;exports.getPermissionsSnapshot=getPermissionsSnapshot;exports.getPlatform=getPlatform;exports.getSettings=getSettings;exports.isOverridden=isOverridden;exports.noteReal=noteReal;exports.onPermissionChange=onPermissionChange;exports.recordCall=recordCall;exports.registerLibrary=registerLibrary;exports.registerRealRequester=registerRealRequester;exports.requestRealPermission=requestRealPermission;exports.resetPermissions=resetPermissions;exports.resolveRequest=resolveRequest;exports.restoreOverrides=restoreOverrides;exports.setOverride=setOverride;exports.setPrompter=setPrompter;exports.subscribePermissions=subscribePermissions;exports.updatePermissionSettings=updatePermissionSettings;var _model=require("./model");var _persistence=require("./persistence");const LOG_LIMIT=200;const SNAPSHOT_LOG=50;const STORE_KEY="__buoyPermissionsStore";const g=globalThis;const state=g[STORE_KEY]??={platform:"ios",booted:false,overrides:new Map,settings:{..._persistence.DEFAULT_SETTINGS},seen:new Map,libraries:new Set,log:[],nextLogId:1,listeners:new Set,snapshot:null,prompter:null,changeHooks:new Set,realRequesters:new Map,host:{isSimulator:null,deviceName:null,bundleId:null},once:new Set};state.once??=new Set;const now=()=>{const e=globalThis.__buoyRealNow;return typeof e==="function"?e():Date.now()};function emit(){state.snapshot=null;for(const e of Array.from(state.listeners)){try{e()}catch{}}}function save(){if(!state.settings.persist){void(0,_persistence.writeSaved)({v:1,overrides:{},settings:state.settings});return}void(0,_persistence.writeSaved)(toSaved())}function toSaved(){return{v:1,overrides:Object.fromEntries(Array.from(state.overrides,([e,r])=>[e,state.once.has(e)?"undetermined":r])),settings:state.settings}}function seen(e){let r=state.seen.get(e);if(!r){r={sources:new Set,real:null,calls:0,lastCallAt:null,lastReadAt:null,changedAt:null};state.seen.set(e,r)}return r}function applySaved(e){if(!e)return;state.settings=e.settings;state.overrides.clear();if(!e.settings.persist)return;for(const[r,t]of Object.entries(e.overrides)){const s=r;state.overrides.set(s,(0,_model.normalizeState)(s,state.platform,t))}}function configurePermissions(e){state.platform=e.platform;if(e.host)state.host=e.host;emit()}function bootPermissions(){if(state.booted)return;state.booted=true;const e=(0,_persistence.readSavedSync)();if(e!==void 0){applySaved(e);emit();return}void(0,_persistence.readSavedAsync)().then(r=>{if(state.overrides.size>0)return;applySaved(r);emit()})}function registerRealRequester(e,r){if(!state.realRequesters.has(e))state.realRequesters.set(e,r)}function canRequestReal(e){return state.realRequesters.has(e)}async function requestRealPermission(e){const r=assertId(e);const t=state.realRequesters.get(r);if(!t)throw new Error(`No installed library can ask the system for ${(0,_model.permissionInfo)(r).label}.`);const s=await t();if(s!==null)noteReal(r,s);return getPermissionsSnapshot()}function setPrompter(e){state.prompter=e}function onPermissionChange(e){state.changeHooks.add(e);return()=>state.changeHooks.delete(e)}function notifyChange(e,r){for(const t of Array.from(state.changeHooks)){try{t({id:e,from:r})}catch{}}}function registerLibrary(e,r){let t=!state.libraries.has(e);state.libraries.add(e);for(const s of r){const n=seen(s);if(!n.sources.has(e)){n.sources.add(e);t=true}}if(t)emit()}function getPlatform(){return state.platform}function getSettings(){return state.settings}function getOverride(e){return state.overrides.get(e)??null}function isOverridden(e){return state.overrides.has(e)}function anyOverride(){return state.overrides.size>0}function noteReal(e,r,t){if(r===null)return;const s=seen(e);if(t)s.sources.add(t);if(s.real===r)return;s.real=r;emit()}function recordCall(e){const r={...e,id:state.nextLogId++,at:now()};state.log.unshift(r);if(state.log.length>LOG_LIMIT)state.log.length=LOG_LIMIT;if(e.permission){const t=seen(e.permission);if(e.kind==="check"||e.kind==="request")t.sources.add(e.source);t.calls+=1;t.lastCallAt=r.at;if(e.kind==="check"||e.kind==="request")t.lastReadAt=r.at;if(e.real!==null&&e.kind!=="gated")t.real=e.real}emit();return r}async function resolveRequest(e){const r=state.overrides.get(e);if(r===void 0)throw new Error(`${e} is not overridden`);if(!(0,_model.canPrompt)(state.platform,r))return{state:r};let t;const s=state.settings.requestAnswer;if(s==="ask"&&state.prompter)t=await state.prompter(e);else t=s==="ask"?"allow":s;const n=state.overrides.get(e);if(n===void 0)return{state:r,answer:t};const o=(0,_model.stateAfterRequest)(e,state.platform,n,t);if(t==="once"&&o==="granted")state.once.add(e);if(o!==n){state.overrides.set(e,o);save();emit();notifyChange(e,"request")}return{state:o,answer:t}}function assertId(e){if(!(0,_model.isPermissionId)(e)){throw new Error(`Unknown permission "${String(e)}". Use one of: ${_model.KNOWN_PERMISSION_IDS.join(", ")}, or android:<android.permission.NAME>.`)}return e}function setOverride(e,r){const t=assertId(e);if(!_model.PERMISSION_STATES.includes(r)){throw new Error(`Unknown state "${String(r)}". Use one of: ${_model.PERMISSION_STATES.join(", ")}.`)}const s=r;const n=(0,_model.supportedStates)(t,state.platform);const o=state.platform==="ios"&&s==="blocked"?"denied":s;if(!n.includes(o)){throw new Error(`${(0,_model.permissionInfo)(t).label} can't be "${s}" on ${state.platform}. It can be: ${n.join(", ")}.`)}if(state.overrides.get(t)!==o||state.once.has(t)){state.overrides.set(t,o);state.once.delete(t);seen(t).changedAt=now();save();emit();notifyChange(t,"tool")}return getPermissionsSnapshot()}function clearOverride(e){const r=assertId(e);if(state.overrides.delete(r)){state.once.delete(r);seen(r).changedAt=now();save();emit();notifyChange(r,"tool")}return getPermissionsSnapshot()}function resetPermissions(){if(state.overrides.size>0){const e=now();for(const r of state.overrides.keys())seen(r).changedAt=e;state.overrides.clear();state.once.clear();save();emit();notifyChange(null,"tool")}return getPermissionsSnapshot()}function getOverrides(){return Object.fromEntries(state.overrides)}function restoreOverrides(e){const r=now();for(const t of state.overrides.keys())seen(t).changedAt=r;state.overrides.clear();state.once.clear();for(const[t,s]of Object.entries(e)){const n=t;if(!s||!(0,_model.isPermissionId)(n))continue;state.overrides.set(n,(0,_model.normalizeState)(n,state.platform,s));seen(n).changedAt=r}save();emit();notifyChange(null,"tool");return getPermissionsSnapshot()}function updatePermissionSettings(e){const r={};for(const[s,n]of Object.entries(e)){if(n!==void 0)r[s]=n}if(r.requestAnswer!==void 0&&!["ask","allow","limited","deny"].includes(r.requestAnswer)){throw new Error('requestAnswer must be "ask", "allow", "limited" or "deny".')}const t=(0,_persistence.parseSettings)({...state.settings,...r});state.settings=t;save();emit();return getPermissionsSnapshot()}function clearPermissionLog(){state.log=[];for(const e of state.seen.values()){e.calls=0;e.lastCallAt=null}emit();return getPermissionsSnapshot()}function warningFor(e,r){if(!e||!r)return null;const t=s=>s==="granted"||s==="limited";if(t(e)&&!t(r)){return"The phone hasn't allowed this, so calls that need it, like getting a position or a photo, still fail."}return null}function getPermissionsSnapshot(){if(state.snapshot)return state.snapshot;const e=new Set([...state.seen.keys(),...state.overrides.keys()]);const r=s=>{const n=_model.KNOWN_PERMISSION_IDS.indexOf(s);return n===-1?1e3:n};const t=Array.from(e).filter(s=>{const n=(0,_model.permissionInfo)(s).only;return!n||n===state.platform}).sort((s,n)=>r(s)-r(n)||s.localeCompare(n)).map(s=>{const n=state.seen.get(s);const o=state.overrides.get(s)??null;const i=n?.real??null;return{id:s,label:(0,_model.permissionInfo)(s).label,states:(0,_model.supportedStates)(s,state.platform),override:o,real:i,effective:o??i,sources:n?Array.from(n.sources).sort():[],calls:n?.calls??0,lastCallAt:n?.lastCallAt??null,lastReadAt:n?.lastReadAt??null,changedAt:n?.changedAt??null,stale:n?.changedAt!=null&&n.lastReadAt!=null&&n.lastReadAt<n.changedAt,once:state.once.has(s),warning:warningFor(o,i),canRequestReal:state.realRequesters.has(s)}});state.snapshot={platform:state.platform,host:state.host,libraries:Array.from(state.libraries).sort(),permissions:t,overriddenCount:state.overrides.size,settings:state.settings,log:state.log.slice(0,SNAPSHOT_LOG)};return state.snapshot}function subscribePermissions(e){state.listeners.add(e);return()=>state.listeners.delete(e)}function __resetPermissionsForTests(e="ios"){state.platform=e;state.booted=false;state.overrides.clear();state.settings={..._persistence.DEFAULT_SETTINGS};state.seen.clear();state.libraries.clear();state.log=[];state.nextLogId=1;state.prompter=null;state.changeHooks.clear();state.realRequesters.clear();state.once.clear();state.listeners.clear();state.host={isSimulator:null,deviceName:null,bundleId:null};state.snapshot=null}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"KNOWN_PERMISSION_IDS",{enumerable:true,get:function(){return _model.KNOWN_PERMISSION_IDS}});Object.defineProperty(exports,"PERMISSIONS_CHIP_ID",{enumerable:true,get:function(){return _PermissionsChip.PERMISSIONS_CHIP_ID}});Object.defineProperty(exports,"PERMISSIONS_ICON_COLOR",{enumerable:true,get:function(){return _sharedUi.PERMISSIONS_ICON_COLOR}});Object.defineProperty(exports,"PERMISSION_STATES",{enumerable:true,get:function(){return _model.PERMISSION_STATES}});Object.defineProperty(exports,"PermissionsBody",{enumerable:true,get:function(){return _PermissionsBody.PermissionsBody}});Object.defineProperty(exports,"PermissionsChip",{enumerable:true,get:function(){return _PermissionsChip.PermissionsChip}});Object.defineProperty(exports,"PermissionsIcon",{enumerable:true,get:function(){return _sharedUi.PermissionsIcon}});Object.defineProperty(exports,"PermissionsToolView",{enumerable:true,get:function(){return _PermissionsToolView.PermissionsToolView}});Object.defineProperty(exports,"clearPermissionOverride",{enumerable:true,get:function(){return _store.clearOverride}});Object.defineProperty(exports,"createPermissionsTool",{enumerable:true,get:function(){return _preset.createPermissionsTool}});Object.defineProperty(exports,"getPermissionOverride",{enumerable:true,get:function(){return _store.getOverride}});Object.defineProperty(exports,"getPermissionsSnapshot",{enumerable:true,get:function(){return _store.getPermissionsSnapshot}});Object.defineProperty(exports,"installPermissions",{enumerable:true,get:function(){return _install.installPermissions}});Object.defineProperty(exports,"isPermissionOverridden",{enumerable:true,get:function(){return _store.isOverridden}});Object.defineProperty(exports,"openPermissionsChip",{enumerable:true,get:function(){return _PermissionsChip.openPermissionsChip}});Object.defineProperty(exports,"permissionInfo",{enumerable:true,get:function(){return _model.permissionInfo}});Object.defineProperty(exports,"permissionsSyncAdapter",{enumerable:true,get:function(){return _permissionsSyncAdapter.permissionsSyncAdapter}});Object.defineProperty(exports,"permissionsToolPreset",{enumerable:true,get:function(){return _preset.permissionsToolPreset}});Object.defineProperty(exports,"resetPermissions",{enumerable:true,get:function(){return _store.resetPermissions}});Object.defineProperty(exports,"setPermissionOverride",{enumerable:true,get:function(){return _store.setOverride}});Object.defineProperty(exports,"stateLabel",{enumerable:true,get:function(){return _model.stateLabel}});Object.defineProperty(exports,"subscribePermissions",{enumerable:true,get:function(){return _store.subscribePermissions}});Object.defineProperty(exports,"supportedStates",{enumerable:true,get:function(){return _model.supportedStates}});Object.defineProperty(exports,"updatePermissionSettings",{enumerable:true,get:function(){return _store.updatePermissionSettings}});var _install=require("./engine/install");var _PermissionsChip=require("./components/PermissionsChip");var _preset=require("./preset");var _PermissionsBody=require("./components/PermissionsBody");var _PermissionsToolView=require("./components/PermissionsToolView");var _sharedUi=require("@buoy-gg/shared-ui");var _permissionsSyncAdapter=require("./sync/permissionsSyncAdapter");var _store=require("./engine/store");var _model=require("./engine/model");const isReactNativeRuntime=typeof navigator!=="undefined"&&navigator.product==="ReactNative";if(isReactNativeRuntime&&typeof __DEV__!=="undefined"&&__DEV__){(0,_install.installPermissions)();(0,_PermissionsChip.watchPermissionsChip)()}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.permissionsToolPreset=exports.createPermissionsTool=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _PermissionsBody=require("./components/PermissionsBody");var _jsxRuntime=require("react/jsx-runtime");const permissionsToolPreset=exports.permissionsToolPreset=(0,_sharedUi.defineToolPreset)({id:"permissions",name:"PERMISSIONS",description:"Test denied, blocked, limited and not-asked permission states",slot:"both",color:_sharedUi.PERMISSIONS_ICON_COLOR,icon:({size:e,color:s})=>(0,_jsxRuntime.jsx)(_sharedUi.PermissionsIcon,{size:e,color:s}),component:_PermissionsBody.PermissionsBody,modal:{subtitle:"choose what the app is allowed to do"}});const createPermissionsTool=exports.createPermissionsTool=(0,_sharedUi.createToolFactory)(permissionsToolPreset);
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.permissionsSyncAdapter=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _expo=require("../engine/adapters/expo");var _appSettings=require("../engine/appSettings");var _store=require("../engine/store");function obj(e){return e&&typeof e==="object"?e:{}}function permissionParam(e){return e.permission??e.id??e.permissionId??e.name}function boolParam(e,r){const t=e[r];if(typeof t==="boolean")return t;if(t==="true")return true;if(t==="false")return false;return void 0}const permissionsSyncAdapter=exports.permissionsSyncAdapter=(0,_sharedUi.createSyncAdapter)({version:1,getSnapshot(){return(0,_store.getPermissionsSnapshot)()},subscribe(e){return(0,_store.subscribePermissions)(e)},actions:{async getState(){await(0,_expo.refreshExpoRealStates)();return(0,_store.getPermissionsSnapshot)()},setOverride(e){const r=obj(e);const t=permissionParam(r);const s=r.state??r.status??r.value;if(t===void 0||s===void 0){throw new Error('setOverride needs `permission` (e.g. "location", "camera", "notifications") and `state` ("undetermined", "granted", "limited", "denied", "blocked" or "restricted").')}return(0,_store.setOverride)(t,s)},clearOverride(e){const r=permissionParam(obj(e));if(r===void 0)throw new Error("clearOverride needs `permission`.");return(0,_store.clearOverride)(r)},requestReal(e){const r=permissionParam(obj(e));if(r===void 0)throw new Error("requestReal needs `permission`.");return(0,_store.requestRealPermission)(r)},resetAll(){return(0,_store.resetPermissions)()},updateSettings(e){const r=obj(e);return(0,_store.updatePermissionSettings)({requestAnswer:r.requestAnswer??r.answer,persist:boolParam(r,"persist"),showChip:boolParam(r,"showChip"),notifyApp:boolParam(r,"notifyApp"),enforce:boolParam(r,"enforce"),interceptSettings:boolParam(r,"interceptSettings")})},clearLog(){return(0,_store.clearPermissionLog)()},simulateReturnFromSettings(){(0,_appSettings.notifyAppOfChange)();return(0,_store.getPermissionsSnapshot)()}}});
@@ -0,0 +1 @@
1
+ "use strict";import{useEffect as i,useSyncExternalStore as t}from"react";import{reloadApp as e}from"@buoy-gg/shared-ui";import{refreshExpoRealStates as m}from"../engine/adapters/expo";import{installPermissions as p}from"../engine/install";import{getPermissionsSnapshot as r,subscribePermissions as c}from"../engine/store";import{permissionsSyncAdapter as a}from"../sync/permissionsSyncAdapter";import{PermissionsToolView as f}from"./PermissionsToolView";import{jsx as u}from"react/jsx-runtime";const l=a.actions;async function d(o,n){const s=l[o];if(!s)throw new Error(`Unknown permissions action: ${o}`);return s(n)}function h(){void e("auto","buoy permissions").catch(()=>{})}export function PermissionsBody(){i(()=>{p();void m()},[]);const o=t(c,r,r);return u(f,{snapshot:o,onAction:d,onReload:h})}
@@ -0,0 +1 @@
1
+ "use strict";import{useEffect as D,useSyncExternalStore as y}from"react";import{StyleSheet as S,Text as h,TouchableOpacity as f,View as a}from"react-native";import{FloatingTool as x,PermissionsIcon as w,X as R,dismissFloatingTool as U,getFloatingTools as k,night as r,openBuoyTool as z,openFloatingTool as v}from"@buoy-gg/shared-ui";import{stateLabel as F}from"../engine/model";import{anyOverride as W,getOverrides as j,getPermissionsSnapshot as P,getSettings as _,resetPermissions as $,restoreOverrides as A,subscribePermissions as I}from"../engine/store";import{jsx as t,jsxs as g}from"react/jsx-runtime";export const PERMISSIONS_CHIP_ID="permissions-chip";const M=8e3;const C={id:PERMISSIONS_CHIP_ID,render:e=>t(PermissionsChip,{...e})};const E=()=>k().some(e=>e.id===PERMISSIONS_CHIP_ID);export function openPermissionsChip(){v(C)}let n=null;const b=new Set;let d=()=>{};function p(e){if(n)clearTimeout(n.timer);n=e;for(const o of Array.from(b))o();d()}function H(e){b.add(e);return()=>{b.delete(e)}}const T=()=>n;function N(){p({overrides:j(),timer:setTimeout(()=>p(null),M)});$()}function V(){const e=n;if(!e)return;p(null);A(e.overrides)}let O=false;export function watchPermissionsChip(){if(O)return;O=true;let e=false;d=()=>{const o=(W()||n!==null)&&_().showChip;if(o&&!e)v(C);else if(!o&&E())U(PERMISSIONS_CHIP_ID);e=o};I(d);d()}export function PermissionsChip({id:e,revealToken:o}){const l=y(I,P,P);const m=y(H,T,T);D(()=>{if(m&&l.overriddenCount>0)p(null)},[m,l.overriddenCount]);const c=l.permissions.filter(L=>L.override!==null);const s=c.length===1?c[0]:null;const u=s?`${s.label}: ${s.once&&s.override==="granted"?"Allowed Once":F(s.id,l.platform,s.override)}`:`${c.length} permissions simulated`;if(m&&c.length===0){return t(x,{id:e,revealToken:o,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:"Move or hide the permissions strip",handleAdornment:t(w,{size:12}),children:g(a,{style:i.row,children:[t(h,{style:i.title,numberOfLines:1,testID:"permissions-chip-summary",children:"Real permissions"}),t(f,{testID:"permissions-chip-undo",accessibilityRole:"button",accessibilityLabel:"Undo, put the simulated permissions back",onPress:V,style:i.undo,hitSlop:{top:8,bottom:8,left:8,right:8},children:t(h,{style:i.undoText,children:"Undo"})})]})})}return t(x,{id:e,revealToken:o,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:`Move or hide the permissions strip. ${u}`,handleAdornment:t(w,{size:12}),children:g(a,{style:i.row,children:[g(f,{testID:"permissions-chip-open",accessibilityRole:"button",accessibilityLabel:`${u}. Open Permissions`,onPress:()=>{z("permissions")},style:i.open,children:[t(a,{style:i.dot}),t(h,{style:i.title,numberOfLines:1,testID:"permissions-chip-summary",children:u})]}),t(a,{style:i.separator}),t(f,{testID:"permissions-chip-reset",accessibilityRole:"button",accessibilityLabel:"Use real permissions",onPress:N,style:i.button,hitSlop:{top:8,bottom:8,left:4,right:8},children:t(R,{size:16,color:r.color.textSecondary})})]})})}const i=S.create({row:{flexDirection:"row",alignItems:"center",gap:10,paddingLeft:12,paddingRight:4,minHeight:40,minWidth:200},open:{flexDirection:"row",alignItems:"center",gap:8,flexShrink:1},dot:{width:7,height:7,borderRadius:4,backgroundColor:r.color.accent},title:{color:r.color.text,fontSize:14,fontWeight:"600",flexShrink:1},button:{width:32,height:32,alignItems:"center",justifyContent:"center",borderRadius:16},undo:{paddingHorizontal:12,paddingVertical:6},undoText:{color:r.color.accent,fontSize:14,fontWeight:"600"},separator:{width:S.hairlineWidth,height:20,backgroundColor:r.color.separator}});
@@ -0,0 +1 @@
1
+ "use strict";import{useEffect as F,useReducer as _,useState as A}from"react";import{ScrollView as E,StyleSheet as W,Text as a,TouchableOpacity as y,View as p}from"react-native";import{Check as q,ChevronLeft as U,ChevronRight as V,NightCard as b,NightFootnote as S,NightRows as v,NightSectionLabel as H,night as n,useSafeAreaInsets as G,useToolScreenHeader as M}from"@buoy-gg/shared-ui";import{stateDescription as Y,stateLabel as x}from"../engine/model";import{jsx as t,jsxs as s,Fragment as C}from"react/jsx-runtime";const z=1500;const J=()=>{const e=globalThis.__buoyRealNow;return typeof e==="function"?e():Date.now()};function K(e,l){if(!e.effective)return"Not Checked";if(e.once&&e.effective==="granted")return"Allowed Once";return x(e.id,l,e.effective)}export function PermissionsToolView({snapshot:e,onAction:l,onReload:h}){const d=G({minBottom:16});const[f,m]=A(null);const[c,g]=A({name:"list"});const o=(u,P)=>{m(null);l(u,P).catch(I=>{m(I instanceof Error?I.message:String(I))})};const r=c.name==="detail"?e?.permissions.find(u=>u.id===c.id):void 0;const k=()=>g(c.name==="detail"&&c.from==="other"?{name:"other"}:{name:"list"});const w=c.name==="other"?"Other Permissions":r?r.label:null;const j=M(w?{title:w,onBack:k,searchable:false}:null,[w,c.name,c.name==="detail"?c.from:null]);if(!e){return t(p,{style:i.waiting,testID:"permissions-waiting",children:t(S,{centered:true,children:"Waiting for the app\u2026"})})}const{platform:D,permissions:$}=e;const O=$.filter(u=>u.calls>0||u.override!==null);const R=$.filter(u=>!(u.calls>0||u.override!==null));const L=(u,P)=>g({name:"detail",id:u,from:P});let T;if(c.name==="detail"&&r){T=t(Z,{row:r,platform:D,log:e.log,run:o,onPicked:k})}else if(c.name==="other"){T=s(p,{children:[t(B,{rows:R,platform:D,onOpen:u=>L(u,"other")}),t(S,{children:"Your app can ask for these but hasn't yet."})]})}else{T=s(C,{children:[O.length>0?t(B,{rows:O,platform:D,onOpen:u=>L(u,"list"),onReload:h}):t(b,{padded:true,children:t(a,{style:i.empty,testID:"permissions-empty",children:"Your app hasn't checked any permissions yet. Open a screen that uses location, the camera or notifications and it will show up here."})}),R.length>0?t(b,{children:s(y,{testID:"permissions-other",accessibilityRole:"button",accessibilityLabel:`Other Permissions, ${R.length}`,activeOpacity:.6,onPress:()=>g({name:"other"}),style:i.row,children:[t(a,{style:i.rowTitle,children:"Other Permissions"}),s(p,{style:i.rowRight,children:[t(a,{style:i.rowValue,children:R.length}),t(V,{size:16,color:n.color.textTertiary})]})]})}):null,e.overriddenCount>0?t(b,{children:t(y,{testID:"permissions-reset",accessibilityRole:"button",accessibilityLabel:"Use Real Permissions",activeOpacity:.6,onPress:()=>o("resetAll"),style:i.row,children:t(a,{style:i.destructive,children:"Use Real Permissions"})})}):null]})}return s(E,{style:i.fill,contentContainerStyle:[i.content,{paddingBottom:d.bottom}],testID:"permissions-scroll",children:[!j&&c.name!=="list"?s(y,{testID:"permissions-back",accessibilityRole:"button",accessibilityLabel:"Back",onPress:k,style:i.inlineBack,children:[t(U,{size:18,color:n.color.accent}),t(a,{style:i.inlineBackText,children:c.name==="detail"&&c.from==="other"?"Other Permissions":"Permissions"}),w?t(a,{style:i.inlineTitle,children:w}):null]}):null,f?t(S,{tone:"danger",centered:true,children:t(a,{testID:"permissions-error",children:f})}):null,T]})}function B({rows:e,platform:l,onOpen:h,onReload:d}){const[,f]=_(o=>o+1,0);const m=J();const c=e.filter(o=>o.stale&&o.changedAt!==null&&m-o.changedAt<z).map(o=>z-(m-o.changedAt));const g=c.length>0?Math.min(...c):null;F(()=>{if(g===null)return;const o=setTimeout(f,g+50);return()=>clearTimeout(o)},[g]);return t(b,{children:t(v,{children:e.map(o=>{const r=o.stale&&o.changedAt!==null&&m-o.changedAt>=z;return s(p,{children:[t(Q,{row:o,platform:l,onPress:()=>h(o.id)}),r?s(p,{style:i.stale,testID:`permissions-stale-${o.id}`,children:[t(a,{style:i.staleText,children:"The app hasn't checked again since this changed."}),d?t(y,{testID:`permissions-reload-${o.id}`,accessibilityRole:"button",accessibilityLabel:"Reload App",onPress:d,hitSlop:{top:8,bottom:8,left:8,right:8},children:t(a,{style:i.staleAction,children:"Reload App"})}):null]}):null]},o.id)})})})}function Q({row:e,platform:l,onPress:h}){const d=e.override!==null;const f=K(e,l);const m=e.real?x(e.id,l,e.real):"Not Checked";return s(y,{testID:`permissions-row-${e.id}`,accessibilityRole:"button",accessibilityLabel:`${e.label}: ${f}${d?`, simulated. Phone: ${m}`:""}`,activeOpacity:.6,onPress:h,style:i.row,children:[s(p,{style:i.rowLeft,children:[t(a,{style:i.rowTitle,children:e.label}),d?s(a,{style:i.rowSub,testID:`permissions-phone-${e.id}`,children:["Phone: ",m]}):null]}),s(p,{style:i.rowRight,children:[d?t(p,{style:i.dot}):null,t(a,{style:[i.rowValue,d?i.rowValueSimulated:null],testID:`permissions-value-${e.id}`,numberOfLines:1,children:f}),t(V,{size:16,color:n.color.textTertiary})]})]})}function N({title:e,detail:l,selected:h,testID:d,onPress:f}){return s(y,{testID:d,accessibilityRole:"button",accessibilityLabel:`${e}. ${l}`,accessibilityState:{selected:h},activeOpacity:.6,onPress:f,style:i.option,children:[s(p,{style:i.optionText,children:[t(a,{style:i.rowTitle,children:e}),t(a,{style:i.optionDetail,children:l})]}),t(p,{style:i.check,children:h?t(q,{size:18,color:n.color.accent}):null})]})}const X={check:"Checked",request:"Asked",settings:"Opened Settings",gated:"Needed it"};function Z({row:e,platform:l,log:h,run:d,onPicked:f}){const m=e.real?x(e.id,l,e.real):null;const c=r=>{if(r===null)d("clearOverride",{permission:e.id});else d("setOverride",{permission:e.id,state:r});f()};const g=h.filter(r=>r.permission===e.id).slice(0,8);const o=e.canRequestReal&&e.real==="undetermined";return s(C,{children:[s(p,{children:[t(H,{children:"What the app sees"}),t(b,{children:s(v,{children:[t(N,{title:"Phone's Setting",detail:m?`Use what the phone says: ${m}.`:"Use what the phone says.",selected:e.override===null,testID:`permissions-state-${e.id}-real`,onPress:()=>c(null)},"real"),e.states.map(r=>t(N,{title:x(e.id,l,r),detail:Y(e.id,l,r),selected:e.override===r,testID:`permissions-state-${e.id}-${r}`,onPress:()=>c(r)},r))]})})]}),o?s(p,{children:[t(b,{children:t(y,{testID:`permissions-request-real-${e.id}`,accessibilityRole:"button",accessibilityLabel:`Show the real system prompt for ${e.label}`,activeOpacity:.6,onPress:()=>d("requestReal",{permission:e.id}),style:i.row,children:t(a,{style:i.action,children:"Show Real Prompt"})})}),t(S,{children:e.warning??"Asks the phone for real, so calls that need this permission work."})]}):e.warning?t(S,{tone:"warning",children:t(a,{testID:`permissions-warning-${e.id}`,children:e.warning})}):null,g.length>0?s(p,{children:[t(H,{children:"Recent"}),t(b,{children:t(v,{children:g.map(r=>t(te,{entry:r,platform:l},r.id))})}),e.sources.length>0?s(S,{children:["Read through ",e.sources.join(", ")]}):null]}):null]})}function ee(e){const l=new Date(e);const h=d=>String(d).padStart(2,"0");return`${h(l.getHours())}:${h(l.getMinutes())}:${h(l.getSeconds())}`}function te({entry:e,platform:l}){const h=e.error?"Failed":e.returned&&e.permission?e.answer==="once"&&e.returned==="granted"?"Allowed Once":x(e.permission,l,e.returned):"";return s(p,{style:i.recentRow,testID:`permissions-log-${e.id}`,children:[t(a,{style:i.recentTime,children:ee(e.at)}),t(a,{style:i.recentVerb,numberOfLines:1,children:X[e.kind]}),t(a,{style:[i.recentResult,e.error?i.recentFailed:null],numberOfLines:1,children:h})]})}const i=W.create({fill:{flex:1},content:{paddingHorizontal:n.gutter,paddingTop:12,gap:n.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},empty:{color:n.color.textSecondary,fontSize:n.font.body,lineHeight:20},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:n.rowPadH,paddingVertical:10},rowLeft:{flexShrink:1,gap:2},rowTitle:{color:n.color.text,fontSize:n.font.row},rowSub:{color:n.color.textTertiary,fontSize:n.font.caption},rowRight:{flexDirection:"row",alignItems:"center",gap:6,flexShrink:1},rowValue:{color:n.color.textSecondary,fontSize:n.font.row},rowValueSimulated:{color:n.color.accent},dot:{width:7,height:7,borderRadius:4,backgroundColor:n.color.accent},stale:{flexDirection:"row",alignItems:"center",flexWrap:"wrap",columnGap:10,rowGap:4,paddingHorizontal:n.rowPadH,paddingBottom:12,marginTop:-4},staleText:{color:n.color.textSecondary,fontSize:n.font.caption,flexShrink:1},staleAction:{color:n.color.accent,fontSize:n.font.caption,fontWeight:"600"},destructive:{color:n.color.danger,fontSize:n.font.row},action:{color:n.color.accent,fontSize:n.font.row},option:{flexDirection:"row",alignItems:"center",gap:12,paddingHorizontal:n.rowPadH,paddingVertical:11,minHeight:50},optionText:{flex:1,gap:2},optionDetail:{color:n.color.textTertiary,fontSize:n.font.caption,lineHeight:17},check:{width:20,alignItems:"center"},inlineBack:{flexDirection:"row",alignItems:"center",gap:4,marginBottom:-8},inlineBackText:{color:n.color.accent,fontSize:n.font.row},inlineTitle:{color:n.color.text,fontSize:n.font.row,fontWeight:"600",marginLeft:"auto"},recentRow:{flexDirection:"row",alignItems:"center",gap:12,paddingHorizontal:n.rowPadH,paddingVertical:10},recentTime:{color:n.color.textTertiary,fontSize:n.font.caption,fontVariant:["tabular-nums"]},recentVerb:{color:n.color.text,fontSize:n.font.body,flex:1},recentResult:{color:n.color.textSecondary,fontSize:n.font.body},recentFailed:{color:n.color.danger}});
@@ -0,0 +1 @@
1
+ "use strict";import{toAndroidCheck as R}from"../model";import{getOverride as _,noteReal as O,recordCall as l,registerLibrary as m,registerRealRequester as p,resolveRequest as T}from"../store";import{wrapMethod as f}from"./wrap";const u="PermissionsAndroid";const h={ACCESS_FINE_LOCATION:"location",ACCESS_COARSE_LOCATION:"location",ACCESS_BACKGROUND_LOCATION:"locationBackground",CAMERA:"camera",RECORD_AUDIO:"microphone",POST_NOTIFICATIONS:"notifications",READ_MEDIA_IMAGES:"photos",READ_MEDIA_VIDEO:"photos",READ_MEDIA_VISUAL_USER_SELECTED:"photos",READ_EXTERNAL_STORAGE:"photos",WRITE_EXTERNAL_STORAGE:"photos",READ_CONTACTS:"contacts",WRITE_CONTACTS:"contacts",READ_CALENDAR:"calendar",WRITE_CALENDAR:"calendar",ACTIVITY_RECOGNITION:"motion",BLUETOOTH_SCAN:"bluetooth",BLUETOOTH_CONNECT:"bluetooth",BLUETOOTH_ADVERTISE:"bluetooth"};export function androidPermissionId(e){const t=e.replace(/^android\.permission\./,"");return h[t]??`android:${e}`}function I(e,t){if(R(e,t))return"granted";if(e==="blocked"||e==="restricted")return"never_ask_again";return"denied"}function C(e){if(e==="granted"||e===true)return"granted";if(e==="never_ask_again")return"blocked";if(e==="denied")return"denied";return null}export function installAndroidAdapter(e){if(!e)return false;f(e,"check",t=>async(...s)=>{const c=String(s[0]);const r=androidPermissionId(c);const i=await t(...s);const n=i===true?"granted":null;O(r,n,u);const a=_(r);if(a===null){l({source:u,method:"check",permission:r,kind:"check",real:n,returned:n,overridden:false});return i}l({source:u,method:"check",permission:r,kind:"check",real:n,returned:a,overridden:true});return R(a,c)});f(e,"request",t=>async(...s)=>{const c=String(s[0]);const r=androidPermissionId(c);if(_(r)===null){const a=await t(...s);const o=C(a);O(r,o,u);l({source:u,method:"request",permission:r,kind:"request",real:o,returned:o,overridden:false});return a}const{state:i,answer:n}=await T(r);l({source:u,method:"request",permission:r,kind:"request",real:null,returned:i,overridden:true,answer:n});return I(i,c)});f(e,"requestMultiple",t=>async(...s)=>{const c=Array.isArray(s[0])?s[0].map(String):[];const r=c.filter(o=>_(androidPermissionId(o))!==null);const i=c.filter(o=>!r.includes(o));const n={};if(i.length>0){const o=await t(i,...s.slice(1));for(const d of i){n[d]=o?.[d];const E=androidPermissionId(d);const A=C(o?.[d]);O(E,A,u);l({source:u,method:"requestMultiple",permission:E,kind:"request",real:A,returned:A,overridden:false})}}const a=new Map;for(const o of r){const d=androidPermissionId(o);if(!a.has(d)){const E=await T(d);a.set(d,E);l({source:u,method:"requestMultiple",permission:d,kind:"request",real:null,returned:E.state,overridden:true,answer:E.answer})}n[o]=I(a.get(d).state,o)}return n});for(const[t,s]of Object.entries(h)){if(t==="ACCESS_COARSE_LOCATION"||t.startsWith("WRITE_")||t==="READ_MEDIA_VIDEO")continue;p(s,async()=>{const c=e.request;const r=c?.__buoyPermissionsOriginal;if(!r)return null;const i=await r.call(e,`android.permission.${t}`);const n=C(i);l({source:u,method:"request (system)",permission:s,kind:"request",real:n,returned:n,overridden:false});return n})}m(u,[]);return true}
@@ -0,0 +1,3 @@
1
+ "use strict";import{fromExpo as f,toExpo as E}from"../model";import{getOverride as h,getPlatform as p,getSettings as O,noteReal as g,recordCall as m,registerLibrary as _,registerRealRequester as C,resolveRequest as I}from"../store";import{codedError as N,wrapMethod as P}from"./wrap";const q={ios:{code:"ERR_DENIED_FOREGROUND_LOCATION_PERMISSION",reason:"Location permission is required to do this operation"},android:{code:"ERR_LOCATION_UNAUTHORIZED",reason:"Not authorized to use location services"}};const R={ios:{code:"ERR_DENIED_BACKGROUND_LOCATION_PERMISSION",reason:"Background location permission is required to do this operation"},android:{code:"ERR_LOCATION_BACKGROUND_UNAUTHORIZED",reason:"Not authorized to use background location services"}};export const EXPO_MODULES=[{module:"ExpoLocation",library:"expo-location",permissions:[{get:"getForegroundPermissionsAsync",request:"requestForegroundPermissionsAsync",permission:"location",flavor:"location"},{get:"getBackgroundPermissionsAsync",request:"requestBackgroundPermissionsAsync",permission:"locationBackground",flavor:"locationBackground"},{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"location",flavor:"location"}],gated:[{method:"getCurrentPositionAsync",permission:"location",...q},{method:"getLastKnownPositionAsync",permission:"location",...q},{method:"watchPositionImplAsync",permission:"location",...q},{method:"startGeofencingAsync",permission:"locationBackground",...R},{method:"startLocationUpdatesAsync",permission:"locationBackground",...R}]},{module:"ExpoMaps",library:"expo-maps",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"location",flavor:"plain"}]},{module:"ExpoCamera",library:"expo-camera",permissions:[{get:"getCameraPermissionsAsync",request:"requestCameraPermissionsAsync",permission:"camera",flavor:"plain"},{get:"getMicrophonePermissionsAsync",request:"requestMicrophonePermissionsAsync",permission:"microphone",flavor:"plain"}]},{module:"ExpoNotificationPermissionsModule",library:"expo-notifications",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"notifications",flavor:"notifications",defaultArgs:s=>s==="ios"?[{allowAlert:true,allowBadge:true,allowSound:true}]:[void 0]}]},{module:"ExpoMediaLibrary",library:"expo-media-library",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"photos",flavor:"privileges",defaultArgs:()=>[false]}],gated:["getAssetsAsync","getAlbumsAsync","getAssetInfoAsync","createAssetAsync","saveToLibraryAsync"].map(s=>({method:s,permission:"photos",ios:{code:"ERR_MEDIA_LIBRARY_PERMISSIONS",reason:"Media Library permission is required to do this operation"}}))},{module:"ExponentImagePicker",library:"expo-image-picker",permissions:[{get:"getCameraPermissionsAsync",request:"requestCameraPermissionsAsync",permission:"camera",flavor:"plain"},{get:"getMediaLibraryPermissionsAsync",request:"requestMediaLibraryPermissionsAsync",permission:"photos",flavor:"privileges",defaultArgs:()=>[false]}],gated:[{method:"launchCameraAsync",permission:"camera",ios:{code:"ERR_MISSING_CAMERA_PERMISSION",reason:"Missing camera or camera roll permission"},android:{code:"ERR_USER_REJECTED_PERMISSIONS",reason:"User rejected permissions"}}]},{module:"ExpoContacts",library:"expo-contacts",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"contacts",flavor:"privileges"}]},{module:"ExpoCalendar",library:"expo-calendar",permissions:[{get:"getCalendarPermissionsAsync",request:"requestCalendarPermissionsAsync",permission:"calendar",flavor:"plain"},{get:"getRemindersPermissionsAsync",request:"requestRemindersPermissionsAsync",permission:"reminders",flavor:"plain"}]},{module:"CalendarNext",library:"expo-calendar",permissions:[{get:"getCalendarPermissions",request:"requestCalendarPermissions",permission:"calendar",flavor:"plain"},{get:"getRemindersPermissions",request:"requestRemindersPermissions",permission:"reminders",flavor:"plain"}]},{module:"ExpoTrackingTransparency",library:"expo-tracking-transparency",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"tracking",flavor:"plain"}]},{module:"ExpoAudio",library:"expo-audio",permissions:[{get:"getRecordingPermissionsAsync",request:"requestRecordingPermissionsAsync",permission:"microphone",flavor:"plain"}]},{module:"ExponentPedometer",library:"expo-sensors",permissions:[{get:"getPermissionsAsync",request:"requestPermissionsAsync",permission:"motion",flavor:"plain"}]}];function b(){const s=globalThis.expo?.modules;return s&&typeof s==="object"?s:null}function v(s){try{return new Set(Object.keys(s))}catch{return new Set}}const S=s=>s==="denied"||s==="blocked"||s==="restricted"||s==="undetermined";function k(s,o,e,r){return r==="ios"?`Calling the '${o}' function has failed
2
+ \u2192 Caused by: ${e}`:`Call to function '${s}.${o}' has been rejected.
3
+ \u2192 Caused by: ${e}`}function x(s,o=[]){if(s.flavor!=="privileges")return[];return o.length>0?o.slice(0,1):[false]}function M(s,o,e){const r=o.library;P(s,e.get,n=>async(...a)=>{const i=p();let t;let c;try{t=await n(...a)}catch(u){c=u}const l=f(t,i);g(e.permission,l,r);const d=h(e.permission);if(d===null){m({source:r,method:e.get,permission:e.permission,kind:"check",real:l,returned:l,overridden:false,error:c?String(c?.message??c):void 0});if(c)throw c;return t}const y=E(d,i,e.flavor,t);m({source:r,method:e.get,permission:e.permission,kind:"check",real:l,returned:d,overridden:true});return y});P(s,e.request,n=>async(...a)=>{const i=p();if(h(e.permission)===null){try{const u=await n(...a);const A=f(u,i);g(e.permission,A,r);m({source:r,method:e.request,permission:e.permission,kind:"request",real:A,returned:A,overridden:false});return u}catch(u){m({source:r,method:e.request,permission:e.permission,kind:"request",real:null,returned:null,overridden:false,error:String(u?.message??u)});throw u}}let t;const c=s[e.get];try{const u=c.__buoyPermissionsOriginal;t=u?await u.apply(s,x(e,a)):void 0}catch{t=void 0}const l=f(t,i);g(e.permission,l,r);const{state:d,answer:y}=await I(e.permission);m({source:r,method:e.request,permission:e.permission,kind:"request",real:l,returned:d,overridden:true,answer:y});return E(d,i,e.flavor,t)})}const w=new Set(["getCurrentPositionAsync","getLastKnownPositionAsync"]);export function coarsenPosition(s){const o=s;if(!o?.coords||typeof o.coords.latitude!=="number"||typeof o.coords.longitude!=="number")return s;const e=r=>Math.round(r/.02)*.02;return{...o,coords:{...o.coords,latitude:Number(e(o.coords.latitude).toFixed(4)),longitude:Number(e(o.coords.longitude).toFixed(4)),accuracy:Math.max(o.coords.accuracy??0,3e3),altitude:null,altitudeAccuracy:null,heading:null,speed:null}}}function D(s,o,e){P(s,e.method,r=>(...n)=>{const a=p();const i=a==="ios"?e.ios:e.android;const t=h(e.permission);const c=O().enforce;if(i&&c&&t!==null&&S(t)){const l=k(o.module,e.method,i.reason,a);m({source:o.library,method:e.method,permission:e.permission,kind:"gated",real:null,returned:t,overridden:true,error:i.code});return Promise.reject(N(i.code,l))}if(c&&t==="limited"&&w.has(e.method)){return Promise.resolve(r(...n)).then(l=>coarsenPosition(l))}return r(...n)})}function L(s,o,e){C(e.permission,async()=>{const r=s[e.request];const n=r?.__buoyPermissionsOriginal??r;if(typeof n!=="function")return null;const a=await n.apply(s,e.defaultArgs?.(p())??[]);const i=f(a,p());m({source:o.library,method:`${e.request} (system)`,permission:e.permission,kind:"request",real:i,returned:i,overridden:false});return i})}export function installExpoAdapter(){const s=b();if(!s)return[];const o=v(s);const e=[];for(const r of EXPO_MODULES){if(!o.has(r.module))continue;let n;try{n=s[r.module]}catch{n=void 0}if(!n||typeof n!=="object")continue;const a=[];for(const i of r.permissions){if(typeof n[i.get]!=="function")continue;M(n,r,i);L(n,r,i);a.push(i.permission)}for(const i of r.gated??[])D(n,r,i);if(a.length>0){_(r.library,a);e.push(r.library)}}return e}export async function refreshExpoRealStates(){const s=b();if(!s)return;const o=v(s);const e=p();const r=[];for(const n of EXPO_MODULES){if(!o.has(n.module))continue;const a=s[n.module];if(!a)continue;const i=new Set;for(const t of n.permissions){if(i.has(t.permission))continue;const c=a[t.get];const l=c?.__buoyPermissionsOriginal??c;if(typeof l!=="function")continue;i.add(t.permission);r.push(Promise.resolve().then(()=>l.apply(a,x(t))).then(d=>g(t.permission,f(d,e),n.library)).catch(()=>{}))}}await Promise.all(r)}
@@ -0,0 +1 @@
1
+ "use strict";import{fromRnp as A,toRnp as k}from"../model";import{getOverride as m,getPlatform as g,noteReal as O,recordCall as f,registerLibrary as w,resolveRequest as R}from"../store";import{androidPermissionId as I}from"./android";import{wrapMethod as p}from"./wrap";const l="react-native-permissions";const _={APP_TRACKING_TRANSPARENCY:"tracking",BLUETOOTH:"bluetooth",CALENDARS:"calendar",CALENDARS_WRITE_ONLY:"calendar",CAMERA:"camera",CONTACTS:"contacts",LOCATION_ALWAYS:"locationBackground",LOCATION_WHEN_IN_USE:"location",MICROPHONE:"microphone",MOTION:"motion",PHOTO_LIBRARY:"photos",PHOTO_LIBRARY_ADD_ONLY:"photos",REMINDERS:"reminders"};export function rnpPermissionId(u){if(u.startsWith("ios.permission.")){return _[u.slice("ios.permission.".length)]??null}if(u.startsWith("android.permission."))return I(u);return null}function S(u){const i=u==="granted";const N=u==="limited";return{alert:i,badge:i,sound:i,lockScreen:i,notificationCenter:i||N,carPlay:false,criticalAlert:false,provisional:N,providesAppSettings:false}}export function installRnPermissionsAdapter(u){if(!u)return false;const i=g();const N=async(o,t,c,s)=>{const e=rnpPermissionId(c);const a=await o(...s);if(!e)return a;const d=A(a,i);O(e,d,l);const n=m(e);f({source:l,method:t,permission:e,kind:"check",real:d,returned:n??d,overridden:n!==null});return n===null?a:k(n,i)};const L=async(o,t,c,s)=>{const e=rnpPermissionId(c);if(!e||m(e)===null){const n=await o(...s);if(e){const r=A(n,i);O(e,r,l);f({source:l,method:t,permission:e,kind:"request",real:r,returned:r,overridden:false})}return n}const{state:a,answer:d}=await R(e);f({source:l,method:t,permission:e,kind:"request",real:null,returned:a,overridden:true,answer:d});return k(a,i)};p(u,"check",o=>(...t)=>N(o,"check",String(t[0]),t));p(u,"request",o=>(...t)=>L(o,"request",String(t[0]),t));p(u,"checkMultiple",o=>async(...t)=>{const c=Array.isArray(t[0])?t[0].map(String):[];const s=await o(...t)??{};const e={...s};for(const a of c){const d=rnpPermissionId(a);if(!d)continue;const n=A(s[a],i);O(d,n,l);const r=m(d);f({source:l,method:"checkMultiple",permission:d,kind:"check",real:n,returned:r??n,overridden:r!==null});if(r!==null)e[a]=k(r,i)}return e});p(u,"requestMultiple",o=>async(...t)=>{const c=Array.isArray(t[0])?t[0].map(String):[];const s=n=>{const r=rnpPermissionId(n);return r!==null&&m(r)!==null};const e=c.filter(n=>!s(n));const a={};if(e.length>0){const n=await o(e,...t.slice(1))??{};for(const r of e){a[r]=n[r];const h=rnpPermissionId(r);if(!h)continue;const q=A(n[r],i);O(h,q,l);f({source:l,method:"requestMultiple",permission:h,kind:"request",real:q,returned:q,overridden:false})}}const d=new Map;for(const n of c.filter(s)){const r=rnpPermissionId(n);if(!d.has(r)){const{state:h,answer:q}=await R(r);d.set(r,h);f({source:l,method:"requestMultiple",permission:r,kind:"request",real:null,returned:h,overridden:true,answer:q})}a[n]=k(d.get(r),i)}return a});p(u,"checkNotifications",o=>async(...t)=>{const c=await o(...t);const s=A(c?.status,i);O("notifications",s,l);const e=m("notifications");f({source:l,method:"checkNotifications",permission:"notifications",kind:"check",real:s,returned:e??s,overridden:e!==null});if(e===null)return c;return{status:k(e,i),settings:{...c?.settings??{},...S(e)}}});p(u,"requestNotifications",o=>async(...t)=>{if(m("notifications")===null){const e=await o(...t);const a=A(e?.status,i);O("notifications",a,l);f({source:l,method:"requestNotifications",permission:"notifications",kind:"request",real:a,returned:a,overridden:false});return e}const{state:c,answer:s}=await R("notifications");f({source:l,method:"requestNotifications",permission:"notifications",kind:"request",real:null,returned:c,overridden:true,answer:s});return{status:k(c,i),settings:S(c)}});const y=o=>t=>async(...c)=>{const s=m("location");if(s===null)return t(...c);f({source:l,method:o,permission:"location",kind:o.startsWith("request")?"request":"check",real:null,returned:s,overridden:true});return s==="limited"?"reduced":"full"};p(u,"checkLocationAccuracy",y("checkLocationAccuracy"));p(u,"requestLocationAccuracy",y("requestLocationAccuracy"));w(l,[]);return true}
@@ -0,0 +1 @@
1
+ "use strict";const e="__buoyPermissionsOriginal";export function originalOf(r,o){const n=r[o];if(typeof n!=="function")return null;return n[e]??n}export function wrapMethod(r,o,n){const t=originalOf(r,o);if(!t)return false;const i=(...u)=>t.apply(r,u);const c=n(i);c[e]=t;try{r[o]=c}catch{return false}return r[o]===c}export function codedError(r,o){const n=new Error(o);n.code=r;return n}
@@ -0,0 +1 @@
1
+ "use strict";import{BUOY_SYNTHETIC_MARK as b}from"@buoy-gg/shared-ui";import{permissionInfo as k,settingsLabel as A,supportedStates as T}from"./model";import{anyOverride as I,getOverride as p,getPermissionsSnapshot as w,getPlatform as a,getSettings as O,recordCall as P,setOverride as R}from"./store";import{wrapMethod as f}from"./adapters/wrap";let d=null;let m=null;export function configureAppSettings(t){d=t.emitter;m=t.alert}function g(t){try{d?.emit("appStateDidChange",{app_state:t,[b]:true})}catch{}}export function simulateLeaveApp(){if(a()==="ios")g("inactive");g("background")}export function simulateReturnToApp(){g("active")}let l=null;let S=false;export function notifyAppOfChange(){if(!d||S)return;if(l)clearTimeout(l);l=setTimeout(()=>{l=null;simulateLeaveApp();setTimeout(simulateReturnToApp,60)},120)}export function settingsTarget(){const{log:t,permissions:r}=w();const n=e=>e==="denied"||e==="blocked"||e==="restricted";const i=t.filter(e=>e.permission&&e.overridden&&p(e.permission)!==null);const o=i.find(e=>n(p(e.permission)));if(o)return o.permission;const c=r.find(e=>e.override!==null&&n(e.override));if(c)return c.id;if(i[0])return i[0].permission;const u=r.find(e=>e.override!==null);return u?.id??null}function C(t){const r=a();return T(t,r).filter(n=>(n!=="undetermined"||r==="ios"&&t==="location")&&n!=="restricted"&&!(r==="android"&&n==="blocked"))}export function openSettingsStandIn(t,r){const n=a();const i=k(t);const o=p(t);P({source:r,method:"openSettings",permission:t,kind:"settings",real:null,returned:o,overridden:true});simulateLeaveApp();S=true;return new Promise(c=>{let u=false;const e=()=>{if(u)return;u=true;S=false;simulateReturnToApp();c()};if(!m){e();return}const v=C(t);const y=n==="android"?v.filter(s=>s!==o).slice(0,2):v;const x=y.map(s=>({text:`${s===o?"\u2713 ":""}${A(t,n,s)}`,onPress:()=>{try{R(t,s)}catch{}e()}}));x.push({text:"Back to App",onPress:e,style:"cancel"});m.alert(i.label,"Buoy's stand-in for Settings. Pick what the app gets when it comes back.",x,{cancelable:true,onDismiss:e})})}function h(){return O().interceptSettings&&I()&&settingsTarget()!==null}function L(t){return typeof t==="string"&&/^app-settings:/i.test(t)}export function installSettingsIntercept(t){if(!t)return;f(t,"openSettings",r=>(...n)=>{if(!h())return r(...n);return openSettingsStandIn(settingsTarget(),"Linking")});f(t,"openURL",r=>(...n)=>{if(!L(n[0])||!h())return r(...n);return openSettingsStandIn(settingsTarget(),"Linking")})}export function installRnpSettingsIntercept(t){if(!t)return;f(t,"openSettings",r=>(...n)=>{const i=n[0];if(i!==void 0&&i!=="application"&&i!=="notifications"||!h()){return r(...n)}const o=i==="notifications"&&p("notifications")!==null?"notifications":settingsTarget();return openSettingsStandIn(o,"react-native-permissions")})}
@@ -0,0 +1 @@
1
+ "use strict";import*as p from"react-native";import{Alert as s,DeviceEventEmitter as a,Linking as m,Platform as c,TurboModuleRegistry as u}from"react-native";import{installAndroidAdapter as d}from"./adapters/android";import{installExpoAdapter as f,refreshExpoRealStates as g}from"./adapters/expo";import{installRnPermissionsAdapter as A}from"./adapters/rnPermissions";import{configureAppSettings as P,installRnpSettingsIntercept as y,installSettingsIntercept as b,notifyAppOfChange as h}from"./appSettings";import{createAlertPrompter as v}from"./prompt";import{bootPermissions as S,configurePermissions as E,getSettings as x,onPermissionChange as I,setPrompter as R}from"./store";const l="__buoyPermissionsInstalled";function D(){const e=globalThis.expo?.modules;const t=i=>{try{return e?.[i]}catch{return void 0}};const o=t("ExpoDevice");const n=t("ExpoApplication");const r=i=>typeof i==="string"&&i?i:null;return{isSimulator:typeof o?.isDevice==="boolean"?!o.isDevice:null,deviceName:r(o?.deviceName),bundleId:r(n?.applicationId)}}function N(){try{const e=u?.get;const t=typeof e==="function"?e("RNPermissions"):null;return t&&typeof t==="object"?t:null}catch{return null}}export function installPermissions(){const e=globalThis;if(e[l])return false;e[l]=true;const t=c.OS==="android"?"android":"ios";E({platform:t,host:D()});S();P({emitter:a??null,alert:s??null});R(v(s));f();if(t==="android"){d(p.PermissionsAndroid)}const o=N();if(o){A(o);y(o)}b(m);I(({from:n})=>{if(n==="tool"&&x().notifyApp)h()});setTimeout(()=>{void g()},1500);return true}
@@ -0,0 +1 @@
1
+ "use strict";export function installPermissions(){return false}
@@ -0,0 +1 @@
1
+ "use strict";export const PERMISSION_STATES=["undetermined","granted","limited","denied","blocked","restricted"];export const REQUEST_ANSWERS=["ask","allow","limited","deny"];const a={location:{id:"location",label:"Location",limited:{ios:"Approximate",android:"Approximate"},purpose:"use your location"},locationBackground:{id:"locationBackground",label:"Background Location",purpose:"use your location in the background"},camera:{id:"camera",label:"Camera",purpose:"access your camera"},microphone:{id:"microphone",label:"Microphone",purpose:"access your microphone"},notifications:{id:"notifications",label:"Notifications",limited:{ios:"Provisional"},purpose:"send you notifications"},photos:{id:"photos",label:"Photos",limited:{ios:"Selected Photos",android:"Selected Photos"},purpose:"access your photos"},contacts:{id:"contacts",label:"Contacts",limited:{ios:"Selected Contacts"},purpose:"access your contacts"},calendar:{id:"calendar",label:"Calendar",purpose:"access your calendar"},reminders:{id:"reminders",label:"Reminders",only:"ios",purpose:"access your reminders"},tracking:{id:"tracking",label:"Tracking",only:"ios",purpose:"track your activity across other companies' apps and websites"},motion:{id:"motion",label:"Motion & Fitness",purpose:"access your motion and fitness activity"},bluetooth:{id:"bluetooth",label:"Bluetooth",purpose:"use Bluetooth"}};export const KNOWN_PERMISSION_IDS=Object.keys(a);export function isPermissionId(e){return typeof e==="string"&&(e in a||e.startsWith("android:")&&e.length>8)}export function permissionInfo(e){const i=a[e];if(i)return i;const n=e.slice("android:".length).replace(/^android\.permission\./,"");return{id:e,label:n.toLowerCase().split("_").map(o=>o.charAt(0).toUpperCase()+o.slice(1)).join(" "),only:"android",purpose:`use ${n.toLowerCase().replace(/_/g," ")}`}}export function supportedStates(e,i){const n=permissionInfo(e);const o=["undetermined","granted"];if(n.limited?.[i])o.push("limited");o.push("denied");if(i==="android")o.push("blocked");if(i==="ios"&&e!=="notifications")o.push("restricted");return o}export function isSupported(e,i,n){return supportedStates(e,i).includes(n)}export function normalizeState(e,i,n){if(isSupported(e,i,n))return n;if(n==="blocked")return"denied";if(n==="restricted")return i==="android"?"blocked":"denied";if(n==="limited")return"granted";return n}export function canPrompt(e,i){if(i==="undetermined")return true;return e==="android"&&i==="denied"}export function stateAfterRequest(e,i,n,o){if(!canPrompt(i,n))return n;if(o==="allow"||o==="once")return"granted";if(o==="limited")return isSupported(e,i,"limited")?"limited":"granted";if(i==="android")return n==="denied"?"blocked":"denied";return"denied"}function p(e,i){if(i==="ios")return e==="location";return e==="camera"||e==="microphone"}export function promptChoices(e,i){const n=permissionInfo(e);const o=n.limited?.[i];const t=i==="ios";const r=[];if(t&&p(e,i))r.push({answer:"once",label:"Allow Once"});if(e==="location"||e==="locationBackground"){r.push({answer:"allow",label:t?"Allow While Using App":"While using the app"})}else{r.push({answer:"allow",label:"Allow"})}if(!t&&p(e,i))r.push({answer:"once",label:"Only this time"});if(o){const d=e==="location"?t?"Allow With Approximate Location":"Approximate location":e==="photos"?t?"Limit Access\u2026":"Select photos":e==="contacts"?"Select Contacts\u2026":`Allow ${o}`;r.push({answer:"limited",label:d})}r.push({answer:"deny",label:t?"Don\u2019t Allow":"Don\u2019t allow"});return r}export function settingsLabel(e,i,n){if(i==="ios"){if(e==="location"||e==="locationBackground"){if(n==="undetermined")return"Ask Next Time";if(n==="granted")return e==="locationBackground"?"Always":"While Using the App";if(n==="limited")return"While Using the App, Approximate";if(n==="denied")return"Never"}if(e==="photos"||e==="contacts"){if(n==="granted")return"Full Access";if(n==="limited")return"Limited Access";if(n==="denied")return"None"}if(e==="notifications"){if(n==="granted")return"Allow Notifications";if(n==="limited")return"Deliver Quietly";if(n==="denied")return"Off"}if(n==="granted")return"Allow";if(n==="denied")return"Don\u2019t Allow"}else{if(e==="location"&&n==="granted")return"Allow only while using the app";if(e==="location"&&n==="limited")return"While using the app, approximate";if(e==="photos"&&n==="granted")return"Allow all";if(e==="photos"&&n==="limited")return"Allow limited access";if(n==="granted")return"Allow";if(n==="denied")return"Don\u2019t allow"}return stateLabel(e,i,n)}export function stateDescription(e,i,n){switch(n){case"undetermined":return"Never asked. The next request shows a prompt.";case"granted":return"Full access.";case"limited":if(e==="location")return"Allowed, with an approximate position.";if(e==="photos")return"Allowed for the photos the person picked.";if(e==="contacts")return"Allowed for the contacts the person picked.";if(e==="notifications")return"Delivered quietly to Notification Center, without asking.";return"Partial access.";case"denied":return i==="ios"?"The person said no. The app can't ask again, only send them to Settings.":"The person said no once. The app can ask one more time.";case"blocked":return"The person said no for good. Only Settings can change it.";case"restricted":return"Turned off by Screen Time or device management. The person can't change it."}}export function fromExpo(e,i){if(!e||typeof e!=="object")return null;const n=e;const o=typeof n.ios?.status==="number"?n.ios.status:void 0;if(o===3||o===4)return"limited";if(n.status==="granted"){if(n.accessPrivileges==="limited")return"limited";if(n.ios?.accuracy==="reduced")return"limited";if(n.android?.accuracy==="coarse")return"limited";return"granted"}if(n.status==="denied"){if(i==="android"&&n.canAskAgain===false)return"blocked";return"denied"}if(n.status==="undetermined")return"undetermined";return null}export function fromRnp(e,i){switch(e){case"granted":return"granted";case"limited":return"limited";case"blocked":return i==="ios"?"denied":"blocked";case"denied":return i==="ios"?"undetermined":"denied";default:return null}}const m=["allowsAlert","allowsBadge","allowsSound","allowsDisplayInNotificationCenter","allowsDisplayOnLockScreen","allowsDisplayInCarPlay","allowsCriticalAlerts","allowsAnnouncements"];export function toExpo(e,i,n,o){const t=o&&typeof o==="object"?o:{};const r=e==="granted"||e==="limited";const d=r?"granted":e==="undetermined"?"undetermined":"denied";const f=e==="undetermined"||i==="android"&&e==="denied";const s={...t,status:d,granted:r,canAskAgain:f,expires:"never"};if(n==="privileges"){s.accessPrivileges=e==="granted"?"all":e==="limited"?"limited":"none"}if(n==="location"||n==="locationBackground"){const l=n==="locationBackground";if(i==="ios"){const c=r?l?"always":"whenInUse":"none";s.ios={...t.ios??{},scope:c,accuracy:e==="limited"?"reduced":"full"};if("scope"in t)s.scope=c}else{const c=e==="granted"?"fine":e==="limited"?"coarse":"none";s.android={...t.android??{},accuracy:c};if("scope"in t)s.scope=c}}if(n==="notifications"){if(i==="ios"){const l=e==="granted"?2:e==="limited"?3:e==="undetermined"?0:1;if(e==="limited"){s.status="undetermined";s.granted=false;s.canAskAgain=true}const c={...t.ios??{},status:l};for(const u of m){c[u]=e==="undetermined"?null:e==="granted"?true:e==="limited"?u==="allowsDisplayInNotificationCenter":false}c.alertStyle=e==="granted"?1:0;s.ios=c}else{s.android={...t.android??{},importance:r?3:0}}}return s}export function toRnp(e,i){switch(e){case"granted":return"granted";case"limited":return"limited";case"undetermined":return"denied";case"denied":return i==="ios"?"blocked":"denied";case"blocked":case"restricted":return"blocked"}}export function toAndroidRequestResult(e){if(e==="granted"||e==="limited")return"granted";if(e==="blocked"||e==="restricted")return"never_ask_again";return"denied"}export function toAndroidCheck(e,i){if(e==="granted")return true;if(e!=="limited")return false;return/ACCESS_COARSE_LOCATION|READ_MEDIA_VISUAL_USER_SELECTED/.test(i)}export function stateLabel(e,i,n){switch(n){case"undetermined":return"Not Asked";case"granted":return"Allowed";case"limited":return permissionInfo(e).limited?.[i]??"Limited";case"denied":return"Denied";case"blocked":return"Blocked";case"restricted":return"Restricted"}}
@@ -0,0 +1 @@
1
+ "use strict";import{devToolsStorageKeys as c,persistentStorage as p}from"@buoy-gg/shared-ui";import{isPermissionId as u,PERMISSION_STATES as S,REQUEST_ANSWERS as f}from"./model";export{readSavedSync}from"./readSavedSync";export const DEFAULT_SETTINGS={requestAnswer:"ask",persist:true,showChip:true,notifyApp:true,enforce:true,interceptSettings:true};export const PERMISSIONS_STORAGE_KEY=c.permissions.state();function r(t,e){return typeof t==="boolean"?t:e}export function parseSettings(t){const e=t&&typeof t==="object"?t:{};return{requestAnswer:f.includes(e.requestAnswer)?e.requestAnswer:DEFAULT_SETTINGS.requestAnswer,persist:r(e.persist,DEFAULT_SETTINGS.persist),showChip:r(e.showChip,DEFAULT_SETTINGS.showChip),notifyApp:r(e.notifyApp,DEFAULT_SETTINGS.notifyApp),enforce:r(e.enforce,DEFAULT_SETTINGS.enforce),interceptSettings:r(e.interceptSettings,DEFAULT_SETTINGS.interceptSettings)}}export function parseSaved(t){if(!t)return null;try{const e=JSON.parse(t);if(!e||e.v!==1)return null;const n={};for(const[o,i]of Object.entries(e.overrides??{})){if(u(o)&&S.includes(i)){n[o]=i}}return{v:1,overrides:n,settings:parseSettings(e.settings)}}catch{return null}}export async function readSavedAsync(){try{return parseSaved(await p.getItem(PERMISSIONS_STORAGE_KEY))}catch{return null}}let s=Promise.resolve();export function writeSaved(t){const e=JSON.stringify(t);s=s.then(()=>p.setItem(PERMISSIONS_STORAGE_KEY,e)).catch(()=>{});return s.then(()=>{})}
@@ -0,0 +1,3 @@
1
+ "use strict";import{permissionInfo as x,promptChoices as y}from"./model";import{getPlatform as S}from"./store";let c;function f(){if(c!==void 0)return c;c=null;try{const n=require("expo-constants");c=(n?.default??n)?.expoConfig??null}catch{}return c}function d(){const n=f()?.name;return typeof n==="string"&&n?n:"This app"}const N={location:{plist:["NSLocationWhenInUseUsageDescription"],plugins:[["expo-location","locationWhenInUsePermission"]]},locationBackground:{plist:["NSLocationAlwaysAndWhenInUseUsageDescription"],plugins:[["expo-location","locationAlwaysAndWhenInUsePermission"]]},camera:{plist:["NSCameraUsageDescription"],plugins:[["expo-camera","cameraPermission"],["expo-image-picker","cameraPermission"]]},microphone:{plist:["NSMicrophoneUsageDescription"],plugins:[["expo-audio","microphonePermission"],["expo-camera","microphonePermission"],["expo-image-picker","microphonePermission"]]},photos:{plist:["NSPhotoLibraryUsageDescription"],plugins:[["expo-image-picker","photosPermission"],["expo-media-library","photosPermission"]]},contacts:{plist:["NSContactsUsageDescription"],plugins:[["expo-contacts","contactsPermission"]]},calendar:{plist:["NSCalendarsFullAccessUsageDescription","NSCalendarsUsageDescription"],plugins:[["expo-calendar","calendarPermission"]]},reminders:{plist:["NSRemindersFullAccessUsageDescription","NSRemindersUsageDescription"],plugins:[["expo-calendar","remindersPermission"]]},tracking:{plist:["NSUserTrackingUsageDescription"],plugins:[["expo-tracking-transparency","userTrackingPermission"]]},motion:{plist:["NSMotionUsageDescription"],plugins:[["expo-sensors","motionPermission"]]},bluetooth:{plist:["NSBluetoothAlwaysUsageDescription"],plugins:[]}};export function readPurposeString(n){const s=N[n];const t=f();if(!s||!t)return null;const a=d();const p=e=>typeof e==="string"&&e.trim()?e.replace(/\$\(PRODUCT_NAME\)/g,a).trim():null;for(const e of s.plist){const i=p(t.ios?.infoPlist?.[e]);if(i)return i}for(const[e,i]of s.plugins){for(const o of t.plugins??[]){if(Array.isArray(o)&&o[0]===e&&o[1]&&typeof o[1]==="object"){const l=p(o[1][i]);if(l)return l}}}return null}const P="Test prompt from Buoy. Your phone's settings won't change.";let h=Promise.resolve();export function createAlertPrompter(n){return s=>{const t=()=>new Promise(p=>{const e=S();const i=x(s);const o=d();const l=e==="ios"?`Allow \u201C${o}\u201D to ${i.purpose}?`:`Allow ${o} to ${i.purpose}?`;const U=y(s,e);let u=false;const m=r=>{if(u)return;u=true;p(r)};const g=e==="ios"?readPurposeString(s):null;n.alert(l,g?`${g}
2
+
3
+ ${P}`:P,U.map(r=>({text:r.label,style:r.answer==="deny"?"cancel":"default",onPress:()=>m(r.answer)})),{cancelable:e==="android",onDismiss:()=>m("deny")})});const a=h.then(t,t);h=a.catch(()=>{});return a}}
@@ -0,0 +1 @@
1
+ "use strict";import{PERMISSIONS_STORAGE_KEY as r,parseSaved as c}from"./persistence";function u(e){const n=encodeURIComponent(e.replace(/~/g,"~0").replace(/\//g,"~1"));return n===e?[e]:[n,e]}export function readSavedSync(){try{const e=require("expo-file-system");if(typeof e?.File!=="function"||!e.Paths?.document)return void 0;const n=new e.File(e.Paths.document,"react-buoy");if(typeof n.textSync!=="function")return void 0;for(const o of u(r)){const t=new e.File(e.Paths.document,"react-buoy",`${o}.json`);if(t.exists)return c(t.textSync())}return null}catch{return void 0}}
@@ -0,0 +1 @@
1
+ "use strict";export function readSavedSync(){return void 0}
@@ -0,0 +1 @@
1
+ "use strict";import{isPermissionId as m,normalizeState as h,permissionInfo as d,PERMISSION_STATES as v,stateAfterRequest as k,canPrompt as q,supportedStates as w,KNOWN_PERMISSION_IDS as A}from"./model";import{DEFAULT_SETTINGS as S,parseSettings as y,readSavedAsync as O,readSavedSync as P,writeSaved as x}from"./persistence";const b=200;const E=50;const I="__buoyPermissionsStore";const _=globalThis;const e=_[I]??={platform:"ios",booted:false,overrides:new Map,settings:{...S},seen:new Map,libraries:new Set,log:[],nextLogId:1,listeners:new Set,snapshot:null,prompter:null,changeHooks:new Set,realRequesters:new Map,host:{isSimulator:null,deviceName:null,bundleId:null},once:new Set};e.once??=new Set;const u=()=>{const t=globalThis.__buoyRealNow;return typeof t==="function"?t():Date.now()};function i(){e.snapshot=null;for(const t of Array.from(e.listeners)){try{t()}catch{}}}function c(){if(!e.settings.persist){void x({v:1,overrides:{},settings:e.settings});return}void x(T())}function T(){return{v:1,overrides:Object.fromEntries(Array.from(e.overrides,([t,r])=>[t,e.once.has(t)?"undetermined":r])),settings:e.settings}}function a(t){let r=e.seen.get(t);if(!r){r={sources:new Set,real:null,calls:0,lastCallAt:null,lastReadAt:null,changedAt:null};e.seen.set(t,r)}return r}function R(t){if(!t)return;e.settings=t.settings;e.overrides.clear();if(!t.settings.persist)return;for(const[r,n]of Object.entries(t.overrides)){const s=r;e.overrides.set(s,h(s,e.platform,n))}}export function configurePermissions(t){e.platform=t.platform;if(t.host)e.host=t.host;i()}export function bootPermissions(){if(e.booted)return;e.booted=true;const t=P();if(t!==void 0){R(t);i();return}void O().then(r=>{if(e.overrides.size>0)return;R(r);i()})}export function registerRealRequester(t,r){if(!e.realRequesters.has(t))e.realRequesters.set(t,r)}export function canRequestReal(t){return e.realRequesters.has(t)}export async function requestRealPermission(t){const r=g(t);const n=e.realRequesters.get(r);if(!n)throw new Error(`No installed library can ask the system for ${d(r).label}.`);const s=await n();if(s!==null)noteReal(r,s);return getPermissionsSnapshot()}export function setPrompter(t){e.prompter=t}export function onPermissionChange(t){e.changeHooks.add(t);return()=>e.changeHooks.delete(t)}function f(t,r){for(const n of Array.from(e.changeHooks)){try{n({id:t,from:r})}catch{}}}export function registerLibrary(t,r){let n=!e.libraries.has(t);e.libraries.add(t);for(const s of r){const o=a(s);if(!o.sources.has(t)){o.sources.add(t);n=true}}if(n)i()}export function getPlatform(){return e.platform}export function getSettings(){return e.settings}export function getOverride(t){return e.overrides.get(t)??null}export function isOverridden(t){return e.overrides.has(t)}export function anyOverride(){return e.overrides.size>0}export function noteReal(t,r,n){if(r===null)return;const s=a(t);if(n)s.sources.add(n);if(s.real===r)return;s.real=r;i()}export function recordCall(t){const r={...t,id:e.nextLogId++,at:u()};e.log.unshift(r);if(e.log.length>b)e.log.length=b;if(t.permission){const n=a(t.permission);if(t.kind==="check"||t.kind==="request")n.sources.add(t.source);n.calls+=1;n.lastCallAt=r.at;if(t.kind==="check"||t.kind==="request")n.lastReadAt=r.at;if(t.real!==null&&t.kind!=="gated")n.real=t.real}i();return r}export async function resolveRequest(t){const r=e.overrides.get(t);if(r===void 0)throw new Error(`${t} is not overridden`);if(!q(e.platform,r))return{state:r};let n;const s=e.settings.requestAnswer;if(s==="ask"&&e.prompter)n=await e.prompter(t);else n=s==="ask"?"allow":s;const o=e.overrides.get(t);if(o===void 0)return{state:r,answer:n};const l=k(t,e.platform,o,n);if(n==="once"&&l==="granted")e.once.add(t);if(l!==o){e.overrides.set(t,l);c();i();f(t,"request")}return{state:l,answer:n}}function g(t){if(!m(t)){throw new Error(`Unknown permission "${String(t)}". Use one of: ${A.join(", ")}, or android:<android.permission.NAME>.`)}return t}export function setOverride(t,r){const n=g(t);if(!v.includes(r)){throw new Error(`Unknown state "${String(r)}". Use one of: ${v.join(", ")}.`)}const s=r;const o=w(n,e.platform);const l=e.platform==="ios"&&s==="blocked"?"denied":s;if(!o.includes(l)){throw new Error(`${d(n).label} can't be "${s}" on ${e.platform}. It can be: ${o.join(", ")}.`)}if(e.overrides.get(n)!==l||e.once.has(n)){e.overrides.set(n,l);e.once.delete(n);a(n).changedAt=u();c();i();f(n,"tool")}return getPermissionsSnapshot()}export function clearOverride(t){const r=g(t);if(e.overrides.delete(r)){e.once.delete(r);a(r).changedAt=u();c();i();f(r,"tool")}return getPermissionsSnapshot()}export function resetPermissions(){if(e.overrides.size>0){const t=u();for(const r of e.overrides.keys())a(r).changedAt=t;e.overrides.clear();e.once.clear();c();i();f(null,"tool")}return getPermissionsSnapshot()}export function getOverrides(){return Object.fromEntries(e.overrides)}export function restoreOverrides(t){const r=u();for(const n of e.overrides.keys())a(n).changedAt=r;e.overrides.clear();e.once.clear();for(const[n,s]of Object.entries(t)){const o=n;if(!s||!m(o))continue;e.overrides.set(o,h(o,e.platform,s));a(o).changedAt=r}c();i();f(null,"tool");return getPermissionsSnapshot()}export function updatePermissionSettings(t){const r={};for(const[s,o]of Object.entries(t)){if(o!==void 0)r[s]=o}if(r.requestAnswer!==void 0&&!["ask","allow","limited","deny"].includes(r.requestAnswer)){throw new Error('requestAnswer must be "ask", "allow", "limited" or "deny".')}const n=y({...e.settings,...r});e.settings=n;c();i();return getPermissionsSnapshot()}export function clearPermissionLog(){e.log=[];for(const t of e.seen.values()){t.calls=0;t.lastCallAt=null}i();return getPermissionsSnapshot()}function N(t,r){if(!t||!r)return null;const n=s=>s==="granted"||s==="limited";if(n(t)&&!n(r)){return"The phone hasn't allowed this, so calls that need it, like getting a position or a photo, still fail."}return null}export function getPermissionsSnapshot(){if(e.snapshot)return e.snapshot;const t=new Set([...e.seen.keys(),...e.overrides.keys()]);const r=s=>{const o=A.indexOf(s);return o===-1?1e3:o};const n=Array.from(t).filter(s=>{const o=d(s).only;return!o||o===e.platform}).sort((s,o)=>r(s)-r(o)||s.localeCompare(o)).map(s=>{const o=e.seen.get(s);const l=e.overrides.get(s)??null;const p=o?.real??null;return{id:s,label:d(s).label,states:w(s,e.platform),override:l,real:p,effective:l??p,sources:o?Array.from(o.sources).sort():[],calls:o?.calls??0,lastCallAt:o?.lastCallAt??null,lastReadAt:o?.lastReadAt??null,changedAt:o?.changedAt??null,stale:o?.changedAt!=null&&o.lastReadAt!=null&&o.lastReadAt<o.changedAt,once:e.once.has(s),warning:N(l,p),canRequestReal:e.realRequesters.has(s)}});e.snapshot={platform:e.platform,host:e.host,libraries:Array.from(e.libraries).sort(),permissions:n,overriddenCount:e.overrides.size,settings:e.settings,log:e.log.slice(0,E)};return e.snapshot}export function subscribePermissions(t){e.listeners.add(t);return()=>e.listeners.delete(t)}export function __resetPermissionsForTests(t="ios"){e.platform=t;e.booted=false;e.overrides.clear();e.settings={...S};e.seen.clear();e.libraries.clear();e.log=[];e.nextLogId=1;e.prompter=null;e.changeHooks.clear();e.realRequesters.clear();e.once.clear();e.listeners.clear();e.host={isSimulator:null,deviceName:null,bundleId:null};e.snapshot=null}
@@ -0,0 +1 @@
1
+ "use strict";import{installPermissions as e}from"./engine/install";import{watchPermissionsChip as s}from"./components/PermissionsChip";const i=typeof navigator!=="undefined"&&navigator.product==="ReactNative";if(i&&typeof __DEV__!=="undefined"&&__DEV__){e();s()}export{permissionsToolPreset,createPermissionsTool}from"./preset";export{PermissionsBody}from"./components/PermissionsBody";export{PermissionsToolView}from"./components/PermissionsToolView";export{PermissionsChip,openPermissionsChip,PERMISSIONS_CHIP_ID}from"./components/PermissionsChip";export{PermissionsIcon,PERMISSIONS_ICON_COLOR}from"@buoy-gg/shared-ui";export{permissionsSyncAdapter}from"./sync/permissionsSyncAdapter";export{installPermissions}from"./engine/install";export{setOverride as setPermissionOverride,clearOverride as clearPermissionOverride,resetPermissions,updatePermissionSettings,getPermissionsSnapshot,subscribePermissions,isOverridden as isPermissionOverridden,getOverride as getPermissionOverride}from"./engine/store";export{supportedStates,stateLabel,permissionInfo,PERMISSION_STATES,KNOWN_PERMISSION_IDS}from"./engine/model";
@@ -0,0 +1 @@
1
+ "use strict";import{PermissionsIcon as e,PERMISSIONS_ICON_COLOR as t,createToolFactory as i,defineToolPreset as r}from"@buoy-gg/shared-ui";import{PermissionsBody as n}from"./components/PermissionsBody";import{jsx as m}from"react/jsx-runtime";export const permissionsToolPreset=r({id:"permissions",name:"PERMISSIONS",description:"Test denied, blocked, limited and not-asked permission states",slot:"both",color:t,icon:({size:o,color:s})=>m(e,{size:o,color:s}),component:n,modal:{subtitle:"choose what the app is allowed to do"}});export const createPermissionsTool=i(permissionsToolPreset);
@@ -0,0 +1 @@
1
+ "use strict";import{createSyncAdapter as a}from"@buoy-gg/shared-ui";import{refreshExpoRealStates as c}from"../engine/adapters/expo";import{notifyAppOfChange as d}from"../engine/appSettings";import{clearOverride as p,clearPermissionLog as f,getPermissionsSnapshot as i,requestRealPermission as m,resetPermissions as l,setOverride as g,subscribePermissions as w,updatePermissionSettings as h}from"../engine/store";function s(e){return e&&typeof e==="object"?e:{}}function o(e){return e.permission??e.id??e.permissionId??e.name}function n(e,r){const t=e[r];if(typeof t==="boolean")return t;if(t==="true")return true;if(t==="false")return false;return void 0}export const permissionsSyncAdapter=a({version:1,getSnapshot(){return i()},subscribe(e){return w(e)},actions:{async getState(){await c();return i()},setOverride(e){const r=s(e);const t=o(r);const u=r.state??r.status??r.value;if(t===void 0||u===void 0){throw new Error('setOverride needs `permission` (e.g. "location", "camera", "notifications") and `state` ("undetermined", "granted", "limited", "denied", "blocked" or "restricted").')}return g(t,u)},clearOverride(e){const r=o(s(e));if(r===void 0)throw new Error("clearOverride needs `permission`.");return p(r)},requestReal(e){const r=o(s(e));if(r===void 0)throw new Error("requestReal needs `permission`.");return m(r)},resetAll(){return l()},updateSettings(e){const r=s(e);return h({requestAnswer:r.requestAnswer??r.answer,persist:n(r,"persist"),showChip:n(r,"showChip"),notifyApp:n(r,"notifyApp"),enforce:n(r,"enforce"),interceptSettings:n(r,"interceptSettings")})},clearLog(){return f()},simulateReturnFromSettings(){d();return i()}}});
@@ -0,0 +1,2 @@
1
+ export declare function PermissionsBody(): import("react").JSX.Element;
2
+ //# sourceMappingURL=PermissionsBody.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { type FloatingToolRenderContext } from "@buoy-gg/shared-ui";
2
+ export declare const PERMISSIONS_CHIP_ID = "permissions-chip";
3
+ export declare function openPermissionsChip(): void;
4
+ /** Open the strip when simulating starts and close it when it stops. Idempotent. */
5
+ export declare function watchPermissionsChip(): void;
6
+ export declare function PermissionsChip({ id, revealToken }: FloatingToolRenderContext): import("react").JSX.Element;
7
+ //# sourceMappingURL=PermissionsChip.d.ts.map