@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
@@ -0,0 +1 @@
1
+ "use client";var ge=Object.defineProperty;var Xe=Object.getOwnPropertyDescriptor;var Qe=Object.getOwnPropertyNames;var et=Object.prototype.hasOwnProperty;var tt=(e,t)=>{for(var n in t)ge(e,n,{get:t[n],enumerable:true})},ye=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Qe(t))!et.call(e,i)&&i!==n&&ge(e,i,{get:()=>t[i],enumerable:!(o=Xe(t,i))||o.enumerable});return e},nt=(e,t,n)=>(ye(e,t,"default"),n&&ye(n,t,"default"));var be=process.env.NODE_ENV!=="production";typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);function Q(){return false}import{useEffect as ot,useSyncExternalStore as we}from"react";var ve={};tt(ve,{AccessibilityInfo:()=>at,ActivityIndicator:()=>nn,Alert:()=>sn,Animated:()=>lt,AppRegistry:()=>dt,AppState:()=>ut,Appearance:()=>ct,BackHandler:()=>pt,Button:()=>on,CheckBox:()=>Tt,Clipboard:()=>mt,DeviceEventEmitter:()=>Ut,Dimensions:()=>ht,Easing:()=>ft,FlatList:()=>Ot,I18nManager:()=>gt,Image:()=>Ct,ImageBackground:()=>Et,InteractionManager:()=>bt,Keyboard:()=>yt,KeyboardAvoidingView:()=>Nt,LayoutAnimation:()=>wt,Linking:()=>vt,LogBox:()=>Vt,Modal:()=>en,NativeEventEmitter:()=>At,NativeModules:()=>st,PanResponder:()=>St,Picker:()=>Dt,PixelRatio:()=>Pt,Platform:()=>xt,Pressable:()=>Qt,ProgressBar:()=>Lt,RefreshControl:()=>qt,SafeAreaView:()=>_t,ScrollView:()=>Ae,SectionList:()=>Mt,Share:()=>Rt,StatusBar:()=>Bt,StyleSheet:()=>j,Switch:()=>tn,Text:()=>h,TextInput:()=>Jt,Touchable:()=>$t,TouchableHighlight:()=>Zt,TouchableNativeFeedback:()=>zt,TouchableOpacity:()=>P,TouchableWithoutFeedback:()=>Xt,UIManager:()=>kt,Vibration:()=>It,View:()=>g,VirtualizedList:()=>jt,YellowBox:()=>Ht,findNodeHandle:()=>rn,unstable_createElement:()=>rt,useColorScheme:()=>Ft,useLocaleContext:()=>Wt,useWindowDimensions:()=>Kt});nt(ve,it);import*as it from"react-native-web";import{unstable_createElement as rt,NativeModules as st,AccessibilityInfo as at,Animated as lt,Appearance as ct,AppRegistry as dt,AppState as ut,BackHandler as pt,Clipboard as mt,Dimensions as ht,Easing as ft,I18nManager as gt,Keyboard as yt,InteractionManager as bt,LayoutAnimation as wt,Linking as vt,NativeEventEmitter as At,PanResponder as St,PixelRatio as Pt,Platform as xt,Share as Rt,StyleSheet as j,UIManager as kt,Vibration as It,CheckBox as Tt,FlatList as Ot,Image as Ct,ImageBackground as Et,KeyboardAvoidingView as Nt,Picker as Dt,ProgressBar as Lt,RefreshControl as qt,SafeAreaView as _t,SectionList as Mt,StatusBar as Bt,Touchable as $t,TouchableNativeFeedback as zt,VirtualizedList as jt,YellowBox as Ht,LogBox as Vt,DeviceEventEmitter as Ut,useColorScheme as Ft,useLocaleContext as Wt,useWindowDimensions as Kt}from"react-native-web";import*as w from"react-native-web";import{createElement as Gt,forwardRef as Yt}from"react";function A(e){let t=Yt((o,i)=>{let{accessibilityState:l,accessibilityValue:c,...m}=o;for(let d of["busy","checked","disabled","expanded","selected"])l?.[d]!==void 0&&m[`aria-${d}`]===void 0&&(m[`aria-${d}`]=l[d]);for(let[d,u]of Object.entries({min:"valuemin",max:"valuemax",now:"valuenow",text:"valuetext"}))c?.[d]!==void 0&&m[`aria-${u}`]===void 0&&(m[`aria-${u}`]=c[d]);return Gt(e,{...m,ref:i})}),n=e.State;return n&&Object.assign(t,{State:n}),t.displayName=e.displayName??e.name??"NativeWebView",t}var g=A(w.View),h=A(w.Text),Jt=A(w.TextInput),P=A(w.TouchableOpacity),Zt=A(w.TouchableHighlight),Xt=A(w.TouchableWithoutFeedback),Qt=A(w.Pressable),Ae=A(w.ScrollView),en=A(w.Modal),tn=A(w.Switch),nn=A(w.ActivityIndicator),on=A(w.Button),rn=w.findNodeHandle,sn={alert(e,t,n,o){if(typeof document>"u")return;let i=document.createElement("dialog");i.dataset.buoyRoot="",i.setAttribute("aria-label",e),i.style.cssText="position:fixed;inset:0;margin:auto;width:min(440px,90vw);padding:24px;border:1px solid #475569;border-radius:14px;background:#17212e;color:#f1f5f9;font:14px system-ui;box-shadow:0 20px 80px #0008;z-index:2147483647";let l=document.createElement("h2");if(l.textContent=e,l.style.cssText="font-size:18px;margin:0 0 12px",i.appendChild(l),t){let u=document.createElement("p");u.textContent=t,u.style.cssText="line-height:1.5;white-space:pre-wrap;margin:0 0 20px",i.appendChild(u)}let c=document.createElement("div");c.style.cssText="display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px";let m=n?.length?n:[{text:"OK"}],d=()=>{i.close?.(),i.remove()};for(let u of m){let S=document.createElement("button");S.type="button",S.textContent=u.text??"OK",S.style.cssText=`padding:9px 14px;border:1px solid #64748b;border-radius:7px;color:white;background:${u.style==="destructive"?"#a52b38":"#283a4d"};cursor:pointer;font:inherit`,S.onclick=()=>{d(),u.onPress?.()},c.appendChild(S)}i.addEventListener("cancel",u=>{u.preventDefault(),o?.cancelable!==false&&(d(),o?.onDismiss?.())}),i.appendChild(c),document.body.appendChild(i),i.showModal?i.showModal():i.setAttribute("open","")}};import{FloatingTool as Se,PermissionsIcon as Pe,X as an,dismissFloatingTool as ln,getFloatingTools as cn,night as L,openBuoyTool as dn,openFloatingTool as xe}from"@buoy-gg/shared-ui/web";var ee=["undetermined","granted","limited","denied","blocked","restricted"],un=["ask","allow","limited","deny"],te={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"}},ne=Object.keys(te);function Re(e){return typeof e=="string"&&(e in te||e.startsWith("android:")&&e.length>8)}function R(e){let t=te[e];if(t)return t;let n=e.slice(8).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 H(e,t){let n=R(e),o=["undetermined","granted"];return n.limited?.[t]&&o.push("limited"),o.push("denied"),t==="android"&&o.push("blocked"),t==="ios"&&e!=="notifications"&&o.push("restricted"),o}function pn(e,t,n){return H(e,t).includes(n)}function mn(e,t,n){return pn(e,t,n)?n:n==="blocked"?"denied":n==="restricted"?t==="android"?"blocked":"denied":n==="limited"?"granted":n}function hn(e,t,n){switch(n){case"undetermined":return"Never asked. The next request shows a prompt.";case"granted":return"Full access.";case"limited":return e==="location"?"Allowed, with an approximate position.":e==="photos"?"Allowed for the photos the person picked.":e==="contacts"?"Allowed for the contacts the person picked.":e==="notifications"?"Delivered quietly to Notification Center, without asking.":"Partial access.";case"denied":return t==="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 fn(e,t){if(!e||typeof e!="object")return null;let n=e,o=typeof n.ios?.status=="number"?n.ios.status:void 0;return o===3||o===4?"limited":n.status==="granted"?n.accessPrivileges==="limited"||n.ios?.accuracy==="reduced"||n.android?.accuracy==="coarse"?"limited":"granted":n.status==="denied"?t==="android"&&n.canAskAgain===false?"blocked":"denied":n.status==="undetermined"?"undetermined":null}function k(e,t,n){switch(n){case"undetermined":return"Not Asked";case"granted":return"Allowed";case"limited":return R(e).limited?.[t]??"Limited";case"denied":return"Denied";case"blocked":return"Blocked";case"restricted":return"Restricted"}}import{devToolsStorageKeys as gn,persistentStorage as yn}from"@buoy-gg/shared-ui/web";var I={requestAnswer:"ask",persist:true,showChip:true,notifyApp:true,enforce:true,interceptSettings:true},bn=gn.permissions.state();function q(e,t){return typeof e=="boolean"?e:t}function wn(e){let t=e&&typeof e=="object"?e:{};return{requestAnswer:un.includes(t.requestAnswer)?t.requestAnswer:I.requestAnswer,persist:q(t.persist,I.persist),showChip:q(t.showChip,I.showChip),notifyApp:q(t.notifyApp,I.notifyApp),enforce:q(t.enforce,I.enforce),interceptSettings:q(t.interceptSettings,I.interceptSettings)}}var oe=Promise.resolve();function ke(e){let t=JSON.stringify(e);return oe=oe.then(()=>yn.setItem(bn,t)).catch(()=>{}),oe.then(()=>{})}var vn=50,Ie="__buoyPermissionsStore",Te=globalThis,r=Te[Ie]??(Te[Ie]={platform:"ios",booted:false,overrides:new Map,settings:{...I},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});r.once??(r.once=new Set);var V=()=>{let e=globalThis.__buoyRealNow;return typeof e=="function"?e():Date.now()};function T(){r.snapshot=null;for(let e of Array.from(r.listeners))try{e()}catch{}}function _(){if(!r.settings.persist){ke({v:1,overrides:{},settings:r.settings});return}ke(An())}function An(){return{v:1,overrides:Object.fromEntries(Array.from(r.overrides,([e,t])=>[e,r.once.has(e)?"undetermined":t])),settings:r.settings}}function C(e){let t=r.seen.get(e);return t||(t={sources:new Set,real:null,calls:0,lastCallAt:null,lastReadAt:null,changedAt:null},r.seen.set(e,t)),t}async function Sn(e){let t=ie(e),n=r.realRequesters.get(t);if(!n)throw new Error(`No installed library can ask the system for ${R(t).label}.`);let o=await n();return o!==null&&Ce(t,o),b()}function U(e,t){for(let n of Array.from(r.changeHooks))try{n({id:e,from:t})}catch{}}function Oe(){return r.platform}function Pn(){return r.settings}function xn(e){return r.overrides.get(e)??null}function Rn(e){return r.overrides.has(e)}function kn(){return r.overrides.size>0}function Ce(e,t,n){if(t===null)return;let o=C(e);n&&o.sources.add(n),o.real!==t&&(o.real=t,T())}function ie(e){if(!Re(e))throw new Error(`Unknown permission "${String(e)}". Use one of: ${ne.join(", ")}, or android:<android.permission.NAME>.`);return e}function Ee(e,t){let n=ie(e);if(!ee.includes(t))throw new Error(`Unknown state "${String(t)}". Use one of: ${ee.join(", ")}.`);let o=t,i=H(n,r.platform),l=r.platform==="ios"&&o==="blocked"?"denied":o;if(!i.includes(l))throw new Error(`${R(n).label} can't be "${o}" on ${r.platform}. It can be: ${i.join(", ")}.`);return(r.overrides.get(n)!==l||r.once.has(n))&&(r.overrides.set(n,l),r.once.delete(n),C(n).changedAt=V(),_(),T(),U(n,"tool")),b()}function Ne(e){let t=ie(e);return r.overrides.delete(t)&&(r.once.delete(t),C(t).changedAt=V(),_(),T(),U(t,"tool")),b()}function re(){if(r.overrides.size>0){let e=V();for(let t of r.overrides.keys())C(t).changedAt=e;r.overrides.clear(),r.once.clear(),_(),T(),U(null,"tool")}return b()}function In(){return Object.fromEntries(r.overrides)}function Tn(e){let t=V();for(let n of r.overrides.keys())C(n).changedAt=t;r.overrides.clear(),r.once.clear();for(let[n,o]of Object.entries(e)){let i=n;!o||!Re(i)||(r.overrides.set(i,mn(i,r.platform,o)),C(i).changedAt=t)}return _(),T(),U(null,"tool"),b()}function De(e){let t={};for(let[o,i]of Object.entries(e))i!==void 0&&(t[o]=i);if(t.requestAnswer!==void 0&&!["ask","allow","limited","deny"].includes(t.requestAnswer))throw new Error('requestAnswer must be "ask", "allow", "limited" or "deny".');let n=wn({...r.settings,...t});return r.settings=n,_(),T(),b()}function On(){r.log=[];for(let e of r.seen.values())e.calls=0,e.lastCallAt=null;return T(),b()}function Cn(e,t){if(!e||!t)return null;let n=o=>o==="granted"||o==="limited";return n(e)&&!n(t)?"The phone hasn't allowed this, so calls that need it, like getting a position or a photo, still fail.":null}function b(){if(r.snapshot)return r.snapshot;let e=new Set([...r.seen.keys(),...r.overrides.keys()]),t=o=>{let i=ne.indexOf(o);return i===-1?1e3:i},n=Array.from(e).filter(o=>{let i=R(o).only;return!i||i===r.platform}).sort((o,i)=>t(o)-t(i)||o.localeCompare(i)).map(o=>{let i=r.seen.get(o),l=r.overrides.get(o)??null,c=i?.real??null;return{id:o,label:R(o).label,states:H(o,r.platform),override:l,real:c,effective:l??c,sources:i?Array.from(i.sources).sort():[],calls:i?.calls??0,lastCallAt:i?.lastCallAt??null,lastReadAt:i?.lastReadAt??null,changedAt:i?.changedAt??null,stale:i?.changedAt!=null&&i.lastReadAt!=null&&i.lastReadAt<i.changedAt,once:r.once.has(o),warning:Cn(l,c),canRequestReal:r.realRequesters.has(o)}});return r.snapshot={platform:r.platform,host:r.host,libraries:Array.from(r.libraries).sort(),permissions:n,overriddenCount:r.overrides.size,settings:r.settings,log:r.log.slice(0,vn)},r.snapshot}function M(e){return r.listeners.add(e),()=>r.listeners.delete(e)}import{jsx as v,jsxs as se}from"react/jsx-runtime";var F="permissions-chip",En=8e3,Le={id:F,render:e=>v(Me,{...e})},Nn=()=>cn().some(e=>e.id===F);function Dn(){xe(Le)}var E=null,ae=new Set,W=()=>{};function K(e){E&&clearTimeout(E.timer),E=e;for(let t of Array.from(ae))t();W()}function Ln(e){return ae.add(e),()=>{ae.delete(e)}}var qe=()=>E;function qn(){K({overrides:In(),timer:setTimeout(()=>K(null),En)}),re()}function _n(){let e=E;e&&(K(null),Tn(e.overrides))}var _e=false;function Mn(){if(_e)return;_e=true;let e=false;W=()=>{let t=(kn()||E!==null)&&Pn().showChip;t&&!e?xe(Le):!t&&Nn()&&ln(F),e=t},M(W),W()}function Me({id:e,revealToken:t}){let n=we(M,b,b),o=we(Ln,qe,qe);ot(()=>{o&&n.overriddenCount>0&&K(null)},[o,n.overriddenCount]);let i=n.permissions.filter(m=>m.override!==null),l=i.length===1?i[0]:null,c=l?`${l.label}: ${l.once&&l.override==="granted"?"Allowed Once":k(l.id,n.platform,l.override)}`:`${i.length} permissions simulated`;return o&&i.length===0?v(Se,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:"Move or hide the permissions strip",handleAdornment:v(Pe,{size:12}),children:se(g,{style:x.row,children:[v(h,{style:x.title,numberOfLines:1,testID:"permissions-chip-summary",children:"Real permissions"}),v(P,{testID:"permissions-chip-undo",accessibilityRole:"button",accessibilityLabel:"Undo, put the simulated permissions back",onPress:_n,style:x.undo,hitSlop:{top:8,bottom:8,left:8,right:8},children:v(h,{style:x.undoText,children:"Undo"})})]})}):v(Se,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:`Move or hide the permissions strip. ${c}`,handleAdornment:v(Pe,{size:12}),children:se(g,{style:x.row,children:[se(P,{testID:"permissions-chip-open",accessibilityRole:"button",accessibilityLabel:`${c}. Open Permissions`,onPress:()=>{dn("permissions")},style:x.open,children:[v(g,{style:x.dot}),v(h,{style:x.title,numberOfLines:1,testID:"permissions-chip-summary",children:c})]}),v(g,{style:x.separator}),v(P,{testID:"permissions-chip-reset",accessibilityRole:"button",accessibilityLabel:"Use real permissions",onPress:qn,style:x.button,hitSlop:{top:8,bottom:8,left:4,right:8},children:v(an,{size:16,color:L.color.textSecondary})})]})})}var x=j.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:L.color.accent},title:{color:L.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:L.color.accent,fontSize:14,fontWeight:"600"},separator:{width:j.hairlineWidth,height:20,backgroundColor:L.color.separator}});import{PermissionsIcon as Bn,PERMISSIONS_ICON_COLOR as $n,createToolFactory as zn,defineToolPreset as jn}from"@buoy-gg/shared-ui/web";import{useEffect as Hn,useSyncExternalStore as Vn}from"react";import{reloadApp as Un}from"@buoy-gg/shared-ui/web";var le={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"}},Be={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"}},Fn=[{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",...le},{method:"getLastKnownPositionAsync",permission:"location",...le},{method:"watchPositionImplAsync",permission:"location",...le},{method:"startGeofencingAsync",permission:"locationBackground",...Be},{method:"startLocationUpdatesAsync",permission:"locationBackground",...Be}]},{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:e=>e==="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(e=>({method:e,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 Wn(){let e=globalThis.expo?.modules;return e&&typeof e=="object"?e:null}function Kn(e){try{return new Set(Object.keys(e))}catch{return new Set}}function Gn(e,t=[]){return e.flavor!=="privileges"?[]:t.length>0?t.slice(0,1):[false]}async function $e(){let e=Wn();if(!e)return;let t=Kn(e),n=Oe(),o=[];for(let i of Fn){if(!t.has(i.module))continue;let l=e[i.module];if(!l)continue;let c=new Set;for(let m of i.permissions){if(c.has(m.permission))continue;let d=l[m.get],u=d?.__buoyPermissionsOriginal??d;typeof u=="function"&&(c.add(m.permission),o.push(Promise.resolve().then(()=>u.apply(l,Gn(m))).then(S=>Ce(m.permission,fn(S,n),i.library)).catch(()=>{})))}}await Promise.all(o)}import{createSyncAdapter as Yn}from"@buoy-gg/shared-ui/web";import{BUOY_SYNTHETIC_MARK as Jn}from"@buoy-gg/shared-ui/web";var ze=null;function ce(e){try{ze?.emit("appStateDidChange",{app_state:e,[Jn]:true})}catch{}}function Zn(){Oe()==="ios"&&ce("inactive"),ce("background")}function Xn(){ce("active")}var G=null,Qn=false;function eo(){!ze||Qn||(G&&clearTimeout(G),G=setTimeout(()=>{G=null,Zn(),setTimeout(Xn,60)},120))}function Y(e){return e&&typeof e=="object"?e:{}}function de(e){return e.permission??e.id??e.permissionId??e.name}function B(e,t){let n=e[t];if(typeof n=="boolean")return n;if(n==="true")return true;if(n==="false")return false}var je=Yn({version:1,getSnapshot(){return b()},subscribe(e){return M(e)},actions:{async getState(){return await $e(),b()},setOverride(e){let t=Y(e),n=de(t),o=t.state??t.status??t.value;if(n===void 0||o===void 0)throw new Error('setOverride needs `permission` (e.g. "location", "camera", "notifications") and `state` ("undetermined", "granted", "limited", "denied", "blocked" or "restricted").');return Ee(n,o)},clearOverride(e){let t=de(Y(e));if(t===void 0)throw new Error("clearOverride needs `permission`.");return Ne(t)},requestReal(e){let t=de(Y(e));if(t===void 0)throw new Error("requestReal needs `permission`.");return Sn(t)},resetAll(){return re()},updateSettings(e){let t=Y(e);return De({requestAnswer:t.requestAnswer??t.answer,persist:B(t,"persist"),showChip:B(t,"showChip"),notifyApp:B(t,"notifyApp"),enforce:B(t,"enforce"),interceptSettings:B(t,"interceptSettings")})},clearLog(){return On()},simulateReturnFromSettings(){return eo(),b()}}});import{useEffect as to,useReducer as no,useState as He}from"react";import{Check as oo,ChevronLeft as io,ChevronRight as Ve,NightCard as O,NightFootnote as N,NightRows as ue,NightSectionLabel as Ue,night as a,useSafeAreaInsets as ro,useToolScreenHeader as so}from"@buoy-gg/shared-ui/web";import{Fragment as Fe,jsx as s,jsxs as f}from"react/jsx-runtime";var pe=1500,ao=()=>{let e=globalThis.__buoyRealNow;return typeof e=="function"?e():Date.now()};function lo(e,t){return e.effective?e.once&&e.effective==="granted"?"Allowed Once":k(e.id,t,e.effective):"Not Checked"}function We({snapshot:e,onAction:t,onReload:n}){let o=ro({minBottom:16}),[i,l]=He(null),[c,m]=He({name:"list"}),d=(y,Z)=>{l(null),t(y,Z).catch(X=>{l(X instanceof Error?X.message:String(X))})},u=c.name==="detail"?e?.permissions.find(y=>y.id===c.id):void 0,S=()=>m(c.name==="detail"&&c.from==="other"?{name:"other"}:{name:"list"}),D=c.name==="other"?"Other Permissions":u?u.label:null,Ze=so(D?{title:D,onBack:S,searchable:false}:null,[D,c.name,c.name==="detail"?c.from:null]);if(!e)return s(g,{style:p.waiting,testID:"permissions-waiting",children:s(N,{centered:true,children:"Waiting for the app\u2026"})});let{platform:J,permissions:me}=e,he=me.filter(y=>y.calls>0||y.override!==null),$=me.filter(y=>!(y.calls>0||y.override!==null)),fe=(y,Z)=>m({name:"detail",id:y,from:Z}),z;return c.name==="detail"&&u?z=s(po,{row:u,platform:J,log:e.log,run:d,onPicked:S}):c.name==="other"?z=f(g,{children:[s(Ke,{rows:$,platform:J,onOpen:y=>fe(y,"other")}),s(N,{children:"Your app can ask for these but hasn't yet."})]}):z=f(Fe,{children:[he.length>0?s(Ke,{rows:he,platform:J,onOpen:y=>fe(y,"list"),onReload:n}):s(O,{padded:true,children:s(h,{style:p.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."})}),$.length>0?s(O,{children:f(P,{testID:"permissions-other",accessibilityRole:"button",accessibilityLabel:`Other Permissions, ${$.length}`,activeOpacity:.6,onPress:()=>m({name:"other"}),style:p.row,children:[s(h,{style:p.rowTitle,children:"Other Permissions"}),f(g,{style:p.rowRight,children:[s(h,{style:p.rowValue,children:$.length}),s(Ve,{size:16,color:a.color.textTertiary})]})]})}):null,e.overriddenCount>0?s(O,{children:s(P,{testID:"permissions-reset",accessibilityRole:"button",accessibilityLabel:"Use Real Permissions",activeOpacity:.6,onPress:()=>d("resetAll"),style:p.row,children:s(h,{style:p.destructive,children:"Use Real Permissions"})})}):null]}),f(Ae,{style:p.fill,contentContainerStyle:[p.content,{paddingBottom:o.bottom}],testID:"permissions-scroll",children:[!Ze&&c.name!=="list"?f(P,{testID:"permissions-back",accessibilityRole:"button",accessibilityLabel:"Back",onPress:S,style:p.inlineBack,children:[s(io,{size:18,color:a.color.accent}),s(h,{style:p.inlineBackText,children:c.name==="detail"&&c.from==="other"?"Other Permissions":"Permissions"}),D?s(h,{style:p.inlineTitle,children:D}):null]}):null,i?s(N,{tone:"danger",centered:true,children:s(h,{testID:"permissions-error",children:i})}):null,z]})}function Ke({rows:e,platform:t,onOpen:n,onReload:o}){let[,i]=no(d=>d+1,0),l=ao(),c=e.filter(d=>d.stale&&d.changedAt!==null&&l-d.changedAt<pe).map(d=>pe-(l-d.changedAt)),m=c.length>0?Math.min(...c):null;return to(()=>{if(m===null)return;let d=setTimeout(i,m+50);return()=>clearTimeout(d)},[m]),s(O,{children:s(ue,{children:e.map(d=>{let u=d.stale&&d.changedAt!==null&&l-d.changedAt>=pe;return f(g,{children:[s(co,{row:d,platform:t,onPress:()=>n(d.id)}),u?f(g,{style:p.stale,testID:`permissions-stale-${d.id}`,children:[s(h,{style:p.staleText,children:"The app hasn't checked again since this changed."}),o?s(P,{testID:`permissions-reload-${d.id}`,accessibilityRole:"button",accessibilityLabel:"Reload App",onPress:o,hitSlop:{top:8,bottom:8,left:8,right:8},children:s(h,{style:p.staleAction,children:"Reload App"})}):null]}):null]},d.id)})})})}function co({row:e,platform:t,onPress:n}){let o=e.override!==null,i=lo(e,t),l=e.real?k(e.id,t,e.real):"Not Checked";return f(P,{testID:`permissions-row-${e.id}`,accessibilityRole:"button",accessibilityLabel:`${e.label}: ${i}${o?`, simulated. Phone: ${l}`:""}`,activeOpacity:.6,onPress:n,style:p.row,children:[f(g,{style:p.rowLeft,children:[s(h,{style:p.rowTitle,children:e.label}),o?f(h,{style:p.rowSub,testID:`permissions-phone-${e.id}`,children:["Phone: ",l]}):null]}),f(g,{style:p.rowRight,children:[o?s(g,{style:p.dot}):null,s(h,{style:[p.rowValue,o?p.rowValueSimulated:null],testID:`permissions-value-${e.id}`,numberOfLines:1,children:i}),s(Ve,{size:16,color:a.color.textTertiary})]})]})}function Ge({title:e,detail:t,selected:n,testID:o,onPress:i}){return f(P,{testID:o,accessibilityRole:"button",accessibilityLabel:`${e}. ${t}`,accessibilityState:{selected:n},activeOpacity:.6,onPress:i,style:p.option,children:[f(g,{style:p.optionText,children:[s(h,{style:p.rowTitle,children:e}),s(h,{style:p.optionDetail,children:t})]}),s(g,{style:p.check,children:n?s(oo,{size:18,color:a.color.accent}):null})]})}var uo={check:"Checked",request:"Asked",settings:"Opened Settings",gated:"Needed it"};function po({row:e,platform:t,log:n,run:o,onPicked:i}){let l=e.real?k(e.id,t,e.real):null,c=u=>{u===null?o("clearOverride",{permission:e.id}):o("setOverride",{permission:e.id,state:u}),i()},m=n.filter(u=>u.permission===e.id).slice(0,8),d=e.canRequestReal&&e.real==="undetermined";return f(Fe,{children:[f(g,{children:[s(Ue,{children:"What the app sees"}),s(O,{children:f(ue,{children:[s(Ge,{title:"Phone's Setting",detail:l?`Use what the phone says: ${l}.`:"Use what the phone says.",selected:e.override===null,testID:`permissions-state-${e.id}-real`,onPress:()=>c(null)},"real"),e.states.map(u=>s(Ge,{title:k(e.id,t,u),detail:hn(e.id,t,u),selected:e.override===u,testID:`permissions-state-${e.id}-${u}`,onPress:()=>c(u)},u))]})})]}),d?f(g,{children:[s(O,{children:s(P,{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:p.row,children:s(h,{style:p.action,children:"Show Real Prompt"})})}),s(N,{children:e.warning??"Asks the phone for real, so calls that need this permission work."})]}):e.warning?s(N,{tone:"warning",children:s(h,{testID:`permissions-warning-${e.id}`,children:e.warning})}):null,m.length>0?f(g,{children:[s(Ue,{children:"Recent"}),s(O,{children:s(ue,{children:m.map(u=>s(ho,{entry:u,platform:t},u.id))})}),e.sources.length>0?f(N,{children:["Read through ",e.sources.join(", ")]}):null]}):null]})}function mo(e){let t=new Date(e),n=o=>String(o).padStart(2,"0");return`${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`}function ho({entry:e,platform:t}){let n=e.error?"Failed":e.returned&&e.permission?e.answer==="once"&&e.returned==="granted"?"Allowed Once":k(e.permission,t,e.returned):"";return f(g,{style:p.recentRow,testID:`permissions-log-${e.id}`,children:[s(h,{style:p.recentTime,children:mo(e.at)}),s(h,{style:p.recentVerb,numberOfLines:1,children:uo[e.kind]}),s(h,{style:[p.recentResult,e.error?p.recentFailed:null],numberOfLines:1,children:n})]})}var p=j.create({fill:{flex:1},content:{paddingHorizontal:a.gutter,paddingTop:12,gap:a.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},empty:{color:a.color.textSecondary,fontSize:a.font.body,lineHeight:20},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:a.rowPadH,paddingVertical:10},rowLeft:{flexShrink:1,gap:2},rowTitle:{color:a.color.text,fontSize:a.font.row},rowSub:{color:a.color.textTertiary,fontSize:a.font.caption},rowRight:{flexDirection:"row",alignItems:"center",gap:6,flexShrink:1},rowValue:{color:a.color.textSecondary,fontSize:a.font.row},rowValueSimulated:{color:a.color.accent},dot:{width:7,height:7,borderRadius:4,backgroundColor:a.color.accent},stale:{flexDirection:"row",alignItems:"center",flexWrap:"wrap",columnGap:10,rowGap:4,paddingHorizontal:a.rowPadH,paddingBottom:12,marginTop:-4},staleText:{color:a.color.textSecondary,fontSize:a.font.caption,flexShrink:1},staleAction:{color:a.color.accent,fontSize:a.font.caption,fontWeight:"600"},destructive:{color:a.color.danger,fontSize:a.font.row},action:{color:a.color.accent,fontSize:a.font.row},option:{flexDirection:"row",alignItems:"center",gap:12,paddingHorizontal:a.rowPadH,paddingVertical:11,minHeight:50},optionText:{flex:1,gap:2},optionDetail:{color:a.color.textTertiary,fontSize:a.font.caption,lineHeight:17},check:{width:20,alignItems:"center"},inlineBack:{flexDirection:"row",alignItems:"center",gap:4,marginBottom:-8},inlineBackText:{color:a.color.accent,fontSize:a.font.row},inlineTitle:{color:a.color.text,fontSize:a.font.row,fontWeight:"600",marginLeft:"auto"},recentRow:{flexDirection:"row",alignItems:"center",gap:12,paddingHorizontal:a.rowPadH,paddingVertical:10},recentTime:{color:a.color.textTertiary,fontSize:a.font.caption,fontVariant:["tabular-nums"]},recentVerb:{color:a.color.text,fontSize:a.font.body,flex:1},recentResult:{color:a.color.textSecondary,fontSize:a.font.body},recentFailed:{color:a.color.danger}});import{jsx as fo}from"react/jsx-runtime";var go=je.actions;async function yo(e,t){let n=go[e];if(!n)throw new Error(`Unknown permissions action: ${e}`);return n(t)}function bo(){Un("auto","buoy permissions").catch(()=>{})}function Ye(){Hn(()=>{Q(),$e()},[]);let e=Vn(M,b,b);return fo(We,{snapshot:e,onAction:yo,onReload:bo})}import{jsx as wo}from"react/jsx-runtime";var Je=jn({id:"permissions",name:"PERMISSIONS",description:"Test denied, blocked, limited and not-asked permission states",slot:"both",color:$n,icon:({size:e,color:t})=>wo(Bn,{size:e,color:t}),component:Ye,modal:{subtitle:"choose what the app is allowed to do"}}),vo=zn(Je);import{PermissionsIcon as Ao,PERMISSIONS_ICON_COLOR as So}from"@buoy-gg/shared-ui/web";var Po=typeof navigator<"u"&&navigator.product==="ReactNative";Po&&typeof be<"u"&&be&&(Q(),Mn());export{ne as KNOWN_PERMISSION_IDS,F as PERMISSIONS_CHIP_ID,So as PERMISSIONS_ICON_COLOR,ee as PERMISSION_STATES,Ye as PermissionsBody,Me as PermissionsChip,Ao as PermissionsIcon,We as PermissionsToolView,Ne as clearPermissionOverride,vo as createPermissionsTool,xn as getPermissionOverride,b as getPermissionsSnapshot,Q as installPermissions,Rn as isPermissionOverridden,Dn as openPermissionsChip,R as permissionInfo,je as permissionsSyncAdapter,Je as permissionsToolPreset,re as resetPermissions,Ee as setPermissionOverride,k as stateLabel,M as subscribePermissions,H as supportedStates,De as updatePermissionSettings};
package/package.json ADDED
@@ -0,0 +1,110 @@
1
+ {
2
+ "name": "@buoy-gg/permissions",
3
+ "version": "7.0.44",
4
+ "description": "Permission state overrides for React Native: make your app see not asked, allowed, limited, denied or blocked for location, camera, notifications and more, without touching device settings. Works with Expo modules, PermissionsAndroid and react-native-permissions.",
5
+ "main": "lib/commonjs/index.js",
6
+ "module": "lib/module/index.js",
7
+ "types": "lib/typescript/index.d.ts",
8
+ "react-native": "lib/module/index.js",
9
+ "source": "src/index.tsx",
10
+ "files": [
11
+ "lib"
12
+ ],
13
+ "sideEffects": [
14
+ "./src/index.tsx",
15
+ "./lib/commonjs/index.js",
16
+ "./lib/module/index.js",
17
+ "./lib/web/**/*.mjs"
18
+ ],
19
+ "dependencies": {
20
+ "@buoy-gg/shared-ui": "^7.0.44"
21
+ },
22
+ "peerDependencies": {
23
+ "react": "*"
24
+ },
25
+ "devDependencies": {
26
+ "@types/react": "^19.1.0",
27
+ "@types/react-native": "^0.73.0",
28
+ "typescript": "~5.8.3"
29
+ },
30
+ "react-native-builder-bob": {
31
+ "source": "src",
32
+ "output": "lib",
33
+ "targets": [
34
+ "commonjs",
35
+ "module",
36
+ [
37
+ "typescript",
38
+ {
39
+ "project": "tsconfig.build.json"
40
+ }
41
+ ]
42
+ ]
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/Buoy-gg/buoy.git",
47
+ "directory": "packages/permissions"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/LovesWorking/react-native-buoy/issues"
51
+ },
52
+ "homepage": "https://buoy.gg/buoy/latest/docs/tools/permissions",
53
+ "publishConfig": {
54
+ "access": "public",
55
+ "tag": "latest"
56
+ },
57
+ "keywords": [
58
+ "react-native",
59
+ "expo",
60
+ "devtools",
61
+ "debugging",
62
+ "react-native-devtools",
63
+ "permissions",
64
+ "expo-location",
65
+ "expo-camera",
66
+ "expo-notifications",
67
+ "react-native-permissions",
68
+ "PermissionsAndroid",
69
+ "testing"
70
+ ],
71
+ "exports": {
72
+ ".": {
73
+ "browser": {
74
+ "types": "./lib/typescript/index.d.ts",
75
+ "default": "./lib/web/index.mjs"
76
+ },
77
+ "import": {
78
+ "types": "./lib/typescript/index.d.ts",
79
+ "default": "./lib/module/index.js"
80
+ },
81
+ "require": {
82
+ "types": "./lib/typescript/index.d.ts",
83
+ "default": "./lib/commonjs/index.js"
84
+ }
85
+ },
86
+ "./web": {
87
+ "types": "./lib/typescript/index.d.ts",
88
+ "default": "./lib/web/index.mjs"
89
+ }
90
+ },
91
+ "peerDependenciesMeta": {
92
+ "react-native": {
93
+ "optional": true
94
+ },
95
+ "react-native-web": {
96
+ "optional": true
97
+ },
98
+ "react-dom": {
99
+ "optional": true
100
+ }
101
+ },
102
+ "scripts": {
103
+ "build": "bob build && pnpm run build:web",
104
+ "typecheck": "tsc --noEmit",
105
+ "clean": "rimraf lib",
106
+ "test": "pnpm run typecheck",
107
+ "postinstall": "echo \"Run pnpm build to compile this package\"",
108
+ "build:web": "node ../../scripts/build-web.mjs permissions"
109
+ }
110
+ }