@buoy-gg/lifecycle 7.0.56 → 7.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/LifecycleToolView.js +1 -1
- package/lib/commonjs/engine/lifecycleStore.js +1 -1
- package/lib/commonjs/engine/native.js +1 -1
- package/lib/commonjs/engine/native.web.js +1 -0
- package/lib/commonjs/engine/readSavedSync.web.js +1 -1
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/sync/lifecycleSyncAdapter.js +1 -1
- package/lib/module/components/LifecycleToolView.js +1 -1
- package/lib/module/engine/lifecycleStore.js +1 -1
- package/lib/module/engine/native.js +1 -1
- package/lib/module/engine/native.web.js +1 -0
- package/lib/module/engine/readSavedSync.web.js +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/sync/lifecycleSyncAdapter.js +1 -1
- package/lib/typescript/engine/lifecycleStore.d.ts +5 -0
- package/lib/typescript/engine/native.d.ts +28 -0
- package/lib/typescript/engine/native.web.d.ts +80 -0
- package/lib/typescript/engine/readSavedSync.web.d.ts +7 -2
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/sync/lifecycleSyncAdapter.d.ts +2 -2
- package/lib/web/index.mjs +1 -1
- package/package.json +5 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.LifecycleToolView=LifecycleToolView;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _format=require("./format");var _jsxRuntime=require("react/jsx-runtime");const LIME="#A3E635";const DURATIONS=[{key:"hold",label:"No limit"},{key:"5000",label:"5 s"},{key:"60000",label:"1 min"},{key:"300000",label:"5 min"},{key:"1800000",label:"30 min"}];const SKIP_FROM_MS=6e4;function useNow(e){const[n,t]=(0,_react.useState)(()=>(0,_sharedUi.realNow)());(0,_react.useEffect)(()=>{if(!e)return void 0;const i=setInterval(()=>t((0,_sharedUi.realNow)()),1e3);return()=>clearInterval(i)},[e]);return e?n:(0,_sharedUi.realNow)()}function LifecycleToolView({snapshot:e,onAction:n}){const t=(0,_sharedUi.useSafeAreaInsets)({minBottom:16});const i=(0,_react.useRef)(null);const[l,r]=(0,_react.useState)(null);const o=(a,s)=>{r(null);i.current?.scrollTo({y:0,animated:true});n(a,s).catch(c=>{r(c instanceof Error?c.message:String(c))})};if(!e){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.waiting,testID:"lifecycle-waiting",children:(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{centered:true,children:"Waiting for the app\u2026"})})}return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{ref:i,style:styles.fill,contentContainerStyle:[styles.content,{paddingBottom:t.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[(0,_jsxRuntime.jsx)(StatusArea,{snapshot:e,run:o}),l?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"danger",centered:true,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"lifecycle-error",children:l})}):null,(0,_jsxRuntime.jsx)(MomentsSection,{snapshot:e,run:o}),(0,_jsxRuntime.jsx)(CustomSection,{snapshot:e,run:o})]})}function StatusArea({snapshot:e,run:n}){const t=(0,_format.simulatedLine)(e);let i;if(e.away)i=(0,_jsxRuntime.jsx)(RunningCard,{snapshot:e,run:n});else if(e.relaunch)i=(0,_jsxRuntime.jsx)(RelaunchResult,{snapshot:e,run:n});else if(e.report)i=(0,_jsxRuntime.jsx)(ReportResult,{snapshot:e,run:n});else{i=(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."})}return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.status,children:[i,t&&!e.away?(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.row,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.simulatedLabel,children:"Simulated"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,testID:"lifecycle-simulated",children:t})]}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Stop Simulating",size:"md",fullWidth:false,testID:"lifecycle-reset",accessibilityLabel:"End every simulation",onPress:()=>n("reset")})]})}):null]})}function RunningCard({snapshot:e,run:n}){const t=useNow(true);const i=e.away;const l=(0,_format.awayTitle)(i.kind,e.platform==="android");const r=e.report;const o=r?r.events.filter(a=>a.whileAway):[];return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.running,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${l} (simulated)`,children:l}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.runningTimer,testID:"lifecycle-hero-status",children:(0,_format.awayTimer)(e,t)}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.runningButton,children:(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>n("returnToApp")})}),r?.finding?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.runningWarning,testID:"lifecycle-report-finding",children:r.finding}):o.length>0?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.runningNote,children:["So far: ",(0,_format.countsLine)(o)]}):null]})}function VerdictHeader({verdict:e}){const n=e.tone==="warn"?_sharedUi.night.color.warning:e.tone==="good"?_sharedUi.night.color.accent:_sharedUi.night.color.text;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.verdict,children:[e.tone==="warn"?(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:20,color:n}):e.tone==="good"?(0,_jsxRuntime.jsx)(_sharedUi.CheckCircle,{size:20,color:n}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.verdictTitle,{color:n}],testID:"lifecycle-verdict",children:e.title}),e.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.verdictDetail,testID:"lifecycle-report-finding",children:e.detail}):null]})]})}const PREVIEW_ROWS=5;function ReportResult({snapshot:e,run:n}){const t=e.report;const i=t.collectingUntil!=null;const l=useNow(i);const[r,o]=(0,_react.useState)(false);const a=(0,_format.verdict)(e,t);const s=t.events.filter(h=>h.whileAway);const c=t.events.filter(h=>!h.whileAway);const d=t.kind!=="signal";const u=i?Math.max(0,(t.collectingUntil??l)-l):0;return(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.result,testID:"lifecycle-report",children:[(0,_jsxRuntime.jsx)(VerdictHeader,{verdict:a}),d||i?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.resultLabel,testID:"lifecycle-report-label",children:d?`${t.label}${i?` \xB7 watching ${Math.ceil(u/1e3)} s`:""}`:`Watching ${Math.ceil(u/1e3)} s`}):null,t.unavailable?null:t.events.length===0?i?null:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[d&&s.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:"While away",events:s,showAll:r}):null,c.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:d?"After returning":"What your app did",events:c,showAll:r}):null,!d&&s.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:"What your app did",events:s,showAll:r}):null]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.resultButtons,children:[(0,_format.groupEvents)(t.events).length>PREVIEW_ROWS?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>o(h=>!h),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:r?"Show Less":"Show All"})}):(0,_jsxRuntime.jsx)(_reactNative.View,{}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>n("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:"Done"})})]})]})})}function EventGroupList({title:e,events:n,showAll:t}){const i=(0,_format.groupEvents)(n);const l=t?i:i.slice(0,PREVIEW_ROWS);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.eventList,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventHeading,children:`${e} \xB7 ${(0,_format.countsLine)(n)}`}),l.map(r=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.event,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventSource,children:(0,_format.sourceLabel)(r.source)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.eventTitle,r.error?styles.eventError:null],numberOfLines:1,children:r.title}),r.count>1?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventCount,children:`\xD7${r.count}`}):null]},`${r.source}-${r.title}`)),i.length>l.length?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,children:`${i.length-l.length} more`}):null]})}const screenName=e=>e==="/"?"the home screen":e;function RelaunchResult({snapshot:e,run:n}){const t=e.relaunch;const i=t.after==null&&t.restored==null&&t.tookMs==null;const l=i?{tone:"neutral",title:"Checking where your app reopened\u2026"}:t.restored===true?{tone:"good",title:`Reopened where you were: ${screenName(t.after)}`}:t.after?{tone:"warn",title:`Opened ${screenName(t.after)} instead of ${screenName(t.before)??"the screen you were on"}`,detail:"The app doesn't restore the last screen after it's closed."}:{tone:"neutral",title:"Couldn't read the screen after reopening"};return(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.result,testID:"lifecycle-relaunch-report",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{testID:"lifecycle-relaunch-result",children:(0,_jsxRuntime.jsx)(VerdictHeader,{verdict:l})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.resultButtons,children:[t.restored===false&&t.beforeHref?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>n("goBackToBeforeRelaunch"),testID:"lifecycle-relaunch-go-back",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:`Go to ${screenName(t.before)}`})}):(0,_jsxRuntime.jsx)(_reactNative.View,{}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>n("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:"Done"})})]})]})})}function MomentsSection({snapshot:e,run:n}){const t=e.host?.appScheme;const[i,l]=(0,_react.useState)(t?`${t}://`:"");const r=e.batteryLibraries.length>0;const o=e.recipes.filter(s=>s.id!=="dying-battery"||r);const a=e.away!=null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Test a moment"}),(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_sharedUi.NightRows,{children:[o.map(s=>(0,_jsxRuntime.jsx)(MomentRow,{recipe:s,disabled:a,onPress:()=>n("runRecipe",{id:s.id})},s.id)),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stack,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Open a link"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inputRow,children:[(0,_jsxRuntime.jsx)(_reactNative.TextInput,{testID:"lifecycle-url-input",accessibilityLabel:"Link to open",value:i,onChangeText:l,placeholder:"myapp://orders/42",placeholderTextColor:_sharedUi.night.color.placeholder,autoCapitalize:"none",autoCorrect:false,keyboardType:"url",returnKeyType:"go",onSubmitEditing:()=>n("openUrl",{url:i}),style:styles.input}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Open",size:"md",fullWidth:false,testID:"lifecycle-url-open",accessibilityLabel:"Open this link in the app",onPress:()=>n("openUrl",{url:i})})]}),e.listeners.deepLink===0?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.warning,children:"Nothing in your app listens for links."}):null]},"link")]})})]})}function MomentRow({recipe:e,disabled:n,onPress:t}){const i=n||!!e.unavailable;return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:`lifecycle-recipe-${e.id}`,accessibilityRole:"button",accessibilityLabel:e.title,accessibilityHint:e.unavailable??e.detail,accessibilityState:{disabled:i},disabled:i,activeOpacity:.6,onPress:t,style:[styles.row,i?styles.rowDisabled:null],children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:e.title}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,children:e.unavailable??e.detail})]}),e.unavailable?null:(0,_jsxRuntime.jsx)(_sharedUi.Play,{size:16,color:_sharedUi.night.color.accent})]})}function CustomSection({snapshot:e,run:n}){const[t,i]=(0,_react.useState)(false);const l=t?_sharedUi.ChevronDown:_sharedUi.ChevronRight;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:t},onPress:()=>i(r=>!r),style:styles.disclosure,hitSlop:8,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.disclosureText,children:"Custom"}),(0,_jsxRuntime.jsx)(l,{size:16,color:_sharedUi.night.color.textSecondary})]}),t?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.customBody,children:[(0,_jsxRuntime.jsx)(LeaveCard,{snapshot:e,run:n}),(0,_jsxRuntime.jsx)(SignalsCard,{snapshot:e,run:n}),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Only your app's JavaScript hears these events. Timers, requests and native code keep running, and a real event from the OS ends the simulation."})]}):null]})}function LeaveCard({snapshot:e,run:n}){const[t,i]=(0,_react.useState)("hold");const l=t==="hold"?null:Number(t);const r=l!=null&&l>=SKIP_FROM_MS;const o=r&&e.clockAvailable;const a=()=>({durationMs:l,skipWait:o});const s=e.platform==="android";const c=e.away!=null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Leave the app"}),(0,_jsxRuntime.jsxs)(_sharedUi.NightCard,{children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.segmentWrap,children:(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:DURATIONS,activeKey:t,size:"sm",testIDPrefix:"lifecycle-duration",onChange:i})}),(0,_jsxRuntime.jsxs)(_sharedUi.NightRows,{children:[(0,_jsxRuntime.jsx)(ActionRow,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:c,onPress:()=>n("background",a())},"background"),(0,_jsxRuntime.jsx)(ActionRow,{title:s?"Pull Down Notifications":"Take a Call",detail:s?"The app stays visible but loses focus":"The app stays visible but inactive, like with Control Center open",testID:"lifecycle-interrupt",disabled:c,onPress:()=>n("interrupt",a())},"interrupt")]})]}),r?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:e.clockAvailable?"Moves the app clock forward instead of waiting.":"Waits in real time. Install @buoy-gg/clock to skip the wait."}):null,e.listeners.appState===0?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"warning",children:"Nothing in your app listens for app state changes."}):null]})}const BATTERY_LEVELS=[{key:"real",label:"Real"},{key:"100",label:"100%"},{key:"20",label:"20%"},{key:"5",label:"5%"}];function SignalsCard({snapshot:e,run:n}){const t=e.platform==="android";const i=e.batteryLibraries.length>0;const l=e.power;const r=e.listeners.memoryWarning===0?"Nothing in your app listens for it":t?"Android never sends this, but your listeners will run":void 0;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Signals"}),(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_sharedUi.NightRows,{children:[(0,_jsxRuntime.jsx)(ActionRow,{title:"Send Memory Warning",detail:r,warn:e.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>n("memoryWarning")},"memory"),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stack,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Appearance"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:[{key:"system",label:"System"},{key:"light",label:"Light"},{key:"dark",label:"Dark"}],activeKey:e.scheme?.scheme??"system",size:"sm",testIDPrefix:"lifecycle-scheme",onChange:o=>n("setColorScheme",{scheme:o})})]},"scheme"),i?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stack,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Battery"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:BATTERY_LEVELS,activeKey:l?String(Math.round(l.level*100)):"real",size:"sm",testIDPrefix:"lifecycle-battery",onChange:o=>o==="real"?n("resetPower"):n("setPower",{level:Number(o)/100})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Charging"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSwitch,{value:l?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:o=>n("setPower",{state:o?"charging":"unplugged"})})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Low Power Mode"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSwitch,{value:l?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:o=>n("setPower",{lowPowerMode:o})})]}),e.listeners.battery===0?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.warning,children:"Nothing in your app listens for battery changes."}):null]},"battery"):null,t?(0,_jsxRuntime.jsx)(ActionRow,{title:"Press Back",detail:"Never closes the app. The result says if a real press would have.",testID:"lifecycle-back",onPress:()=>n("pressBack")},"back"):null]})}),i?null:(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Battery needs expo-battery or react-native-device-info in your app."})]})}function ActionRow({title:e,detail:n,warn:t,testID:i,disabled:l,onPress:r}){return(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:i,accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{disabled:!!l},activeOpacity:.6,disabled:l,onPress:r,style:[styles.row,l?styles.rowDisabled:null],children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionTitle,children:e}),n?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:t?styles.warning:styles.detail,children:n}):null]})})}const styles=_reactNative.StyleSheet.create({fill:{flex:1},content:{paddingHorizontal:_sharedUi.night.gutter,paddingTop:8,gap:_sharedUi.night.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},status:{gap:12},intro:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body,lineHeight:20,paddingHorizontal:_sharedUi.night.labelInset,paddingTop:4},running:{alignItems:"center",paddingTop:12,gap:6},runningTitle:{color:LIME,fontSize:30,fontWeight:"300"},runningTimer:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.row,fontWeight:"500",fontVariant:["tabular-nums"]},runningButton:{alignSelf:"stretch",marginTop:10},runningWarning:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption,textAlign:"center",marginTop:4},runningNote:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,textAlign:"center",marginTop:4},simulatedLabel:{color:LIME,fontSize:_sharedUi.night.font.micro,fontWeight:"600",textTransform:"uppercase",letterSpacing:.4},result:{paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:14,gap:12},verdict:{flexDirection:"row",gap:10,alignItems:"flex-start"},verdictTitle:{fontSize:_sharedUi.night.font.title,fontWeight:"600"},verdictDetail:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:18},resultLabel:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,fontVariant:["tabular-nums"]},resultButtons:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},link:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.row,fontWeight:"500"},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:10},rowText:{flex:1,gap:2},rowDisabled:{opacity:.4},rowTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row},actionTitle:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.row},detail:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption},warning:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption},stack:{paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:12,gap:10},segmentWrap:{paddingHorizontal:_sharedUi.night.rowPadH,paddingTop:12,paddingBottom:4},inlineRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},inputRow:{flexDirection:"row",alignItems:"center",gap:8},input:{flex:1,color:_sharedUi.night.color.text,fontFamily:_sharedUi.monoFont,fontSize:14,backgroundColor:_sharedUi.night.color.bg,borderRadius:_sharedUi.night.radius.input,borderWidth:1,borderColor:_sharedUi.night.color.border,paddingHorizontal:12,paddingVertical:8},disclosure:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:_sharedUi.night.labelInset},disclosureText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.label,fontWeight:"600",textTransform:"uppercase",letterSpacing:.8},customBody:{gap:_sharedUi.night.groupGap,marginTop:12},eventList:{gap:6},eventHeading:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},event:{flexDirection:"row",gap:8,alignItems:"baseline"},eventSource:{width:56,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption},eventTitle:{flex:1,color:_sharedUi.night.color.text,fontSize:13,fontFamily:_sharedUi.monoFont},eventError:{color:_sharedUi.night.color.danger},eventCount:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600",fontVariant:["tabular-nums"]}});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.LifecycleToolView=LifecycleToolView;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _format=require("./format");var _jsxRuntime=require("react/jsx-runtime");const LIME="#A3E635";const DURATIONS=[{key:"hold",label:"No limit"},{key:"5000",label:"5 s"},{key:"60000",label:"1 min"},{key:"300000",label:"5 min"},{key:"1800000",label:"30 min"}];const SKIP_FROM_MS=6e4;function useNow(e){const[n,t]=(0,_react.useState)(()=>(0,_sharedUi.realNow)());(0,_react.useEffect)(()=>{if(!e)return void 0;const i=setInterval(()=>t((0,_sharedUi.realNow)()),1e3);return()=>clearInterval(i)},[e]);return e?n:(0,_sharedUi.realNow)()}function LifecycleToolView({snapshot:e,onAction:n}){const t=(0,_sharedUi.useSafeAreaInsets)({minBottom:16});const i=(0,_react.useRef)(null);const[l,r]=(0,_react.useState)(null);const o=(a,s)=>{r(null);i.current?.scrollTo({y:0,animated:true});n(a,s).catch(c=>{r(c instanceof Error?c.message:String(c))})};if(!e){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.waiting,testID:"lifecycle-waiting",children:(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{centered:true,children:"Waiting for the app\u2026"})})}return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{ref:i,style:styles.fill,contentContainerStyle:[styles.content,{paddingBottom:t.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[(0,_jsxRuntime.jsx)(StatusArea,{snapshot:e,run:o}),l?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"danger",centered:true,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"lifecycle-error",children:l})}):null,(0,_jsxRuntime.jsx)(MomentsSection,{snapshot:e,run:o}),(0,_jsxRuntime.jsx)(CustomSection,{snapshot:e,run:o})]})}function StatusArea({snapshot:e,run:n}){const t=(0,_format.simulatedLine)(e);let i;if(e.away)i=(0,_jsxRuntime.jsx)(RunningCard,{snapshot:e,run:n});else if(e.relaunch)i=(0,_jsxRuntime.jsx)(RelaunchResult,{snapshot:e,run:n});else if(e.report)i=(0,_jsxRuntime.jsx)(ReportResult,{snapshot:e,run:n});else{i=(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."})}return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.status,children:[i,t&&!e.away?(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.row,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.simulatedLabel,children:"Simulated"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,testID:"lifecycle-simulated",children:t})]}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Stop Simulating",size:"md",fullWidth:false,testID:"lifecycle-reset",accessibilityLabel:"End every simulation",onPress:()=>n("reset")})]})}):null]})}function RunningCard({snapshot:e,run:n}){const t=useNow(true);const i=e.away;const l=(0,_format.awayTitle)(i.kind,e.platform==="android");const r=e.report;const o=r?r.events.filter(a=>a.whileAway):[];return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.running,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${l} (simulated)`,children:l}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.runningTimer,testID:"lifecycle-hero-status",children:(0,_format.awayTimer)(e,t)}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.runningButton,children:(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>n("returnToApp")})}),r?.finding?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.runningWarning,testID:"lifecycle-report-finding",children:r.finding}):o.length>0?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.runningNote,children:["So far: ",(0,_format.countsLine)(o)]}):null]})}function VerdictHeader({verdict:e}){const n=e.tone==="warn"?_sharedUi.night.color.warning:e.tone==="good"?_sharedUi.night.color.accent:_sharedUi.night.color.text;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.verdict,children:[e.tone==="warn"?(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:20,color:n}):e.tone==="good"?(0,_jsxRuntime.jsx)(_sharedUi.CheckCircle,{size:20,color:n}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.verdictTitle,{color:n}],testID:"lifecycle-verdict",children:e.title}),e.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.verdictDetail,testID:"lifecycle-report-finding",children:e.detail}):null]})]})}const PREVIEW_ROWS=5;function ReportResult({snapshot:e,run:n}){const t=e.report;const i=t.collectingUntil!=null;const l=useNow(i);const[r,o]=(0,_react.useState)(false);const a=(0,_format.verdict)(e,t);const s=t.events.filter(h=>h.whileAway);const c=t.events.filter(h=>!h.whileAway);const d=t.kind!=="signal";const u=i?Math.max(0,(t.collectingUntil??l)-l):0;return(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.result,testID:"lifecycle-report",children:[(0,_jsxRuntime.jsx)(VerdictHeader,{verdict:a}),d||i?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.resultLabel,testID:"lifecycle-report-label",children:d?`${t.label}${i?` \xB7 watching ${Math.ceil(u/1e3)} s`:""}`:`Watching ${Math.ceil(u/1e3)} s`}):null,t.unavailable?null:t.events.length===0?i?null:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[d&&s.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:"While away",events:s,showAll:r}):null,c.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:d?"After returning":"What your app did",events:c,showAll:r}):null,!d&&s.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:"What your app did",events:s,showAll:r}):null]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.resultButtons,children:[(0,_format.groupEvents)(t.events).length>PREVIEW_ROWS?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>o(h=>!h),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:r?"Show Less":"Show All"})}):(0,_jsxRuntime.jsx)(_reactNative.View,{}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>n("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:"Done"})})]})]})})}function EventGroupList({title:e,events:n,showAll:t}){const i=(0,_format.groupEvents)(n);const l=t?i:i.slice(0,PREVIEW_ROWS);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.eventList,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventHeading,children:`${e} \xB7 ${(0,_format.countsLine)(n)}`}),l.map(r=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.event,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventSource,children:(0,_format.sourceLabel)(r.source)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.eventTitle,r.error?styles.eventError:null],numberOfLines:1,children:r.title}),r.count>1?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventCount,children:`\xD7${r.count}`}):null]},`${r.source}-${r.title}`)),i.length>l.length?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,children:`${i.length-l.length} more`}):null]})}const screenName=e=>e==="/"?"the home screen":e;function RelaunchResult({snapshot:e,run:n}){const t=e.relaunch;const i=t.after==null&&t.restored==null&&t.tookMs==null;const l=i?{tone:"neutral",title:"Checking where your app reopened\u2026"}:t.restored===true?{tone:"good",title:`Reopened where you were: ${screenName(t.after)}`}:t.after?{tone:"warn",title:`Opened ${screenName(t.after)} instead of ${screenName(t.before)??"the screen you were on"}`,detail:"The app doesn't restore the last screen after it's closed."}:{tone:"neutral",title:"Couldn't read the screen after reopening"};return(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.result,testID:"lifecycle-relaunch-report",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{testID:"lifecycle-relaunch-result",children:(0,_jsxRuntime.jsx)(VerdictHeader,{verdict:l})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.resultButtons,children:[t.restored===false&&t.beforeHref?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>n("goBackToBeforeRelaunch"),testID:"lifecycle-relaunch-go-back",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:`Go to ${screenName(t.before)}`})}):(0,_jsxRuntime.jsx)(_reactNative.View,{}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>n("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.link,children:"Done"})})]})]})})}function MomentsSection({snapshot:e,run:n}){const t=e.host?.appScheme;const[i,l]=(0,_react.useState)(t?`${t}://`:"");const r=e.batteryLibraries.length>0;const o=e.recipes.filter(s=>s.id!=="dying-battery"||r);const a=e.away!=null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Test a moment"}),(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_sharedUi.NightRows,{children:[o.map(s=>(0,_jsxRuntime.jsx)(MomentRow,{recipe:s,disabled:a,onPress:()=>n("runRecipe",{id:s.id})},s.id)),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stack,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Open a link"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inputRow,children:[(0,_jsxRuntime.jsx)(_reactNative.TextInput,{testID:"lifecycle-url-input",accessibilityLabel:"Link to open",value:i,onChangeText:l,placeholder:"myapp://orders/42",placeholderTextColor:_sharedUi.night.color.placeholder,autoCapitalize:"none",autoCorrect:false,keyboardType:"url",returnKeyType:"go",onSubmitEditing:()=>n("openUrl",{url:i}),style:styles.input}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Open",size:"md",fullWidth:false,testID:"lifecycle-url-open",accessibilityLabel:"Open this link in the app",onPress:()=>n("openUrl",{url:i})})]}),e.listeners.deepLink===0?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.warning,children:"Nothing in your app listens for links."}):null]},"link")]})})]})}function MomentRow({recipe:e,disabled:n,onPress:t}){const i=n||!!e.unavailable;return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:`lifecycle-recipe-${e.id}`,accessibilityRole:"button",accessibilityLabel:e.title,accessibilityHint:e.unavailable??e.detail,accessibilityState:{disabled:i},disabled:i,activeOpacity:.6,onPress:t,style:[styles.row,i?styles.rowDisabled:null],children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:e.title}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,children:e.unavailable??e.detail})]}),e.unavailable?null:(0,_jsxRuntime.jsx)(_sharedUi.Play,{size:16,color:_sharedUi.night.color.accent})]})}function CustomSection({snapshot:e,run:n}){const[t,i]=(0,_react.useState)(false);const l=t?_sharedUi.ChevronDown:_sharedUi.ChevronRight;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:t},onPress:()=>i(r=>!r),style:styles.disclosure,hitSlop:8,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.disclosureText,children:"Custom"}),(0,_jsxRuntime.jsx)(l,{size:16,color:_sharedUi.night.color.textSecondary})]}),t?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.customBody,children:[(0,_jsxRuntime.jsx)(LeaveCard,{snapshot:e,run:n}),(0,_jsxRuntime.jsx)(SignalsCard,{snapshot:e,run:n}),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Only your app's JavaScript hears these events. Timers, requests and native code keep running, and a real event from the OS ends the simulation."})]}):null]})}function LeaveCard({snapshot:e,run:n}){const[t,i]=(0,_react.useState)("hold");const l=t==="hold"?null:Number(t);const r=l!=null&&l>=SKIP_FROM_MS;const o=r&&e.clockAvailable;const a=()=>({durationMs:l,skipWait:o});const s=e.platform==="android";const c=e.away!=null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Leave the app"}),(0,_jsxRuntime.jsxs)(_sharedUi.NightCard,{children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.segmentWrap,children:(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:DURATIONS,activeKey:t,size:"sm",testIDPrefix:"lifecycle-duration",onChange:i})}),(0,_jsxRuntime.jsxs)(_sharedUi.NightRows,{children:[(0,_jsxRuntime.jsx)(ActionRow,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:c,onPress:()=>n("background",a())},"background"),(0,_jsxRuntime.jsx)(ActionRow,{title:s?"Pull Down Notifications":"Take a Call",detail:s?"The app stays visible but loses focus":"The app stays visible but inactive, like with Control Center open",testID:"lifecycle-interrupt",disabled:c,onPress:()=>n("interrupt",a())},"interrupt")]})]}),r?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:e.clockAvailable?"Moves the app clock forward instead of waiting.":"Waits in real time. Install @buoy-gg/clock to skip the wait."}):null,e.listeners.appState===0?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"warning",children:"Nothing in your app listens for app state changes."}):null]})}const BATTERY_LEVELS=[{key:"real",label:"Real"},{key:"100",label:"100%"},{key:"20",label:"20%"},{key:"5",label:"5%"}];function SignalsCard({snapshot:e,run:n}){const t=e.platform==="android";const i=e.batteryLibraries.length>0;const l=e.power;const r=e.listeners.memoryWarning===0?"Nothing in your app listens for it":t?"Android never sends this, but your listeners will run":void 0;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Signals"}),(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_sharedUi.NightRows,{children:[(0,_jsxRuntime.jsx)(ActionRow,{title:"Send Memory Warning",detail:r,warn:e.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>n("memoryWarning")},"memory"),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stack,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Appearance"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:[{key:"system",label:"System"},{key:"light",label:"Light"},{key:"dark",label:"Dark"}],activeKey:e.scheme?.scheme??"system",size:"sm",testIDPrefix:"lifecycle-scheme",onChange:o=>n("setColorScheme",{scheme:o})})]},"scheme"),i?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stack,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Battery"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:BATTERY_LEVELS,activeKey:l?String(Math.round(l.level*100)):"real",size:"sm",testIDPrefix:"lifecycle-battery",onChange:o=>o==="real"?n("resetPower"):n("setPower",{level:Number(o)/100})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Charging"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSwitch,{value:l?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:o=>n("setPower",{state:o?"charging":"unplugged"})})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:"Low Power Mode"}),(0,_jsxRuntime.jsx)(_sharedUi.NightSwitch,{value:l?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:o=>n("setPower",{lowPowerMode:o})})]}),e.listeners.battery===0?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.warning,children:"Nothing in your app listens for battery changes."}):null]},"battery"):null,t?(0,_jsxRuntime.jsx)(ActionRow,{title:"Press Back",detail:"Never closes the app. The result says if a real press would have.",testID:"lifecycle-back",onPress:()=>n("pressBack")},"back"):null]})}),i?null:(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Battery needs expo-battery, react-native-device-info or @capacitor/device in your app."})]})}function ActionRow({title:e,detail:n,warn:t,testID:i,disabled:l,onPress:r}){return(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:i,accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{disabled:!!l},activeOpacity:.6,disabled:l,onPress:r,style:[styles.row,l?styles.rowDisabled:null],children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionTitle,children:e}),n?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:t?styles.warning:styles.detail,children:n}):null]})})}const styles=_reactNative.StyleSheet.create({fill:{flex:1},content:{paddingHorizontal:_sharedUi.night.gutter,paddingTop:8,gap:_sharedUi.night.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},status:{gap:12},intro:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body,lineHeight:20,paddingHorizontal:_sharedUi.night.labelInset,paddingTop:4},running:{alignItems:"center",paddingTop:12,gap:6},runningTitle:{color:LIME,fontSize:30,fontWeight:"300"},runningTimer:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.row,fontWeight:"500",fontVariant:["tabular-nums"]},runningButton:{alignSelf:"stretch",marginTop:10},runningWarning:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption,textAlign:"center",marginTop:4},runningNote:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,textAlign:"center",marginTop:4},simulatedLabel:{color:LIME,fontSize:_sharedUi.night.font.micro,fontWeight:"600",textTransform:"uppercase",letterSpacing:.4},result:{paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:14,gap:12},verdict:{flexDirection:"row",gap:10,alignItems:"flex-start"},verdictTitle:{fontSize:_sharedUi.night.font.title,fontWeight:"600"},verdictDetail:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:18},resultLabel:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,fontVariant:["tabular-nums"]},resultButtons:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},link:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.row,fontWeight:"500"},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:10},rowText:{flex:1,gap:2},rowDisabled:{opacity:.4},rowTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row},actionTitle:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.row},detail:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption},warning:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption},stack:{paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:12,gap:10},segmentWrap:{paddingHorizontal:_sharedUi.night.rowPadH,paddingTop:12,paddingBottom:4},inlineRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},inputRow:{flexDirection:"row",alignItems:"center",gap:8},input:{flex:1,color:_sharedUi.night.color.text,fontFamily:_sharedUi.monoFont,fontSize:14,backgroundColor:_sharedUi.night.color.bg,borderRadius:_sharedUi.night.radius.input,borderWidth:1,borderColor:_sharedUi.night.color.border,paddingHorizontal:12,paddingVertical:8},disclosure:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:_sharedUi.night.labelInset},disclosureText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.label,fontWeight:"600",textTransform:"uppercase",letterSpacing:.8},customBody:{gap:_sharedUi.night.groupGap,marginTop:12},eventList:{gap:6},eventHeading:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},event:{flexDirection:"row",gap:8,alignItems:"baseline"},eventSource:{width:56,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption},eventTitle:{flex:1,color:_sharedUi.night.color.text,fontSize:13,fontFamily:_sharedUi.monoFont},eventError:{color:_sharedUi.night.color.danger},eventCount:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600",fontVariant:["tabular-nums"]}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.FLUSH_GRACE_MS=void 0;exports.__resetLifecycleForTests=__resetLifecycleForTests;exports.bootLifecycle=bootLifecycle;exports.clearReport=clearReport;exports.dismissRelaunchReport=dismissRelaunchReport;exports.getLifecycleSettings=getLifecycleSettings;exports.getLifecycleSnapshot=getLifecycleSnapshot;exports.goBackToBeforeRelaunch=goBackToBeforeRelaunch;exports.interrupt=interrupt;exports.memoryWarning=memoryWarning;exports.openDeepLink=openDeepLink;exports.prepareRelaunch=prepareRelaunch;exports.pressBack=pressBack;exports.refreshSnapshot=refreshSnapshot;exports.relaunchApp=relaunchApp;exports.resetColorScheme=resetColorScheme;exports.resetLifecycle=resetLifecycle;exports.resetPower=resetPower;exports.returnToApp=returnToApp;exports.sendToBackground=sendToBackground;exports.setColorScheme=setColorScheme;exports.setPower=setPower;exports.subscribeLifecycle=subscribeLifecycle;exports.updateSettings=updateSettings;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _utils=require("@buoy-gg/shared-ui/utils");var _native=require("./native");var _persistence=require("./persistence");function timers(){const e=globalThis.__buoyRealTimers;return e??globalThis}function later(e,t){return timers().setTimeout(e,t)}function cancel(e){if(e!=null)timers().clearTimeout(e)}const LOG_LIMIT=30;let settings={..._persistence.DEFAULT_SETTINGS};let away=null;let power=null;let scheme=null;let report=null;let relaunch=null;let log=[];let returnTimer=null;let reportTimer=null;let stopWatching=null;let restorePower=[];let reportSeq=0;let markReturn=()=>{};const subscribers=new Set;let cached=null;function notify(){cached=null;for(const e of Array.from(subscribers)){try{e()}catch{}}}function addLog(e){log=[{at:(0,_sharedUi.realNow)(),text:e},...log].slice(0,LOG_LIMIT)}function persist(){void(0,_persistence.writeSaved)({v:1,settings,pendingRelaunch:null})}function readHost(){const e=(0,_native.expoModule)("ExpoDevice");const t=(0,_native.expoModule)("ExpoApplication");const r=o=>typeof o==="string"&&o?o:null;return{isSimulator:typeof e?.isDevice==="boolean"?!e.isDevice:null,deviceName:r(e?.deviceName),bundleId:r(t?.applicationId),os:r(e?.osName)??(0,_native.getPlatform)(),appScheme:readAppScheme()}}function readAppScheme(){try{let e=(0,_native.expoModule)("ExponentConstants")?.manifest;if(typeof e==="string")e=JSON.parse(e);const t=e?.scheme;const r=Array.isArray(t)?t[0]:t;return typeof r==="string"&&r?r:null}catch{return null}}let host=null;function batteryLibraries(){const e=[];if((0,_native.expoModule)("ExpoBattery"))e.push("expo-battery");if((0,_native.deviceInfoModule)())e.push("react-native-device-info");return e}function batteryListeners(){let e=null;const t=o=>{if(o==null)return;e=(e??0)+o};const r=(0,_native.expoModule)("ExpoBattery");for(const o of EXPO_BATTERY_EVENTS)t((0,_native.expoListenerCount)(r,o));if((0,_native.deviceInfoModule)())for(const o of DEVICE_INFO_EVENTS)t((0,_native.appListenerCount)(o));return e}function clockModule(){try{return(0,_utils.loadToolModule)("@buoy-gg/clock")}catch{return null}}function getLifecycleSnapshot(){if(cached)return cached;cached={platform:(0,_native.getPlatform)(),host:host??=readHost(),realAppState:(0,_sharedUi.getRealAppState)(),away,power,scheme,listeners:{appState:(0,_native.appListenerCount)("appStateDidChange"),focus:(0,_native.appListenerCount)("appStateFocusChange"),memoryWarning:(0,_native.appListenerCount)("memoryWarning"),deepLink:(0,_native.appListenerCount)("url"),battery:batteryListeners()},batteryLibraries:batteryLibraries(),clockAvailable:typeof clockModule()?.shift==="function",report,relaunch,log,settings,active:away!=null||power!=null||scheme!=null};return cached}function refreshSnapshot(){notify();return getLifecycleSnapshot()}function subscribeLifecycle(e){subscribers.add(e);return()=>subscribers.delete(e)}function getLifecycleSettings(){return settings}const REPORT_SOURCES=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"];const REPORT_EVENT_LIMIT=40;const FLUSH_GRACE_MS=exports.FLUSH_GRACE_MS=1e3;function loadWatchEvents(){try{const e=(0,_utils.loadToolModule)("@buoy-gg/events");return typeof e.watchEvents==="function"?e.watchEvents:null}catch{return null}}function finishReport(){cancel(reportTimer);reportTimer=null;stopWatching?.();stopWatching=null;if(report&&report.collectingUntil!=null){report={...report,collectingUntil:null};notify()}}function startReport(e,t,r,o){finishReport();const a=(0,_sharedUi.realNow)();const i=++reportSeq;report={id:i,label:e,kind:t,signal:o,startedAt:a,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:r};const l=loadWatchEvents();if(!l){report={...report,collectingUntil:null,unavailable:"Install @buoy-gg/events to see what the app did after a simulation."};return}const s=Date.now();const f=()=>away?Number.MAX_SAFE_INTEGER:u;let u=Number.MAX_SAFE_INTEGER;markReturn=()=>{u=Date.now()};stopWatching=l(REPORT_SOURCES,d=>{if(!report||report.id!==i)return;const c=d.filter(n=>!(n.source.startsWith("react-query")&&n.status==="pending")).sort((n,p)=>n.timestamp-p.timestamp);const m=c.filter((n,p)=>p===0||!(n.source===c[p-1].source&&n.title===c[p-1].title&&n.timestamp-c[p-1].timestamp<250));const h={};for(const n of m)h[n.source]=(h[n.source]??0)+1;const g=m.map(n=>({source:n.source,title:n.title,subtitle:n.subtitle,status:n.status,at:Math.max(0,n.timestamp-s),whileAway:n.timestamp<f()}));const v=g.filter(n=>n.whileAway&&n.source==="network"&&n.at>=FLUSH_GRACE_MS).length;report={...report,counts:h,events:g.slice(0,REPORT_EVENT_LIMIT),finding:v>0&&report.kind==="background"?`The app kept making network requests in the background: ${v} after its first second away.`:void 0};notify()},s)}function extendReport(){if(!report||report.collectingUntil==null||!stopWatching)return;const e=(0,_sharedUi.realNow)()+settings.reportWindowMs;report={...report,collectingUntil:e};cancel(reportTimer);reportTimer=later(finishReport,settings.reportWindowMs)}function oneShotReport(e,t,r){startReport(e,"signal",r,t);markReturn();extendReport()}function clearReturnTimer(){cancel(returnTimer);returnTimer=null}function describeDuration(e){if(e<6e4)return`${Math.round(e/1e3)} s`;if(e<36e5)return`${Math.round(e/6e4)} min`;const t=e/36e5;return`${Number.isInteger(t)?t:t.toFixed(1)} h`}function goAway(e,t={}){if(away)returnToApp();const r=typeof t.durationMs==="number"&&t.durationMs>0?t.durationMs:null;if(t.skipWait&&r==null){throw new Error("skipWait needs a duration (durationMs).")}const o=t.skipWait?clockModule():null;if(t.skipWait&&typeof o?.shift!=="function"){throw new Error("Skipping the wait needs @buoy-gg/clock. Install it, or wait in real time.")}const a=(e==="background"?"Background":"Interruption")+(r?` ${describeDuration(r)}`:"")+(t.skipWait?" (clock skipped)":"");startReport(a,e);if((0,_native.getPlatform)()==="android"){(0,_native.emitFocus)(false);if(e==="background")(0,_native.emitAppState)("background")}else{(0,_native.emitAppState)("inactive");if(e==="background")(0,_native.emitAppState)("background")}away={kind:e,startedAt:(0,_sharedUi.realNow)(),returnAt:r&&!t.skipWait?(0,_sharedUi.realNow)()+r:null,skippedMs:t.skipWait?r:null};addLog(`${a}: app ${e==="background"?"sent to the background":"interrupted"}`);if(t.skipWait&&r&&o?.shift){o.shift(r);addLog(`App clock moved ahead ${describeDuration(r)}`);return returnToApp()}if(away.returnAt!=null){returnTimer=later(()=>{returnTimer=null;if(away)returnToApp()},r)}notify();return getLifecycleSnapshot()}function sendToBackground(e){return goAway("background",e)}function interrupt(e){return goAway("inactive",e)}function returnToApp(){clearReturnTimer();if(!away)return getLifecycleSnapshot();const e=away;away=null;if((0,_native.getPlatform)()==="android"){if(e.kind==="background")(0,_native.emitAppState)("active");(0,_native.emitFocus)(true)}else{(0,_native.emitAppState)("active")}const t=e.skippedMs??(0,_sharedUi.realNow)()-e.startedAt;addLog(`Returned to the app after ${describeDuration(t)}`);markReturn();extendReport();notify();return getLifecycleSnapshot()}let watchingReal=false;function watchRealAppState(){if(watchingReal)return;watchingReal=true;(0,_sharedUi.subscribeRealAppState)(e=>{if(away){clearReturnTimer();away=null;addLog(`The OS reported "${e}", which ended the simulation`);markReturn();extendReport()}notify()})}function memoryWarning(){const e=(0,_native.getPlatform)()==="android"?"Android never sends this event to React Native; only iOS does. Listeners ran anyway.":void 0;oneShotReport("Memory warning","memoryWarning",e);(0,_native.emitDevice)("memoryWarning");addLog("Memory warning sent");notify();return getLifecycleSnapshot()}function openDeepLink(e){const t=typeof e==="string"?e.trim():"";if(!/^[a-z][a-z0-9+.-]*:/i.test(t)){throw new Error('A deep link needs a scheme, like "myapp://orders/42" or "https://example.com/x".')}oneShotReport(`Deep link ${t}`,"deepLink");(0,_native.emitDevice)("url",{url:t});addLog(`Deep link delivered: ${t}`);notify();return getLifecycleSnapshot()}function pressBack(){if((0,_native.getPlatform)()!=="android"){throw new Error("The hardware back button only exists on Android.")}const e=_reactNative.BackHandler;const t=e.exitApp;let r=false;e.exitApp=()=>{r=true};oneShotReport("Back button","back");try{(0,_native.emitDevice)("hardwareBackPress")}finally{e.exitApp=t}if(report){report={...report,note:r?"No screen handled back, so a real press would have left the app.":"A screen handled back."}}addLog(r?"Back pressed: nothing handled it":"Back pressed: handled by the app");notify();return{handled:!r,snapshot:getLifecycleSnapshot()}}function currentScheme(){try{const e=_reactNative.Appearance.getColorScheme();return e==="light"||e==="dark"?e:null}catch{return null}}function setColorScheme(e,t="js"){if(e!=="light"&&e!=="dark")throw new Error('scheme must be "light" or "dark".');const r=scheme?scheme.previous:currentScheme();if(scheme?.mode==="native"&&t==="js")_reactNative.Appearance.setColorScheme?.("unspecified");oneShotReport(`Color scheme ${e}`,"colorScheme");if(t==="native"&&typeof _reactNative.Appearance.setColorScheme==="function"){_reactNative.Appearance.setColorScheme(e)}else{(0,_native.emitDevice)("appearanceChanged",{colorScheme:e})}scheme={scheme:e,mode:t,previous:r};addLog(`Color scheme set to ${e}${t==="native"?" (native)":""}`);notify();return getLifecycleSnapshot()}function restoreScheme(){if(!scheme)return;const e=scheme;scheme=null;if(e.mode==="native"&&typeof _reactNative.Appearance.setColorScheme==="function"){_reactNative.Appearance.setColorScheme("unspecified")}else if(e.previous){(0,_native.emitDevice)("appearanceChanged",{colorScheme:e.previous})}addLog("Color scheme back to the system value")}function resetColorScheme(){restoreScheme();notify();return getLifecycleSnapshot()}const EXPO_BATTERY_EVENTS=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"];const DEVICE_INFO_EVENTS=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"];const EXPO_STATE={unknown:0,unplugged:1,charging:2,full:3};function applyPower(e,t){for(const s of restorePower)s();restorePower=[];const r=[];const o=[];const a=(s,f,u,d)=>{const c=(0,_native.wrapGetter)(f,u,d);if(c)restorePower.push(c);else if(typeof f[u]==="function")o.push(`${s} ${u}`)};const i=(0,_native.expoModule)("ExpoBattery");if(i){r.push("expo-battery");a("expo-battery",i,"isLowPowerModeEnabledAsync",()=>Promise.resolve(e.lowPowerMode));a("expo-battery",i,"getBatteryLevelAsync",()=>Promise.resolve(e.level));a("expo-battery",i,"getBatteryStateAsync",()=>Promise.resolve(EXPO_STATE[e.state]));if(typeof i.emit==="function"){if(e.lowPowerMode!==t?.lowPowerMode)i.emit("Expo.powerModeDidChange",{lowPowerMode:e.lowPowerMode});if(e.state!==t?.state)i.emit("Expo.batteryStateDidChange",{batteryState:EXPO_STATE[e.state]});if(e.level!==t?.level)i.emit("Expo.batteryLevelDidChange",{batteryLevel:e.level})}}const l=(0,_native.deviceInfoModule)();if(l){r.push("react-native-device-info");const s=()=>({batteryLevel:e.level,batteryState:e.state,lowPowerMode:e.lowPowerMode});a("react-native-device-info",l,"getPowerState",()=>Promise.resolve(s()));a("react-native-device-info",l,"getPowerStateSync",s);a("react-native-device-info",l,"getBatteryLevel",()=>Promise.resolve(e.level));a("react-native-device-info",l,"getBatteryLevelSync",()=>e.level);a("react-native-device-info",l,"isBatteryCharging",()=>Promise.resolve(e.state==="charging"));a("react-native-device-info",l,"isBatteryChargingSync",()=>e.state==="charging");(0,_native.emitDevice)("RNDeviceInfo_powerStateDidChange",s());if(e.level!==t?.level){(0,_native.emitDevice)("RNDeviceInfo_batteryLevelDidChange",e.level);if(e.level<=.2)(0,_native.emitDevice)("RNDeviceInfo_batteryLevelIsLow",e.level)}}return{reached:r,realGetters:o}}function setPower(e){const t=batteryLibraries();if(t.length===0){throw new Error("Nothing in this app reads battery state: neither expo-battery nor react-native-device-info is installed.")}const r=typeof e.level==="number"&&Number.isFinite(e.level)?Math.min(1,Math.max(0,e.level>1?e.level/100:e.level)):power?.level??1;const o={lowPowerMode:e.lowPowerMode??power?.lowPowerMode??false,level:r,state:e.state??power?.state??"unplugged"};if(!(o.state in EXPO_STATE))throw new Error('state must be "unplugged", "charging", "full" or "unknown".');oneShotReport(`Battery ${Math.round(o.level*100)}%${o.lowPowerMode?", low power":""}`,"battery");const{reached:a,realGetters:i}=applyPower(o,power);power={...o,reached:a,realGetters:i};addLog(`Battery set to ${Math.round(o.level*100)}%, ${o.state}${o.lowPowerMode?", low power mode on":""}`);notify();return getLifecycleSnapshot()}function restoreRealPower(){if(!power)return;for(const r of restorePower)r();restorePower=[];power=null;const e=(0,_native.expoModule)("ExpoBattery");if(e&&typeof e.emit==="function"){Promise.all([e.isLowPowerModeEnabledAsync?.(),e.getBatteryStateAsync?.(),e.getBatteryLevelAsync?.()]).then(([r,o,a])=>{if(typeof r==="boolean")e.emit("Expo.powerModeDidChange",{lowPowerMode:r});if(typeof o==="number")e.emit("Expo.batteryStateDidChange",{batteryState:o});if(typeof a==="number")e.emit("Expo.batteryLevelDidChange",{batteryLevel:a})}).catch(()=>{})}const t=(0,_native.deviceInfoModule)();if(t&&typeof t.getPowerState==="function"){Promise.resolve(t.getPowerState()).then(r=>(0,_native.emitDevice)("RNDeviceInfo_powerStateDidChange",r)).catch(()=>{})}addLog("Battery back to the real values")}function resetPower(){restoreRealPower();notify();return getLifecycleSnapshot()}async function relaunchApp(){await prepareRelaunch();later(()=>{void(0,_sharedUi.reloadApp)("auto","buoy lifecycle relaunch").catch(e=>{addLog(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`);persist();notify()})},250);return getLifecycleSnapshot()}async function prepareRelaunch(){const e=(0,_sharedUi.getSafeCurrentRoute)();const t={at:(0,_sharedUi.realNow)(),pathname:e?.pathname??null,href:e?.href??null};addLog(`Relaunching from ${t.pathname??"an unknown screen"}`);resetAll(false);await(0,_persistence.writeSaved)({v:1,settings,pendingRelaunch:t});notify();return getLifecycleSnapshot()}const RESTORE_SETTLE_MS=2500;function checkRestore(e){relaunch={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null};notify();later(()=>{const t=(0,_sharedUi.getSafeCurrentRoute)();const r=t?.pathname??null;relaunch={...relaunch,after:r,tookMs:(0,_sharedUi.realNow)()-e.at,restored:e.pathname!=null&&r!=null?r===e.pathname:null};addLog(relaunch.restored===true?`Relaunch restored ${r}`:`Relaunch landed on ${r??"an unknown screen"}${e.pathname?`, was on ${e.pathname}`:""}`);notify()},RESTORE_SETTLE_MS)}function goBackToBeforeRelaunch(){const e=relaunch?.beforeHref;if(!e)throw new Error("There is no route to go back to.");const t=(0,_sharedUi.getSafeRouter)();if(!t)throw new Error("Going back needs expo-router.");(t.navigate??t.push)?.(e);addLog(`Went back to ${e}`);notify();return getLifecycleSnapshot()}function dismissRelaunchReport(){relaunch=null;notify();return getLifecycleSnapshot()}function resetAll(e){if(away)returnToApp();restoreRealPower();restoreScheme();if(e)addLog("Everything back to real")}function resetLifecycle(){resetAll(true);notify();return getLifecycleSnapshot()}function clearReport(){finishReport();report=null;notify();return getLifecycleSnapshot()}function updateSettings(e){settings={showChip:typeof e.showChip==="boolean"?e.showChip:settings.showChip,reportWindowMs:typeof e.reportWindowMs==="number"&&Number.isFinite(e.reportWindowMs)?Math.min(6e4,Math.max(1e3,e.reportWindowMs)):settings.reportWindowMs};persist();notify();return getLifecycleSnapshot()}let booted=false;function bootLifecycle(){if(booted)return;booted=true;(0,_sharedUi.getRealAppState)();watchRealAppState();const e=r=>{if(!r)return;settings=r.settings;if(r.pendingRelaunch){void(0,_persistence.writeSaved)({v:1,settings,pendingRelaunch:null});checkRestore(r.pendingRelaunch)}notify()};const t=(0,_persistence.readSavedSync)();if(t!==void 0)e(t);else void(0,_persistence.readSavedAsync)().then(e)}function __resetLifecycleForTests(){clearReturnTimer();finishReport();for(const e of restorePower)e();restorePower=[];settings={..._persistence.DEFAULT_SETTINGS};away=null;power=null;scheme=null;report=null;relaunch=null;log=[];booted=false;cached=null;host=null}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.FLUSH_GRACE_MS=void 0;exports.__resetLifecycleForTests=__resetLifecycleForTests;exports.bootLifecycle=bootLifecycle;exports.clearReport=clearReport;exports.dismissRelaunchReport=dismissRelaunchReport;exports.getLifecycleSettings=getLifecycleSettings;exports.getLifecycleSnapshot=getLifecycleSnapshot;exports.goBackToBeforeRelaunch=goBackToBeforeRelaunch;exports.interrupt=interrupt;exports.memoryWarning=memoryWarning;exports.openDeepLink=openDeepLink;exports.prepareRelaunch=prepareRelaunch;exports.pressBack=pressBack;exports.pressBackAsync=pressBackAsync;exports.refreshSnapshot=refreshSnapshot;exports.relaunchApp=relaunchApp;exports.resetColorScheme=resetColorScheme;exports.resetLifecycle=resetLifecycle;exports.resetPower=resetPower;exports.returnToApp=returnToApp;exports.sendToBackground=sendToBackground;exports.setColorScheme=setColorScheme;exports.setPower=setPower;exports.subscribeLifecycle=subscribeLifecycle;exports.updateSettings=updateSettings;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _utils=require("@buoy-gg/shared-ui/utils");var _native=require("./native");var _persistence=require("./persistence");function timers(){const e=globalThis.__buoyRealTimers;return e??globalThis}function later(e,t){return timers().setTimeout(e,t)}function cancel(e){if(e!=null)timers().clearTimeout(e)}const LOG_LIMIT=30;let settings={..._persistence.DEFAULT_SETTINGS};let away=null;let power=null;let scheme=null;let report=null;let relaunch=null;let log=[];let returnTimer=null;let reportTimer=null;let stopWatching=null;let restorePower=[];let reportSeq=0;let markReturn=()=>{};const subscribers=new Set;let cached=null;function notify(){cached=null;for(const e of Array.from(subscribers)){try{e()}catch{}}}function addLog(e){log=[{at:(0,_sharedUi.realNow)(),text:e},...log].slice(0,LOG_LIMIT)}function persist(){void(0,_persistence.writeSaved)({v:1,settings,pendingRelaunch:null})}function readHost(){const e=_native.capacitorShell?.host();if(e)return{...e,os:(0,_native.getPlatform)(),appScheme:null};const t=(0,_native.expoModule)("ExpoDevice");const r=(0,_native.expoModule)("ExpoApplication");const o=n=>typeof n==="string"&&n?n:null;return{isSimulator:typeof t?.isDevice==="boolean"?!t.isDevice:null,deviceName:o(t?.deviceName),bundleId:o(r?.applicationId),os:o(t?.osName)??(0,_native.getPlatform)(),appScheme:readAppScheme()}}function readAppScheme(){try{let e=(0,_native.expoModule)("ExponentConstants")?.manifest;if(typeof e==="string")e=JSON.parse(e);const t=e?.scheme;const r=Array.isArray(t)?t[0]:t;return typeof r==="string"&&r?r:null}catch{return null}}let host=null;function batteryLibraries(){const e=[];if((0,_native.expoModule)("ExpoBattery"))e.push("expo-battery");if((0,_native.deviceInfoModule)())e.push("react-native-device-info");if(_native.capacitorShell?.battery.available())e.push("@capacitor/device");return e}function batteryListeners(){let e=null;const t=o=>{if(o==null)return;e=(e??0)+o};const r=(0,_native.expoModule)("ExpoBattery");for(const o of EXPO_BATTERY_EVENTS)t((0,_native.expoListenerCount)(r,o));if((0,_native.deviceInfoModule)())for(const o of DEVICE_INFO_EVENTS)t((0,_native.appListenerCount)(o));return e}function clockModule(){try{return(0,_utils.loadToolModule)("@buoy-gg/clock")}catch{return null}}function getLifecycleSnapshot(){if(cached)return cached;cached={platform:(0,_native.getPlatform)(),host:host??=readHost(),realAppState:(0,_sharedUi.getRealAppState)(),away,power,scheme,listeners:{appState:(0,_native.appListenerCount)("appStateDidChange"),focus:(0,_native.appListenerCount)("appStateFocusChange"),memoryWarning:(0,_native.appListenerCount)("memoryWarning"),deepLink:(0,_native.appListenerCount)("url"),battery:batteryListeners()},batteryLibraries:batteryLibraries(),clockAvailable:typeof clockModule()?.shift==="function",report,relaunch,log,settings,active:away!=null||power!=null||scheme!=null};return cached}function refreshSnapshot(){notify();return getLifecycleSnapshot()}function subscribeLifecycle(e){subscribers.add(e);return()=>subscribers.delete(e)}function getLifecycleSettings(){return settings}const REPORT_SOURCES=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"];const REPORT_EVENT_LIMIT=40;const FLUSH_GRACE_MS=exports.FLUSH_GRACE_MS=1e3;function loadWatchEvents(){try{const e=(0,_utils.loadToolModule)("@buoy-gg/events");return typeof e.watchEvents==="function"?e.watchEvents:null}catch{return null}}function finishReport(){cancel(reportTimer);reportTimer=null;stopWatching?.();stopWatching=null;if(report&&report.collectingUntil!=null){report={...report,collectingUntil:null};notify()}}function startReport(e,t,r,o){finishReport();const n=(0,_sharedUi.realNow)();const i=++reportSeq;report={id:i,label:e,kind:t,signal:o,startedAt:n,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:r};const l=loadWatchEvents();if(!l){report={...report,collectingUntil:null,unavailable:"Install @buoy-gg/events to see what the app did after a simulation."};return}const s=Date.now();const f=()=>away?Number.MAX_SAFE_INTEGER:u;let u=Number.MAX_SAFE_INTEGER;markReturn=()=>{u=Date.now()};stopWatching=l(REPORT_SOURCES,d=>{if(!report||report.id!==i)return;const c=d.filter(a=>!(a.source.startsWith("react-query")&&a.status==="pending")).sort((a,p)=>a.timestamp-p.timestamp);const m=c.filter((a,p)=>p===0||!(a.source===c[p-1].source&&a.title===c[p-1].title&&a.timestamp-c[p-1].timestamp<250));const h={};for(const a of m)h[a.source]=(h[a.source]??0)+1;const v=m.map(a=>({source:a.source,title:a.title,subtitle:a.subtitle,status:a.status,at:Math.max(0,a.timestamp-s),whileAway:a.timestamp<f()}));const g=v.filter(a=>a.whileAway&&a.source==="network"&&a.at>=FLUSH_GRACE_MS).length;report={...report,counts:h,events:v.slice(0,REPORT_EVENT_LIMIT),finding:g>0&&report.kind==="background"?`The app kept making network requests in the background: ${g} after its first second away.`:void 0};notify()},s)}function extendReport(){if(!report||report.collectingUntil==null||!stopWatching)return;const e=(0,_sharedUi.realNow)()+settings.reportWindowMs;report={...report,collectingUntil:e};cancel(reportTimer);reportTimer=later(finishReport,settings.reportWindowMs)}function oneShotReport(e,t,r){startReport(e,"signal",r,t);markReturn();extendReport()}function clearReturnTimer(){cancel(returnTimer);returnTimer=null}function describeDuration(e){if(e<6e4)return`${Math.round(e/1e3)} s`;if(e<36e5)return`${Math.round(e/6e4)} min`;const t=e/36e5;return`${Number.isInteger(t)?t:t.toFixed(1)} h`}function goAway(e,t={}){if(away)returnToApp();const r=typeof t.durationMs==="number"&&t.durationMs>0?t.durationMs:null;if(t.skipWait&&r==null){throw new Error("skipWait needs a duration (durationMs).")}const o=t.skipWait?clockModule():null;if(t.skipWait&&typeof o?.shift!=="function"){throw new Error("Skipping the wait needs @buoy-gg/clock. Install it, or wait in real time.")}const n=(e==="background"?"Background":"Interruption")+(r?` ${describeDuration(r)}`:"")+(t.skipWait?" (clock skipped)":"");startReport(n,e);if((0,_native.getPlatform)()==="android"){(0,_native.emitFocus)(false);if(e==="background")(0,_native.emitAppState)("background")}else{(0,_native.emitAppState)("inactive");if(e==="background")(0,_native.emitAppState)("background")}away={kind:e,startedAt:(0,_sharedUi.realNow)(),returnAt:r&&!t.skipWait?(0,_sharedUi.realNow)()+r:null,skippedMs:t.skipWait?r:null};addLog(`${n}: app ${e==="background"?"sent to the background":"interrupted"}`);if(t.skipWait&&r&&o?.shift){o.shift(r);addLog(`App clock moved ahead ${describeDuration(r)}`);return returnToApp()}if(away.returnAt!=null){returnTimer=later(()=>{returnTimer=null;if(away)returnToApp()},r)}notify();return getLifecycleSnapshot()}function sendToBackground(e){return goAway("background",e)}function interrupt(e){return goAway("inactive",e)}function returnToApp(){clearReturnTimer();if(!away)return getLifecycleSnapshot();const e=away;away=null;if((0,_native.getPlatform)()==="android"){if(e.kind==="background")(0,_native.emitAppState)("active");(0,_native.emitFocus)(true)}else{(0,_native.emitAppState)("active")}const t=e.skippedMs??(0,_sharedUi.realNow)()-e.startedAt;addLog(`Returned to the app after ${describeDuration(t)}`);markReturn();extendReport();notify();return getLifecycleSnapshot()}let watchingReal=false;function watchRealAppState(){if(watchingReal)return;watchingReal=true;(0,_sharedUi.subscribeRealAppState)(e=>{if(away){clearReturnTimer();away=null;(0,_native.endSimulation)();addLog(`The OS reported "${e}", which ended the simulation`);markReturn();extendReport()}notify()})}function memoryWarning(){if(_native.capacitorShell)throw new Error("Capacitor has no memory warning event, so there is nothing to send.");const e=(0,_native.getPlatform)()==="android"?"Android never sends this event to React Native; only iOS does. Listeners ran anyway.":void 0;oneShotReport("Memory warning","memoryWarning",e);(0,_native.emitDevice)("memoryWarning");addLog("Memory warning sent");notify();return getLifecycleSnapshot()}function openDeepLink(e){const t=typeof e==="string"?e.trim():"";if(!/^[a-z][a-z0-9+.-]*:/i.test(t)){throw new Error('A deep link needs a scheme, like "myapp://orders/42" or "https://example.com/x".')}oneShotReport(`Deep link ${t}`,"deepLink");(0,_native.emitDevice)("url",{url:t});addLog(`Deep link delivered: ${t}`);notify();return getLifecycleSnapshot()}async function pressBackAsync(){if(!_native.capacitorShell)return pressBack();if((0,_native.getPlatform)()!=="android"){throw new Error("The hardware back button only exists on Android.")}oneShotReport("Back button","back");const e=await _native.capacitorShell.pressBack();if(report)report={...report,note:e.note};addLog(e.exited?"Back pressed: the app tried to exit":e.handled?"Back pressed: handled by the app":`Back pressed: ${e.note}`);notify();return{handled:e.handled,snapshot:getLifecycleSnapshot()}}function pressBack(){if((0,_native.getPlatform)()!=="android"){throw new Error("The hardware back button only exists on Android.")}const e=_reactNative.BackHandler;const t=e.exitApp;let r=false;e.exitApp=()=>{r=true};oneShotReport("Back button","back");try{(0,_native.emitDevice)("hardwareBackPress")}finally{e.exitApp=t}if(report){report={...report,note:r?"No screen handled back, so a real press would have left the app.":"A screen handled back."}}addLog(r?"Back pressed: nothing handled it":"Back pressed: handled by the app");notify();return{handled:!r,snapshot:getLifecycleSnapshot()}}function currentScheme(){try{const e=_reactNative.Appearance.getColorScheme();return e==="light"||e==="dark"?e:null}catch{return null}}function setColorScheme(e,t="js"){if(e!=="light"&&e!=="dark")throw new Error('scheme must be "light" or "dark".');if(_native.capacitorShell){if(t==="native")throw new Error('A Capacitor app has no native color scheme override. Use mode "js".');const o=scheme?scheme.previous:currentScheme();oneShotReport(`Color scheme ${e}`,"colorScheme");_native.capacitorShell.colorScheme(e);scheme={scheme:e,mode:t,previous:o};addLog(`Color scheme set to ${e}`);notify();return getLifecycleSnapshot()}const r=scheme?scheme.previous:currentScheme();if(scheme?.mode==="native"&&t==="js")_reactNative.Appearance.setColorScheme?.("unspecified");oneShotReport(`Color scheme ${e}`,"colorScheme");if(t==="native"&&typeof _reactNative.Appearance.setColorScheme==="function"){_reactNative.Appearance.setColorScheme(e)}else{(0,_native.emitDevice)("appearanceChanged",{colorScheme:e})}scheme={scheme:e,mode:t,previous:r};addLog(`Color scheme set to ${e}${t==="native"?" (native)":""}`);notify();return getLifecycleSnapshot()}function restoreScheme(){if(!scheme)return;const e=scheme;scheme=null;if(_native.capacitorShell){_native.capacitorShell.colorScheme(null)}else if(e.mode==="native"&&typeof _reactNative.Appearance.setColorScheme==="function"){_reactNative.Appearance.setColorScheme("unspecified")}else if(e.previous){(0,_native.emitDevice)("appearanceChanged",{colorScheme:e.previous})}addLog("Color scheme back to the system value")}function resetColorScheme(){restoreScheme();notify();return getLifecycleSnapshot()}const EXPO_BATTERY_EVENTS=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"];const DEVICE_INFO_EVENTS=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"];const EXPO_STATE={unknown:0,unplugged:1,charging:2,full:3};function applyPower(e,t){for(const s of restorePower)s();restorePower=[];const r=[];const o=[];const n=(s,f,u,d)=>{const c=(0,_native.wrapGetter)(f,u,d);if(c)restorePower.push(c);else if(typeof f[u]==="function")o.push(`${s} ${u}`)};const i=(0,_native.expoModule)("ExpoBattery");if(i){r.push("expo-battery");n("expo-battery",i,"isLowPowerModeEnabledAsync",()=>Promise.resolve(e.lowPowerMode));n("expo-battery",i,"getBatteryLevelAsync",()=>Promise.resolve(e.level));n("expo-battery",i,"getBatteryStateAsync",()=>Promise.resolve(EXPO_STATE[e.state]));if(typeof i.emit==="function"){if(e.lowPowerMode!==t?.lowPowerMode)i.emit("Expo.powerModeDidChange",{lowPowerMode:e.lowPowerMode});if(e.state!==t?.state)i.emit("Expo.batteryStateDidChange",{batteryState:EXPO_STATE[e.state]});if(e.level!==t?.level)i.emit("Expo.batteryLevelDidChange",{batteryLevel:e.level})}}if(_native.capacitorShell?.battery.available()){r.push("@capacitor/device");_native.capacitorShell.battery.set({level:e.level,state:e.state});restorePower.push(()=>_native.capacitorShell?.battery.set(null))}const l=(0,_native.deviceInfoModule)();if(l){r.push("react-native-device-info");const s=()=>({batteryLevel:e.level,batteryState:e.state,lowPowerMode:e.lowPowerMode});n("react-native-device-info",l,"getPowerState",()=>Promise.resolve(s()));n("react-native-device-info",l,"getPowerStateSync",s);n("react-native-device-info",l,"getBatteryLevel",()=>Promise.resolve(e.level));n("react-native-device-info",l,"getBatteryLevelSync",()=>e.level);n("react-native-device-info",l,"isBatteryCharging",()=>Promise.resolve(e.state==="charging"));n("react-native-device-info",l,"isBatteryChargingSync",()=>e.state==="charging");(0,_native.emitDevice)("RNDeviceInfo_powerStateDidChange",s());if(e.level!==t?.level){(0,_native.emitDevice)("RNDeviceInfo_batteryLevelDidChange",e.level);if(e.level<=.2)(0,_native.emitDevice)("RNDeviceInfo_batteryLevelIsLow",e.level)}}return{reached:r,realGetters:o}}function setPower(e){const t=batteryLibraries();if(t.length===0){throw new Error("Nothing in this app reads battery state: expo-battery, react-native-device-info and @capacitor/device are all missing.")}const r=typeof e.level==="number"&&Number.isFinite(e.level)?Math.min(1,Math.max(0,e.level>1?e.level/100:e.level)):power?.level??1;const o={lowPowerMode:e.lowPowerMode??power?.lowPowerMode??false,level:r,state:e.state??power?.state??"unplugged"};if(!(o.state in EXPO_STATE))throw new Error('state must be "unplugged", "charging", "full" or "unknown".');oneShotReport(`Battery ${Math.round(o.level*100)}%${o.lowPowerMode?", low power":""}`,"battery");const{reached:n,realGetters:i}=applyPower(o,power);power={...o,reached:n,realGetters:i};addLog(`Battery set to ${Math.round(o.level*100)}%, ${o.state}${o.lowPowerMode?", low power mode on":""}`);notify();return getLifecycleSnapshot()}function restoreRealPower(){if(!power)return;for(const r of restorePower)r();restorePower=[];power=null;const e=(0,_native.expoModule)("ExpoBattery");if(e&&typeof e.emit==="function"){Promise.all([e.isLowPowerModeEnabledAsync?.(),e.getBatteryStateAsync?.(),e.getBatteryLevelAsync?.()]).then(([r,o,n])=>{if(typeof r==="boolean")e.emit("Expo.powerModeDidChange",{lowPowerMode:r});if(typeof o==="number")e.emit("Expo.batteryStateDidChange",{batteryState:o});if(typeof n==="number")e.emit("Expo.batteryLevelDidChange",{batteryLevel:n})}).catch(()=>{})}const t=(0,_native.deviceInfoModule)();if(t&&typeof t.getPowerState==="function"){Promise.resolve(t.getPowerState()).then(r=>(0,_native.emitDevice)("RNDeviceInfo_powerStateDidChange",r)).catch(()=>{})}addLog("Battery back to the real values")}function resetPower(){restoreRealPower();notify();return getLifecycleSnapshot()}async function relaunchApp(){await prepareRelaunch();later(()=>{void(0,_sharedUi.reloadApp)("auto","buoy lifecycle relaunch").catch(e=>{addLog(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`);persist();notify()})},250);return getLifecycleSnapshot()}async function prepareRelaunch(){const e=(0,_sharedUi.getSafeCurrentRoute)();const t={at:(0,_sharedUi.realNow)(),pathname:e?.pathname??null,href:e?.href??null};addLog(`Relaunching from ${t.pathname??"an unknown screen"}`);resetAll(false);await(0,_persistence.writeSaved)({v:1,settings,pendingRelaunch:t});notify();return getLifecycleSnapshot()}const RESTORE_SETTLE_MS=2500;function checkRestore(e){relaunch={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null};notify();later(()=>{const t=(0,_sharedUi.getSafeCurrentRoute)();const r=t?.pathname??null;relaunch={...relaunch,after:r,tookMs:(0,_sharedUi.realNow)()-e.at,restored:e.pathname!=null&&r!=null?r===e.pathname:null};addLog(relaunch.restored===true?`Relaunch restored ${r}`:`Relaunch landed on ${r??"an unknown screen"}${e.pathname?`, was on ${e.pathname}`:""}`);notify()},RESTORE_SETTLE_MS)}function goBackToBeforeRelaunch(){const e=relaunch?.beforeHref;if(!e)throw new Error("There is no route to go back to.");const t=(0,_sharedUi.getSafeRouter)();if(!t)throw new Error("Going back needs expo-router.");(t.navigate??t.push)?.(e);addLog(`Went back to ${e}`);notify();return getLifecycleSnapshot()}function dismissRelaunchReport(){relaunch=null;notify();return getLifecycleSnapshot()}function resetAll(e){if(away)returnToApp();restoreRealPower();restoreScheme();if(e)addLog("Everything back to real")}function resetLifecycle(){resetAll(true);notify();return getLifecycleSnapshot()}function clearReport(){finishReport();report=null;notify();return getLifecycleSnapshot()}function updateSettings(e){settings={showChip:typeof e.showChip==="boolean"?e.showChip:settings.showChip,reportWindowMs:typeof e.reportWindowMs==="number"&&Number.isFinite(e.reportWindowMs)?Math.min(6e4,Math.max(1e3,e.reportWindowMs)):settings.reportWindowMs};persist();notify();return getLifecycleSnapshot()}let booted=false;function bootLifecycle(){if(booted)return;booted=true;(0,_native.prepareColorScheme)();void _native.capacitorShell?.loadHost().then(()=>{host=null;notify()});(0,_sharedUi.getRealAppState)();watchRealAppState();const e=r=>{if(!r)return;settings=r.settings;if(r.pendingRelaunch){void(0,_persistence.writeSaved)({v:1,settings,pendingRelaunch:null});checkRestore(r.pendingRelaunch)}notify()};const t=(0,_persistence.readSavedSync)();if(t!==void 0)e(t);else void(0,_persistence.readSavedAsync)().then(e)}function __resetLifecycleForTests(){clearReturnTimer();finishReport();for(const e of restorePower)e();restorePower=[];settings={..._persistence.DEFAULT_SETTINGS};away=null;power=null;scheme=null;report=null;relaunch=null;log=[];booted=false;cached=null;host=null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.appListenerCount=appListenerCount;exports.deviceInfoModule=deviceInfoModule;exports.emitAppState=emitAppState;exports.emitDevice=emitDevice;exports.emitFocus=emitFocus;exports.expoListenerCount=expoListenerCount;exports.expoModule=expoModule;exports.getPlatform=getPlatform;exports.wrapGetter=wrapGetter;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");function getPlatform(){const e=_reactNative.Platform.OS;return e==="ios"||e==="android"||e==="web"?e:"other"}function emitDevice(e,t){if(t===void 0)_reactNative.DeviceEventEmitter.emit(e);else _reactNative.DeviceEventEmitter.emit(e,t)}function emitAppState(e){emitDevice("appStateDidChange",{app_state:e,[_sharedUi.BUOY_SYNTHETIC_MARK]:true})}function emitFocus(e){emitDevice("appStateFocusChange",e)}function internalListeners(e,t){if(e==="appStateDidChange")return t>0?1:0;return 0}function ownListeners(e){const t=globalThis.__buoyOwnDeviceListeners;return t?.[e]??0}function appListenerCount(e){const t=_reactNative.DeviceEventEmitter;if(typeof t.listenerCount!=="function")return null;const n=t.listenerCount(e);return Math.max(0,n-internalListeners(e,n)-ownListeners(e))}function expoModule(e){const t=globalThis.expo?.modules;const n=t?.[e];return n&&typeof n==="object"?n:null}function expoListenerCount(e,t){if(!e||typeof e.listenerCount!=="function")return null;try{return e.listenerCount(t)}catch{return null}}function deviceInfoModule(){const e=_reactNative.NativeModules.RNDeviceInfo;return e&&typeof e==="object"?e:null}function wrapGetter(e,t,n){if(typeof e[t]!=="function")return null;const o=e[t];try{e[t]=n;if(e[t]!==n)return null}catch{return null}return()=>{try{e[t]=o}catch{}}}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.appListenerCount=appListenerCount;exports.capacitorShell=void 0;exports.deviceInfoModule=deviceInfoModule;exports.emitAppState=emitAppState;exports.emitDevice=emitDevice;exports.emitFocus=emitFocus;exports.endSimulation=endSimulation;exports.expoListenerCount=expoListenerCount;exports.expoModule=expoModule;exports.getPlatform=getPlatform;exports.prepareColorScheme=prepareColorScheme;exports.wrapGetter=wrapGetter;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");function getPlatform(){const e=_reactNative.Platform.OS;return e==="ios"||e==="android"||e==="web"?e:"other"}function emitDevice(e,t){if(t===void 0)_reactNative.DeviceEventEmitter.emit(e);else _reactNative.DeviceEventEmitter.emit(e,t)}function emitAppState(e){emitDevice("appStateDidChange",{app_state:e,[_sharedUi.BUOY_SYNTHETIC_MARK]:true})}function emitFocus(e){emitDevice("appStateFocusChange",e)}const capacitorShell=exports.capacitorShell=null;function endSimulation(){}function prepareColorScheme(){}function internalListeners(e,t){if(e==="appStateDidChange")return t>0?1:0;return 0}function ownListeners(e){const t=globalThis.__buoyOwnDeviceListeners;return t?.[e]??0}function appListenerCount(e){const t=_reactNative.DeviceEventEmitter;if(typeof t.listenerCount!=="function")return null;const n=t.listenerCount(e);return Math.max(0,n-internalListeners(e,n)-ownListeners(e))}function expoModule(e){const t=globalThis.expo?.modules;const n=t?.[e];return n&&typeof n==="object"?n:null}function expoListenerCount(e,t){if(!e||typeof e.listenerCount!=="function")return null;try{return e.listenerCount(t)}catch{return null}}function deviceInfoModule(){const e=_reactNative.NativeModules.RNDeviceInfo;return e&&typeof e==="object"?e:null}function wrapGetter(e,t,n){if(typeof e[t]!=="function")return null;const o=e[t];try{e[t]=n;if(e[t]!==n)return null}catch{return null}return()=>{try{e[t]=o}catch{}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.appListenerCount=appListenerCount;exports.capacitorShell=void 0;exports.deviceInfoModule=deviceInfoModule;exports.emitAppState=emitAppState;exports.emitDevice=emitDevice;exports.emitFocus=emitFocus;exports.endSimulation=endSimulation;exports.expoListenerCount=expoListenerCount;exports.expoModule=expoModule;exports.getPlatform=getPlatform;exports.prepareColorScheme=prepareColorScheme;exports.wrapGetter=wrapGetter;var _license=require("@buoy-gg/license");var _sharedUi=require("@buoy-gg/shared-ui");function getPlatform(){return(0,_license.capacitorPlatform)()??"web"}function inShell(){if((0,_license.capacitorPlatform)()===null||!(0,_license.installCapacitorBridge)())return false;watchGetters();return true}let gettersWatched=false;function watchGetters(){if(gettersWatched)return;gettersWatched=true;(0,_license.interceptCapacitor)({plugin:"App",methods:["getState"],promise:(e,t)=>active?t():{isActive:false}})}function doc(){const e=globalThis.document;return e&&typeof e.dispatchEvent==="function"?e:null}function dispatchDocumentEvent(e){const t=doc();if(!t)return;const n=globalThis.Event;if(!n)return;const r=new n(e);r[_sharedUi.BUOY_SYNTHETIC_MARK]=true;t.dispatchEvent(r)}function setVisibility(e){const t=doc();if(!t)return;if(e===null){delete t.visibilityState;delete t.hidden}else{Object.defineProperty(t,"visibilityState",{configurable:true,get:()=>e});Object.defineProperty(t,"hidden",{configurable:true,get:()=>e==="hidden"})}dispatchDocumentEvent("visibilitychange")}let active=true;let paused=false;function setActive(e){if(active===e)return;active=e;(0,_license.emitCapacitorEvent)("App","appStateChange",{isActive:e})}function emitAppState(e){if(!inShell())return;if(e==="inactive"){setActive(false);return}if(e==="background"){setActive(false);if(!paused){paused=true;(0,_license.emitCapacitorEvent)("App","pause",{});dispatchDocumentEvent("pause");setVisibility("hidden")}return}if(paused){paused=false;setVisibility(null);(0,_license.emitCapacitorEvent)("App","resume",{});dispatchDocumentEvent("resume")}setActive(true)}function endSimulation(){if(paused)setVisibilityQuietly(null);paused=false;active=true}function setVisibilityQuietly(e){const t=doc();if(!t||e!==null)return;delete t.visibilityState;delete t.hidden}function emitFocus(e){}function emitDevice(e,t){if(!inShell())return;if(e==="url"){(0,_license.emitCapacitorEvent)("App","appUrlOpen",t)}}const CAPACITOR_EVENTS={appStateDidChange:["appStateChange","pause","resume"],url:["appUrlOpen"],hardwareBackPress:["backButton"]};function appListenerCount(e){if(!inShell())return null;const t=CAPACITOR_EVENTS[e];if(!t)return 0;return t.reduce((n,r)=>n+(0,_license.capacitorListenerCount)("App",r),0)}const EXIT_WAIT_MS=400;function realSetTimeout(e,t){const n=globalThis.__buoyRealTimers;if(typeof n?.setTimeout==="function")n.setTimeout(e,t);else setTimeout(e,t)}const capacitorShell=exports.capacitorShell={async pressBack(){if(!inShell())throw new Error("The back button needs a Capacitor app.");const e=globalThis.history;const t=Boolean(e&&e.length>1);const n=(0,_license.capacitorListenerCount)("App","backButton");if(n===0){if(t)e?.back();return{exited:false,handled:false,note:t?"No back listener, so the WebView went back a page.":"No back listener and no page to go back to, so nothing happened."}}let r=false;const i=(0,_license.interceptCapacitor)({plugin:"App",methods:["exitApp"],promise:()=>{r=true;return void 0},callback:()=>{r=true;return(0,_license.makeCapacitorCallbackId)()}});try{(0,_license.emitCapacitorEvent)("App","backButton",{canGoBack:t});dispatchDocumentEvent("backbutton");await new Promise(a=>realSetTimeout(a,EXIT_WAIT_MS))}finally{i()}return{exited:r,handled:!r,note:r?"The app called App.exitApp(), so a real press would have left the app.":"The app's back listener handled it."}},host(){return(0,_license.getCapacitorAppHost)()},loadHost(){return inShell()?(0,_license.loadCapacitorAppHost)():Promise.resolve(null)},colorScheme(e){if(!inShell())throw new Error("The color scheme needs a Capacitor app.");patchMatchesGetter();const t=(0,_license.getColorSchemeQueries)();const n=t.map(r=>r.matches);schemeOverride=e;t.forEach((r,i)=>{const a=r.matches;if(a!==n[i])sendChange(r,a)})},battery:{available(){return inShell()&&(0,_license.hasCapacitorPlugin)("Device")},set(e){batteryOverride=e;if(e&&!batteryWatched){batteryWatched=true;(0,_license.interceptCapacitor)({plugin:"Device",methods:["getBatteryInfo"],promise:(t,n)=>batteryOverride?{batteryLevel:batteryOverride.level,isCharging:batteryOverride.state==="charging"||batteryOverride.state==="full"}:n()})}}}};let schemeOverride=null;let matchesPatched=false;function overrideMatches(e){const t=e&&Object.getOwnPropertyDescriptor(e,"matches");if(!e||!t?.get||!t.configurable)return false;const n=t.get;Object.defineProperty(e,"matches",{...t,get(){const r=n.call(this);const i=schemeOverride?(0,_license.colorSchemeQueryValue)(String(this.media??"")):null;return i?schemeOverride===i:r}});return true}function patchMatchesGetter(){if(matchesPatched)return;const e=globalThis.MediaQueryListEvent;overrideMatches(e?.prototype);const t=globalThis.MediaQueryList;if(overrideMatches(t?.prototype))matchesPatched=true}function sendChange(e,t){const n=String(e.media??"");const r=globalThis.MediaQueryListEvent;let i;try{i=r?new r("change",{matches:t,media:n}):new Event("change")}catch{i=new Event("change")}if(!r){Object.defineProperty(i,"matches",{value:t});Object.defineProperty(i,"media",{value:n})}try{e.dispatchEvent(i)}catch(a){globalThis.console?.error(a)}}function prepareColorScheme(){}let batteryOverride=null;let batteryWatched=false;function expoModule(e){return null}function expoListenerCount(e,t){return null}function deviceInfoModule(){return null}function wrapGetter(e,t,n){if(typeof e[t]!=="function")return null;const r=e[t];try{e[t]=n;if(e[t]!==n)return null}catch{return null}return()=>{try{e[t]=r}catch{}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.readSavedSync=readSavedSync;function readSavedSync(){return void 0}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.readSavedSync=readSavedSync;var _persistence=require("./persistence");function readSavedSync(){try{const e=globalThis.localStorage;if(!e)return void 0;return(0,_persistence.parseSaved)(e.getItem(_persistence.LIFECYCLE_STORAGE_KEY))}catch{return void 0}}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"LIFECYCLE_CHIP_ID",{enumerable:true,get:function(){return _LifecycleChip.LIFECYCLE_CHIP_ID}});Object.defineProperty(exports,"LIFECYCLE_TOOL_ICON_COLOR",{enumerable:true,get:function(){return _sharedUi.LIFECYCLE_TOOL_ICON_COLOR}});Object.defineProperty(exports,"LifecycleBody",{enumerable:true,get:function(){return _LifecycleBody.LifecycleBody}});Object.defineProperty(exports,"LifecycleChip",{enumerable:true,get:function(){return _LifecycleChip.LifecycleChip}});Object.defineProperty(exports,"LifecycleToolIcon",{enumerable:true,get:function(){return _sharedUi.LifecycleToolIcon}});Object.defineProperty(exports,"LifecycleToolView",{enumerable:true,get:function(){return _LifecycleToolView.LifecycleToolView}});Object.defineProperty(exports,"RECIPES",{enumerable:true,get:function(){return _recipes.RECIPES}});Object.defineProperty(exports,"bootLifecycle",{enumerable:true,get:function(){return _lifecycleStore.bootLifecycle}});Object.defineProperty(exports,"createLifecycleTool",{enumerable:true,get:function(){return _preset.createLifecycleTool}});Object.defineProperty(exports,"getLifecycleSnapshot",{enumerable:true,get:function(){return _lifecycleStore.getLifecycleSnapshot}});Object.defineProperty(exports,"interrupt",{enumerable:true,get:function(){return _lifecycleStore.interrupt}});Object.defineProperty(exports,"lifecycleSyncAdapter",{enumerable:true,get:function(){return _lifecycleSyncAdapter.lifecycleSyncAdapter}});Object.defineProperty(exports,"lifecycleToolPreset",{enumerable:true,get:function(){return _preset.lifecycleToolPreset}});Object.defineProperty(exports,"memoryWarning",{enumerable:true,get:function(){return _lifecycleStore.memoryWarning}});Object.defineProperty(exports,"openDeepLink",{enumerable:true,get:function(){return _lifecycleStore.openDeepLink}});Object.defineProperty(exports,"parseDurationMs",{enumerable:true,get:function(){return _lifecycleSyncAdapter.parseDurationMs}});Object.defineProperty(exports,"pressBack",{enumerable:true,get:function(){return _lifecycleStore.pressBack}});Object.defineProperty(exports,"relaunchApp",{enumerable:true,get:function(){return _lifecycleStore.relaunchApp}});Object.defineProperty(exports,"resetLifecycle",{enumerable:true,get:function(){return _lifecycleStore.resetLifecycle}});Object.defineProperty(exports,"resetPower",{enumerable:true,get:function(){return _lifecycleStore.resetPower}});Object.defineProperty(exports,"returnToApp",{enumerable:true,get:function(){return _lifecycleStore.returnToApp}});Object.defineProperty(exports,"runRecipe",{enumerable:true,get:function(){return _recipes.runRecipe}});Object.defineProperty(exports,"sendToBackground",{enumerable:true,get:function(){return _lifecycleStore.sendToBackground}});Object.defineProperty(exports,"setColorScheme",{enumerable:true,get:function(){return _lifecycleStore.setColorScheme}});Object.defineProperty(exports,"setPower",{enumerable:true,get:function(){return _lifecycleStore.setPower}});Object.defineProperty(exports,"subscribeLifecycle",{enumerable:true,get:function(){return _lifecycleStore.subscribeLifecycle}});var _lifecycleStore=require("./engine/lifecycleStore");var _LifecycleChip=require("./components/LifecycleChip");var _readSavedSync=require("./engine/readSavedSync");var _preset=require("./preset");var _LifecycleBody=require("./components/LifecycleBody");var _LifecycleToolView=require("./components/LifecycleToolView");var _sharedUi=require("@buoy-gg/shared-ui");var _lifecycleSyncAdapter=require("./sync/lifecycleSyncAdapter");var _recipes=require("./engine/recipes");const isReactNativeRuntime=typeof navigator!=="undefined"&&navigator.product==="ReactNative";if(isReactNativeRuntime){(0,_LifecycleChip.watchLifecycleChip)();const e=typeof __DEV__!=="undefined"&&__DEV__;if(e||(0,_readSavedSync.readSavedSync)()?.pendingRelaunch)(0,_lifecycleStore.bootLifecycle)()}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"LIFECYCLE_CHIP_ID",{enumerable:true,get:function(){return _LifecycleChip.LIFECYCLE_CHIP_ID}});Object.defineProperty(exports,"LIFECYCLE_TOOL_ICON_COLOR",{enumerable:true,get:function(){return _sharedUi.LIFECYCLE_TOOL_ICON_COLOR}});Object.defineProperty(exports,"LifecycleBody",{enumerable:true,get:function(){return _LifecycleBody.LifecycleBody}});Object.defineProperty(exports,"LifecycleChip",{enumerable:true,get:function(){return _LifecycleChip.LifecycleChip}});Object.defineProperty(exports,"LifecycleToolIcon",{enumerable:true,get:function(){return _sharedUi.LifecycleToolIcon}});Object.defineProperty(exports,"LifecycleToolView",{enumerable:true,get:function(){return _LifecycleToolView.LifecycleToolView}});Object.defineProperty(exports,"RECIPES",{enumerable:true,get:function(){return _recipes.RECIPES}});Object.defineProperty(exports,"bootLifecycle",{enumerable:true,get:function(){return _lifecycleStore.bootLifecycle}});Object.defineProperty(exports,"createLifecycleTool",{enumerable:true,get:function(){return _preset.createLifecycleTool}});Object.defineProperty(exports,"getLifecycleSnapshot",{enumerable:true,get:function(){return _lifecycleStore.getLifecycleSnapshot}});Object.defineProperty(exports,"interrupt",{enumerable:true,get:function(){return _lifecycleStore.interrupt}});Object.defineProperty(exports,"lifecycleSyncAdapter",{enumerable:true,get:function(){return _lifecycleSyncAdapter.lifecycleSyncAdapter}});Object.defineProperty(exports,"lifecycleToolPreset",{enumerable:true,get:function(){return _preset.lifecycleToolPreset}});Object.defineProperty(exports,"memoryWarning",{enumerable:true,get:function(){return _lifecycleStore.memoryWarning}});Object.defineProperty(exports,"openDeepLink",{enumerable:true,get:function(){return _lifecycleStore.openDeepLink}});Object.defineProperty(exports,"parseDurationMs",{enumerable:true,get:function(){return _lifecycleSyncAdapter.parseDurationMs}});Object.defineProperty(exports,"pressBack",{enumerable:true,get:function(){return _lifecycleStore.pressBack}});Object.defineProperty(exports,"pressBackAsync",{enumerable:true,get:function(){return _lifecycleStore.pressBackAsync}});Object.defineProperty(exports,"relaunchApp",{enumerable:true,get:function(){return _lifecycleStore.relaunchApp}});Object.defineProperty(exports,"resetLifecycle",{enumerable:true,get:function(){return _lifecycleStore.resetLifecycle}});Object.defineProperty(exports,"resetPower",{enumerable:true,get:function(){return _lifecycleStore.resetPower}});Object.defineProperty(exports,"returnToApp",{enumerable:true,get:function(){return _lifecycleStore.returnToApp}});Object.defineProperty(exports,"runRecipe",{enumerable:true,get:function(){return _recipes.runRecipe}});Object.defineProperty(exports,"sendToBackground",{enumerable:true,get:function(){return _lifecycleStore.sendToBackground}});Object.defineProperty(exports,"setColorScheme",{enumerable:true,get:function(){return _lifecycleStore.setColorScheme}});Object.defineProperty(exports,"setPower",{enumerable:true,get:function(){return _lifecycleStore.setPower}});Object.defineProperty(exports,"subscribeLifecycle",{enumerable:true,get:function(){return _lifecycleStore.subscribeLifecycle}});var _lifecycleStore=require("./engine/lifecycleStore");var _LifecycleChip=require("./components/LifecycleChip");var _readSavedSync=require("./engine/readSavedSync");var _preset=require("./preset");var _LifecycleBody=require("./components/LifecycleBody");var _LifecycleToolView=require("./components/LifecycleToolView");var _sharedUi=require("@buoy-gg/shared-ui");var _lifecycleSyncAdapter=require("./sync/lifecycleSyncAdapter");var _recipes=require("./engine/recipes");const isReactNativeRuntime=typeof navigator!=="undefined"&&navigator.product==="ReactNative";const isCapacitorShell=(()=>{try{const e=globalThis.Capacitor;return e?.isNativePlatform?.()===true}catch{return false}})();if(isReactNativeRuntime||isCapacitorShell){(0,_LifecycleChip.watchLifecycleChip)();const e=typeof __DEV__!=="undefined"&&__DEV__;if(e||(0,_readSavedSync.readSavedSync)()?.pendingRelaunch)(0,_lifecycleStore.bootLifecycle)()}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.lifecycleSyncAdapter=void 0;exports.parseDurationMs=parseDurationMs;var _sharedUi=require("@buoy-gg/shared-ui");var _lifecycleStore=require("../engine/lifecycleStore");var _recipes=require("../engine/recipes");function obj(e){return e&&typeof e==="object"?e:{}}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 UNITS={ms:1,s:1e3,m:6e4,min:6e4,h:36e5,d:864e5};function parseDurationMs(e){if(e==null||e==="")return null;if(typeof e==="number")return Number.isFinite(e)&&e>0?e:null;if(typeof e!=="string")return null;const r=/^\s*(\d+(?:\.\d+)?)\s*(ms|s|min|m|h|d)?\s*$/i.exec(e);if(!r)throw new Error(`Can't read the duration "${e}". Use ms or a value like "30s", "5m", "2h".`);return Number(r[1])*UNITS[(r[2]??"ms").toLowerCase()]}function awayOptions(e){const r=obj(e);return{durationMs:parseDurationMs(r.duration??r.durationMs??r.for),skipWait:boolParam(r,"skipWait")??false}}function snapshot(e=(0,_lifecycleStore.getLifecycleSnapshot)()){return{...e,recipes:_recipes.RECIPES.map(r=>({id:r.id,title:r.title,detail:r.detail,unavailable:(0,_recipes.recipeAvailability)(r,e)}))}}const lifecycleSyncAdapter=exports.lifecycleSyncAdapter=(0,_sharedUi.createSyncAdapter)({version:1,getSnapshot(){return snapshot()},subscribe(e){return(0,_lifecycleStore.subscribeLifecycle)(e)},actions:{getState(){return snapshot((0,_lifecycleStore.refreshSnapshot)())},background(e){return snapshot((0,_lifecycleStore.sendToBackground)(awayOptions(e)))},interrupt(e){return snapshot((0,_lifecycleStore.interrupt)(awayOptions(e)))},returnToApp(){return snapshot((0,_lifecycleStore.returnToApp)())},memoryWarning(){return snapshot((0,_lifecycleStore.memoryWarning)())},openUrl(e){const r=obj(e);const t=r.url??r.link??r.href;if(typeof t!=="string")throw new Error('openUrl needs `url`, like "myapp://orders/42".');return snapshot((0,_lifecycleStore.openDeepLink)(t))},pressBack(){const e=(0,_lifecycleStore.
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.lifecycleSyncAdapter=void 0;exports.parseDurationMs=parseDurationMs;var _sharedUi=require("@buoy-gg/shared-ui");var _lifecycleStore=require("../engine/lifecycleStore");var _recipes=require("../engine/recipes");function obj(e){return e&&typeof e==="object"?e:{}}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 UNITS={ms:1,s:1e3,m:6e4,min:6e4,h:36e5,d:864e5};function parseDurationMs(e){if(e==null||e==="")return null;if(typeof e==="number")return Number.isFinite(e)&&e>0?e:null;if(typeof e!=="string")return null;const r=/^\s*(\d+(?:\.\d+)?)\s*(ms|s|min|m|h|d)?\s*$/i.exec(e);if(!r)throw new Error(`Can't read the duration "${e}". Use ms or a value like "30s", "5m", "2h".`);return Number(r[1])*UNITS[(r[2]??"ms").toLowerCase()]}function awayOptions(e){const r=obj(e);return{durationMs:parseDurationMs(r.duration??r.durationMs??r.for),skipWait:boolParam(r,"skipWait")??false}}function snapshot(e=(0,_lifecycleStore.getLifecycleSnapshot)()){return{...e,recipes:_recipes.RECIPES.map(r=>({id:r.id,title:r.title,detail:r.detail,unavailable:(0,_recipes.recipeAvailability)(r,e)}))}}const lifecycleSyncAdapter=exports.lifecycleSyncAdapter=(0,_sharedUi.createSyncAdapter)({version:1,getSnapshot(){return snapshot()},subscribe(e){return(0,_lifecycleStore.subscribeLifecycle)(e)},actions:{getState(){return snapshot((0,_lifecycleStore.refreshSnapshot)())},background(e){return snapshot((0,_lifecycleStore.sendToBackground)(awayOptions(e)))},interrupt(e){return snapshot((0,_lifecycleStore.interrupt)(awayOptions(e)))},returnToApp(){return snapshot((0,_lifecycleStore.returnToApp)())},memoryWarning(){return snapshot((0,_lifecycleStore.memoryWarning)())},openUrl(e){const r=obj(e);const t=r.url??r.link??r.href;if(typeof t!=="string")throw new Error('openUrl needs `url`, like "myapp://orders/42".');return snapshot((0,_lifecycleStore.openDeepLink)(t))},async pressBack(){const e=await(0,_lifecycleStore.pressBackAsync)();return{...snapshot(e.snapshot),handled:e.handled}},setColorScheme(e){const r=obj(e);const t=r.scheme??r.colorScheme;if(t==="system")return snapshot((0,_lifecycleStore.resetColorScheme)());if(t!=="light"&&t!=="dark"){throw new Error('setColorScheme needs `scheme`: "light", "dark" or "system".')}const n=r.mode==="native"?"native":"js";return snapshot((0,_lifecycleStore.setColorScheme)(t,n))},setPower(e){const r=obj(e);const t=r.level??r.batteryLevel;return snapshot((0,_lifecycleStore.setPower)({lowPowerMode:boolParam(r,"lowPowerMode"),level:typeof t==="number"?t:typeof t==="string"?Number(t):void 0,state:typeof r.state==="string"?r.state:void 0}))},resetPower(){return snapshot((0,_lifecycleStore.resetPower)())},async relaunch(){return snapshot(await(0,_lifecycleStore.relaunchApp)())},async prepareRelaunch(){return snapshot(await(0,_lifecycleStore.prepareRelaunch)())},goBackToBeforeRelaunch(){return snapshot((0,_lifecycleStore.goBackToBeforeRelaunch)())},dismissRelaunchReport(){return snapshot((0,_lifecycleStore.dismissRelaunchReport)())},async runRecipe(e){const r=obj(e);const t=r.id??r.recipe;if(typeof t!=="string"){throw new Error(`runRecipe needs \`id\`: ${_recipes.RECIPES.map(n=>n.id).join(", ")}.`)}return snapshot(await(0,_recipes.runRecipe)(t))},clearReport(){return snapshot((0,_lifecycleStore.clearReport)())},reset(){return snapshot((0,_lifecycleStore.resetLifecycle)())},updateSettings(e){const r=obj(e);const t=r.reportWindowMs??r.reportWindow;return snapshot((0,_lifecycleStore.updateSettings)({showChip:boolParam(r,"showChip"),reportWindowMs:t!=null?parseDurationMs(t)??void 0:void 0}))}}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useEffect as $,useRef as V,useState as w}from"react";import{ScrollView as O,StyleSheet as j,Text as a,TextInput as F,TouchableOpacity as p,View as u}from"react-native";import{AlertTriangle as _,CheckCircle as U,ChevronDown as K,ChevronRight as G,NightButton as D,NightCard as b,NightFootnote as m,NightRows as I,NightSectionLabel as x,NightSegmented as z,NightSwitch as L,Play as q,monoFont as A,night as l,realNow as C,useSafeAreaInsets as Y}from"@buoy-gg/shared-ui";import{awayTimer as J,awayTitle as Q,countsLine as W,groupEvents as N,simulatedLine as X,sourceLabel as Z,verdict as ee}from"./format";import{jsx as e,jsxs as c,Fragment as te}from"react/jsx-runtime";const B="#A3E635";const ne=[{key:"hold",label:"No limit"},{key:"5000",label:"5 s"},{key:"60000",label:"1 min"},{key:"300000",label:"5 min"},{key:"1800000",label:"30 min"}];const le=6e4;function H(t){const[r,i]=w(()=>C());$(()=>{if(!t)return void 0;const o=setInterval(()=>i(C()),1e3);return()=>clearInterval(o)},[t]);return t?r:C()}export function LifecycleToolView({snapshot:t,onAction:r}){const i=Y({minBottom:16});const o=V(null);const[s,d]=w(null);const y=(f,h)=>{d(null);o.current?.scrollTo({y:0,animated:true});r(f,h).catch(g=>{d(g instanceof Error?g.message:String(g))})};if(!t){return e(u,{style:n.waiting,testID:"lifecycle-waiting",children:e(m,{centered:true,children:"Waiting for the app\u2026"})})}return c(O,{ref:o,style:n.fill,contentContainerStyle:[n.content,{paddingBottom:i.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[e(ie,{snapshot:t,run:y}),s?e(m,{tone:"danger",centered:true,children:e(a,{testID:"lifecycle-error",children:s})}):null,e(ae,{snapshot:t,run:y}),e(de,{snapshot:t,run:y})]})}function ie({snapshot:t,run:r}){const i=X(t);let o;if(t.away)o=e(re,{snapshot:t,run:r});else if(t.relaunch)o=e(ce,{snapshot:t,run:r});else if(t.report)o=e(oe,{snapshot:t,run:r});else{o=e(a,{style:n.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."})}return c(u,{style:n.status,children:[o,i&&!t.away?e(b,{children:c(u,{style:n.row,children:[c(u,{style:n.rowText,children:[e(a,{style:n.simulatedLabel,children:"Simulated"}),e(a,{style:n.rowTitle,testID:"lifecycle-simulated",children:i})]}),e(D,{label:"Stop Simulating",size:"md",fullWidth:false,testID:"lifecycle-reset",accessibilityLabel:"End every simulation",onPress:()=>r("reset")})]})}):null]})}function re({snapshot:t,run:r}){const i=H(true);const o=t.away;const s=Q(o.kind,t.platform==="android");const d=t.report;const y=d?d.events.filter(f=>f.whileAway):[];return c(u,{style:n.running,children:[e(a,{style:n.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${s} (simulated)`,children:s}),e(a,{style:n.runningTimer,testID:"lifecycle-hero-status",children:J(t,i)}),e(u,{style:n.runningButton,children:e(D,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>r("returnToApp")})}),d?.finding?e(a,{style:n.runningWarning,testID:"lifecycle-report-finding",children:d.finding}):y.length>0?c(a,{style:n.runningNote,children:["So far: ",W(y)]}):null]})}function E({verdict:t}){const r=t.tone==="warn"?l.color.warning:t.tone==="good"?l.color.accent:l.color.text;return c(u,{style:n.verdict,children:[t.tone==="warn"?e(_,{size:20,color:r}):t.tone==="good"?e(U,{size:20,color:r}):null,c(u,{style:n.rowText,children:[e(a,{style:[n.verdictTitle,{color:r}],testID:"lifecycle-verdict",children:t.title}),t.detail?e(a,{style:n.verdictDetail,testID:"lifecycle-report-finding",children:t.detail}):null]})]})}const M=5;function oe({snapshot:t,run:r}){const i=t.report;const o=i.collectingUntil!=null;const s=H(o);const[d,y]=w(false);const f=ee(t,i);const h=i.events.filter(v=>v.whileAway);const g=i.events.filter(v=>!v.whileAway);const S=i.kind!=="signal";const R=o?Math.max(0,(i.collectingUntil??s)-s):0;return e(b,{children:c(u,{style:n.result,testID:"lifecycle-report",children:[e(E,{verdict:f}),S||o?e(a,{style:n.resultLabel,testID:"lifecycle-report-label",children:S?`${i.label}${o?` \xB7 watching ${Math.ceil(R/1e3)} s`:""}`:`Watching ${Math.ceil(R/1e3)} s`}):null,i.unavailable?null:i.events.length===0?o?null:e(a,{style:n.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):c(te,{children:[S&&h.length>0?e(P,{title:"While away",events:h,showAll:d}):null,g.length>0?e(P,{title:S?"After returning":"What your app did",events:g,showAll:d}):null,!S&&h.length>0?e(P,{title:"What your app did",events:h,showAll:d}):null]}),c(u,{style:n.resultButtons,children:[N(i.events).length>M?e(p,{onPress:()=>y(v=>!v),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:d?"Show Less":"Show All"})}):e(u,{}),e(p,{onPress:()=>r("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:"Done"})})]})]})})}function P({title:t,events:r,showAll:i}){const o=N(r);const s=i?o:o.slice(0,M);return c(u,{style:n.eventList,children:[e(a,{style:n.eventHeading,children:`${t} \xB7 ${W(r)}`}),s.map(d=>c(u,{style:n.event,children:[e(a,{style:n.eventSource,children:Z(d.source)}),e(a,{style:[n.eventTitle,d.error?n.eventError:null],numberOfLines:1,children:d.title}),d.count>1?e(a,{style:n.eventCount,children:`\xD7${d.count}`}):null]},`${d.source}-${d.title}`)),o.length>s.length?e(a,{style:n.detail,children:`${o.length-s.length} more`}):null]})}const T=t=>t==="/"?"the home screen":t;function ce({snapshot:t,run:r}){const i=t.relaunch;const o=i.after==null&&i.restored==null&&i.tookMs==null;const s=o?{tone:"neutral",title:"Checking where your app reopened\u2026"}:i.restored===true?{tone:"good",title:`Reopened where you were: ${T(i.after)}`}:i.after?{tone:"warn",title:`Opened ${T(i.after)} instead of ${T(i.before)??"the screen you were on"}`,detail:"The app doesn't restore the last screen after it's closed."}:{tone:"neutral",title:"Couldn't read the screen after reopening"};return e(b,{children:c(u,{style:n.result,testID:"lifecycle-relaunch-report",children:[e(u,{testID:"lifecycle-relaunch-result",children:e(E,{verdict:s})}),c(u,{style:n.resultButtons,children:[i.restored===false&&i.beforeHref?e(p,{onPress:()=>r("goBackToBeforeRelaunch"),testID:"lifecycle-relaunch-go-back",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:`Go to ${T(i.before)}`})}):e(u,{}),e(p,{onPress:()=>r("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:"Done"})})]})]})})}function ae({snapshot:t,run:r}){const i=t.host?.appScheme;const[o,s]=w(i?`${i}://`:"");const d=t.batteryLibraries.length>0;const y=t.recipes.filter(h=>h.id!=="dying-battery"||d);const f=t.away!=null;return c(u,{children:[e(x,{children:"Test a moment"}),e(b,{children:c(I,{children:[y.map(h=>e(se,{recipe:h,disabled:f,onPress:()=>r("runRecipe",{id:h.id})},h.id)),c(u,{style:n.stack,children:[e(a,{style:n.rowTitle,children:"Open a link"}),c(u,{style:n.inputRow,children:[e(F,{testID:"lifecycle-url-input",accessibilityLabel:"Link to open",value:o,onChangeText:s,placeholder:"myapp://orders/42",placeholderTextColor:l.color.placeholder,autoCapitalize:"none",autoCorrect:false,keyboardType:"url",returnKeyType:"go",onSubmitEditing:()=>r("openUrl",{url:o}),style:n.input}),e(D,{label:"Open",size:"md",fullWidth:false,testID:"lifecycle-url-open",accessibilityLabel:"Open this link in the app",onPress:()=>r("openUrl",{url:o})})]}),t.listeners.deepLink===0?e(a,{style:n.warning,children:"Nothing in your app listens for links."}):null]},"link")]})})]})}function se({recipe:t,disabled:r,onPress:i}){const o=r||!!t.unavailable;return c(p,{testID:`lifecycle-recipe-${t.id}`,accessibilityRole:"button",accessibilityLabel:t.title,accessibilityHint:t.unavailable??t.detail,accessibilityState:{disabled:o},disabled:o,activeOpacity:.6,onPress:i,style:[n.row,o?n.rowDisabled:null],children:[c(u,{style:n.rowText,children:[e(a,{style:n.rowTitle,children:t.title}),e(a,{style:n.detail,children:t.unavailable??t.detail})]}),t.unavailable?null:e(q,{size:16,color:l.color.accent})]})}function de({snapshot:t,run:r}){const[i,o]=w(false);const s=i?K:G;return c(u,{children:[c(p,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:i},onPress:()=>o(d=>!d),style:n.disclosure,hitSlop:8,children:[e(a,{style:n.disclosureText,children:"Custom"}),e(s,{size:16,color:l.color.textSecondary})]}),i?c(u,{style:n.customBody,children:[e(ue,{snapshot:t,run:r}),e(he,{snapshot:t,run:r}),e(m,{children:"Only your app's JavaScript hears these events. Timers, requests and native code keep running, and a real event from the OS ends the simulation."})]}):null]})}function ue({snapshot:t,run:r}){const[i,o]=w("hold");const s=i==="hold"?null:Number(i);const d=s!=null&&s>=le;const y=d&&t.clockAvailable;const f=()=>({durationMs:s,skipWait:y});const h=t.platform==="android";const g=t.away!=null;return c(u,{children:[e(x,{children:"Leave the app"}),c(b,{children:[e(u,{style:n.segmentWrap,children:e(z,{tabs:ne,activeKey:i,size:"sm",testIDPrefix:"lifecycle-duration",onChange:o})}),c(I,{children:[e(k,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:g,onPress:()=>r("background",f())},"background"),e(k,{title:h?"Pull Down Notifications":"Take a Call",detail:h?"The app stays visible but loses focus":"The app stays visible but inactive, like with Control Center open",testID:"lifecycle-interrupt",disabled:g,onPress:()=>r("interrupt",f())},"interrupt")]})]}),d?e(m,{children:t.clockAvailable?"Moves the app clock forward instead of waiting.":"Waits in real time. Install @buoy-gg/clock to skip the wait."}):null,t.listeners.appState===0?e(m,{tone:"warning",children:"Nothing in your app listens for app state changes."}):null]})}const ye=[{key:"real",label:"Real"},{key:"100",label:"100%"},{key:"20",label:"20%"},{key:"5",label:"5%"}];function he({snapshot:t,run:r}){const i=t.platform==="android";const o=t.batteryLibraries.length>0;const s=t.power;const d=t.listeners.memoryWarning===0?"Nothing in your app listens for it":i?"Android never sends this, but your listeners will run":void 0;return c(u,{children:[e(x,{children:"Signals"}),e(b,{children:c(I,{children:[e(k,{title:"Send Memory Warning",detail:d,warn:t.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>r("memoryWarning")},"memory"),c(u,{style:n.stack,children:[e(a,{style:n.rowTitle,children:"Appearance"}),e(z,{tabs:[{key:"system",label:"System"},{key:"light",label:"Light"},{key:"dark",label:"Dark"}],activeKey:t.scheme?.scheme??"system",size:"sm",testIDPrefix:"lifecycle-scheme",onChange:y=>r("setColorScheme",{scheme:y})})]},"scheme"),o?c(u,{style:n.stack,children:[e(a,{style:n.rowTitle,children:"Battery"}),e(z,{tabs:ye,activeKey:s?String(Math.round(s.level*100)):"real",size:"sm",testIDPrefix:"lifecycle-battery",onChange:y=>y==="real"?r("resetPower"):r("setPower",{level:Number(y)/100})}),c(u,{style:n.inlineRow,children:[e(a,{style:n.rowTitle,children:"Charging"}),e(L,{value:s?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:y=>r("setPower",{state:y?"charging":"unplugged"})})]}),c(u,{style:n.inlineRow,children:[e(a,{style:n.rowTitle,children:"Low Power Mode"}),e(L,{value:s?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:y=>r("setPower",{lowPowerMode:y})})]}),t.listeners.battery===0?e(a,{style:n.warning,children:"Nothing in your app listens for battery changes."}):null]},"battery"):null,i?e(k,{title:"Press Back",detail:"Never closes the app. The result says if a real press would have.",testID:"lifecycle-back",onPress:()=>r("pressBack")},"back"):null]})}),o?null:e(m,{children:"Battery needs expo-battery or react-native-device-info in your app."})]})}function k({title:t,detail:r,warn:i,testID:o,disabled:s,onPress:d}){return e(p,{testID:o,accessibilityRole:"button",accessibilityLabel:t,accessibilityState:{disabled:!!s},activeOpacity:.6,disabled:s,onPress:d,style:[n.row,s?n.rowDisabled:null],children:c(u,{style:n.rowText,children:[e(a,{style:n.actionTitle,children:t}),r?e(a,{style:i?n.warning:n.detail,children:r}):null]})})}const n=j.create({fill:{flex:1},content:{paddingHorizontal:l.gutter,paddingTop:8,gap:l.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},status:{gap:12},intro:{color:l.color.textSecondary,fontSize:l.font.body,lineHeight:20,paddingHorizontal:l.labelInset,paddingTop:4},running:{alignItems:"center",paddingTop:12,gap:6},runningTitle:{color:B,fontSize:30,fontWeight:"300"},runningTimer:{color:l.color.textSecondary,fontSize:l.font.row,fontWeight:"500",fontVariant:["tabular-nums"]},runningButton:{alignSelf:"stretch",marginTop:10},runningWarning:{color:l.color.warning,fontSize:l.font.caption,textAlign:"center",marginTop:4},runningNote:{color:l.color.textTertiary,fontSize:l.font.caption,textAlign:"center",marginTop:4},simulatedLabel:{color:B,fontSize:l.font.micro,fontWeight:"600",textTransform:"uppercase",letterSpacing:.4},result:{paddingHorizontal:l.rowPadH,paddingVertical:14,gap:12},verdict:{flexDirection:"row",gap:10,alignItems:"flex-start"},verdictTitle:{fontSize:l.font.title,fontWeight:"600"},verdictDetail:{color:l.color.textSecondary,fontSize:l.font.caption,lineHeight:18},resultLabel:{color:l.color.textTertiary,fontSize:l.font.caption,fontVariant:["tabular-nums"]},resultButtons:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},link:{color:l.color.accent,fontSize:l.font.row,fontWeight:"500"},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:l.rowPadH,paddingVertical:10},rowText:{flex:1,gap:2},rowDisabled:{opacity:.4},rowTitle:{color:l.color.text,fontSize:l.font.row},actionTitle:{color:l.color.accent,fontSize:l.font.row},detail:{color:l.color.textTertiary,fontSize:l.font.caption},warning:{color:l.color.warning,fontSize:l.font.caption},stack:{paddingHorizontal:l.rowPadH,paddingVertical:12,gap:10},segmentWrap:{paddingHorizontal:l.rowPadH,paddingTop:12,paddingBottom:4},inlineRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},inputRow:{flexDirection:"row",alignItems:"center",gap:8},input:{flex:1,color:l.color.text,fontFamily:A,fontSize:14,backgroundColor:l.color.bg,borderRadius:l.radius.input,borderWidth:1,borderColor:l.color.border,paddingHorizontal:12,paddingVertical:8},disclosure:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:l.labelInset},disclosureText:{color:l.color.textSecondary,fontSize:l.font.label,fontWeight:"600",textTransform:"uppercase",letterSpacing:.8},customBody:{gap:l.groupGap,marginTop:12},eventList:{gap:6},eventHeading:{color:l.color.textSecondary,fontSize:l.font.caption,fontWeight:"600"},event:{flexDirection:"row",gap:8,alignItems:"baseline"},eventSource:{width:56,color:l.color.textTertiary,fontSize:l.font.caption},eventTitle:{flex:1,color:l.color.text,fontSize:13,fontFamily:A},eventError:{color:l.color.danger},eventCount:{color:l.color.textSecondary,fontSize:l.font.caption,fontWeight:"600",fontVariant:["tabular-nums"]}});
|
|
1
|
+
"use strict";import{useEffect as $,useRef as V,useState as w}from"react";import{ScrollView as O,StyleSheet as j,Text as a,TextInput as F,TouchableOpacity as p,View as u}from"react-native";import{AlertTriangle as _,CheckCircle as U,ChevronDown as K,ChevronRight as G,NightButton as D,NightCard as b,NightFootnote as m,NightRows as I,NightSectionLabel as x,NightSegmented as z,NightSwitch as L,Play as q,monoFont as A,night as l,realNow as C,useSafeAreaInsets as Y}from"@buoy-gg/shared-ui";import{awayTimer as J,awayTitle as Q,countsLine as W,groupEvents as N,simulatedLine as X,sourceLabel as Z,verdict as ee}from"./format";import{jsx as e,jsxs as c,Fragment as te}from"react/jsx-runtime";const B="#A3E635";const ne=[{key:"hold",label:"No limit"},{key:"5000",label:"5 s"},{key:"60000",label:"1 min"},{key:"300000",label:"5 min"},{key:"1800000",label:"30 min"}];const le=6e4;function H(t){const[r,i]=w(()=>C());$(()=>{if(!t)return void 0;const o=setInterval(()=>i(C()),1e3);return()=>clearInterval(o)},[t]);return t?r:C()}export function LifecycleToolView({snapshot:t,onAction:r}){const i=Y({minBottom:16});const o=V(null);const[s,d]=w(null);const y=(f,h)=>{d(null);o.current?.scrollTo({y:0,animated:true});r(f,h).catch(g=>{d(g instanceof Error?g.message:String(g))})};if(!t){return e(u,{style:n.waiting,testID:"lifecycle-waiting",children:e(m,{centered:true,children:"Waiting for the app\u2026"})})}return c(O,{ref:o,style:n.fill,contentContainerStyle:[n.content,{paddingBottom:i.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[e(ie,{snapshot:t,run:y}),s?e(m,{tone:"danger",centered:true,children:e(a,{testID:"lifecycle-error",children:s})}):null,e(ae,{snapshot:t,run:y}),e(de,{snapshot:t,run:y})]})}function ie({snapshot:t,run:r}){const i=X(t);let o;if(t.away)o=e(re,{snapshot:t,run:r});else if(t.relaunch)o=e(ce,{snapshot:t,run:r});else if(t.report)o=e(oe,{snapshot:t,run:r});else{o=e(a,{style:n.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."})}return c(u,{style:n.status,children:[o,i&&!t.away?e(b,{children:c(u,{style:n.row,children:[c(u,{style:n.rowText,children:[e(a,{style:n.simulatedLabel,children:"Simulated"}),e(a,{style:n.rowTitle,testID:"lifecycle-simulated",children:i})]}),e(D,{label:"Stop Simulating",size:"md",fullWidth:false,testID:"lifecycle-reset",accessibilityLabel:"End every simulation",onPress:()=>r("reset")})]})}):null]})}function re({snapshot:t,run:r}){const i=H(true);const o=t.away;const s=Q(o.kind,t.platform==="android");const d=t.report;const y=d?d.events.filter(f=>f.whileAway):[];return c(u,{style:n.running,children:[e(a,{style:n.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${s} (simulated)`,children:s}),e(a,{style:n.runningTimer,testID:"lifecycle-hero-status",children:J(t,i)}),e(u,{style:n.runningButton,children:e(D,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>r("returnToApp")})}),d?.finding?e(a,{style:n.runningWarning,testID:"lifecycle-report-finding",children:d.finding}):y.length>0?c(a,{style:n.runningNote,children:["So far: ",W(y)]}):null]})}function E({verdict:t}){const r=t.tone==="warn"?l.color.warning:t.tone==="good"?l.color.accent:l.color.text;return c(u,{style:n.verdict,children:[t.tone==="warn"?e(_,{size:20,color:r}):t.tone==="good"?e(U,{size:20,color:r}):null,c(u,{style:n.rowText,children:[e(a,{style:[n.verdictTitle,{color:r}],testID:"lifecycle-verdict",children:t.title}),t.detail?e(a,{style:n.verdictDetail,testID:"lifecycle-report-finding",children:t.detail}):null]})]})}const M=5;function oe({snapshot:t,run:r}){const i=t.report;const o=i.collectingUntil!=null;const s=H(o);const[d,y]=w(false);const f=ee(t,i);const h=i.events.filter(v=>v.whileAway);const g=i.events.filter(v=>!v.whileAway);const S=i.kind!=="signal";const R=o?Math.max(0,(i.collectingUntil??s)-s):0;return e(b,{children:c(u,{style:n.result,testID:"lifecycle-report",children:[e(E,{verdict:f}),S||o?e(a,{style:n.resultLabel,testID:"lifecycle-report-label",children:S?`${i.label}${o?` \xB7 watching ${Math.ceil(R/1e3)} s`:""}`:`Watching ${Math.ceil(R/1e3)} s`}):null,i.unavailable?null:i.events.length===0?o?null:e(a,{style:n.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):c(te,{children:[S&&h.length>0?e(P,{title:"While away",events:h,showAll:d}):null,g.length>0?e(P,{title:S?"After returning":"What your app did",events:g,showAll:d}):null,!S&&h.length>0?e(P,{title:"What your app did",events:h,showAll:d}):null]}),c(u,{style:n.resultButtons,children:[N(i.events).length>M?e(p,{onPress:()=>y(v=>!v),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:d?"Show Less":"Show All"})}):e(u,{}),e(p,{onPress:()=>r("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:"Done"})})]})]})})}function P({title:t,events:r,showAll:i}){const o=N(r);const s=i?o:o.slice(0,M);return c(u,{style:n.eventList,children:[e(a,{style:n.eventHeading,children:`${t} \xB7 ${W(r)}`}),s.map(d=>c(u,{style:n.event,children:[e(a,{style:n.eventSource,children:Z(d.source)}),e(a,{style:[n.eventTitle,d.error?n.eventError:null],numberOfLines:1,children:d.title}),d.count>1?e(a,{style:n.eventCount,children:`\xD7${d.count}`}):null]},`${d.source}-${d.title}`)),o.length>s.length?e(a,{style:n.detail,children:`${o.length-s.length} more`}):null]})}const T=t=>t==="/"?"the home screen":t;function ce({snapshot:t,run:r}){const i=t.relaunch;const o=i.after==null&&i.restored==null&&i.tookMs==null;const s=o?{tone:"neutral",title:"Checking where your app reopened\u2026"}:i.restored===true?{tone:"good",title:`Reopened where you were: ${T(i.after)}`}:i.after?{tone:"warn",title:`Opened ${T(i.after)} instead of ${T(i.before)??"the screen you were on"}`,detail:"The app doesn't restore the last screen after it's closed."}:{tone:"neutral",title:"Couldn't read the screen after reopening"};return e(b,{children:c(u,{style:n.result,testID:"lifecycle-relaunch-report",children:[e(u,{testID:"lifecycle-relaunch-result",children:e(E,{verdict:s})}),c(u,{style:n.resultButtons,children:[i.restored===false&&i.beforeHref?e(p,{onPress:()=>r("goBackToBeforeRelaunch"),testID:"lifecycle-relaunch-go-back",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:`Go to ${T(i.before)}`})}):e(u,{}),e(p,{onPress:()=>r("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:e(a,{style:n.link,children:"Done"})})]})]})})}function ae({snapshot:t,run:r}){const i=t.host?.appScheme;const[o,s]=w(i?`${i}://`:"");const d=t.batteryLibraries.length>0;const y=t.recipes.filter(h=>h.id!=="dying-battery"||d);const f=t.away!=null;return c(u,{children:[e(x,{children:"Test a moment"}),e(b,{children:c(I,{children:[y.map(h=>e(se,{recipe:h,disabled:f,onPress:()=>r("runRecipe",{id:h.id})},h.id)),c(u,{style:n.stack,children:[e(a,{style:n.rowTitle,children:"Open a link"}),c(u,{style:n.inputRow,children:[e(F,{testID:"lifecycle-url-input",accessibilityLabel:"Link to open",value:o,onChangeText:s,placeholder:"myapp://orders/42",placeholderTextColor:l.color.placeholder,autoCapitalize:"none",autoCorrect:false,keyboardType:"url",returnKeyType:"go",onSubmitEditing:()=>r("openUrl",{url:o}),style:n.input}),e(D,{label:"Open",size:"md",fullWidth:false,testID:"lifecycle-url-open",accessibilityLabel:"Open this link in the app",onPress:()=>r("openUrl",{url:o})})]}),t.listeners.deepLink===0?e(a,{style:n.warning,children:"Nothing in your app listens for links."}):null]},"link")]})})]})}function se({recipe:t,disabled:r,onPress:i}){const o=r||!!t.unavailable;return c(p,{testID:`lifecycle-recipe-${t.id}`,accessibilityRole:"button",accessibilityLabel:t.title,accessibilityHint:t.unavailable??t.detail,accessibilityState:{disabled:o},disabled:o,activeOpacity:.6,onPress:i,style:[n.row,o?n.rowDisabled:null],children:[c(u,{style:n.rowText,children:[e(a,{style:n.rowTitle,children:t.title}),e(a,{style:n.detail,children:t.unavailable??t.detail})]}),t.unavailable?null:e(q,{size:16,color:l.color.accent})]})}function de({snapshot:t,run:r}){const[i,o]=w(false);const s=i?K:G;return c(u,{children:[c(p,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:i},onPress:()=>o(d=>!d),style:n.disclosure,hitSlop:8,children:[e(a,{style:n.disclosureText,children:"Custom"}),e(s,{size:16,color:l.color.textSecondary})]}),i?c(u,{style:n.customBody,children:[e(ue,{snapshot:t,run:r}),e(he,{snapshot:t,run:r}),e(m,{children:"Only your app's JavaScript hears these events. Timers, requests and native code keep running, and a real event from the OS ends the simulation."})]}):null]})}function ue({snapshot:t,run:r}){const[i,o]=w("hold");const s=i==="hold"?null:Number(i);const d=s!=null&&s>=le;const y=d&&t.clockAvailable;const f=()=>({durationMs:s,skipWait:y});const h=t.platform==="android";const g=t.away!=null;return c(u,{children:[e(x,{children:"Leave the app"}),c(b,{children:[e(u,{style:n.segmentWrap,children:e(z,{tabs:ne,activeKey:i,size:"sm",testIDPrefix:"lifecycle-duration",onChange:o})}),c(I,{children:[e(k,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:g,onPress:()=>r("background",f())},"background"),e(k,{title:h?"Pull Down Notifications":"Take a Call",detail:h?"The app stays visible but loses focus":"The app stays visible but inactive, like with Control Center open",testID:"lifecycle-interrupt",disabled:g,onPress:()=>r("interrupt",f())},"interrupt")]})]}),d?e(m,{children:t.clockAvailable?"Moves the app clock forward instead of waiting.":"Waits in real time. Install @buoy-gg/clock to skip the wait."}):null,t.listeners.appState===0?e(m,{tone:"warning",children:"Nothing in your app listens for app state changes."}):null]})}const ye=[{key:"real",label:"Real"},{key:"100",label:"100%"},{key:"20",label:"20%"},{key:"5",label:"5%"}];function he({snapshot:t,run:r}){const i=t.platform==="android";const o=t.batteryLibraries.length>0;const s=t.power;const d=t.listeners.memoryWarning===0?"Nothing in your app listens for it":i?"Android never sends this, but your listeners will run":void 0;return c(u,{children:[e(x,{children:"Signals"}),e(b,{children:c(I,{children:[e(k,{title:"Send Memory Warning",detail:d,warn:t.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>r("memoryWarning")},"memory"),c(u,{style:n.stack,children:[e(a,{style:n.rowTitle,children:"Appearance"}),e(z,{tabs:[{key:"system",label:"System"},{key:"light",label:"Light"},{key:"dark",label:"Dark"}],activeKey:t.scheme?.scheme??"system",size:"sm",testIDPrefix:"lifecycle-scheme",onChange:y=>r("setColorScheme",{scheme:y})})]},"scheme"),o?c(u,{style:n.stack,children:[e(a,{style:n.rowTitle,children:"Battery"}),e(z,{tabs:ye,activeKey:s?String(Math.round(s.level*100)):"real",size:"sm",testIDPrefix:"lifecycle-battery",onChange:y=>y==="real"?r("resetPower"):r("setPower",{level:Number(y)/100})}),c(u,{style:n.inlineRow,children:[e(a,{style:n.rowTitle,children:"Charging"}),e(L,{value:s?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:y=>r("setPower",{state:y?"charging":"unplugged"})})]}),c(u,{style:n.inlineRow,children:[e(a,{style:n.rowTitle,children:"Low Power Mode"}),e(L,{value:s?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:y=>r("setPower",{lowPowerMode:y})})]}),t.listeners.battery===0?e(a,{style:n.warning,children:"Nothing in your app listens for battery changes."}):null]},"battery"):null,i?e(k,{title:"Press Back",detail:"Never closes the app. The result says if a real press would have.",testID:"lifecycle-back",onPress:()=>r("pressBack")},"back"):null]})}),o?null:e(m,{children:"Battery needs expo-battery, react-native-device-info or @capacitor/device in your app."})]})}function k({title:t,detail:r,warn:i,testID:o,disabled:s,onPress:d}){return e(p,{testID:o,accessibilityRole:"button",accessibilityLabel:t,accessibilityState:{disabled:!!s},activeOpacity:.6,disabled:s,onPress:d,style:[n.row,s?n.rowDisabled:null],children:c(u,{style:n.rowText,children:[e(a,{style:n.actionTitle,children:t}),r?e(a,{style:i?n.warning:n.detail,children:r}):null]})})}const n=j.create({fill:{flex:1},content:{paddingHorizontal:l.gutter,paddingTop:8,gap:l.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},status:{gap:12},intro:{color:l.color.textSecondary,fontSize:l.font.body,lineHeight:20,paddingHorizontal:l.labelInset,paddingTop:4},running:{alignItems:"center",paddingTop:12,gap:6},runningTitle:{color:B,fontSize:30,fontWeight:"300"},runningTimer:{color:l.color.textSecondary,fontSize:l.font.row,fontWeight:"500",fontVariant:["tabular-nums"]},runningButton:{alignSelf:"stretch",marginTop:10},runningWarning:{color:l.color.warning,fontSize:l.font.caption,textAlign:"center",marginTop:4},runningNote:{color:l.color.textTertiary,fontSize:l.font.caption,textAlign:"center",marginTop:4},simulatedLabel:{color:B,fontSize:l.font.micro,fontWeight:"600",textTransform:"uppercase",letterSpacing:.4},result:{paddingHorizontal:l.rowPadH,paddingVertical:14,gap:12},verdict:{flexDirection:"row",gap:10,alignItems:"flex-start"},verdictTitle:{fontSize:l.font.title,fontWeight:"600"},verdictDetail:{color:l.color.textSecondary,fontSize:l.font.caption,lineHeight:18},resultLabel:{color:l.color.textTertiary,fontSize:l.font.caption,fontVariant:["tabular-nums"]},resultButtons:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},link:{color:l.color.accent,fontSize:l.font.row,fontWeight:"500"},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:l.rowPadH,paddingVertical:10},rowText:{flex:1,gap:2},rowDisabled:{opacity:.4},rowTitle:{color:l.color.text,fontSize:l.font.row},actionTitle:{color:l.color.accent,fontSize:l.font.row},detail:{color:l.color.textTertiary,fontSize:l.font.caption},warning:{color:l.color.warning,fontSize:l.font.caption},stack:{paddingHorizontal:l.rowPadH,paddingVertical:12,gap:10},segmentWrap:{paddingHorizontal:l.rowPadH,paddingTop:12,paddingBottom:4},inlineRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},inputRow:{flexDirection:"row",alignItems:"center",gap:8},input:{flex:1,color:l.color.text,fontFamily:A,fontSize:14,backgroundColor:l.color.bg,borderRadius:l.radius.input,borderWidth:1,borderColor:l.color.border,paddingHorizontal:12,paddingVertical:8},disclosure:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:l.labelInset},disclosureText:{color:l.color.textSecondary,fontSize:l.font.label,fontWeight:"600",textTransform:"uppercase",letterSpacing:.8},customBody:{gap:l.groupGap,marginTop:12},eventList:{gap:6},eventHeading:{color:l.color.textSecondary,fontSize:l.font.caption,fontWeight:"600"},event:{flexDirection:"row",gap:8,alignItems:"baseline"},eventSource:{width:56,color:l.color.textTertiary,fontSize:l.font.caption},eventTitle:{flex:1,color:l.color.text,fontSize:13,fontFamily:A},eventError:{color:l.color.danger},eventCount:{color:l.color.textSecondary,fontSize:l.font.caption,fontWeight:"600",fontVariant:["tabular-nums"]}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{Appearance as M,BackHandler as he}from"react-native";import{getRealAppState as Q,getSafeCurrentRoute as Z,getSafeRouter as me,realNow as g,reloadApp as ye,subscribeRealAppState as ge}from"@buoy-gg/shared-ui";import{loadToolModule as ee}from"@buoy-gg/shared-ui/utils";import{appListenerCount as C,deviceInfoModule as T,emitAppState as x,emitDevice as y,emitFocus as te,expoListenerCount as we,expoModule as b,getPlatform as A,wrapGetter as ve}from"./native";import{DEFAULT_SETTINGS as re,readSavedAsync as be,readSavedSync as Se,writeSaved as G}from"./persistence";function ne(){const e=globalThis.__buoyRealTimers;return e??globalThis}function P(e,t){return ne().setTimeout(e,t)}function q(e){if(e!=null)ne().clearTimeout(e)}const ke=30;let f={...re};let c=null;let h=null;let m=null;let i=null;let w=null;let D=[];let N=null;let $=null;let I=null;let S=[];let Ee=0;let B=()=>{};const U=new Set;let R=null;function o(){R=null;for(const e of Array.from(U)){try{e()}catch{}}}function s(e){D=[{at:g(),text:e},...D].slice(0,ke)}function oe(){void G({v:1,settings:f,pendingRelaunch:null})}function Me(){const e=b("ExpoDevice");const t=b("ExpoApplication");const r=n=>typeof n==="string"&&n?n:null;return{isSimulator:typeof e?.isDevice==="boolean"?!e.isDevice:null,deviceName:r(e?.deviceName),bundleId:r(t?.applicationId),os:r(e?.osName)??A(),appScheme:Ae()}}function Ae(){try{let e=b("ExponentConstants")?.manifest;if(typeof e==="string")e=JSON.parse(e);const t=e?.scheme;const r=Array.isArray(t)?t[0]:t;return typeof r==="string"&&r?r:null}catch{return null}}let ae=null;function ie(){const e=[];if(b("ExpoBattery"))e.push("expo-battery");if(T())e.push("react-native-device-info");return e}function Re(){let e=null;const t=n=>{if(n==null)return;e=(e??0)+n};const r=b("ExpoBattery");for(const n of Pe)t(we(r,n));if(T())for(const n of De)t(C(n));return e}function le(){try{return ee("@buoy-gg/clock")}catch{return null}}export function getLifecycleSnapshot(){if(R)return R;R={platform:A(),host:ae??=Me(),realAppState:Q(),away:c,power:h,scheme:m,listeners:{appState:C("appStateDidChange"),focus:C("appStateFocusChange"),memoryWarning:C("memoryWarning"),deepLink:C("url"),battery:Re()},batteryLibraries:ie(),clockAvailable:typeof le()?.shift==="function",report:i,relaunch:w,log:D,settings:f,active:c!=null||h!=null||m!=null};return R}export function refreshSnapshot(){o();return getLifecycleSnapshot()}export function subscribeLifecycle(e){U.add(e);return()=>U.delete(e)}export function getLifecycleSettings(){return f}const Ce=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"];const xe=40;export const FLUSH_GRACE_MS=1e3;function Le(){try{const e=ee("@buoy-gg/events");return typeof e.watchEvents==="function"?e.watchEvents:null}catch{return null}}function W(){q($);$=null;I?.();I=null;if(i&&i.collectingUntil!=null){i={...i,collectingUntil:null};o()}}function se(e,t,r,n){W();const l=g();const u=++Ee;i={id:u,label:e,kind:t,signal:n,startedAt:l,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:r};const p=Le();if(!p){i={...i,collectingUntil:null,unavailable:"Install @buoy-gg/events to see what the app did after a simulation."};return}const d=Date.now();const _=()=>c?Number.MAX_SAFE_INTEGER:k;let k=Number.MAX_SAFE_INTEGER;B=()=>{k=Date.now()};I=p(Ce,F=>{if(!i||i.id!==u)return;const v=F.filter(a=>!(a.source.startsWith("react-query")&&a.status==="pending")).sort((a,E)=>a.timestamp-E.timestamp);const J=v.filter((a,E)=>E===0||!(a.source===v[E-1].source&&a.title===v[E-1].title&&a.timestamp-v[E-1].timestamp<250));const O={};for(const a of J)O[a.source]=(O[a.source]??0)+1;const Y=J.map(a=>({source:a.source,title:a.title,subtitle:a.subtitle,status:a.status,at:Math.max(0,a.timestamp-d),whileAway:a.timestamp<_()}));const K=Y.filter(a=>a.whileAway&&a.source==="network"&&a.at>=FLUSH_GRACE_MS).length;i={...i,counts:O,events:Y.slice(0,xe),finding:K>0&&i.kind==="background"?`The app kept making network requests in the background: ${K} after its first second away.`:void 0};o()},d)}function H(){if(!i||i.collectingUntil==null||!I)return;const e=g()+f.reportWindowMs;i={...i,collectingUntil:e};q($);$=P(W,f.reportWindowMs)}function L(e,t,r){se(e,"signal",r,t);B();H()}function X(){q(N);N=null}function V(e){if(e<6e4)return`${Math.round(e/1e3)} s`;if(e<36e5)return`${Math.round(e/6e4)} min`;const t=e/36e5;return`${Number.isInteger(t)?t:t.toFixed(1)} h`}function ce(e,t={}){if(c)returnToApp();const r=typeof t.durationMs==="number"&&t.durationMs>0?t.durationMs:null;if(t.skipWait&&r==null){throw new Error("skipWait needs a duration (durationMs).")}const n=t.skipWait?le():null;if(t.skipWait&&typeof n?.shift!=="function"){throw new Error("Skipping the wait needs @buoy-gg/clock. Install it, or wait in real time.")}const l=(e==="background"?"Background":"Interruption")+(r?` ${V(r)}`:"")+(t.skipWait?" (clock skipped)":"");se(l,e);if(A()==="android"){te(false);if(e==="background")x("background")}else{x("inactive");if(e==="background")x("background")}c={kind:e,startedAt:g(),returnAt:r&&!t.skipWait?g()+r:null,skippedMs:t.skipWait?r:null};s(`${l}: app ${e==="background"?"sent to the background":"interrupted"}`);if(t.skipWait&&r&&n?.shift){n.shift(r);s(`App clock moved ahead ${V(r)}`);return returnToApp()}if(c.returnAt!=null){N=P(()=>{N=null;if(c)returnToApp()},r)}o();return getLifecycleSnapshot()}export function sendToBackground(e){return ce("background",e)}export function interrupt(e){return ce("inactive",e)}export function returnToApp(){X();if(!c)return getLifecycleSnapshot();const e=c;c=null;if(A()==="android"){if(e.kind==="background")x("active");te(true)}else{x("active")}const t=e.skippedMs??g()-e.startedAt;s(`Returned to the app after ${V(t)}`);B();H();o();return getLifecycleSnapshot()}let ue=false;function _e(){if(ue)return;ue=true;ge(e=>{if(c){X();c=null;s(`The OS reported "${e}", which ended the simulation`);B();H()}o()})}export function memoryWarning(){const e=A()==="android"?"Android never sends this event to React Native; only iOS does. Listeners ran anyway.":void 0;L("Memory warning","memoryWarning",e);y("memoryWarning");s("Memory warning sent");o();return getLifecycleSnapshot()}export function openDeepLink(e){const t=typeof e==="string"?e.trim():"";if(!/^[a-z][a-z0-9+.-]*:/i.test(t)){throw new Error('A deep link needs a scheme, like "myapp://orders/42" or "https://example.com/x".')}L(`Deep link ${t}`,"deepLink");y("url",{url:t});s(`Deep link delivered: ${t}`);o();return getLifecycleSnapshot()}export function pressBack(){if(A()!=="android"){throw new Error("The hardware back button only exists on Android.")}const e=he;const t=e.exitApp;let r=false;e.exitApp=()=>{r=true};L("Back button","back");try{y("hardwareBackPress")}finally{e.exitApp=t}if(i){i={...i,note:r?"No screen handled back, so a real press would have left the app.":"A screen handled back."}}s(r?"Back pressed: nothing handled it":"Back pressed: handled by the app");o();return{handled:!r,snapshot:getLifecycleSnapshot()}}function Te(){try{const e=M.getColorScheme();return e==="light"||e==="dark"?e:null}catch{return null}}export function setColorScheme(e,t="js"){if(e!=="light"&&e!=="dark")throw new Error('scheme must be "light" or "dark".');const r=m?m.previous:Te();if(m?.mode==="native"&&t==="js")M.setColorScheme?.("unspecified");L(`Color scheme ${e}`,"colorScheme");if(t==="native"&&typeof M.setColorScheme==="function"){M.setColorScheme(e)}else{y("appearanceChanged",{colorScheme:e})}m={scheme:e,mode:t,previous:r};s(`Color scheme set to ${e}${t==="native"?" (native)":""}`);o();return getLifecycleSnapshot()}function fe(){if(!m)return;const e=m;m=null;if(e.mode==="native"&&typeof M.setColorScheme==="function"){M.setColorScheme("unspecified")}else if(e.previous){y("appearanceChanged",{colorScheme:e.previous})}s("Color scheme back to the system value")}export function resetColorScheme(){fe();o();return getLifecycleSnapshot()}const Pe=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"];const De=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"];const j={unknown:0,unplugged:1,charging:2,full:3};function Ne(e,t){for(const d of S)d();S=[];const r=[];const n=[];const l=(d,_,k,F)=>{const v=ve(_,k,F);if(v)S.push(v);else if(typeof _[k]==="function")n.push(`${d} ${k}`)};const u=b("ExpoBattery");if(u){r.push("expo-battery");l("expo-battery",u,"isLowPowerModeEnabledAsync",()=>Promise.resolve(e.lowPowerMode));l("expo-battery",u,"getBatteryLevelAsync",()=>Promise.resolve(e.level));l("expo-battery",u,"getBatteryStateAsync",()=>Promise.resolve(j[e.state]));if(typeof u.emit==="function"){if(e.lowPowerMode!==t?.lowPowerMode)u.emit("Expo.powerModeDidChange",{lowPowerMode:e.lowPowerMode});if(e.state!==t?.state)u.emit("Expo.batteryStateDidChange",{batteryState:j[e.state]});if(e.level!==t?.level)u.emit("Expo.batteryLevelDidChange",{batteryLevel:e.level})}}const p=T();if(p){r.push("react-native-device-info");const d=()=>({batteryLevel:e.level,batteryState:e.state,lowPowerMode:e.lowPowerMode});l("react-native-device-info",p,"getPowerState",()=>Promise.resolve(d()));l("react-native-device-info",p,"getPowerStateSync",d);l("react-native-device-info",p,"getBatteryLevel",()=>Promise.resolve(e.level));l("react-native-device-info",p,"getBatteryLevelSync",()=>e.level);l("react-native-device-info",p,"isBatteryCharging",()=>Promise.resolve(e.state==="charging"));l("react-native-device-info",p,"isBatteryChargingSync",()=>e.state==="charging");y("RNDeviceInfo_powerStateDidChange",d());if(e.level!==t?.level){y("RNDeviceInfo_batteryLevelDidChange",e.level);if(e.level<=.2)y("RNDeviceInfo_batteryLevelIsLow",e.level)}}return{reached:r,realGetters:n}}export function setPower(e){const t=ie();if(t.length===0){throw new Error("Nothing in this app reads battery state: neither expo-battery nor react-native-device-info is installed.")}const r=typeof e.level==="number"&&Number.isFinite(e.level)?Math.min(1,Math.max(0,e.level>1?e.level/100:e.level)):h?.level??1;const n={lowPowerMode:e.lowPowerMode??h?.lowPowerMode??false,level:r,state:e.state??h?.state??"unplugged"};if(!(n.state in j))throw new Error('state must be "unplugged", "charging", "full" or "unknown".');L(`Battery ${Math.round(n.level*100)}%${n.lowPowerMode?", low power":""}`,"battery");const{reached:l,realGetters:u}=Ne(n,h);h={...n,reached:l,realGetters:u};s(`Battery set to ${Math.round(n.level*100)}%, ${n.state}${n.lowPowerMode?", low power mode on":""}`);o();return getLifecycleSnapshot()}function pe(){if(!h)return;for(const r of S)r();S=[];h=null;const e=b("ExpoBattery");if(e&&typeof e.emit==="function"){Promise.all([e.isLowPowerModeEnabledAsync?.(),e.getBatteryStateAsync?.(),e.getBatteryLevelAsync?.()]).then(([r,n,l])=>{if(typeof r==="boolean")e.emit("Expo.powerModeDidChange",{lowPowerMode:r});if(typeof n==="number")e.emit("Expo.batteryStateDidChange",{batteryState:n});if(typeof l==="number")e.emit("Expo.batteryLevelDidChange",{batteryLevel:l})}).catch(()=>{})}const t=T();if(t&&typeof t.getPowerState==="function"){Promise.resolve(t.getPowerState()).then(r=>y("RNDeviceInfo_powerStateDidChange",r)).catch(()=>{})}s("Battery back to the real values")}export function resetPower(){pe();o();return getLifecycleSnapshot()}export async function relaunchApp(){await prepareRelaunch();P(()=>{void ye("auto","buoy lifecycle relaunch").catch(e=>{s(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`);oe();o()})},250);return getLifecycleSnapshot()}export async function prepareRelaunch(){const e=Z();const t={at:g(),pathname:e?.pathname??null,href:e?.href??null};s(`Relaunching from ${t.pathname??"an unknown screen"}`);de(false);await G({v:1,settings:f,pendingRelaunch:t});o();return getLifecycleSnapshot()}const $e=2500;function Ie(e){w={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null};o();P(()=>{const t=Z();const r=t?.pathname??null;w={...w,after:r,tookMs:g()-e.at,restored:e.pathname!=null&&r!=null?r===e.pathname:null};s(w.restored===true?`Relaunch restored ${r}`:`Relaunch landed on ${r??"an unknown screen"}${e.pathname?`, was on ${e.pathname}`:""}`);o()},$e)}export function goBackToBeforeRelaunch(){const e=w?.beforeHref;if(!e)throw new Error("There is no route to go back to.");const t=me();if(!t)throw new Error("Going back needs expo-router.");(t.navigate??t.push)?.(e);s(`Went back to ${e}`);o();return getLifecycleSnapshot()}export function dismissRelaunchReport(){w=null;o();return getLifecycleSnapshot()}function de(e){if(c)returnToApp();pe();fe();if(e)s("Everything back to real")}export function resetLifecycle(){de(true);o();return getLifecycleSnapshot()}export function clearReport(){W();i=null;o();return getLifecycleSnapshot()}export function updateSettings(e){f={showChip:typeof e.showChip==="boolean"?e.showChip:f.showChip,reportWindowMs:typeof e.reportWindowMs==="number"&&Number.isFinite(e.reportWindowMs)?Math.min(6e4,Math.max(1e3,e.reportWindowMs)):f.reportWindowMs};oe();o();return getLifecycleSnapshot()}let z=false;export function bootLifecycle(){if(z)return;z=true;Q();_e();const e=r=>{if(!r)return;f=r.settings;if(r.pendingRelaunch){void G({v:1,settings:f,pendingRelaunch:null});Ie(r.pendingRelaunch)}o()};const t=Se();if(t!==void 0)e(t);else void be().then(e)}export function __resetLifecycleForTests(){X();W();for(const e of S)e();S=[];f={...re};c=null;h=null;m=null;i=null;w=null;D=[];z=false;R=null;ae=null}
|
|
1
|
+
"use strict";import{Appearance as C,BackHandler as ye}from"react-native";import{getRealAppState as ee,getSafeCurrentRoute as te,getSafeRouter as we,realNow as g,reloadApp as ge,subscribeRealAppState as ve}from"@buoy-gg/shared-ui";import{loadToolModule as re}from"@buoy-gg/shared-ui/utils";import{appListenerCount as L,capacitorShell as p,deviceInfoModule as P,endSimulation as be,prepareColorScheme as Se,emitAppState as T,emitDevice as w,emitFocus as oe,expoListenerCount as ke,expoModule as E,getPlatform as v,wrapGetter as Ee}from"./native";import{DEFAULT_SETTINGS as ne,readSavedAsync as Ae,readSavedSync as Me,writeSaved as U}from"./persistence";function ae(){const e=globalThis.__buoyRealTimers;return e??globalThis}function D(e,t){return ae().setTimeout(e,t)}function q(e){if(e!=null)ae().clearTimeout(e)}const Re=30;let d={...ne};let c=null;let y=null;let f=null;let a=null;let b=null;let B=[];let $=null;let N=null;let I=null;let S=[];let Ce=0;let W=()=>{};const H=new Set;let x=null;function n(){x=null;for(const e of Array.from(H)){try{e()}catch{}}}function s(e){B=[{at:g(),text:e},...B].slice(0,Re)}function ie(){void U({v:1,settings:d,pendingRelaunch:null})}function xe(){const e=p?.host();if(e)return{...e,os:v(),appScheme:null};const t=E("ExpoDevice");const r=E("ExpoApplication");const o=i=>typeof i==="string"&&i?i:null;return{isSimulator:typeof t?.isDevice==="boolean"?!t.isDevice:null,deviceName:o(t?.deviceName),bundleId:o(r?.applicationId),os:o(t?.osName)??v(),appScheme:Le()}}function Le(){try{let e=E("ExponentConstants")?.manifest;if(typeof e==="string")e=JSON.parse(e);const t=e?.scheme;const r=Array.isArray(t)?t[0]:t;return typeof r==="string"&&r?r:null}catch{return null}}let X=null;function le(){const e=[];if(E("ExpoBattery"))e.push("expo-battery");if(P())e.push("react-native-device-info");if(p?.battery.available())e.push("@capacitor/device");return e}function Te(){let e=null;const t=o=>{if(o==null)return;e=(e??0)+o};const r=E("ExpoBattery");for(const o of $e)t(ke(r,o));if(P())for(const o of Ne)t(L(o));return e}function se(){try{return re("@buoy-gg/clock")}catch{return null}}export function getLifecycleSnapshot(){if(x)return x;x={platform:v(),host:X??=xe(),realAppState:ee(),away:c,power:y,scheme:f,listeners:{appState:L("appStateDidChange"),focus:L("appStateFocusChange"),memoryWarning:L("memoryWarning"),deepLink:L("url"),battery:Te()},batteryLibraries:le(),clockAvailable:typeof se()?.shift==="function",report:a,relaunch:b,log:B,settings:d,active:c!=null||y!=null||f!=null};return x}export function refreshSnapshot(){n();return getLifecycleSnapshot()}export function subscribeLifecycle(e){H.add(e);return()=>H.delete(e)}export function getLifecycleSettings(){return d}const _e=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"];const Pe=40;export const FLUSH_GRACE_MS=1e3;function De(){try{const e=re("@buoy-gg/events");return typeof e.watchEvents==="function"?e.watchEvents:null}catch{return null}}function F(){q(N);N=null;I?.();I=null;if(a&&a.collectingUntil!=null){a={...a,collectingUntil:null};n()}}function ce(e,t,r,o){F();const i=g();const u=++Ce;a={id:u,label:e,kind:t,signal:o,startedAt:i,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:r};const h=De();if(!h){a={...a,collectingUntil:null,unavailable:"Install @buoy-gg/events to see what the app did after a simulation."};return}const m=Date.now();const _=()=>c?Number.MAX_SAFE_INTEGER:M;let M=Number.MAX_SAFE_INTEGER;W=()=>{M=Date.now()};I=h(_e,O=>{if(!a||a.id!==u)return;const k=O.filter(l=>!(l.source.startsWith("react-query")&&l.status==="pending")).sort((l,R)=>l.timestamp-R.timestamp);const K=k.filter((l,R)=>R===0||!(l.source===k[R-1].source&&l.title===k[R-1].title&&l.timestamp-k[R-1].timestamp<250));const G={};for(const l of K)G[l.source]=(G[l.source]??0)+1;const Q=K.map(l=>({source:l.source,title:l.title,subtitle:l.subtitle,status:l.status,at:Math.max(0,l.timestamp-m),whileAway:l.timestamp<_()}));const Z=Q.filter(l=>l.whileAway&&l.source==="network"&&l.at>=FLUSH_GRACE_MS).length;a={...a,counts:G,events:Q.slice(0,Pe),finding:Z>0&&a.kind==="background"?`The app kept making network requests in the background: ${Z} after its first second away.`:void 0};n()},m)}function j(){if(!a||a.collectingUntil==null||!I)return;const e=g()+d.reportWindowMs;a={...a,collectingUntil:e};q(N);N=D(F,d.reportWindowMs)}function A(e,t,r){ce(e,"signal",r,t);W();j()}function V(){q($);$=null}function z(e){if(e<6e4)return`${Math.round(e/1e3)} s`;if(e<36e5)return`${Math.round(e/6e4)} min`;const t=e/36e5;return`${Number.isInteger(t)?t:t.toFixed(1)} h`}function ue(e,t={}){if(c)returnToApp();const r=typeof t.durationMs==="number"&&t.durationMs>0?t.durationMs:null;if(t.skipWait&&r==null){throw new Error("skipWait needs a duration (durationMs).")}const o=t.skipWait?se():null;if(t.skipWait&&typeof o?.shift!=="function"){throw new Error("Skipping the wait needs @buoy-gg/clock. Install it, or wait in real time.")}const i=(e==="background"?"Background":"Interruption")+(r?` ${z(r)}`:"")+(t.skipWait?" (clock skipped)":"");ce(i,e);if(v()==="android"){oe(false);if(e==="background")T("background")}else{T("inactive");if(e==="background")T("background")}c={kind:e,startedAt:g(),returnAt:r&&!t.skipWait?g()+r:null,skippedMs:t.skipWait?r:null};s(`${i}: app ${e==="background"?"sent to the background":"interrupted"}`);if(t.skipWait&&r&&o?.shift){o.shift(r);s(`App clock moved ahead ${z(r)}`);return returnToApp()}if(c.returnAt!=null){$=D(()=>{$=null;if(c)returnToApp()},r)}n();return getLifecycleSnapshot()}export function sendToBackground(e){return ue("background",e)}export function interrupt(e){return ue("inactive",e)}export function returnToApp(){V();if(!c)return getLifecycleSnapshot();const e=c;c=null;if(v()==="android"){if(e.kind==="background")T("active");oe(true)}else{T("active")}const t=e.skippedMs??g()-e.startedAt;s(`Returned to the app after ${z(t)}`);W();j();n();return getLifecycleSnapshot()}let pe=false;function Be(){if(pe)return;pe=true;ve(e=>{if(c){V();c=null;be();s(`The OS reported "${e}", which ended the simulation`);W();j()}n()})}export function memoryWarning(){if(p)throw new Error("Capacitor has no memory warning event, so there is nothing to send.");const e=v()==="android"?"Android never sends this event to React Native; only iOS does. Listeners ran anyway.":void 0;A("Memory warning","memoryWarning",e);w("memoryWarning");s("Memory warning sent");n();return getLifecycleSnapshot()}export function openDeepLink(e){const t=typeof e==="string"?e.trim():"";if(!/^[a-z][a-z0-9+.-]*:/i.test(t)){throw new Error('A deep link needs a scheme, like "myapp://orders/42" or "https://example.com/x".')}A(`Deep link ${t}`,"deepLink");w("url",{url:t});s(`Deep link delivered: ${t}`);n();return getLifecycleSnapshot()}export async function pressBackAsync(){if(!p)return pressBack();if(v()!=="android"){throw new Error("The hardware back button only exists on Android.")}A("Back button","back");const e=await p.pressBack();if(a)a={...a,note:e.note};s(e.exited?"Back pressed: the app tried to exit":e.handled?"Back pressed: handled by the app":`Back pressed: ${e.note}`);n();return{handled:e.handled,snapshot:getLifecycleSnapshot()}}export function pressBack(){if(v()!=="android"){throw new Error("The hardware back button only exists on Android.")}const e=ye;const t=e.exitApp;let r=false;e.exitApp=()=>{r=true};A("Back button","back");try{w("hardwareBackPress")}finally{e.exitApp=t}if(a){a={...a,note:r?"No screen handled back, so a real press would have left the app.":"A screen handled back."}}s(r?"Back pressed: nothing handled it":"Back pressed: handled by the app");n();return{handled:!r,snapshot:getLifecycleSnapshot()}}function fe(){try{const e=C.getColorScheme();return e==="light"||e==="dark"?e:null}catch{return null}}export function setColorScheme(e,t="js"){if(e!=="light"&&e!=="dark")throw new Error('scheme must be "light" or "dark".');if(p){if(t==="native")throw new Error('A Capacitor app has no native color scheme override. Use mode "js".');const o=f?f.previous:fe();A(`Color scheme ${e}`,"colorScheme");p.colorScheme(e);f={scheme:e,mode:t,previous:o};s(`Color scheme set to ${e}`);n();return getLifecycleSnapshot()}const r=f?f.previous:fe();if(f?.mode==="native"&&t==="js")C.setColorScheme?.("unspecified");A(`Color scheme ${e}`,"colorScheme");if(t==="native"&&typeof C.setColorScheme==="function"){C.setColorScheme(e)}else{w("appearanceChanged",{colorScheme:e})}f={scheme:e,mode:t,previous:r};s(`Color scheme set to ${e}${t==="native"?" (native)":""}`);n();return getLifecycleSnapshot()}function de(){if(!f)return;const e=f;f=null;if(p){p.colorScheme(null)}else if(e.mode==="native"&&typeof C.setColorScheme==="function"){C.setColorScheme("unspecified")}else if(e.previous){w("appearanceChanged",{colorScheme:e.previous})}s("Color scheme back to the system value")}export function resetColorScheme(){de();n();return getLifecycleSnapshot()}const $e=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"];const Ne=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"];const J={unknown:0,unplugged:1,charging:2,full:3};function Ie(e,t){for(const m of S)m();S=[];const r=[];const o=[];const i=(m,_,M,O)=>{const k=Ee(_,M,O);if(k)S.push(k);else if(typeof _[M]==="function")o.push(`${m} ${M}`)};const u=E("ExpoBattery");if(u){r.push("expo-battery");i("expo-battery",u,"isLowPowerModeEnabledAsync",()=>Promise.resolve(e.lowPowerMode));i("expo-battery",u,"getBatteryLevelAsync",()=>Promise.resolve(e.level));i("expo-battery",u,"getBatteryStateAsync",()=>Promise.resolve(J[e.state]));if(typeof u.emit==="function"){if(e.lowPowerMode!==t?.lowPowerMode)u.emit("Expo.powerModeDidChange",{lowPowerMode:e.lowPowerMode});if(e.state!==t?.state)u.emit("Expo.batteryStateDidChange",{batteryState:J[e.state]});if(e.level!==t?.level)u.emit("Expo.batteryLevelDidChange",{batteryLevel:e.level})}}if(p?.battery.available()){r.push("@capacitor/device");p.battery.set({level:e.level,state:e.state});S.push(()=>p?.battery.set(null))}const h=P();if(h){r.push("react-native-device-info");const m=()=>({batteryLevel:e.level,batteryState:e.state,lowPowerMode:e.lowPowerMode});i("react-native-device-info",h,"getPowerState",()=>Promise.resolve(m()));i("react-native-device-info",h,"getPowerStateSync",m);i("react-native-device-info",h,"getBatteryLevel",()=>Promise.resolve(e.level));i("react-native-device-info",h,"getBatteryLevelSync",()=>e.level);i("react-native-device-info",h,"isBatteryCharging",()=>Promise.resolve(e.state==="charging"));i("react-native-device-info",h,"isBatteryChargingSync",()=>e.state==="charging");w("RNDeviceInfo_powerStateDidChange",m());if(e.level!==t?.level){w("RNDeviceInfo_batteryLevelDidChange",e.level);if(e.level<=.2)w("RNDeviceInfo_batteryLevelIsLow",e.level)}}return{reached:r,realGetters:o}}export function setPower(e){const t=le();if(t.length===0){throw new Error("Nothing in this app reads battery state: expo-battery, react-native-device-info and @capacitor/device are all missing.")}const r=typeof e.level==="number"&&Number.isFinite(e.level)?Math.min(1,Math.max(0,e.level>1?e.level/100:e.level)):y?.level??1;const o={lowPowerMode:e.lowPowerMode??y?.lowPowerMode??false,level:r,state:e.state??y?.state??"unplugged"};if(!(o.state in J))throw new Error('state must be "unplugged", "charging", "full" or "unknown".');A(`Battery ${Math.round(o.level*100)}%${o.lowPowerMode?", low power":""}`,"battery");const{reached:i,realGetters:u}=Ie(o,y);y={...o,reached:i,realGetters:u};s(`Battery set to ${Math.round(o.level*100)}%, ${o.state}${o.lowPowerMode?", low power mode on":""}`);n();return getLifecycleSnapshot()}function he(){if(!y)return;for(const r of S)r();S=[];y=null;const e=E("ExpoBattery");if(e&&typeof e.emit==="function"){Promise.all([e.isLowPowerModeEnabledAsync?.(),e.getBatteryStateAsync?.(),e.getBatteryLevelAsync?.()]).then(([r,o,i])=>{if(typeof r==="boolean")e.emit("Expo.powerModeDidChange",{lowPowerMode:r});if(typeof o==="number")e.emit("Expo.batteryStateDidChange",{batteryState:o});if(typeof i==="number")e.emit("Expo.batteryLevelDidChange",{batteryLevel:i})}).catch(()=>{})}const t=P();if(t&&typeof t.getPowerState==="function"){Promise.resolve(t.getPowerState()).then(r=>w("RNDeviceInfo_powerStateDidChange",r)).catch(()=>{})}s("Battery back to the real values")}export function resetPower(){he();n();return getLifecycleSnapshot()}export async function relaunchApp(){await prepareRelaunch();D(()=>{void ge("auto","buoy lifecycle relaunch").catch(e=>{s(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`);ie();n()})},250);return getLifecycleSnapshot()}export async function prepareRelaunch(){const e=te();const t={at:g(),pathname:e?.pathname??null,href:e?.href??null};s(`Relaunching from ${t.pathname??"an unknown screen"}`);me(false);await U({v:1,settings:d,pendingRelaunch:t});n();return getLifecycleSnapshot()}const We=2500;function Fe(e){b={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null};n();D(()=>{const t=te();const r=t?.pathname??null;b={...b,after:r,tookMs:g()-e.at,restored:e.pathname!=null&&r!=null?r===e.pathname:null};s(b.restored===true?`Relaunch restored ${r}`:`Relaunch landed on ${r??"an unknown screen"}${e.pathname?`, was on ${e.pathname}`:""}`);n()},We)}export function goBackToBeforeRelaunch(){const e=b?.beforeHref;if(!e)throw new Error("There is no route to go back to.");const t=we();if(!t)throw new Error("Going back needs expo-router.");(t.navigate??t.push)?.(e);s(`Went back to ${e}`);n();return getLifecycleSnapshot()}export function dismissRelaunchReport(){b=null;n();return getLifecycleSnapshot()}function me(e){if(c)returnToApp();he();de();if(e)s("Everything back to real")}export function resetLifecycle(){me(true);n();return getLifecycleSnapshot()}export function clearReport(){F();a=null;n();return getLifecycleSnapshot()}export function updateSettings(e){d={showChip:typeof e.showChip==="boolean"?e.showChip:d.showChip,reportWindowMs:typeof e.reportWindowMs==="number"&&Number.isFinite(e.reportWindowMs)?Math.min(6e4,Math.max(1e3,e.reportWindowMs)):d.reportWindowMs};ie();n();return getLifecycleSnapshot()}let Y=false;export function bootLifecycle(){if(Y)return;Y=true;Se();void p?.loadHost().then(()=>{X=null;n()});ee();Be();const e=r=>{if(!r)return;d=r.settings;if(r.pendingRelaunch){void U({v:1,settings:d,pendingRelaunch:null});Fe(r.pendingRelaunch)}n()};const t=Me();if(t!==void 0)e(t);else void Ae().then(e)}export function __resetLifecycleForTests(){V();F();for(const e of S)e();S=[];d={...ne};c=null;y=null;f=null;a=null;b=null;B=[];Y=false;x=null;X=null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{DeviceEventEmitter as o,NativeModules as i,Platform as u}from"react-native";import{BUOY_SYNTHETIC_MARK as c}from"@buoy-gg/shared-ui";export function getPlatform(){const t=u.OS;return t==="ios"||t==="android"||t==="web"?t:"other"}export function emitDevice(t,n){if(n===void 0)o.emit(t);else o.emit(t,n)}export function emitAppState(t){emitDevice("appStateDidChange",{app_state:t,[c]:true})}export function emitFocus(t){emitDevice("appStateFocusChange",t)}function
|
|
1
|
+
"use strict";import{DeviceEventEmitter as o,NativeModules as i,Platform as u}from"react-native";import{BUOY_SYNTHETIC_MARK as c}from"@buoy-gg/shared-ui";export function getPlatform(){const t=u.OS;return t==="ios"||t==="android"||t==="web"?t:"other"}export function emitDevice(t,n){if(n===void 0)o.emit(t);else o.emit(t,n)}export function emitAppState(t){emitDevice("appStateDidChange",{app_state:t,[c]:true})}export function emitFocus(t){emitDevice("appStateFocusChange",t)}export const capacitorShell=null;export function endSimulation(){}export function prepareColorScheme(){}function l(t,n){if(t==="appStateDidChange")return n>0?1:0;return 0}function p(t){const n=globalThis.__buoyOwnDeviceListeners;return n?.[t]??0}export function appListenerCount(t){const n=o;if(typeof n.listenerCount!=="function")return null;const e=n.listenerCount(t);return Math.max(0,e-l(t,e)-p(t))}export function expoModule(t){const n=globalThis.expo?.modules;const e=n?.[t];return e&&typeof e==="object"?e:null}export function expoListenerCount(t,n){if(!t||typeof t.listenerCount!=="function")return null;try{return t.listenerCount(n)}catch{return null}}export function deviceInfoModule(){const t=i.RNDeviceInfo;return t&&typeof t==="object"?t:null}export function wrapGetter(t,n,e){if(typeof t[n]!=="function")return null;const r=t[n];try{t[n]=e;if(t[n]!==e)return null}catch{return null}return()=>{try{t[n]=r}catch{}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{capacitorListenerCount as m,capacitorPlatform as g,emitCapacitorEvent as c,hasCapacitorPlugin as S,installCapacitorBridge as w,interceptCapacitor as f,makeCapacitorCallbackId as E,getCapacitorAppHost as x,loadCapacitorAppHost as k,colorSchemeQueryValue as P,getColorSchemeQueries as O}from"@buoy-gg/license";import{BUOY_SYNTHETIC_MARK as _}from"@buoy-gg/shared-ui";export function getPlatform(){return g()??"web"}function o(){if(g()===null||!w())return false;B();return true}let v=false;function B(){if(v)return;v=true;f({plugin:"App",methods:["getState"],promise:(e,t)=>p?t():{isActive:false}})}function d(){const e=globalThis.document;return e&&typeof e.dispatchEvent==="function"?e:null}function u(e){const t=d();if(!t)return;const r=globalThis.Event;if(!r)return;const n=new r(e);n[_]=true;t.dispatchEvent(n)}function y(e){const t=d();if(!t)return;if(e===null){delete t.visibilityState;delete t.hidden}else{Object.defineProperty(t,"visibilityState",{configurable:true,get:()=>e});Object.defineProperty(t,"hidden",{configurable:true,get:()=>e==="hidden"})}u("visibilitychange")}let p=true;let l=false;function h(e){if(p===e)return;p=e;c("App","appStateChange",{isActive:e})}export function emitAppState(e){if(!o())return;if(e==="inactive"){h(false);return}if(e==="background"){h(false);if(!l){l=true;c("App","pause",{});u("pause");y("hidden")}return}if(l){l=false;y(null);c("App","resume",{});u("resume")}h(true)}export function endSimulation(){if(l)M(null);l=false;p=true}function M(e){const t=d();if(!t||e!==null)return;delete t.visibilityState;delete t.hidden}export function emitFocus(e){}export function emitDevice(e,t){if(!o())return;if(e==="url"){c("App","appUrlOpen",t)}}const I={appStateDidChange:["appStateChange","pause","resume"],url:["appUrlOpen"],hardwareBackPress:["backButton"]};export function appListenerCount(e){if(!o())return null;const t=I[e];if(!t)return 0;return t.reduce((r,n)=>r+m("App",n),0)}const L=400;function j(e,t){const r=globalThis.__buoyRealTimers;if(typeof r?.setTimeout==="function")r.setTimeout(e,t);else setTimeout(e,t)}export const capacitorShell={async pressBack(){if(!o())throw new Error("The back button needs a Capacitor app.");const e=globalThis.history;const t=Boolean(e&&e.length>1);const r=m("App","backButton");if(r===0){if(t)e?.back();return{exited:false,handled:false,note:t?"No back listener, so the WebView went back a page.":"No back listener and no page to go back to, so nothing happened."}}let n=false;const i=f({plugin:"App",methods:["exitApp"],promise:()=>{n=true;return void 0},callback:()=>{n=true;return E()}});try{c("App","backButton",{canGoBack:t});u("backbutton");await new Promise(a=>j(a,L))}finally{i()}return{exited:n,handled:!n,note:n?"The app called App.exitApp(), so a real press would have left the app.":"The app's back listener handled it."}},host(){return x()},loadHost(){return o()?k():Promise.resolve(null)},colorScheme(e){if(!o())throw new Error("The color scheme needs a Capacitor app.");D();const t=O();const r=t.map(n=>n.matches);b=e;t.forEach((n,i)=>{const a=n.matches;if(a!==r[i])Q(n,a)})},battery:{available(){return o()&&S("Device")},set(e){s=e;if(e&&!A){A=true;f({plugin:"Device",methods:["getBatteryInfo"],promise:(t,r)=>s?{batteryLevel:s.level,isCharging:s.state==="charging"||s.state==="full"}:r()})}}}};let b=null;let C=false;function T(e){const t=e&&Object.getOwnPropertyDescriptor(e,"matches");if(!e||!t?.get||!t.configurable)return false;const r=t.get;Object.defineProperty(e,"matches",{...t,get(){const n=r.call(this);const i=b?P(String(this.media??"")):null;return i?b===i:n}});return true}function D(){if(C)return;const e=globalThis.MediaQueryListEvent;T(e?.prototype);const t=globalThis.MediaQueryList;if(T(t?.prototype))C=true}function Q(e,t){const r=String(e.media??"");const n=globalThis.MediaQueryListEvent;let i;try{i=n?new n("change",{matches:t,media:r}):new Event("change")}catch{i=new Event("change")}if(!n){Object.defineProperty(i,"matches",{value:t});Object.defineProperty(i,"media",{value:r})}try{e.dispatchEvent(i)}catch(a){globalThis.console?.error(a)}}export function prepareColorScheme(){}let s=null;let A=false;export function expoModule(e){return null}export function expoListenerCount(e,t){return null}export function deviceInfoModule(){return null}export function wrapGetter(e,t,r){if(typeof e[t]!=="function")return null;const n=e[t];try{e[t]=r;if(e[t]!==r)return null}catch{return null}return()=>{try{e[t]=n}catch{}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";export function readSavedSync(){return void 0}
|
|
1
|
+
"use strict";import{LIFECYCLE_STORAGE_KEY as r,parseSaved as t}from"./persistence";export function readSavedSync(){try{const e=globalThis.localStorage;if(!e)return void 0;return t(e.getItem(r))}catch{return void 0}}
|
package/lib/module/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{bootLifecycle as o}from"./engine/lifecycleStore";import{watchLifecycleChip as r}from"./components/LifecycleChip";import{readSavedSync as c}from"./engine/readSavedSync";const t=typeof navigator!=="undefined"&&navigator.product==="ReactNative";if(t){r();const e=typeof __DEV__!=="undefined"&&__DEV__;if(e||c()?.pendingRelaunch)o()}export{lifecycleToolPreset,createLifecycleTool}from"./preset";export{LifecycleBody}from"./components/LifecycleBody";export{LifecycleToolView}from"./components/LifecycleToolView";export{LifecycleChip,LIFECYCLE_CHIP_ID}from"./components/LifecycleChip";export{LifecycleToolIcon,LIFECYCLE_TOOL_ICON_COLOR}from"@buoy-gg/shared-ui";export{lifecycleSyncAdapter,parseDurationMs}from"./sync/lifecycleSyncAdapter";export{bootLifecycle,sendToBackground,interrupt,returnToApp,memoryWarning,openDeepLink,pressBack,setColorScheme,setPower,resetPower,relaunchApp,resetLifecycle,getLifecycleSnapshot,subscribeLifecycle}from"./engine/lifecycleStore";export{RECIPES,runRecipe}from"./engine/recipes";
|
|
1
|
+
"use strict";import{bootLifecycle as o}from"./engine/lifecycleStore";import{watchLifecycleChip as r}from"./components/LifecycleChip";import{readSavedSync as c}from"./engine/readSavedSync";const t=typeof navigator!=="undefined"&&navigator.product==="ReactNative";const i=(()=>{try{const e=globalThis.Capacitor;return e?.isNativePlatform?.()===true}catch{return false}})();if(t||i){r();const e=typeof __DEV__!=="undefined"&&__DEV__;if(e||c()?.pendingRelaunch)o()}export{lifecycleToolPreset,createLifecycleTool}from"./preset";export{LifecycleBody}from"./components/LifecycleBody";export{LifecycleToolView}from"./components/LifecycleToolView";export{LifecycleChip,LIFECYCLE_CHIP_ID}from"./components/LifecycleChip";export{LifecycleToolIcon,LIFECYCLE_TOOL_ICON_COLOR}from"@buoy-gg/shared-ui";export{lifecycleSyncAdapter,parseDurationMs}from"./sync/lifecycleSyncAdapter";export{bootLifecycle,sendToBackground,interrupt,returnToApp,memoryWarning,openDeepLink,pressBack,pressBackAsync,setColorScheme,setPower,resetPower,relaunchApp,resetLifecycle,getLifecycleSnapshot,subscribeLifecycle}from"./engine/lifecycleStore";export{RECIPES,runRecipe}from"./engine/recipes";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{createSyncAdapter as a}from"@buoy-gg/shared-ui";import{clearReport as p,dismissRelaunchReport as l,getLifecycleSnapshot as d,goBackToBeforeRelaunch as f,interrupt as m,memoryWarning as h,openDeepLink as w,
|
|
1
|
+
"use strict";import{createSyncAdapter as a}from"@buoy-gg/shared-ui";import{clearReport as p,dismissRelaunchReport as l,getLifecycleSnapshot as d,goBackToBeforeRelaunch as f,interrupt as m,memoryWarning as h,openDeepLink as w,pressBackAsync as y,prepareRelaunch as g,refreshSnapshot as b,relaunchApp as S,resetLifecycle as k,resetColorScheme as R,resetPower as C,returnToApp as P,sendToBackground as A,setColorScheme as B,setPower as M,subscribeLifecycle as W,updateSettings as E}from"../engine/lifecycleStore";import{RECIPES as u,recipeAvailability as L,runRecipe as T}from"../engine/recipes";function o(e){return e&&typeof e==="object"?e:{}}function i(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 _={ms:1,s:1e3,m:6e4,min:6e4,h:36e5,d:864e5};export function parseDurationMs(e){if(e==null||e==="")return null;if(typeof e==="number")return Number.isFinite(e)&&e>0?e:null;if(typeof e!=="string")return null;const r=/^\s*(\d+(?:\.\d+)?)\s*(ms|s|min|m|h|d)?\s*$/i.exec(e);if(!r)throw new Error(`Can't read the duration "${e}". Use ms or a value like "30s", "5m", "2h".`);return Number(r[1])*_[(r[2]??"ms").toLowerCase()]}function c(e){const r=o(e);return{durationMs:parseDurationMs(r.duration??r.durationMs??r.for),skipWait:i(r,"skipWait")??false}}function n(e=d()){return{...e,recipes:u.map(r=>({id:r.id,title:r.title,detail:r.detail,unavailable:L(r,e)}))}}export const lifecycleSyncAdapter=a({version:1,getSnapshot(){return n()},subscribe(e){return W(e)},actions:{getState(){return n(b())},background(e){return n(A(c(e)))},interrupt(e){return n(m(c(e)))},returnToApp(){return n(P())},memoryWarning(){return n(h())},openUrl(e){const r=o(e);const t=r.url??r.link??r.href;if(typeof t!=="string")throw new Error('openUrl needs `url`, like "myapp://orders/42".');return n(w(t))},async pressBack(){const e=await y();return{...n(e.snapshot),handled:e.handled}},setColorScheme(e){const r=o(e);const t=r.scheme??r.colorScheme;if(t==="system")return n(R());if(t!=="light"&&t!=="dark"){throw new Error('setColorScheme needs `scheme`: "light", "dark" or "system".')}const s=r.mode==="native"?"native":"js";return n(B(t,s))},setPower(e){const r=o(e);const t=r.level??r.batteryLevel;return n(M({lowPowerMode:i(r,"lowPowerMode"),level:typeof t==="number"?t:typeof t==="string"?Number(t):void 0,state:typeof r.state==="string"?r.state:void 0}))},resetPower(){return n(C())},async relaunch(){return n(await S())},async prepareRelaunch(){return n(await g())},goBackToBeforeRelaunch(){return n(f())},dismissRelaunchReport(){return n(l())},async runRecipe(e){const r=o(e);const t=r.id??r.recipe;if(typeof t!=="string"){throw new Error(`runRecipe needs \`id\`: ${u.map(s=>s.id).join(", ")}.`)}return n(await T(t))},clearReport(){return n(p())},reset(){return n(k())},updateSettings(e){const r=o(e);const t=r.reportWindowMs??r.reportWindow;return n(E({showChip:i(r,"showChip"),reportWindowMs:t!=null?parseDurationMs(t)??void 0:void 0}))}}});
|
|
@@ -137,6 +137,11 @@ export interface BackResult {
|
|
|
137
137
|
handled: boolean;
|
|
138
138
|
snapshot: LifecycleSnapshot;
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* `pressBack` for every runtime. In a Capacitor app the app's `App.exitApp()`
|
|
142
|
+
* arrives a moment after the press, so the answer is async there.
|
|
143
|
+
*/
|
|
144
|
+
export declare function pressBackAsync(): Promise<BackResult>;
|
|
140
145
|
/**
|
|
141
146
|
* Android's back button. When no handler takes the press, React Native would
|
|
142
147
|
* call BackHandler.exitApp(); the tool swaps that for a recorder so the app
|
|
@@ -5,6 +5,34 @@ export declare function emitDevice(name: string, payload?: unknown): void;
|
|
|
5
5
|
export declare function emitAppState(state: SimAppState): void;
|
|
6
6
|
/** Android window focus; iOS never sends it. */
|
|
7
7
|
export declare function emitFocus(focused: boolean): void;
|
|
8
|
+
export interface CapacitorBackPress {
|
|
9
|
+
exited: boolean;
|
|
10
|
+
handled: boolean;
|
|
11
|
+
note: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CapacitorShell {
|
|
14
|
+
pressBack(): Promise<CapacitorBackPress>;
|
|
15
|
+
host(): {
|
|
16
|
+
isSimulator: boolean | null;
|
|
17
|
+
deviceName: string | null;
|
|
18
|
+
bundleId: string | null;
|
|
19
|
+
} | null;
|
|
20
|
+
loadHost(): Promise<unknown>;
|
|
21
|
+
colorScheme(next: "light" | "dark" | null): void;
|
|
22
|
+
battery: {
|
|
23
|
+
available(): boolean;
|
|
24
|
+
set(next: {
|
|
25
|
+
level: number;
|
|
26
|
+
state: string;
|
|
27
|
+
} | null): void;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Null on React Native: the web build's twin drives a Capacitor shell. */
|
|
31
|
+
export declare const capacitorShell: CapacitorShell | null;
|
|
32
|
+
/** The OS ended a simulation (web build only; React Native has nothing to undo). */
|
|
33
|
+
export declare function endSimulation(): void;
|
|
34
|
+
/** Web build only: answer color scheme queries from boot on. */
|
|
35
|
+
export declare function prepareColorScheme(): void;
|
|
8
36
|
/** How many of the APP's listeners a device event has (React Native's and Buoy's removed). */
|
|
9
37
|
export declare function appListenerCount(event: string): number | null;
|
|
10
38
|
export type ExpoModule = Record<string, unknown> & {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export type SimAppState = "active" | "background" | "inactive";
|
|
2
|
+
export type Platformish = "ios" | "android" | "web" | "other";
|
|
3
|
+
export declare function getPlatform(): Platformish;
|
|
4
|
+
/**
|
|
5
|
+
* The app state sequence, as Capacitor's shells send it. iOS: resign active
|
|
6
|
+
* (`appStateChange` false), then did-enter-background (`pause`). Android: the
|
|
7
|
+
* activity's onPause sends both. Coming back: `resume`, then
|
|
8
|
+
* `appStateChange` true.
|
|
9
|
+
*/
|
|
10
|
+
export declare function emitAppState(state: SimAppState): void;
|
|
11
|
+
/**
|
|
12
|
+
* The OS sent a real lifecycle event during a simulation: drop the simulated
|
|
13
|
+
* state without telling the app again (the OS already did).
|
|
14
|
+
*/
|
|
15
|
+
export declare function endSimulation(): void;
|
|
16
|
+
/** Android window focus: a Capacitor app has no event for it. */
|
|
17
|
+
export declare function emitFocus(_focused: boolean): void;
|
|
18
|
+
/** React Native device events the store sends, mapped to the Capacitor ones. */
|
|
19
|
+
export declare function emitDevice(name: string, payload?: unknown): void;
|
|
20
|
+
/**
|
|
21
|
+
* How many of the APP's listeners an event has. Counts `@capacitor/app`
|
|
22
|
+
* listeners only; document listeners can't be counted. Null outside Capacitor.
|
|
23
|
+
*/
|
|
24
|
+
export declare function appListenerCount(event: string): number | null;
|
|
25
|
+
export interface CapacitorBackPress {
|
|
26
|
+
/** The app called `App.exitApp()`, which the tool held back. */
|
|
27
|
+
exited: boolean;
|
|
28
|
+
/** The app had a back listener, so the press went to it. */
|
|
29
|
+
handled: boolean;
|
|
30
|
+
/** What a real press would have done. */
|
|
31
|
+
note: string;
|
|
32
|
+
}
|
|
33
|
+
export declare const capacitorShell: {
|
|
34
|
+
/**
|
|
35
|
+
* Capacitor's Android back: with `backButton` listeners, they get
|
|
36
|
+
* `{ canGoBack }` and the document gets `backbutton` (Ionic reads that).
|
|
37
|
+
* With none, the WebView goes back in its history, or nothing happens.
|
|
38
|
+
* `App.exitApp()` calls are held back while the press settles, and
|
|
39
|
+
* reported instead.
|
|
40
|
+
*/
|
|
41
|
+
pressBack(): Promise<CapacitorBackPress>;
|
|
42
|
+
/** Bundle id, simulator flag and device name, for host-side tools (MCP `real: true`). */
|
|
43
|
+
host(): {
|
|
44
|
+
isSimulator: boolean | null;
|
|
45
|
+
deviceName: string | null;
|
|
46
|
+
bundleId: string | null;
|
|
47
|
+
} | null;
|
|
48
|
+
loadHost(): Promise<unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* Answer `prefers-color-scheme` queries with `next`, or the system again
|
|
51
|
+
* with null. Queries the app made before Buoy loaded keep the system value.
|
|
52
|
+
*/
|
|
53
|
+
colorScheme(next: "light" | "dark" | null): void;
|
|
54
|
+
/** Battery through `@capacitor/device`'s `getBatteryInfo`. */
|
|
55
|
+
battery: {
|
|
56
|
+
available(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Answer `getBatteryInfo` with these values, or pass it through again
|
|
59
|
+
* with null. Capacitor's Device plugin has no battery events and no low
|
|
60
|
+
* power mode, so apps only see the new values when they ask.
|
|
61
|
+
*/
|
|
62
|
+
set(next: {
|
|
63
|
+
level: number;
|
|
64
|
+
state: string;
|
|
65
|
+
} | null): void;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/** Kept so React Native builds and old callers link; tracking starts in license's hook. */
|
|
69
|
+
export declare function prepareColorScheme(): void;
|
|
70
|
+
export type ExpoModule = Record<string, unknown> & {
|
|
71
|
+
emit?: (event: string, ...args: unknown[]) => void;
|
|
72
|
+
listenerCount?: (event: string) => number;
|
|
73
|
+
};
|
|
74
|
+
export declare function expoModule(_name: string): ExpoModule | null;
|
|
75
|
+
export declare function expoListenerCount(_module: ExpoModule | null, _event: string): number | null;
|
|
76
|
+
export declare function deviceInfoModule(): Record<string, unknown> | null;
|
|
77
|
+
type Restore = () => void;
|
|
78
|
+
export declare function wrapGetter(target: Record<string, unknown>, key: string, replacement: (...args: unknown[]) => unknown): Restore | null;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=native.web.d.ts.map
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type
|
|
2
|
-
/**
|
|
1
|
+
import { type SavedLifecycle } from "./persistence";
|
|
2
|
+
/**
|
|
3
|
+
* The saved state, read synchronously. The web build's persistentStorage
|
|
4
|
+
* writes plain `localStorage`, so a relaunch the tool started is found at the
|
|
5
|
+
* new page's first line (the Capacitor case). `undefined` when there is no
|
|
6
|
+
* `localStorage`.
|
|
7
|
+
*/
|
|
3
8
|
export declare function readSavedSync(): SavedLifecycle | null | undefined;
|
|
4
9
|
//# sourceMappingURL=readSavedSync.web.d.ts.map
|
|
@@ -6,7 +6,7 @@ export { LifecycleChip, LIFECYCLE_CHIP_ID } from "./components/LifecycleChip";
|
|
|
6
6
|
export { LifecycleToolIcon, LIFECYCLE_TOOL_ICON_COLOR } from "@buoy-gg/shared-ui";
|
|
7
7
|
export { lifecycleSyncAdapter, parseDurationMs } from "./sync/lifecycleSyncAdapter";
|
|
8
8
|
export type { LifecycleSyncSnapshot, LifecycleRecipeInfo, LifecycleAction, } from "./sync/lifecycleSyncAdapter";
|
|
9
|
-
export { bootLifecycle, sendToBackground, interrupt, returnToApp, memoryWarning, openDeepLink, pressBack, setColorScheme, setPower, resetPower, relaunchApp, resetLifecycle, getLifecycleSnapshot, subscribeLifecycle, } from "./engine/lifecycleStore";
|
|
9
|
+
export { bootLifecycle, sendToBackground, interrupt, returnToApp, memoryWarning, openDeepLink, pressBack, pressBackAsync, setColorScheme, setPower, resetPower, relaunchApp, resetLifecycle, getLifecycleSnapshot, subscribeLifecycle, } from "./engine/lifecycleStore";
|
|
10
10
|
export type { LifecycleSnapshot, AwayOptions, PowerInput, SimulationReport, RelaunchReport, BatteryState, } from "./engine/lifecycleStore";
|
|
11
11
|
export { RECIPES, runRecipe } from "./engine/recipes";
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -17,9 +17,9 @@ export declare const lifecycleSyncAdapter: import("@buoy-gg/shared-ui").SyncAdap
|
|
|
17
17
|
returnToApp(): LifecycleSyncSnapshot;
|
|
18
18
|
memoryWarning(): LifecycleSyncSnapshot;
|
|
19
19
|
openUrl(params: unknown): LifecycleSyncSnapshot;
|
|
20
|
-
pressBack(): LifecycleSyncSnapshot & {
|
|
20
|
+
pressBack(): Promise<LifecycleSyncSnapshot & {
|
|
21
21
|
handled: boolean;
|
|
22
|
-
}
|
|
22
|
+
}>;
|
|
23
23
|
setColorScheme(params: unknown): LifecycleSyncSnapshot;
|
|
24
24
|
setPower(params: unknown): LifecycleSyncSnapshot;
|
|
25
25
|
resetPower(): LifecycleSyncSnapshot;
|
package/lib/web/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";var _e=Object.defineProperty;var Gt=Object.getOwnPropertyDescriptor;var Jt=Object.getOwnPropertyNames;var Xt=Object.prototype.hasOwnProperty;var Qt=(e,t)=>{for(var n in t)_e(e,n,{get:t[n],enumerable:true})},je=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Jt(t))!Xt.call(e,o)&&o!==n&&_e(e,o,{get:()=>t[o],enumerable:!(r=Gt(t,o))||r.enumerable});return e},Zt=(e,t,n)=>(je(e,t,"default"),n&&je(n,t,"default"));var He=process.env.NODE_ENV!=="production";typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);var Ve={};Qt(Ve,{AccessibilityInfo:()=>nn,ActivityIndicator:()=>Kn,Alert:()=>Jn,Animated:()=>rn,AppRegistry:()=>on,AppState:()=>ln,Appearance:()=>W,BackHandler:()=>Ue,Button:()=>Yn,CheckBox:()=>kn,Clipboard:()=>an,DeviceEventEmitter:()=>Z,Dimensions:()=>sn,Easing:()=>cn,FlatList:()=>Sn,I18nManager:()=>un,Image:()=>xn,ImageBackground:()=>Cn,InteractionManager:()=>pn,Keyboard:()=>dn,KeyboardAvoidingView:()=>Tn,LayoutAnimation:()=>hn,Linking:()=>fn,LogBox:()=>Wn,Modal:()=>qn,NativeEventEmitter:()=>yn,NativeModules:()=>qe,PanResponder:()=>gn,Picker:()=>In,PixelRatio:()=>mn,Platform:()=>Ke,Pressable:()=>Vn,ProgressBar:()=>Mn,RefreshControl:()=>Ln,SafeAreaView:()=>Dn,ScrollView:()=>Ge,SectionList:()=>An,Share:()=>wn,StatusBar:()=>Pn,StyleSheet:()=>de,Switch:()=>Un,Text:()=>u,TextInput:()=>Ye,Touchable:()=>En,TouchableHighlight:()=>jn,TouchableNativeFeedback:()=>Rn,TouchableOpacity:()=>D,TouchableWithoutFeedback:()=>Hn,UIManager:()=>bn,Vibration:()=>vn,View:()=>p,VirtualizedList:()=>$n,YellowBox:()=>Nn,findNodeHandle:()=>Gn,unstable_createElement:()=>tn,useColorScheme:()=>Bn,useLocaleContext:()=>zn,useWindowDimensions:()=>On});Zt(Ve,en);import*as en from"react-native-web";import{unstable_createElement as tn,NativeModules as qe,AccessibilityInfo as nn,Animated as rn,Appearance as W,AppRegistry as on,AppState as ln,BackHandler as Ue,Clipboard as an,Dimensions as sn,Easing as cn,I18nManager as un,Keyboard as dn,InteractionManager as pn,LayoutAnimation as hn,Linking as fn,NativeEventEmitter as yn,PanResponder as gn,PixelRatio as mn,Platform as Ke,Share as wn,StyleSheet as de,UIManager as bn,Vibration as vn,CheckBox as kn,FlatList as Sn,Image as xn,ImageBackground as Cn,KeyboardAvoidingView as Tn,Picker as In,ProgressBar as Mn,RefreshControl as Ln,SafeAreaView as Dn,SectionList as An,StatusBar as Pn,Touchable as En,TouchableNativeFeedback as Rn,VirtualizedList as $n,YellowBox as Nn,LogBox as Wn,DeviceEventEmitter as Z,useColorScheme as Bn,useLocaleContext as zn,useWindowDimensions as On}from"react-native-web";import*as x from"react-native-web";import{createElement as Fn,forwardRef as _n}from"react";function T(e){let t=_n((r,o)=>{let{accessibilityState:a,accessibilityValue:c,...d}=r;for(let f of["busy","checked","disabled","expanded","selected"])a?.[f]!==void 0&&d[`aria-${f}`]===void 0&&(d[`aria-${f}`]=a[f]);for(let[f,y]of Object.entries({min:"valuemin",max:"valuemax",now:"valuenow",text:"valuetext"}))c?.[f]!==void 0&&d[`aria-${y}`]===void 0&&(d[`aria-${y}`]=c[f]);return Fn(e,{...d,ref:o})}),n=e.State;return n&&Object.assign(t,{State:n}),t.displayName=e.displayName??e.name??"NativeWebView",t}var p=T(x.View),u=T(x.Text),Ye=T(x.TextInput),D=T(x.TouchableOpacity),jn=T(x.TouchableHighlight),Hn=T(x.TouchableWithoutFeedback),Vn=T(x.Pressable),Ge=T(x.ScrollView),qn=T(x.Modal),Un=T(x.Switch),Kn=T(x.ActivityIndicator),Yn=T(x.Button),Gn=x.findNodeHandle,Jn={alert(e,t,n,r){if(typeof document>"u")return;let o=document.createElement("dialog");o.dataset.buoyRoot="",o.setAttribute("aria-label",e),o.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 a=document.createElement("h2");if(a.textContent=e,a.style.cssText="font-size:18px;margin:0 0 12px",o.appendChild(a),t){let y=document.createElement("p");y.textContent=t,y.style.cssText="line-height:1.5;white-space:pre-wrap;margin:0 0 20px",o.appendChild(y)}let c=document.createElement("div");c.style.cssText="display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px";let d=n?.length?n:[{text:"OK"}],f=()=>{o.close?.(),o.remove()};for(let y of d){let S=document.createElement("button");S.type="button",S.textContent=y.text??"OK",S.style.cssText=`padding:9px 14px;border:1px solid #64748b;border-radius:7px;color:white;background:${y.style==="destructive"?"#a52b38":"#283a4d"};cursor:pointer;font:inherit`,S.onclick=()=>{f(),y.onPress?.()},c.appendChild(S)}o.addEventListener("cancel",y=>{y.preventDefault(),r?.cancelable!==false&&(f(),r?.onDismiss?.())}),o.appendChild(c),document.body.appendChild(o),o.showModal?o.showModal():o.setAttribute("open","")}};import{getRealAppState as Je,getSafeCurrentRoute as Xe,getSafeRouter as Xn,realNow as $,reloadApp as Qn,subscribeRealAppState as Zn}from"@buoy-gg/shared-ui/web";import{loadToolModule as Qe}from"@buoy-gg/shared-ui/web/utils";import{BUOY_SYNTHETIC_MARK as er}from"@buoy-gg/shared-ui/web";function _(){let e=Ke.OS;return e==="ios"||e==="android"||e==="web"?e:"other"}function I(e,t){t===void 0?Z.emit(e):Z.emit(e,t)}function K(e){I("appStateDidChange",{app_state:e,[er]:true})}function Ze(e){I("appStateFocusChange",e)}function tr(e,t){return e==="appStateDidChange"&&t>0?1:0}function nr(e){return globalThis.__buoyOwnDeviceListeners?.[e]??0}function Y(e){let t=Z;if(typeof t.listenerCount!="function")return null;let n=t.listenerCount(e);return Math.max(0,n-tr(e,n)-nr(e))}function B(e){let t=globalThis.expo?.modules?.[e];return t&&typeof t=="object"?t:null}function rr(e,t){if(!e||typeof e.listenerCount!="function")return null;try{return e.listenerCount(t)}catch{return null}}function ee(){let e=qe.RNDeviceInfo;return e&&typeof e=="object"?e:null}function or(e,t,n){if(typeof e[t]!="function")return null;let r=e[t];try{if(e[t]=n,e[t]!==n)return null}catch{return null}return()=>{try{e[t]=r}catch{}}}import{devToolsStorageKeys as ir,persistentStorage as et}from"@buoy-gg/shared-ui/web";var pe={showChip:true,reportWindowMs:5e3},tt=ir.lifecycle.state();function lr(e,t){return typeof e=="number"&&Number.isFinite(e)?e:t}function nt(e){return typeof e=="string"?e:null}function ar(e){if(!e)return null;try{let t=JSON.parse(e);if(!t||t.v!==1)return null;let n=t.settings??{},r=t.pendingRelaunch;return{v:1,settings:{showChip:typeof n.showChip=="boolean"?n.showChip:pe.showChip,reportWindowMs:Math.min(6e4,Math.max(1e3,lr(n.reportWindowMs,pe.reportWindowMs)))},pendingRelaunch:r&&typeof r.at=="number"?{at:r.at,pathname:nt(r.pathname),href:nt(r.href)}:null}}catch{return null}}async function sr(){try{return ar(await et.getItem(tt))}catch{return null}}var he=Promise.resolve();function fe(e){let t=JSON.stringify(e);return he=he.then(()=>et.setItem(tt,t)).catch(()=>{}),he.then(()=>{})}function rt(){return globalThis.__buoyRealTimers??globalThis}function te(e,t){return rt().setTimeout(e,t)}function ye(e){e!=null&&rt().clearTimeout(e)}var cr=30,M={...pe},C=null,A=null,P=null,b=null,z=null,ge=[],ne=null,re=null,oe=null,G=[],ur=0,ie=()=>{},me=new Set,le=null;function m(){le=null;for(let e of Array.from(me))try{e()}catch{}}function k(e){ge=[{at:$(),text:e},...ge].slice(0,cr)}function ot(){fe({v:1,settings:M,pendingRelaunch:null})}function dr(){let e=B("ExpoDevice"),t=B("ExpoApplication"),n=r=>typeof r=="string"&&r?r:null;return{isSimulator:typeof e?.isDevice=="boolean"?!e.isDevice:null,deviceName:n(e?.deviceName),bundleId:n(t?.applicationId),os:n(e?.osName)??_(),appScheme:pr()}}function pr(){try{let e=B("ExponentConstants")?.manifest;typeof e=="string"&&(e=JSON.parse(e));let t=e?.scheme,n=Array.isArray(t)?t[0]:t;return typeof n=="string"&&n?n:null}catch{return null}}var it=null;function lt(){let e=[];return B("ExpoBattery")&&e.push("expo-battery"),ee()&&e.push("react-native-device-info"),e}function hr(){let e=null,t=r=>{r!=null&&(e=(e??0)+r)},n=B("ExpoBattery");for(let r of kr)t(rr(n,r));if(ee())for(let r of Sr)t(Y(r));return e}function at(){try{return Qe("@buoy-gg/clock")}catch{return null}}function g(){return le||(le={platform:_(),host:it??(it=dr()),realAppState:Je(),away:C,power:A,scheme:P,listeners:{appState:Y("appStateDidChange"),focus:Y("appStateFocusChange"),memoryWarning:Y("memoryWarning"),deepLink:Y("url"),battery:hr()},batteryLibraries:lt(),clockAvailable:typeof at()?.shift=="function",report:b,relaunch:z,log:ge,settings:M,active:C!=null||A!=null||P!=null},le)}function st(){return m(),g()}function J(e){return me.add(e),()=>me.delete(e)}function fr(){return M}var yr=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"],gr=40,ct=1e3;function mr(){try{let e=Qe("@buoy-gg/events");return typeof e.watchEvents=="function"?e.watchEvents:null}catch{return null}}function we(){ye(re),re=null,oe?.(),oe=null,b&&b.collectingUntil!=null&&(b={...b,collectingUntil:null},m())}function ut(e,t,n,r){we();let o=$(),a=++ur;b={id:a,label:e,kind:t,signal:r,startedAt:o,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:n};let c=mr();if(!c){b={...b,collectingUntil:null,unavailable:"Install @buoy-gg/events to see what the app did after a simulation."};return}let d=Date.now(),f=()=>C?Number.MAX_SAFE_INTEGER:y,y=Number.MAX_SAFE_INTEGER;ie=()=>{y=Date.now()},oe=c(yr,S=>{if(!b||b.id!==a)return;let L=S.filter(w=>!(w.source.startsWith("react-query")&&w.status==="pending")).sort((w,F)=>w.timestamp-F.timestamp),R=L.filter((w,F)=>F===0||!(w.source===L[F-1].source&&w.title===L[F-1].title&&w.timestamp-L[F-1].timestamp<250)),ue={};for(let w of R)ue[w.source]=(ue[w.source]??0)+1;let Oe=R.map(w=>({source:w.source,title:w.title,subtitle:w.subtitle,status:w.status,at:Math.max(0,w.timestamp-d),whileAway:w.timestamp<f()})),Fe=Oe.filter(w=>w.whileAway&&w.source==="network"&&w.at>=ct).length;b={...b,counts:ue,events:Oe.slice(0,gr),finding:Fe>0&&b.kind==="background"?`The app kept making network requests in the background: ${Fe} after its first second away.`:void 0},m()},d)}function be(){if(!b||b.collectingUntil==null||!oe)return;let e=$()+M.reportWindowMs;b={...b,collectingUntil:e},ye(re),re=te(we,M.reportWindowMs)}function X(e,t,n){ut(e,"signal",n,t),ie(),be()}function dt(){ye(ne),ne=null}function ve(e){if(e<6e4)return`${Math.round(e/1e3)} s`;if(e<36e5)return`${Math.round(e/6e4)} min`;let t=e/36e5;return`${Number.isInteger(t)?t:t.toFixed(1)} h`}function pt(e,t={}){C&&O();let n=typeof t.durationMs=="number"&&t.durationMs>0?t.durationMs:null;if(t.skipWait&&n==null)throw new Error("skipWait needs a duration (durationMs).");let r=t.skipWait?at():null;if(t.skipWait&&typeof r?.shift!="function")throw new Error("Skipping the wait needs @buoy-gg/clock. Install it, or wait in real time.");let o=(e==="background"?"Background":"Interruption")+(n?` ${ve(n)}`:"")+(t.skipWait?" (clock skipped)":"");return ut(o,e),_()==="android"?(Ze(false),e==="background"&&K("background")):(K("inactive"),e==="background"&&K("background")),C={kind:e,startedAt:$(),returnAt:n&&!t.skipWait?$()+n:null,skippedMs:t.skipWait?n:null},k(`${o}: app ${e==="background"?"sent to the background":"interrupted"}`),t.skipWait&&n&&r?.shift?(r.shift(n),k(`App clock moved ahead ${ve(n)}`),O()):(C.returnAt!=null&&(ne=te(()=>{ne=null,C&&O()},n)),m(),g())}function j(e){return pt("background",e)}function ke(e){return pt("inactive",e)}function O(){if(dt(),!C)return g();let e=C;C=null,_()==="android"?(e.kind==="background"&&K("active"),Ze(true)):K("active");let t=e.skippedMs??$()-e.startedAt;return k(`Returned to the app after ${ve(t)}`),ie(),be(),m(),g()}var ht=false;function wr(){ht||(ht=true,Zn(e=>{C&&(dt(),C=null,k(`The OS reported "${e}", which ended the simulation`),ie(),be()),m()}))}function Se(){let e=_()==="android"?"Android never sends this event to React Native; only iOS does. Listeners ran anyway.":void 0;return X("Memory warning","memoryWarning",e),I("memoryWarning"),k("Memory warning sent"),m(),g()}function ft(e){let t=typeof e=="string"?e.trim():"";if(!/^[a-z][a-z0-9+.-]*:/i.test(t))throw new Error('A deep link needs a scheme, like "myapp://orders/42" or "https://example.com/x".');return X(`Deep link ${t}`,"deepLink"),I("url",{url:t}),k(`Deep link delivered: ${t}`),m(),g()}function yt(){if(_()!=="android")throw new Error("The hardware back button only exists on Android.");let e=Ue,t=e.exitApp,n=false;e.exitApp=()=>{n=true},X("Back button","back");try{I("hardwareBackPress")}finally{e.exitApp=t}return b&&(b={...b,note:n?"No screen handled back, so a real press would have left the app.":"A screen handled back."}),k(n?"Back pressed: nothing handled it":"Back pressed: handled by the app"),m(),{handled:!n,snapshot:g()}}function br(){try{let e=W.getColorScheme();return e==="light"||e==="dark"?e:null}catch{return null}}function gt(e,t="js"){if(e!=="light"&&e!=="dark")throw new Error('scheme must be "light" or "dark".');let n=P?P.previous:br();return P?.mode==="native"&&t==="js"&&W.setColorScheme?.("unspecified"),X(`Color scheme ${e}`,"colorScheme"),t==="native"&&typeof W.setColorScheme=="function"?W.setColorScheme(e):I("appearanceChanged",{colorScheme:e}),P={scheme:e,mode:t,previous:n},k(`Color scheme set to ${e}${t==="native"?" (native)":""}`),m(),g()}function mt(){if(!P)return;let e=P;P=null,e.mode==="native"&&typeof W.setColorScheme=="function"?W.setColorScheme("unspecified"):e.previous&&I("appearanceChanged",{colorScheme:e.previous}),k("Color scheme back to the system value")}function vr(){return mt(),m(),g()}var kr=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"],Sr=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"],xe={unknown:0,unplugged:1,charging:2,full:3};function xr(e,t){for(let d of G)d();G=[];let n=[],r=[],o=(d,f,y,S)=>{let L=or(f,y,S);L?G.push(L):typeof f[y]=="function"&&r.push(`${d} ${y}`)},a=B("ExpoBattery");a&&(n.push("expo-battery"),o("expo-battery",a,"isLowPowerModeEnabledAsync",()=>Promise.resolve(e.lowPowerMode)),o("expo-battery",a,"getBatteryLevelAsync",()=>Promise.resolve(e.level)),o("expo-battery",a,"getBatteryStateAsync",()=>Promise.resolve(xe[e.state])),typeof a.emit=="function"&&(e.lowPowerMode!==t?.lowPowerMode&&a.emit("Expo.powerModeDidChange",{lowPowerMode:e.lowPowerMode}),e.state!==t?.state&&a.emit("Expo.batteryStateDidChange",{batteryState:xe[e.state]}),e.level!==t?.level&&a.emit("Expo.batteryLevelDidChange",{batteryLevel:e.level})));let c=ee();if(c){n.push("react-native-device-info");let d=()=>({batteryLevel:e.level,batteryState:e.state,lowPowerMode:e.lowPowerMode});o("react-native-device-info",c,"getPowerState",()=>Promise.resolve(d())),o("react-native-device-info",c,"getPowerStateSync",d),o("react-native-device-info",c,"getBatteryLevel",()=>Promise.resolve(e.level)),o("react-native-device-info",c,"getBatteryLevelSync",()=>e.level),o("react-native-device-info",c,"isBatteryCharging",()=>Promise.resolve(e.state==="charging")),o("react-native-device-info",c,"isBatteryChargingSync",()=>e.state==="charging"),I("RNDeviceInfo_powerStateDidChange",d()),e.level!==t?.level&&(I("RNDeviceInfo_batteryLevelDidChange",e.level),e.level<=.2&&I("RNDeviceInfo_batteryLevelIsLow",e.level))}return{reached:n,realGetters:r}}function Ce(e){if(lt().length===0)throw new Error("Nothing in this app reads battery state: neither expo-battery nor react-native-device-info is installed.");let t=typeof e.level=="number"&&Number.isFinite(e.level)?Math.min(1,Math.max(0,e.level>1?e.level/100:e.level)):A?.level??1,n={lowPowerMode:e.lowPowerMode??A?.lowPowerMode??false,level:t,state:e.state??A?.state??"unplugged"};if(!(n.state in xe))throw new Error('state must be "unplugged", "charging", "full" or "unknown".');X(`Battery ${Math.round(n.level*100)}%${n.lowPowerMode?", low power":""}`,"battery");let{reached:r,realGetters:o}=xr(n,A);return A={...n,reached:r,realGetters:o},k(`Battery set to ${Math.round(n.level*100)}%, ${n.state}${n.lowPowerMode?", low power mode on":""}`),m(),g()}function wt(){if(!A)return;for(let n of G)n();G=[],A=null;let e=B("ExpoBattery");e&&typeof e.emit=="function"&&Promise.all([e.isLowPowerModeEnabledAsync?.(),e.getBatteryStateAsync?.(),e.getBatteryLevelAsync?.()]).then(([n,r,o])=>{typeof n=="boolean"&&e.emit("Expo.powerModeDidChange",{lowPowerMode:n}),typeof r=="number"&&e.emit("Expo.batteryStateDidChange",{batteryState:r}),typeof o=="number"&&e.emit("Expo.batteryLevelDidChange",{batteryLevel:o})}).catch(()=>{});let t=ee();t&&typeof t.getPowerState=="function"&&Promise.resolve(t.getPowerState()).then(n=>I("RNDeviceInfo_powerStateDidChange",n)).catch(()=>{}),k("Battery back to the real values")}function bt(){return wt(),m(),g()}async function Te(){return await vt(),te(()=>{Qn("auto","buoy lifecycle relaunch").catch(e=>{k(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`),ot(),m()})},250),g()}async function vt(){let e=Xe(),t={at:$(),pathname:e?.pathname??null,href:e?.href??null};return k(`Relaunching from ${t.pathname??"an unknown screen"}`),kt(false),await fe({v:1,settings:M,pendingRelaunch:t}),m(),g()}var Cr=2500;function Tr(e){z={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null},m(),te(()=>{let t=Xe()?.pathname??null;z={...z,after:t,tookMs:$()-e.at,restored:e.pathname!=null&&t!=null?t===e.pathname:null},k(z.restored===true?`Relaunch restored ${t}`:`Relaunch landed on ${t??"an unknown screen"}${e.pathname?`, was on ${e.pathname}`:""}`),m()},Cr)}function Ir(){let e=z?.beforeHref;if(!e)throw new Error("There is no route to go back to.");let t=Xn();if(!t)throw new Error("Going back needs expo-router.");return(t.navigate??t.push)?.(e),k(`Went back to ${e}`),m(),g()}function Mr(){return z=null,m(),g()}function kt(e){C&&O(),wt(),mt(),e&&k("Everything back to real")}function Ie(){return kt(true),m(),g()}function Lr(){return we(),b=null,m(),g()}function Dr(e){return M={showChip:typeof e.showChip=="boolean"?e.showChip:M.showChip,reportWindowMs:typeof e.reportWindowMs=="number"&&Number.isFinite(e.reportWindowMs)?Math.min(6e4,Math.max(1e3,e.reportWindowMs)):M.reportWindowMs},ot(),m(),g()}var St=false;function Me(){if(St)return;St=true,Je(),wr();let e=n=>{n&&(M=n.settings,n.pendingRelaunch&&(fe({v:1,settings:M,pendingRelaunch:null}),Tr(n.pendingRelaunch)),m())},t=void 0;t!==void 0?e(t):sr().then(e)}import{useEffect as Ar,useState as Pr,useSyncExternalStore as Er}from"react";import{FloatingTool as Rr,LifecycleToolIcon as $r,dismissFloatingTool as Nr,getFloatingTools as Wr,night as Le,openFloatingTool as Br,realNow as xt}from"@buoy-gg/shared-ui/web";function Ct(e){let t=Math.max(0,Math.round(e/1e3)),n=Math.floor(t/3600),r=Math.floor(t%3600/60),o=t%60,a=n>0?String(r).padStart(2,"0"):String(r);return`${n>0?`${n}:`:""}${a}:${String(o).padStart(2,"0")}`}function Tt(e,t){return e==="background"?"In the background":t?"Lost focus":"Interrupted"}function It(e,t){let n=e.away;if(!n)return"";let r=Ct(t-n.startedAt);return n.returnAt!=null?`${r} of ${Ct(n.returnAt-n.startedAt)}`:r}function Mt(e){let t=[];return e.scheme&&t.push(`${e.scheme.scheme==="dark"?"Dark":"Light"} mode`),e.power&&t.push(`Battery ${Math.round(e.power.level*100)}%${e.power.lowPowerMode?", Low Power Mode":""}`),t.join(" \xB7 ")}var zr={network:["request","requests"],"react-query":["query event","query events"],"react-query-query":["query update","query updates"],"react-query-mutation":["mutation","mutations"],route:["route change","route changes"],"storage-async":["storage write","storage writes"],"storage-mmkv":["MMKV write","MMKV writes"],redux:["Redux action","Redux actions"],zustand:["Zustand update","Zustand updates"],jotai:["Jotai update","Jotai updates"]};function Or(e,t){let[n,r]=zr[e]??[e,e];return`${t} ${t===1?n:r}`}function Lt(e){let t={};for(let n of e)t[n.source]=(t[n.source]??0)+1;return Object.entries(t).sort((n,r)=>r[1]-n[1]).map(([n,r])=>Or(n,r)).join(", ")}function Fr(e){return e==="route"?"Route":e==="network"?"Network":e.startsWith("react-query")?"Query":e.startsWith("storage")?"Storage":e.charAt(0).toUpperCase()+e.slice(1)}function Dt(e){let t=new Map;for(let n of e){let r=`${n.source}\0${n.title}`,o=t.get(r);o?(o.count+=1,o.error||(o.error=n.status==="error")):t.set(r,{source:n.source,title:n.title,subtitle:n.subtitle,error:n.status==="error",count:1})}return[...t.values()]}var _r={memoryWarning:"memory warnings",deepLink:"links",colorScheme:"color scheme changes",battery:"battery changes",back:"the back button"};function jr(e,t){switch(t){case"memoryWarning":return e.listeners.memoryWarning;case"deepLink":return e.listeners.deepLink;case"battery":return e.listeners.battery;default:return null}}function Hr(e,t){switch(t.signal){case"memoryWarning":return"Memory warning sent";case"deepLink":return`Opened ${t.label.replace(/^Deep link /,"")}`;case"colorScheme":return e.scheme?`Switched to ${e.scheme.scheme} mode`:"Appearance changed";default:return t.label}}function Vr(e,t){if(t.unavailable)return{tone:"neutral",title:"Install @buoy-gg/events to see what your app did"};let n=t.events.filter(o=>o.whileAway),r=t.collectingUntil!=null;if(t.kind==="signal"&&t.signal)return t.signal==="back"&&t.note?{tone:t.note.startsWith("No screen")?"warn":"good",title:t.note}:jr(e,t.signal)===0?{tone:"warn",title:`Nothing in your app listens for ${_r[t.signal]}`,detail:t.note}:{tone:"neutral",title:Hr(e,t),detail:t.note};if(t.finding){let o=n.some(d=>d.source.startsWith("react-query")),a=n.filter(d=>d.source==="network"&&d.at>=ct).length,c=`${a} ${a===1?"request":"requests"} after its first second away.`;return{tone:"warn",title:"Kept making requests in the background",detail:o?`${c} If these are React Query refetches, connect focusManager to AppState.`:c}}return e.listeners.appState===0?{tone:"warn",title:"Nothing in your app listens for app state changes",detail:"Your code can't react when people leave the app or come back."}:r&&e.away?{tone:"neutral",title:"Watching your app"}:t.kind==="background"?{tone:"good",title:"Nothing kept running in the background"}:{tone:"neutral",title:"Came back from the interruption"}}import{jsx as E,jsxs as At}from"react/jsx-runtime";var ae="lifecycle-chip",qr={id:ae,render:e=>E(Et,{...e})},Ur=()=>Wr().some(e=>e.id===ae),Pt=false;function Kr(){if(Pt)return;Pt=true;let e=false,t=()=>{let n=g().active&&fr().showChip;n&&!e?Br(qr):!n&&Ur()&&Nr(ae),e=n};J(t),t()}function Yr(e){let[t,n]=Pr(xt);return Ar(()=>{if(!e)return;let r=setInterval(()=>n(xt()),1e3);return()=>clearInterval(r)},[e]),t}function Et({id:e,revealToken:t}){let n=Er(J,g,g),r=Yr(n.away!=null),o=n.away,a=o?Tt(o.kind,n.platform==="android"):"Simulating",c=o?It(n,r):Mt(n);return E(Rr,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:`Move or hide the lifecycle chip. ${a}`,children:At(p,{style:N.row,children:[E($r,{size:18}),At(p,{style:N.text,children:[E(u,{style:N.title,numberOfLines:1,testID:"lifecycle-chip-title",children:a}),E(u,{style:N.detail,numberOfLines:1,testID:"lifecycle-chip-detail",children:c})]}),o?E(D,{testID:"lifecycle-chip-return",accessibilityRole:"button",accessibilityLabel:"Return to the app",onPress:()=>O(),style:N.pill,hitSlop:{top:8,bottom:8,left:4,right:8},children:E(u,{style:N.pillText,children:"Return"})}):E(D,{testID:"lifecycle-chip-reset",accessibilityRole:"button",accessibilityLabel:"End every simulation",onPress:()=>Ie(),style:N.pill,hitSlop:{top:8,bottom:8,left:4,right:8},children:E(u,{style:N.pillText,children:"Stop"})})]})})}var N=de.create({row:{flexDirection:"row",alignItems:"center",gap:10,paddingLeft:10,paddingRight:4,paddingVertical:6,minWidth:230},text:{flexShrink:1,minWidth:120},title:{color:"#A3E635",fontSize:14,fontWeight:"600"},detail:{color:Le.color.textSecondary,fontSize:11,fontVariant:["tabular-nums"]},pill:{paddingHorizontal:12,height:28,marginRight:4,borderRadius:14,alignItems:"center",justifyContent:"center",backgroundColor:Le.color.accentFill},pillText:{color:Le.color.accent,fontSize:13,fontWeight:"600"}});import{LifecycleToolIcon as Gr,LIFECYCLE_TOOL_ICON_COLOR as Jr,createToolFactory as Xr,defineToolPreset as Qr}from"@buoy-gg/shared-ui/web";import{useEffect as Rt,useRef as $t,useState as Zr}from"react";import{FeatureGate as eo,openBuoyTool as to}from"@buoy-gg/shared-ui/web";import{useToolHost as no}from"@buoy-gg/core/web";import{createSyncAdapter as ro}from"@buoy-gg/shared-ui/web";var Nt=6e4,Q=[{id:"phone-call",title:"Take a phone call",detail:"The app pauses for 20 seconds, then comes back",run:()=>ke({durationMs:2e4})},{id:"quick-switch",title:"Switch apps for a moment",detail:"Hidden for 5 seconds, then back",run:()=>j({durationMs:5e3})},{id:"away-31m",title:"Come back in 31 minutes",detail:"Catches 30-minute session timeouts. Moves the clock, so there's no wait",needsClock:true,run:()=>j({durationMs:31*Nt,skipWait:true})},{id:"overnight",title:"Come back the next morning",detail:"9 hours later. Moves the clock, so there's no wait",needsClock:true,run:()=>j({durationMs:540*Nt,skipWait:true})},{id:"low-memory",title:"Run low on memory",detail:"A memory warning, then 10 seconds in the background",run:()=>(Se(),j({durationMs:1e4}))},{id:"dying-battery",title:"Battery almost empty",detail:"5% with Low Power Mode on",needsBattery:true,run:()=>Ce({level:.05,lowPowerMode:true,state:"unplugged"})},{id:"relaunch",title:"Close and reopen the app",detail:"Restarts JavaScript, then checks it reopens where you were",run:()=>Te()}];function Wt(e,t=g()){return e.needsClock&&!t.clockAvailable?"Install @buoy-gg/clock to skip the wait":e.needsBattery&&t.batteryLibraries.length===0?"Needs expo-battery or react-native-device-info":null}function Bt(e){let t=Q.find(r=>r.id===e);if(!t)throw new Error(`Unknown recipe "${e}". Recipes: ${Q.map(r=>r.id).join(", ")}.`);let n=Wt(t);if(n)throw new Error(`${t.title}: ${n}.`);return t.run()}function H(e){return e&&typeof e=="object"?e:{}}function De(e,t){let n=e[t];if(typeof n=="boolean")return n;if(n==="true")return true;if(n==="false")return false}var oo={ms:1,s:1e3,m:6e4,min:6e4,h:36e5,d:864e5};function Ae(e){if(e==null||e==="")return null;if(typeof e=="number")return Number.isFinite(e)&&e>0?e:null;if(typeof e!="string")return null;let t=/^\s*(\d+(?:\.\d+)?)\s*(ms|s|min|m|h|d)?\s*$/i.exec(e);if(!t)throw new Error(`Can't read the duration "${e}". Use ms or a value like "30s", "5m", "2h".`);return Number(t[1])*oo[(t[2]??"ms").toLowerCase()]}function zt(e){let t=H(e);return{durationMs:Ae(t.duration??t.durationMs??t.for),skipWait:De(t,"skipWait")??false}}function v(e=g()){return{...e,recipes:Q.map(t=>({id:t.id,title:t.title,detail:t.detail,unavailable:Wt(t,e)}))}}var Pe=ro({version:1,getSnapshot(){return v()},subscribe(e){return J(e)},actions:{getState(){return v(st())},background(e){return v(j(zt(e)))},interrupt(e){return v(ke(zt(e)))},returnToApp(){return v(O())},memoryWarning(){return v(Se())},openUrl(e){let t=H(e),n=t.url??t.link??t.href;if(typeof n!="string")throw new Error('openUrl needs `url`, like "myapp://orders/42".');return v(ft(n))},pressBack(){let e=yt();return{...v(e.snapshot),handled:e.handled}},setColorScheme(e){let t=H(e),n=t.scheme??t.colorScheme;if(n==="system")return v(vr());if(n!=="light"&&n!=="dark")throw new Error('setColorScheme needs `scheme`: "light", "dark" or "system".');let r=t.mode==="native"?"native":"js";return v(gt(n,r))},setPower(e){let t=H(e),n=t.level??t.batteryLevel;return v(Ce({lowPowerMode:De(t,"lowPowerMode"),level:typeof n=="number"?n:typeof n=="string"?Number(n):void 0,state:typeof t.state=="string"?t.state:void 0}))},resetPower(){return v(bt())},async relaunch(){return v(await Te())},async prepareRelaunch(){return v(await vt())},goBackToBeforeRelaunch(){return v(Ir())},dismissRelaunchReport(){return v(Mr())},async runRecipe(e){let t=H(e),n=t.id??t.recipe;if(typeof n!="string")throw new Error(`runRecipe needs \`id\`: ${Q.map(r=>r.id).join(", ")}.`);return v(await Bt(n))},clearReport(){return v(Lr())},reset(){return v(Ie())},updateSettings(e){let t=H(e),n=t.reportWindowMs??t.reportWindow;return v(Dr({showChip:De(t,"showChip"),reportWindowMs:n!=null?Ae(n)??void 0:void 0}))}}});import{useEffect as io,useRef as lo,useState as V}from"react";import{AlertTriangle as ao,CheckCircle as so,ChevronDown as co,ChevronRight as uo,NightButton as Ee,NightCard as q,NightFootnote as U,NightRows as Re,NightSectionLabel as $e,NightSegmented as Ne,NightSwitch as Ot,Play as po,monoFont as Ft,night as s,realNow as We,useSafeAreaInsets as ho}from"@buoy-gg/shared-ui/web";import{Fragment as fo,jsx as i,jsxs as h}from"react/jsx-runtime";var _t="#A3E635",yo=[{key:"hold",label:"No limit"},{key:"5000",label:"5 s"},{key:"60000",label:"1 min"},{key:"300000",label:"5 min"},{key:"1800000",label:"30 min"}],go=6e4;function jt(e){let[t,n]=V(()=>We());return io(()=>{if(!e)return;let r=setInterval(()=>n(We()),1e3);return()=>clearInterval(r)},[e]),e?t:We()}function Ht({snapshot:e,onAction:t}){let n=ho({minBottom:16}),r=lo(null),[o,a]=V(null),c=(d,f)=>{a(null),r.current?.scrollTo({y:0,animated:true}),t(d,f).catch(y=>{a(y instanceof Error?y.message:String(y))})};return e?h(Ge,{ref:r,style:l.fill,contentContainerStyle:[l.content,{paddingBottom:n.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[i(mo,{snapshot:e,run:c}),o?i(U,{tone:"danger",centered:true,children:i(u,{testID:"lifecycle-error",children:o})}):null,i(ko,{snapshot:e,run:c}),i(xo,{snapshot:e,run:c})]}):i(p,{style:l.waiting,testID:"lifecycle-waiting",children:i(U,{centered:true,children:"Waiting for the app\u2026"})})}function mo({snapshot:e,run:t}){let n=Mt(e),r;return e.away?r=i(wo,{snapshot:e,run:t}):e.relaunch?r=i(vo,{snapshot:e,run:t}):e.report?r=i(bo,{snapshot:e,run:t}):r=i(u,{style:l.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."}),h(p,{style:l.status,children:[r,n&&!e.away?i(q,{children:h(p,{style:l.row,children:[h(p,{style:l.rowText,children:[i(u,{style:l.simulatedLabel,children:"Simulated"}),i(u,{style:l.rowTitle,testID:"lifecycle-simulated",children:n})]}),i(Ee,{label:"Stop Simulating",size:"md",fullWidth:false,testID:"lifecycle-reset",accessibilityLabel:"End every simulation",onPress:()=>t("reset")})]})}):null]})}function wo({snapshot:e,run:t}){let n=jt(true),r=e.away,o=Tt(r.kind,e.platform==="android"),a=e.report,c=a?a.events.filter(d=>d.whileAway):[];return h(p,{style:l.running,children:[i(u,{style:l.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${o} (simulated)`,children:o}),i(u,{style:l.runningTimer,testID:"lifecycle-hero-status",children:It(e,n)}),i(p,{style:l.runningButton,children:i(Ee,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>t("returnToApp")})}),a?.finding?i(u,{style:l.runningWarning,testID:"lifecycle-report-finding",children:a.finding}):c.length>0?h(u,{style:l.runningNote,children:["So far: ",Lt(c)]}):null]})}function Vt({verdict:e}){let t=e.tone==="warn"?s.color.warning:e.tone==="good"?s.color.accent:s.color.text;return h(p,{style:l.verdict,children:[e.tone==="warn"?i(ao,{size:20,color:t}):e.tone==="good"?i(so,{size:20,color:t}):null,h(p,{style:l.rowText,children:[i(u,{style:[l.verdictTitle,{color:t}],testID:"lifecycle-verdict",children:e.title}),e.detail?i(u,{style:l.verdictDetail,testID:"lifecycle-report-finding",children:e.detail}):null]})]})}var qt=5;function bo({snapshot:e,run:t}){let n=e.report,r=n.collectingUntil!=null,o=jt(r),[a,c]=V(false),d=Vr(e,n),f=n.events.filter(R=>R.whileAway),y=n.events.filter(R=>!R.whileAway),S=n.kind!=="signal",L=r?Math.max(0,(n.collectingUntil??o)-o):0;return i(q,{children:h(p,{style:l.result,testID:"lifecycle-report",children:[i(Vt,{verdict:d}),S||r?i(u,{style:l.resultLabel,testID:"lifecycle-report-label",children:S?`${n.label}${r?` \xB7 watching ${Math.ceil(L/1e3)} s`:""}`:`Watching ${Math.ceil(L/1e3)} s`}):null,n.unavailable?null:n.events.length===0?r?null:i(u,{style:l.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):h(fo,{children:[S&&f.length>0?i(Be,{title:"While away",events:f,showAll:a}):null,y.length>0?i(Be,{title:S?"After returning":"What your app did",events:y,showAll:a}):null,!S&&f.length>0?i(Be,{title:"What your app did",events:f,showAll:a}):null]}),h(p,{style:l.resultButtons,children:[Dt(n.events).length>qt?i(D,{onPress:()=>c(R=>!R),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:a?"Show Less":"Show All"})}):i(p,{}),i(D,{onPress:()=>t("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:"Done"})})]})]})})}function Be({title:e,events:t,showAll:n}){let r=Dt(t),o=n?r:r.slice(0,qt);return h(p,{style:l.eventList,children:[i(u,{style:l.eventHeading,children:`${e} \xB7 ${Lt(t)}`}),o.map(a=>h(p,{style:l.event,children:[i(u,{style:l.eventSource,children:Fr(a.source)}),i(u,{style:[l.eventTitle,a.error?l.eventError:null],numberOfLines:1,children:a.title}),a.count>1?i(u,{style:l.eventCount,children:`\xD7${a.count}`}):null]},`${a.source}-${a.title}`)),r.length>o.length?i(u,{style:l.detail,children:`${r.length-o.length} more`}):null]})}var se=e=>e==="/"?"the home screen":e;function vo({snapshot:e,run:t}){let n=e.relaunch,r=n.after==null&&n.restored==null&&n.tookMs==null?{tone:"neutral",title:"Checking where your app reopened\u2026"}:n.restored===true?{tone:"good",title:`Reopened where you were: ${se(n.after)}`}:n.after?{tone:"warn",title:`Opened ${se(n.after)} instead of ${se(n.before)??"the screen you were on"}`,detail:"The app doesn't restore the last screen after it's closed."}:{tone:"neutral",title:"Couldn't read the screen after reopening"};return i(q,{children:h(p,{style:l.result,testID:"lifecycle-relaunch-report",children:[i(p,{testID:"lifecycle-relaunch-result",children:i(Vt,{verdict:r})}),h(p,{style:l.resultButtons,children:[n.restored===false&&n.beforeHref?i(D,{onPress:()=>t("goBackToBeforeRelaunch"),testID:"lifecycle-relaunch-go-back",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:`Go to ${se(n.before)}`})}):i(p,{}),i(D,{onPress:()=>t("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:"Done"})})]})]})})}function ko({snapshot:e,run:t}){let n=e.host?.appScheme,[r,o]=V(n?`${n}://`:""),a=e.batteryLibraries.length>0,c=e.recipes.filter(f=>f.id!=="dying-battery"||a),d=e.away!=null;return h(p,{children:[i($e,{children:"Test a moment"}),i(q,{children:h(Re,{children:[c.map(f=>i(So,{recipe:f,disabled:d,onPress:()=>t("runRecipe",{id:f.id})},f.id)),h(p,{style:l.stack,children:[i(u,{style:l.rowTitle,children:"Open a link"}),h(p,{style:l.inputRow,children:[i(Ye,{testID:"lifecycle-url-input",accessibilityLabel:"Link to open",value:r,onChangeText:o,placeholder:"myapp://orders/42",placeholderTextColor:s.color.placeholder,autoCapitalize:"none",autoCorrect:false,keyboardType:"url",returnKeyType:"go",onSubmitEditing:()=>t("openUrl",{url:r}),style:l.input}),i(Ee,{label:"Open",size:"md",fullWidth:false,testID:"lifecycle-url-open",accessibilityLabel:"Open this link in the app",onPress:()=>t("openUrl",{url:r})})]}),e.listeners.deepLink===0?i(u,{style:l.warning,children:"Nothing in your app listens for links."}):null]},"link")]})})]})}function So({recipe:e,disabled:t,onPress:n}){let r=t||!!e.unavailable;return h(D,{testID:`lifecycle-recipe-${e.id}`,accessibilityRole:"button",accessibilityLabel:e.title,accessibilityHint:e.unavailable??e.detail,accessibilityState:{disabled:r},disabled:r,activeOpacity:.6,onPress:n,style:[l.row,r?l.rowDisabled:null],children:[h(p,{style:l.rowText,children:[i(u,{style:l.rowTitle,children:e.title}),i(u,{style:l.detail,children:e.unavailable??e.detail})]}),e.unavailable?null:i(po,{size:16,color:s.color.accent})]})}function xo({snapshot:e,run:t}){let[n,r]=V(false),o=n?co:uo;return h(p,{children:[h(D,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:n},onPress:()=>r(a=>!a),style:l.disclosure,hitSlop:8,children:[i(u,{style:l.disclosureText,children:"Custom"}),i(o,{size:16,color:s.color.textSecondary})]}),n?h(p,{style:l.customBody,children:[i(Co,{snapshot:e,run:t}),i(Io,{snapshot:e,run:t}),i(U,{children:"Only your app's JavaScript hears these events. Timers, requests and native code keep running, and a real event from the OS ends the simulation."})]}):null]})}function Co({snapshot:e,run:t}){let[n,r]=V("hold"),o=n==="hold"?null:Number(n),a=o!=null&&o>=go,c=a&&e.clockAvailable,d=()=>({durationMs:o,skipWait:c}),f=e.platform==="android",y=e.away!=null;return h(p,{children:[i($e,{children:"Leave the app"}),h(q,{children:[i(p,{style:l.segmentWrap,children:i(Ne,{tabs:yo,activeKey:n,size:"sm",testIDPrefix:"lifecycle-duration",onChange:r})}),h(Re,{children:[i(ce,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:y,onPress:()=>t("background",d())},"background"),i(ce,{title:f?"Pull Down Notifications":"Take a Call",detail:f?"The app stays visible but loses focus":"The app stays visible but inactive, like with Control Center open",testID:"lifecycle-interrupt",disabled:y,onPress:()=>t("interrupt",d())},"interrupt")]})]}),a?i(U,{children:e.clockAvailable?"Moves the app clock forward instead of waiting.":"Waits in real time. Install @buoy-gg/clock to skip the wait."}):null,e.listeners.appState===0?i(U,{tone:"warning",children:"Nothing in your app listens for app state changes."}):null]})}var To=[{key:"real",label:"Real"},{key:"100",label:"100%"},{key:"20",label:"20%"},{key:"5",label:"5%"}];function Io({snapshot:e,run:t}){let n=e.platform==="android",r=e.batteryLibraries.length>0,o=e.power,a=e.listeners.memoryWarning===0?"Nothing in your app listens for it":n?"Android never sends this, but your listeners will run":void 0;return h(p,{children:[i($e,{children:"Signals"}),i(q,{children:h(Re,{children:[i(ce,{title:"Send Memory Warning",detail:a,warn:e.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>t("memoryWarning")},"memory"),h(p,{style:l.stack,children:[i(u,{style:l.rowTitle,children:"Appearance"}),i(Ne,{tabs:[{key:"system",label:"System"},{key:"light",label:"Light"},{key:"dark",label:"Dark"}],activeKey:e.scheme?.scheme??"system",size:"sm",testIDPrefix:"lifecycle-scheme",onChange:c=>t("setColorScheme",{scheme:c})})]},"scheme"),r?h(p,{style:l.stack,children:[i(u,{style:l.rowTitle,children:"Battery"}),i(Ne,{tabs:To,activeKey:o?String(Math.round(o.level*100)):"real",size:"sm",testIDPrefix:"lifecycle-battery",onChange:c=>c==="real"?t("resetPower"):t("setPower",{level:Number(c)/100})}),h(p,{style:l.inlineRow,children:[i(u,{style:l.rowTitle,children:"Charging"}),i(Ot,{value:o?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:c=>t("setPower",{state:c?"charging":"unplugged"})})]}),h(p,{style:l.inlineRow,children:[i(u,{style:l.rowTitle,children:"Low Power Mode"}),i(Ot,{value:o?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:c=>t("setPower",{lowPowerMode:c})})]}),e.listeners.battery===0?i(u,{style:l.warning,children:"Nothing in your app listens for battery changes."}):null]},"battery"):null,n?i(ce,{title:"Press Back",detail:"Never closes the app. The result says if a real press would have.",testID:"lifecycle-back",onPress:()=>t("pressBack")},"back"):null]})}),r?null:i(U,{children:"Battery needs expo-battery or react-native-device-info in your app."})]})}function ce({title:e,detail:t,warn:n,testID:r,disabled:o,onPress:a}){return i(D,{testID:r,accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{disabled:!!o},activeOpacity:.6,disabled:o,onPress:a,style:[l.row,o?l.rowDisabled:null],children:h(p,{style:l.rowText,children:[i(u,{style:l.actionTitle,children:e}),t?i(u,{style:n?l.warning:l.detail,children:t}):null]})})}var l=de.create({fill:{flex:1},content:{paddingHorizontal:s.gutter,paddingTop:8,gap:s.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},status:{gap:12},intro:{color:s.color.textSecondary,fontSize:s.font.body,lineHeight:20,paddingHorizontal:s.labelInset,paddingTop:4},running:{alignItems:"center",paddingTop:12,gap:6},runningTitle:{color:_t,fontSize:30,fontWeight:"300"},runningTimer:{color:s.color.textSecondary,fontSize:s.font.row,fontWeight:"500",fontVariant:["tabular-nums"]},runningButton:{alignSelf:"stretch",marginTop:10},runningWarning:{color:s.color.warning,fontSize:s.font.caption,textAlign:"center",marginTop:4},runningNote:{color:s.color.textTertiary,fontSize:s.font.caption,textAlign:"center",marginTop:4},simulatedLabel:{color:_t,fontSize:s.font.micro,fontWeight:"600",textTransform:"uppercase",letterSpacing:.4},result:{paddingHorizontal:s.rowPadH,paddingVertical:14,gap:12},verdict:{flexDirection:"row",gap:10,alignItems:"flex-start"},verdictTitle:{fontSize:s.font.title,fontWeight:"600"},verdictDetail:{color:s.color.textSecondary,fontSize:s.font.caption,lineHeight:18},resultLabel:{color:s.color.textTertiary,fontSize:s.font.caption,fontVariant:["tabular-nums"]},resultButtons:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},link:{color:s.color.accent,fontSize:s.font.row,fontWeight:"500"},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:s.rowPadH,paddingVertical:10},rowText:{flex:1,gap:2},rowDisabled:{opacity:.4},rowTitle:{color:s.color.text,fontSize:s.font.row},actionTitle:{color:s.color.accent,fontSize:s.font.row},detail:{color:s.color.textTertiary,fontSize:s.font.caption},warning:{color:s.color.warning,fontSize:s.font.caption},stack:{paddingHorizontal:s.rowPadH,paddingVertical:12,gap:10},segmentWrap:{paddingHorizontal:s.rowPadH,paddingTop:12,paddingBottom:4},inlineRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},inputRow:{flexDirection:"row",alignItems:"center",gap:8},input:{flex:1,color:s.color.text,fontFamily:Ft,fontSize:14,backgroundColor:s.color.bg,borderRadius:s.radius.input,borderWidth:1,borderColor:s.color.border,paddingHorizontal:12,paddingVertical:8},disclosure:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:s.labelInset},disclosureText:{color:s.color.textSecondary,fontSize:s.font.label,fontWeight:"600",textTransform:"uppercase",letterSpacing:.8},customBody:{gap:s.groupGap,marginTop:12},eventList:{gap:6},eventHeading:{color:s.color.textSecondary,fontSize:s.font.caption,fontWeight:"600"},event:{flexDirection:"row",gap:8,alignItems:"baseline"},eventSource:{width:56,color:s.color.textTertiary,fontSize:s.font.caption},eventTitle:{flex:1,color:s.color.text,fontSize:13,fontFamily:Ft},eventError:{color:s.color.danger},eventCount:{color:s.color.textSecondary,fontSize:s.font.caption,fontWeight:"600",fontVariant:["tabular-nums"]}});import{jsx as Ut}from"react/jsx-runtime";var Mo=Pe.actions;async function Lo(e,t){let n=Mo[e];if(!n)throw new Error(`Unknown lifecycle action: ${e}`);return n(t)}var ze=()=>Pe.getSnapshot();function Kt(){let[e,t]=Zr(ze),n=no(),r=$t(false);Rt(()=>(Me(),st(),t(ze()),J(()=>t(ze()))),[]);let o=e.away!=null,a=$t(o);return Rt(()=>{let c=o&&!a.current;a.current=o,c&&!r.current?(r.current=true,n.minimize()):!o&&r.current&&(r.current=false,to("lifecycle"))},[o,n]),Ut(eo,{featureName:"Lifecycle Simulator",children:Ut(Ht,{snapshot:e,onAction:Lo})})}import{jsx as Do}from"react/jsx-runtime";var Yt=Qr({id:"lifecycle",name:"LIFECYCLE",description:"See what your app does when people leave and come back",slot:"both",color:Jr,icon:({size:e,color:t})=>Do(Gr,{size:e,color:t}),component:Kt,modal:{subtitle:"what your app does when people leave"}}),Ao=Xr(Yt);import{LifecycleToolIcon as Po,LIFECYCLE_TOOL_ICON_COLOR as Eo}from"@buoy-gg/shared-ui/web";var Ro=typeof navigator<"u"&&navigator.product==="ReactNative";Ro&&(Kr(),(typeof He<"u"&&He||void 0)&&Me());export{ae as LIFECYCLE_CHIP_ID,Eo as LIFECYCLE_TOOL_ICON_COLOR,Kt as LifecycleBody,Et as LifecycleChip,Po as LifecycleToolIcon,Ht as LifecycleToolView,Q as RECIPES,Me as bootLifecycle,Ao as createLifecycleTool,g as getLifecycleSnapshot,ke as interrupt,Pe as lifecycleSyncAdapter,Yt as lifecycleToolPreset,Se as memoryWarning,ft as openDeepLink,Ae as parseDurationMs,yt as pressBack,Te as relaunchApp,Ie as resetLifecycle,bt as resetPower,O as returnToApp,Bt as runRecipe,j as sendToBackground,gt as setColorScheme,Ce as setPower,J as subscribeLifecycle};
|
|
1
|
+
"use client";var Ze=Object.defineProperty;var fn=Object.getOwnPropertyDescriptor;var yn=Object.getOwnPropertyNames;var gn=Object.prototype.hasOwnProperty;var mn=(e,t)=>{for(var n in t)Ze(e,n,{get:t[n],enumerable:true})},et=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of yn(t))!gn.call(e,o)&&o!==n&&Ze(e,o,{get:()=>t[o],enumerable:!(r=fn(t,o))||r.enumerable});return e},bn=(e,t,n)=>(et(e,t,"default"),n&&et(n,t,"default"));var tt=(()=>{try{let e=globalThis.Capacitor;if(e&&typeof e.isNativePlatform=="function"&&e.isNativePlatform())return e.DEBUG===true}catch{}return process.env.NODE_ENV!=="production"})();typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);var nt={};mn(nt,{AccessibilityInfo:()=>Sn,ActivityIndicator:()=>fr,Alert:()=>mr,Animated:()=>xn,AppRegistry:()=>Cn,AppState:()=>Tn,Appearance:()=>O,BackHandler:()=>rt,Button:()=>yr,CheckBox:()=>Hn,Clipboard:()=>An,DeviceEventEmitter:()=>rr,Dimensions:()=>In,Easing:()=>Ln,FlatList:()=>Fn,I18nManager:()=>Mn,Image:()=>_n,ImageBackground:()=>Vn,InteractionManager:()=>En,Keyboard:()=>Pn,KeyboardAvoidingView:()=>qn,LayoutAnimation:()=>Dn,Linking:()=>Rn,LogBox:()=>nr,Modal:()=>pr,NativeEventEmitter:()=>Bn,NativeModules:()=>kn,PanResponder:()=>Wn,Picker:()=>Un,PixelRatio:()=>$n,Platform:()=>Nn,Pressable:()=>dr,ProgressBar:()=>Kn,RefreshControl:()=>Gn,SafeAreaView:()=>Jn,ScrollView:()=>it,SectionList:()=>Qn,Share:()=>On,StatusBar:()=>Yn,StyleSheet:()=>me,Switch:()=>hr,Text:()=>u,TextInput:()=>ot,Touchable:()=>Xn,TouchableHighlight:()=>cr,TouchableNativeFeedback:()=>Zn,TouchableOpacity:()=>P,TouchableWithoutFeedback:()=>ur,UIManager:()=>zn,Vibration:()=>jn,View:()=>p,VirtualizedList:()=>er,YellowBox:()=>tr,findNodeHandle:()=>gr,unstable_createElement:()=>vn,useColorScheme:()=>or,useLocaleContext:()=>ir,useWindowDimensions:()=>ar});bn(nt,wn);import*as wn from"react-native-web";import{unstable_createElement as vn,NativeModules as kn,AccessibilityInfo as Sn,Animated as xn,Appearance as O,AppRegistry as Cn,AppState as Tn,BackHandler as rt,Clipboard as An,Dimensions as In,Easing as Ln,I18nManager as Mn,Keyboard as Pn,InteractionManager as En,LayoutAnimation as Dn,Linking as Rn,NativeEventEmitter as Bn,PanResponder as Wn,PixelRatio as $n,Platform as Nn,Share as On,StyleSheet as me,UIManager as zn,Vibration as jn,CheckBox as Hn,FlatList as Fn,Image as _n,ImageBackground as Vn,KeyboardAvoidingView as qn,Picker as Un,ProgressBar as Kn,RefreshControl as Gn,SafeAreaView as Jn,SectionList as Qn,StatusBar as Yn,Touchable as Xn,TouchableNativeFeedback as Zn,VirtualizedList as er,YellowBox as tr,LogBox as nr,DeviceEventEmitter as rr,useColorScheme as or,useLocaleContext as ir,useWindowDimensions as ar}from"react-native-web";import*as x from"react-native-web";import{createElement as lr,forwardRef as sr}from"react";function A(e){let t=sr((r,o)=>{let{accessibilityState:a,accessibilityValue:c,...d}=r;for(let f of["busy","checked","disabled","expanded","selected"])a?.[f]!==void 0&&d[`aria-${f}`]===void 0&&(d[`aria-${f}`]=a[f]);for(let[f,y]of Object.entries({min:"valuemin",max:"valuemax",now:"valuenow",text:"valuetext"}))c?.[f]!==void 0&&d[`aria-${y}`]===void 0&&(d[`aria-${y}`]=c[f]);return lr(e,{...d,ref:o})}),n=e.State;return n&&Object.assign(t,{State:n}),t.displayName=e.displayName??e.name??"NativeWebView",t}var p=A(x.View),u=A(x.Text),ot=A(x.TextInput),P=A(x.TouchableOpacity),cr=A(x.TouchableHighlight),ur=A(x.TouchableWithoutFeedback),dr=A(x.Pressable),it=A(x.ScrollView),pr=A(x.Modal),hr=A(x.Switch),fr=A(x.ActivityIndicator),yr=A(x.Button),gr=x.findNodeHandle,mr={alert(e,t,n,r){if(typeof document>"u")return;let o=document.createElement("dialog");o.dataset.buoyRoot="",o.setAttribute("aria-label",e),o.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 a=document.createElement("h2");if(a.textContent=e,a.style.cssText="font-size:18px;margin:0 0 12px",o.appendChild(a),t){let y=document.createElement("p");y.textContent=t,y.style.cssText="line-height:1.5;white-space:pre-wrap;margin:0 0 20px",o.appendChild(y)}let c=document.createElement("div");c.style.cssText="display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px";let d=n?.length?n:[{text:"OK"}],f=()=>{o.close?.(),o.remove()};for(let y of d){let S=document.createElement("button");S.type="button",S.textContent=y.text??"OK",S.style.cssText=`padding:9px 14px;border:1px solid #64748b;border-radius:7px;color:white;background:${y.style==="destructive"?"#a52b38":"#283a4d"};cursor:pointer;font:inherit`,S.onclick=()=>{f(),y.onPress?.()},c.appendChild(S)}o.addEventListener("cancel",y=>{y.preventDefault(),r?.cancelable!==false&&(f(),r?.onDismiss?.())}),o.appendChild(c),document.body.appendChild(o),o.showModal?o.showModal():o.setAttribute("open","")}};import{getRealAppState as at,getSafeCurrentRoute as lt,getSafeRouter as br,realNow as W,reloadApp as wr,subscribeRealAppState as vr}from"@buoy-gg/shared-ui/web";import{loadToolModule as st}from"@buoy-gg/shared-ui/web/utils";import{capacitorListenerCount as ct,capacitorPlatform as ut,emitCapacitorEvent as X,hasCapacitorPlugin as kr,installCapacitorBridge as Sr,interceptCapacitor as be,makeCapacitorCallbackId as xr,getCapacitorAppHost as Cr,loadCapacitorAppHost as Tr,colorSchemeQueryValue as Ar,getColorSchemeQueries as Ir}from"@buoy-gg/license/web";import{BUOY_SYNTHETIC_MARK as Lr}from"@buoy-gg/shared-ui/web";function $(){return ut()??"web"}function z(){return ut()===null||!Sr()?false:(Mr(),true)}var dt=false;function Mr(){dt||(dt=true,be({plugin:"App",methods:["getState"],promise:(e,t)=>ie?t():{isActive:false}}))}function we(){let e=globalThis.document;return e&&typeof e.dispatchEvent=="function"?e:null}function oe(e){let t=we();if(!t)return;let n=globalThis.Event;if(!n)return;let r=new n(e);r[Lr]=true,t.dispatchEvent(r)}function pt(e){let t=we();t&&(e===null?(delete t.visibilityState,delete t.hidden):(Object.defineProperty(t,"visibilityState",{configurable:true,get:()=>e}),Object.defineProperty(t,"hidden",{configurable:true,get:()=>e==="hidden"})),oe("visibilitychange"))}var ie=true,q=false;function ve(e){ie!==e&&(ie=e,X("App","appStateChange",{isActive:e}))}function Z(e){if(z()){if(e==="inactive"){ve(false);return}if(e==="background"){ve(false),q||(q=true,X("App","pause",{}),oe("pause"),pt("hidden"));return}q&&(q=false,pt(null),X("App","resume",{}),oe("resume")),ve(true)}}function Pr(){q&&Er(null),q=false,ie=true}function Er(e){let t=we();!t||e!==null||(delete t.visibilityState,delete t.hidden)}function E(e,t){z()&&e==="url"&&X("App","appUrlOpen",t)}var Dr={appStateDidChange:["appStateChange","pause","resume"],url:["appUrlOpen"],hardwareBackPress:["backButton"]};function ee(e){if(!z())return null;let t=Dr[e];return t?t.reduce((n,r)=>n+ct("App",r),0):0}var Rr=400;function Br(e,t){let n=globalThis.__buoyRealTimers;typeof n?.setTimeout=="function"?n.setTimeout(e,t):setTimeout(e,t)}var C={async pressBack(){if(!z())throw new Error("The back button needs a Capacitor app.");let e=globalThis.history,t=!!(e&&e.length>1);if(ct("App","backButton")===0)return t&&e?.back(),{exited:false,handled:false,note:t?"No back listener, so the WebView went back a page.":"No back listener and no page to go back to, so nothing happened."};let n=false,r=be({plugin:"App",methods:["exitApp"],promise:()=>{n=true},callback:()=>(n=true,xr())});try{X("App","backButton",{canGoBack:t}),oe("backbutton"),await new Promise(o=>Br(o,Rr))}finally{r()}return{exited:n,handled:!n,note:n?"The app called App.exitApp(), so a real press would have left the app.":"The app's back listener handled it."}},host(){return Cr()},loadHost(){return z()?Tr():Promise.resolve(null)},colorScheme(e){if(!z())throw new Error("The color scheme needs a Capacitor app.");Wr();let t=Ir(),n=t.map(r=>r.matches);ke=e,t.forEach((r,o)=>{let a=r.matches;a!==n[o]&&$r(r,a)})},battery:{available(){return z()&&kr("Device")},set(e){te=e,e&&!yt&&(yt=true,be({plugin:"Device",methods:["getBatteryInfo"],promise:(t,n)=>te?{batteryLevel:te.level,isCharging:te.state==="charging"||te.state==="full"}:n()}))}}},ke=null,ht=false;function ft(e){let t=e&&Object.getOwnPropertyDescriptor(e,"matches");if(!e||!t?.get||!t.configurable)return false;let n=t.get;return Object.defineProperty(e,"matches",{...t,get(){let r=n.call(this),o=ke?Ar(String(this.media??"")):null;return o?ke===o:r}}),true}function Wr(){if(ht)return;let e=globalThis.MediaQueryListEvent;ft(e?.prototype);let t=globalThis.MediaQueryList;ft(t?.prototype)&&(ht=true)}function $r(e,t){let n=String(e.media??""),r=globalThis.MediaQueryListEvent,o;try{o=r?new r("change",{matches:t,media:n}):new Event("change")}catch{o=new Event("change")}r||(Object.defineProperty(o,"matches",{value:t}),Object.defineProperty(o,"media",{value:n}));try{e.dispatchEvent(o)}catch(a){globalThis.console?.error(a)}}var te=null,yt=false;function j(e){return null}function Nr(e,t){return null}function ae(){return null}function Or(e,t,n){if(typeof e[t]!="function")return null;let r=e[t];try{if(e[t]=n,e[t]!==n)return null}catch{return null}return()=>{try{e[t]=r}catch{}}}import{devToolsStorageKeys as zr,persistentStorage as gt}from"@buoy-gg/shared-ui/web";function mt(){try{let e=globalThis.localStorage;return e?wt(e.getItem(xe)):void 0}catch{return}}var Se={showChip:true,reportWindowMs:5e3},xe=zr.lifecycle.state();function jr(e,t){return typeof e=="number"&&Number.isFinite(e)?e:t}function bt(e){return typeof e=="string"?e:null}function wt(e){if(!e)return null;try{let t=JSON.parse(e);if(!t||t.v!==1)return null;let n=t.settings??{},r=t.pendingRelaunch;return{v:1,settings:{showChip:typeof n.showChip=="boolean"?n.showChip:Se.showChip,reportWindowMs:Math.min(6e4,Math.max(1e3,jr(n.reportWindowMs,Se.reportWindowMs)))},pendingRelaunch:r&&typeof r.at=="number"?{at:r.at,pathname:bt(r.pathname),href:bt(r.href)}:null}}catch{return null}}async function Hr(){try{return wt(await gt.getItem(xe))}catch{return null}}var Ce=Promise.resolve();function Te(e){let t=JSON.stringify(e);return Ce=Ce.then(()=>gt.setItem(xe,t)).catch(()=>{}),Ce.then(()=>{})}function vt(){return globalThis.__buoyRealTimers??globalThis}function le(e,t){return vt().setTimeout(e,t)}function Ae(e){e!=null&&vt().clearTimeout(e)}var Fr=30,L={...Se},T=null,D=null,I=null,b=null,H=null,Ie=[],se=null,ce=null,ue=null,U=[],_r=0,de=()=>{},Le=new Set,pe=null;function g(){pe=null;for(let e of Array.from(Le))try{e()}catch{}}function k(e){Ie=[{at:W(),text:e},...Ie].slice(0,Fr)}function kt(){Te({v:1,settings:L,pendingRelaunch:null})}function Vr(){let e=C?.host();if(e)return{...e,os:$(),appScheme:null};let t=j("ExpoDevice"),n=j("ExpoApplication"),r=o=>typeof o=="string"&&o?o:null;return{isSimulator:typeof t?.isDevice=="boolean"?!t.isDevice:null,deviceName:r(t?.deviceName),bundleId:r(n?.applicationId),os:r(t?.osName)??$(),appScheme:qr()}}function qr(){try{let e=j("ExponentConstants")?.manifest;typeof e=="string"&&(e=JSON.parse(e));let t=e?.scheme,n=Array.isArray(t)?t[0]:t;return typeof n=="string"&&n?n:null}catch{return null}}var Me=null;function St(){let e=[];return j("ExpoBattery")&&e.push("expo-battery"),ae()&&e.push("react-native-device-info"),C?.battery.available()&&e.push("@capacitor/device"),e}function Ur(){let e=null,t=r=>{r!=null&&(e=(e??0)+r)},n=j("ExpoBattery");for(let r of Zr)t(Nr(n,r));if(ae())for(let r of eo)t(ee(r));return e}function xt(){try{return st("@buoy-gg/clock")}catch{return null}}function m(){return pe||(pe={platform:$(),host:Me??(Me=Vr()),realAppState:at(),away:T,power:D,scheme:I,listeners:{appState:ee("appStateDidChange"),focus:ee("appStateFocusChange"),memoryWarning:ee("memoryWarning"),deepLink:ee("url"),battery:Ur()},batteryLibraries:St(),clockAvailable:typeof xt()?.shift=="function",report:b,relaunch:H,log:Ie,settings:L,active:T!=null||D!=null||I!=null},pe)}function Ct(){return g(),m()}function ne(e){return Le.add(e),()=>Le.delete(e)}function Kr(){return L}var Gr=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"],Jr=40,Tt=1e3;function Qr(){try{let e=st("@buoy-gg/events");return typeof e.watchEvents=="function"?e.watchEvents:null}catch{return null}}function Pe(){Ae(ce),ce=null,ue?.(),ue=null,b&&b.collectingUntil!=null&&(b={...b,collectingUntil:null},g())}function At(e,t,n,r){Pe();let o=W(),a=++_r;b={id:a,label:e,kind:t,signal:r,startedAt:o,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:n};let c=Qr();if(!c){b={...b,collectingUntil:null,unavailable:"Install @buoy-gg/events to see what the app did after a simulation."};return}let d=Date.now(),f=()=>T?Number.MAX_SAFE_INTEGER:y,y=Number.MAX_SAFE_INTEGER;de=()=>{y=Date.now()},ue=c(Gr,S=>{if(!b||b.id!==a)return;let M=S.filter(w=>!(w.source.startsWith("react-query")&&w.status==="pending")).sort((w,V)=>w.timestamp-V.timestamp),B=M.filter((w,V)=>V===0||!(w.source===M[V-1].source&&w.title===M[V-1].title&&w.timestamp-M[V-1].timestamp<250)),ge={};for(let w of B)ge[w.source]=(ge[w.source]??0)+1;let Ye=B.map(w=>({source:w.source,title:w.title,subtitle:w.subtitle,status:w.status,at:Math.max(0,w.timestamp-d),whileAway:w.timestamp<f()})),Xe=Ye.filter(w=>w.whileAway&&w.source==="network"&&w.at>=Tt).length;b={...b,counts:ge,events:Ye.slice(0,Jr),finding:Xe>0&&b.kind==="background"?`The app kept making network requests in the background: ${Xe} after its first second away.`:void 0},g()},d)}function Ee(){if(!b||b.collectingUntil==null||!ue)return;let e=W()+L.reportWindowMs;b={...b,collectingUntil:e},Ae(ce),ce=le(Pe,L.reportWindowMs)}function F(e,t,n){At(e,"signal",n,t),de(),Ee()}function It(){Ae(se),se=null}function De(e){if(e<6e4)return`${Math.round(e/1e3)} s`;if(e<36e5)return`${Math.round(e/6e4)} min`;let t=e/36e5;return`${Number.isInteger(t)?t:t.toFixed(1)} h`}function Lt(e,t={}){T&&_();let n=typeof t.durationMs=="number"&&t.durationMs>0?t.durationMs:null;if(t.skipWait&&n==null)throw new Error("skipWait needs a duration (durationMs).");let r=t.skipWait?xt():null;if(t.skipWait&&typeof r?.shift!="function")throw new Error("Skipping the wait needs @buoy-gg/clock. Install it, or wait in real time.");let o=(e==="background"?"Background":"Interruption")+(n?` ${De(n)}`:"")+(t.skipWait?" (clock skipped)":"");return At(o,e),$()==="android"?e==="background"&&Z("background"):(Z("inactive"),e==="background"&&Z("background")),T={kind:e,startedAt:W(),returnAt:n&&!t.skipWait?W()+n:null,skippedMs:t.skipWait?n:null},k(`${o}: app ${e==="background"?"sent to the background":"interrupted"}`),t.skipWait&&n&&r?.shift?(r.shift(n),k(`App clock moved ahead ${De(n)}`),_()):(T.returnAt!=null&&(se=le(()=>{se=null,T&&_()},n)),g(),m())}function K(e){return Lt("background",e)}function Re(e){return Lt("inactive",e)}function _(){if(It(),!T)return m();let e=T;T=null,$()==="android"?(e.kind==="background"&&Z("active"),void 0):Z("active");let t=e.skippedMs??W()-e.startedAt;return k(`Returned to the app after ${De(t)}`),de(),Ee(),g(),m()}var Mt=false;function Yr(){Mt||(Mt=true,vr(e=>{T&&(It(),T=null,Pr(),k(`The OS reported "${e}", which ended the simulation`),de(),Ee()),g()}))}function Be(){if(C)throw new Error("Capacitor has no memory warning event, so there is nothing to send.");let e=$()==="android"?"Android never sends this event to React Native; only iOS does. Listeners ran anyway.":void 0;return F("Memory warning","memoryWarning",e),E("memoryWarning"),k("Memory warning sent"),g(),m()}function Pt(e){let t=typeof e=="string"?e.trim():"";if(!/^[a-z][a-z0-9+.-]*:/i.test(t))throw new Error('A deep link needs a scheme, like "myapp://orders/42" or "https://example.com/x".');return F(`Deep link ${t}`,"deepLink"),E("url",{url:t}),k(`Deep link delivered: ${t}`),g(),m()}async function Et(){if(!C)return Dt();if($()!=="android")throw new Error("The hardware back button only exists on Android.");F("Back button","back");let e=await C.pressBack();return b&&(b={...b,note:e.note}),k(e.exited?"Back pressed: the app tried to exit":e.handled?"Back pressed: handled by the app":`Back pressed: ${e.note}`),g(),{handled:e.handled,snapshot:m()}}function Dt(){if($()!=="android")throw new Error("The hardware back button only exists on Android.");let e=rt,t=e.exitApp,n=false;e.exitApp=()=>{n=true},F("Back button","back");try{E("hardwareBackPress")}finally{e.exitApp=t}return b&&(b={...b,note:n?"No screen handled back, so a real press would have left the app.":"A screen handled back."}),k(n?"Back pressed: nothing handled it":"Back pressed: handled by the app"),g(),{handled:!n,snapshot:m()}}function Rt(){try{let e=O.getColorScheme();return e==="light"||e==="dark"?e:null}catch{return null}}function Bt(e,t="js"){if(e!=="light"&&e!=="dark")throw new Error('scheme must be "light" or "dark".');if(C){if(t==="native")throw new Error('A Capacitor app has no native color scheme override. Use mode "js".');let r=I?I.previous:Rt();return F(`Color scheme ${e}`,"colorScheme"),C.colorScheme(e),I={scheme:e,mode:t,previous:r},k(`Color scheme set to ${e}`),g(),m()}let n=I?I.previous:Rt();return I?.mode==="native"&&t==="js"&&O.setColorScheme?.("unspecified"),F(`Color scheme ${e}`,"colorScheme"),t==="native"&&typeof O.setColorScheme=="function"?O.setColorScheme(e):E("appearanceChanged",{colorScheme:e}),I={scheme:e,mode:t,previous:n},k(`Color scheme set to ${e}${t==="native"?" (native)":""}`),g(),m()}function Wt(){if(!I)return;let e=I;I=null,C?C.colorScheme(null):e.mode==="native"&&typeof O.setColorScheme=="function"?O.setColorScheme("unspecified"):e.previous&&E("appearanceChanged",{colorScheme:e.previous}),k("Color scheme back to the system value")}function Xr(){return Wt(),g(),m()}var Zr=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"],eo=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"],We={unknown:0,unplugged:1,charging:2,full:3};function to(e,t){for(let d of U)d();U=[];let n=[],r=[],o=(d,f,y,S)=>{let M=Or(f,y,S);M?U.push(M):typeof f[y]=="function"&&r.push(`${d} ${y}`)},a=j("ExpoBattery");a&&(n.push("expo-battery"),o("expo-battery",a,"isLowPowerModeEnabledAsync",()=>Promise.resolve(e.lowPowerMode)),o("expo-battery",a,"getBatteryLevelAsync",()=>Promise.resolve(e.level)),o("expo-battery",a,"getBatteryStateAsync",()=>Promise.resolve(We[e.state])),typeof a.emit=="function"&&(e.lowPowerMode!==t?.lowPowerMode&&a.emit("Expo.powerModeDidChange",{lowPowerMode:e.lowPowerMode}),e.state!==t?.state&&a.emit("Expo.batteryStateDidChange",{batteryState:We[e.state]}),e.level!==t?.level&&a.emit("Expo.batteryLevelDidChange",{batteryLevel:e.level}))),C?.battery.available()&&(n.push("@capacitor/device"),C.battery.set({level:e.level,state:e.state}),U.push(()=>C?.battery.set(null)));let c=ae();if(c){n.push("react-native-device-info");let d=()=>({batteryLevel:e.level,batteryState:e.state,lowPowerMode:e.lowPowerMode});o("react-native-device-info",c,"getPowerState",()=>Promise.resolve(d())),o("react-native-device-info",c,"getPowerStateSync",d),o("react-native-device-info",c,"getBatteryLevel",()=>Promise.resolve(e.level)),o("react-native-device-info",c,"getBatteryLevelSync",()=>e.level),o("react-native-device-info",c,"isBatteryCharging",()=>Promise.resolve(e.state==="charging")),o("react-native-device-info",c,"isBatteryChargingSync",()=>e.state==="charging"),E("RNDeviceInfo_powerStateDidChange",d()),e.level!==t?.level&&(E("RNDeviceInfo_batteryLevelDidChange",e.level),e.level<=.2&&E("RNDeviceInfo_batteryLevelIsLow",e.level))}return{reached:n,realGetters:r}}function $e(e){if(St().length===0)throw new Error("Nothing in this app reads battery state: expo-battery, react-native-device-info and @capacitor/device are all missing.");let t=typeof e.level=="number"&&Number.isFinite(e.level)?Math.min(1,Math.max(0,e.level>1?e.level/100:e.level)):D?.level??1,n={lowPowerMode:e.lowPowerMode??D?.lowPowerMode??false,level:t,state:e.state??D?.state??"unplugged"};if(!(n.state in We))throw new Error('state must be "unplugged", "charging", "full" or "unknown".');F(`Battery ${Math.round(n.level*100)}%${n.lowPowerMode?", low power":""}`,"battery");let{reached:r,realGetters:o}=to(n,D);return D={...n,reached:r,realGetters:o},k(`Battery set to ${Math.round(n.level*100)}%, ${n.state}${n.lowPowerMode?", low power mode on":""}`),g(),m()}function $t(){if(!D)return;for(let n of U)n();U=[],D=null;let e=j("ExpoBattery");e&&typeof e.emit=="function"&&Promise.all([e.isLowPowerModeEnabledAsync?.(),e.getBatteryStateAsync?.(),e.getBatteryLevelAsync?.()]).then(([n,r,o])=>{typeof n=="boolean"&&e.emit("Expo.powerModeDidChange",{lowPowerMode:n}),typeof r=="number"&&e.emit("Expo.batteryStateDidChange",{batteryState:r}),typeof o=="number"&&e.emit("Expo.batteryLevelDidChange",{batteryLevel:o})}).catch(()=>{});let t=ae();t&&typeof t.getPowerState=="function"&&Promise.resolve(t.getPowerState()).then(n=>E("RNDeviceInfo_powerStateDidChange",n)).catch(()=>{}),k("Battery back to the real values")}function Nt(){return $t(),g(),m()}async function Ne(){return await Ot(),le(()=>{wr("auto","buoy lifecycle relaunch").catch(e=>{k(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`),kt(),g()})},250),m()}async function Ot(){let e=lt(),t={at:W(),pathname:e?.pathname??null,href:e?.href??null};return k(`Relaunching from ${t.pathname??"an unknown screen"}`),zt(false),await Te({v:1,settings:L,pendingRelaunch:t}),g(),m()}var no=2500;function ro(e){H={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null},g(),le(()=>{let t=lt()?.pathname??null;H={...H,after:t,tookMs:W()-e.at,restored:e.pathname!=null&&t!=null?t===e.pathname:null},k(H.restored===true?`Relaunch restored ${t}`:`Relaunch landed on ${t??"an unknown screen"}${e.pathname?`, was on ${e.pathname}`:""}`),g()},no)}function oo(){let e=H?.beforeHref;if(!e)throw new Error("There is no route to go back to.");let t=br();if(!t)throw new Error("Going back needs expo-router.");return(t.navigate??t.push)?.(e),k(`Went back to ${e}`),g(),m()}function io(){return H=null,g(),m()}function zt(e){T&&_(),$t(),Wt(),e&&k("Everything back to real")}function Oe(){return zt(true),g(),m()}function ao(){return Pe(),b=null,g(),m()}function lo(e){return L={showChip:typeof e.showChip=="boolean"?e.showChip:L.showChip,reportWindowMs:typeof e.reportWindowMs=="number"&&Number.isFinite(e.reportWindowMs)?Math.min(6e4,Math.max(1e3,e.reportWindowMs)):L.reportWindowMs},kt(),g(),m()}var jt=false;function ze(){if(jt)return;jt=true,C?.loadHost().then(()=>{Me=null,g()}),at(),Yr();let e=n=>{n&&(L=n.settings,n.pendingRelaunch&&(Te({v:1,settings:L,pendingRelaunch:null}),ro(n.pendingRelaunch)),g())},t=mt();t!==void 0?e(t):Hr().then(e)}import{useEffect as so,useState as co,useSyncExternalStore as uo}from"react";import{FloatingTool as po,LifecycleToolIcon as ho,dismissFloatingTool as fo,getFloatingTools as yo,night as je,openFloatingTool as go,realNow as Ht}from"@buoy-gg/shared-ui/web";function Ft(e){let t=Math.max(0,Math.round(e/1e3)),n=Math.floor(t/3600),r=Math.floor(t%3600/60),o=t%60,a=n>0?String(r).padStart(2,"0"):String(r);return`${n>0?`${n}:`:""}${a}:${String(o).padStart(2,"0")}`}function _t(e,t){return e==="background"?"In the background":t?"Lost focus":"Interrupted"}function Vt(e,t){let n=e.away;if(!n)return"";let r=Ft(t-n.startedAt);return n.returnAt!=null?`${r} of ${Ft(n.returnAt-n.startedAt)}`:r}function qt(e){let t=[];return e.scheme&&t.push(`${e.scheme.scheme==="dark"?"Dark":"Light"} mode`),e.power&&t.push(`Battery ${Math.round(e.power.level*100)}%${e.power.lowPowerMode?", Low Power Mode":""}`),t.join(" \xB7 ")}var mo={network:["request","requests"],"react-query":["query event","query events"],"react-query-query":["query update","query updates"],"react-query-mutation":["mutation","mutations"],route:["route change","route changes"],"storage-async":["storage write","storage writes"],"storage-mmkv":["MMKV write","MMKV writes"],redux:["Redux action","Redux actions"],zustand:["Zustand update","Zustand updates"],jotai:["Jotai update","Jotai updates"]};function bo(e,t){let[n,r]=mo[e]??[e,e];return`${t} ${t===1?n:r}`}function Ut(e){let t={};for(let n of e)t[n.source]=(t[n.source]??0)+1;return Object.entries(t).sort((n,r)=>r[1]-n[1]).map(([n,r])=>bo(n,r)).join(", ")}function wo(e){return e==="route"?"Route":e==="network"?"Network":e.startsWith("react-query")?"Query":e.startsWith("storage")?"Storage":e.charAt(0).toUpperCase()+e.slice(1)}function Kt(e){let t=new Map;for(let n of e){let r=`${n.source}\0${n.title}`,o=t.get(r);o?(o.count+=1,o.error||(o.error=n.status==="error")):t.set(r,{source:n.source,title:n.title,subtitle:n.subtitle,error:n.status==="error",count:1})}return[...t.values()]}var vo={memoryWarning:"memory warnings",deepLink:"links",colorScheme:"color scheme changes",battery:"battery changes",back:"the back button"};function ko(e,t){switch(t){case"memoryWarning":return e.listeners.memoryWarning;case"deepLink":return e.listeners.deepLink;case"battery":return e.listeners.battery;default:return null}}function So(e,t){switch(t.signal){case"memoryWarning":return"Memory warning sent";case"deepLink":return`Opened ${t.label.replace(/^Deep link /,"")}`;case"colorScheme":return e.scheme?`Switched to ${e.scheme.scheme} mode`:"Appearance changed";default:return t.label}}function xo(e,t){if(t.unavailable)return{tone:"neutral",title:"Install @buoy-gg/events to see what your app did"};let n=t.events.filter(o=>o.whileAway),r=t.collectingUntil!=null;if(t.kind==="signal"&&t.signal)return t.signal==="back"&&t.note?{tone:t.note.startsWith("No screen")?"warn":"good",title:t.note}:ko(e,t.signal)===0?{tone:"warn",title:`Nothing in your app listens for ${vo[t.signal]}`,detail:t.note}:{tone:"neutral",title:So(e,t),detail:t.note};if(t.finding){let o=n.some(d=>d.source.startsWith("react-query")),a=n.filter(d=>d.source==="network"&&d.at>=Tt).length,c=`${a} ${a===1?"request":"requests"} after its first second away.`;return{tone:"warn",title:"Kept making requests in the background",detail:o?`${c} If these are React Query refetches, connect focusManager to AppState.`:c}}return e.listeners.appState===0?{tone:"warn",title:"Nothing in your app listens for app state changes",detail:"Your code can't react when people leave the app or come back."}:r&&e.away?{tone:"neutral",title:"Watching your app"}:t.kind==="background"?{tone:"good",title:"Nothing kept running in the background"}:{tone:"neutral",title:"Came back from the interruption"}}import{jsx as R,jsxs as Gt}from"react/jsx-runtime";var he="lifecycle-chip",Co={id:he,render:e=>R(Qt,{...e})},To=()=>yo().some(e=>e.id===he),Jt=false;function Ao(){if(Jt)return;Jt=true;let e=false,t=()=>{let n=m().active&&Kr().showChip;n&&!e?go(Co):!n&&To()&&fo(he),e=n};ne(t),t()}function Io(e){let[t,n]=co(Ht);return so(()=>{if(!e)return;let r=setInterval(()=>n(Ht()),1e3);return()=>clearInterval(r)},[e]),t}function Qt({id:e,revealToken:t}){let n=uo(ne,m,m),r=Io(n.away!=null),o=n.away,a=o?_t(o.kind,n.platform==="android"):"Simulating",c=o?Vt(n,r):qt(n);return R(po,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:`Move or hide the lifecycle chip. ${a}`,children:Gt(p,{style:N.row,children:[R(ho,{size:18}),Gt(p,{style:N.text,children:[R(u,{style:N.title,numberOfLines:1,testID:"lifecycle-chip-title",children:a}),R(u,{style:N.detail,numberOfLines:1,testID:"lifecycle-chip-detail",children:c})]}),o?R(P,{testID:"lifecycle-chip-return",accessibilityRole:"button",accessibilityLabel:"Return to the app",onPress:()=>_(),style:N.pill,hitSlop:{top:8,bottom:8,left:4,right:8},children:R(u,{style:N.pillText,children:"Return"})}):R(P,{testID:"lifecycle-chip-reset",accessibilityRole:"button",accessibilityLabel:"End every simulation",onPress:()=>Oe(),style:N.pill,hitSlop:{top:8,bottom:8,left:4,right:8},children:R(u,{style:N.pillText,children:"Stop"})})]})})}var N=me.create({row:{flexDirection:"row",alignItems:"center",gap:10,paddingLeft:10,paddingRight:4,paddingVertical:6,minWidth:230},text:{flexShrink:1,minWidth:120},title:{color:"#A3E635",fontSize:14,fontWeight:"600"},detail:{color:je.color.textSecondary,fontSize:11,fontVariant:["tabular-nums"]},pill:{paddingHorizontal:12,height:28,marginRight:4,borderRadius:14,alignItems:"center",justifyContent:"center",backgroundColor:je.color.accentFill},pillText:{color:je.color.accent,fontSize:13,fontWeight:"600"}});import{LifecycleToolIcon as Lo,LIFECYCLE_TOOL_ICON_COLOR as Mo,createToolFactory as Po,defineToolPreset as Eo}from"@buoy-gg/shared-ui/web";import{useEffect as Yt,useRef as Xt,useState as Do}from"react";import{FeatureGate as Ro,openBuoyTool as Bo}from"@buoy-gg/shared-ui/web";import{useToolHost as Wo}from"@buoy-gg/core/web";import{createSyncAdapter as $o}from"@buoy-gg/shared-ui/web";var Zt=6e4,re=[{id:"phone-call",title:"Take a phone call",detail:"The app pauses for 20 seconds, then comes back",run:()=>Re({durationMs:2e4})},{id:"quick-switch",title:"Switch apps for a moment",detail:"Hidden for 5 seconds, then back",run:()=>K({durationMs:5e3})},{id:"away-31m",title:"Come back in 31 minutes",detail:"Catches 30-minute session timeouts. Moves the clock, so there's no wait",needsClock:true,run:()=>K({durationMs:31*Zt,skipWait:true})},{id:"overnight",title:"Come back the next morning",detail:"9 hours later. Moves the clock, so there's no wait",needsClock:true,run:()=>K({durationMs:540*Zt,skipWait:true})},{id:"low-memory",title:"Run low on memory",detail:"A memory warning, then 10 seconds in the background",run:()=>(Be(),K({durationMs:1e4}))},{id:"dying-battery",title:"Battery almost empty",detail:"5% with Low Power Mode on",needsBattery:true,run:()=>$e({level:.05,lowPowerMode:true,state:"unplugged"})},{id:"relaunch",title:"Close and reopen the app",detail:"Restarts JavaScript, then checks it reopens where you were",run:()=>Ne()}];function en(e,t=m()){return e.needsClock&&!t.clockAvailable?"Install @buoy-gg/clock to skip the wait":e.needsBattery&&t.batteryLibraries.length===0?"Needs expo-battery or react-native-device-info":null}function tn(e){let t=re.find(r=>r.id===e);if(!t)throw new Error(`Unknown recipe "${e}". Recipes: ${re.map(r=>r.id).join(", ")}.`);let n=en(t);if(n)throw new Error(`${t.title}: ${n}.`);return t.run()}function G(e){return e&&typeof e=="object"?e:{}}function He(e,t){let n=e[t];if(typeof n=="boolean")return n;if(n==="true")return true;if(n==="false")return false}var No={ms:1,s:1e3,m:6e4,min:6e4,h:36e5,d:864e5};function Fe(e){if(e==null||e==="")return null;if(typeof e=="number")return Number.isFinite(e)&&e>0?e:null;if(typeof e!="string")return null;let t=/^\s*(\d+(?:\.\d+)?)\s*(ms|s|min|m|h|d)?\s*$/i.exec(e);if(!t)throw new Error(`Can't read the duration "${e}". Use ms or a value like "30s", "5m", "2h".`);return Number(t[1])*No[(t[2]??"ms").toLowerCase()]}function nn(e){let t=G(e);return{durationMs:Fe(t.duration??t.durationMs??t.for),skipWait:He(t,"skipWait")??false}}function v(e=m()){return{...e,recipes:re.map(t=>({id:t.id,title:t.title,detail:t.detail,unavailable:en(t,e)}))}}var _e=$o({version:1,getSnapshot(){return v()},subscribe(e){return ne(e)},actions:{getState(){return v(Ct())},background(e){return v(K(nn(e)))},interrupt(e){return v(Re(nn(e)))},returnToApp(){return v(_())},memoryWarning(){return v(Be())},openUrl(e){let t=G(e),n=t.url??t.link??t.href;if(typeof n!="string")throw new Error('openUrl needs `url`, like "myapp://orders/42".');return v(Pt(n))},async pressBack(){let e=await Et();return{...v(e.snapshot),handled:e.handled}},setColorScheme(e){let t=G(e),n=t.scheme??t.colorScheme;if(n==="system")return v(Xr());if(n!=="light"&&n!=="dark")throw new Error('setColorScheme needs `scheme`: "light", "dark" or "system".');let r=t.mode==="native"?"native":"js";return v(Bt(n,r))},setPower(e){let t=G(e),n=t.level??t.batteryLevel;return v($e({lowPowerMode:He(t,"lowPowerMode"),level:typeof n=="number"?n:typeof n=="string"?Number(n):void 0,state:typeof t.state=="string"?t.state:void 0}))},resetPower(){return v(Nt())},async relaunch(){return v(await Ne())},async prepareRelaunch(){return v(await Ot())},goBackToBeforeRelaunch(){return v(oo())},dismissRelaunchReport(){return v(io())},async runRecipe(e){let t=G(e),n=t.id??t.recipe;if(typeof n!="string")throw new Error(`runRecipe needs \`id\`: ${re.map(r=>r.id).join(", ")}.`);return v(await tn(n))},clearReport(){return v(ao())},reset(){return v(Oe())},updateSettings(e){let t=G(e),n=t.reportWindowMs??t.reportWindow;return v(lo({showChip:He(t,"showChip"),reportWindowMs:n!=null?Fe(n)??void 0:void 0}))}}});import{useEffect as Oo,useRef as zo,useState as J}from"react";import{AlertTriangle as jo,CheckCircle as Ho,ChevronDown as Fo,ChevronRight as _o,NightButton as Ve,NightCard as Q,NightFootnote as Y,NightRows as qe,NightSectionLabel as Ue,NightSegmented as Ke,NightSwitch as rn,Play as Vo,monoFont as on,night as s,realNow as Ge,useSafeAreaInsets as qo}from"@buoy-gg/shared-ui/web";import{Fragment as Uo,jsx as i,jsxs as h}from"react/jsx-runtime";var an="#A3E635",Ko=[{key:"hold",label:"No limit"},{key:"5000",label:"5 s"},{key:"60000",label:"1 min"},{key:"300000",label:"5 min"},{key:"1800000",label:"30 min"}],Go=6e4;function ln(e){let[t,n]=J(()=>Ge());return Oo(()=>{if(!e)return;let r=setInterval(()=>n(Ge()),1e3);return()=>clearInterval(r)},[e]),e?t:Ge()}function sn({snapshot:e,onAction:t}){let n=qo({minBottom:16}),r=zo(null),[o,a]=J(null),c=(d,f)=>{a(null),r.current?.scrollTo({y:0,animated:true}),t(d,f).catch(y=>{a(y instanceof Error?y.message:String(y))})};return e?h(it,{ref:r,style:l.fill,contentContainerStyle:[l.content,{paddingBottom:n.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[i(Jo,{snapshot:e,run:c}),o?i(Y,{tone:"danger",centered:true,children:i(u,{testID:"lifecycle-error",children:o})}):null,i(Zo,{snapshot:e,run:c}),i(ti,{snapshot:e,run:c})]}):i(p,{style:l.waiting,testID:"lifecycle-waiting",children:i(Y,{centered:true,children:"Waiting for the app\u2026"})})}function Jo({snapshot:e,run:t}){let n=qt(e),r;return e.away?r=i(Qo,{snapshot:e,run:t}):e.relaunch?r=i(Xo,{snapshot:e,run:t}):e.report?r=i(Yo,{snapshot:e,run:t}):r=i(u,{style:l.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."}),h(p,{style:l.status,children:[r,n&&!e.away?i(Q,{children:h(p,{style:l.row,children:[h(p,{style:l.rowText,children:[i(u,{style:l.simulatedLabel,children:"Simulated"}),i(u,{style:l.rowTitle,testID:"lifecycle-simulated",children:n})]}),i(Ve,{label:"Stop Simulating",size:"md",fullWidth:false,testID:"lifecycle-reset",accessibilityLabel:"End every simulation",onPress:()=>t("reset")})]})}):null]})}function Qo({snapshot:e,run:t}){let n=ln(true),r=e.away,o=_t(r.kind,e.platform==="android"),a=e.report,c=a?a.events.filter(d=>d.whileAway):[];return h(p,{style:l.running,children:[i(u,{style:l.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${o} (simulated)`,children:o}),i(u,{style:l.runningTimer,testID:"lifecycle-hero-status",children:Vt(e,n)}),i(p,{style:l.runningButton,children:i(Ve,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>t("returnToApp")})}),a?.finding?i(u,{style:l.runningWarning,testID:"lifecycle-report-finding",children:a.finding}):c.length>0?h(u,{style:l.runningNote,children:["So far: ",Ut(c)]}):null]})}function cn({verdict:e}){let t=e.tone==="warn"?s.color.warning:e.tone==="good"?s.color.accent:s.color.text;return h(p,{style:l.verdict,children:[e.tone==="warn"?i(jo,{size:20,color:t}):e.tone==="good"?i(Ho,{size:20,color:t}):null,h(p,{style:l.rowText,children:[i(u,{style:[l.verdictTitle,{color:t}],testID:"lifecycle-verdict",children:e.title}),e.detail?i(u,{style:l.verdictDetail,testID:"lifecycle-report-finding",children:e.detail}):null]})]})}var un=5;function Yo({snapshot:e,run:t}){let n=e.report,r=n.collectingUntil!=null,o=ln(r),[a,c]=J(false),d=xo(e,n),f=n.events.filter(B=>B.whileAway),y=n.events.filter(B=>!B.whileAway),S=n.kind!=="signal",M=r?Math.max(0,(n.collectingUntil??o)-o):0;return i(Q,{children:h(p,{style:l.result,testID:"lifecycle-report",children:[i(cn,{verdict:d}),S||r?i(u,{style:l.resultLabel,testID:"lifecycle-report-label",children:S?`${n.label}${r?` \xB7 watching ${Math.ceil(M/1e3)} s`:""}`:`Watching ${Math.ceil(M/1e3)} s`}):null,n.unavailable?null:n.events.length===0?r?null:i(u,{style:l.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):h(Uo,{children:[S&&f.length>0?i(Je,{title:"While away",events:f,showAll:a}):null,y.length>0?i(Je,{title:S?"After returning":"What your app did",events:y,showAll:a}):null,!S&&f.length>0?i(Je,{title:"What your app did",events:f,showAll:a}):null]}),h(p,{style:l.resultButtons,children:[Kt(n.events).length>un?i(P,{onPress:()=>c(B=>!B),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:a?"Show Less":"Show All"})}):i(p,{}),i(P,{onPress:()=>t("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:"Done"})})]})]})})}function Je({title:e,events:t,showAll:n}){let r=Kt(t),o=n?r:r.slice(0,un);return h(p,{style:l.eventList,children:[i(u,{style:l.eventHeading,children:`${e} \xB7 ${Ut(t)}`}),o.map(a=>h(p,{style:l.event,children:[i(u,{style:l.eventSource,children:wo(a.source)}),i(u,{style:[l.eventTitle,a.error?l.eventError:null],numberOfLines:1,children:a.title}),a.count>1?i(u,{style:l.eventCount,children:`\xD7${a.count}`}):null]},`${a.source}-${a.title}`)),r.length>o.length?i(u,{style:l.detail,children:`${r.length-o.length} more`}):null]})}var fe=e=>e==="/"?"the home screen":e;function Xo({snapshot:e,run:t}){let n=e.relaunch,r=n.after==null&&n.restored==null&&n.tookMs==null?{tone:"neutral",title:"Checking where your app reopened\u2026"}:n.restored===true?{tone:"good",title:`Reopened where you were: ${fe(n.after)}`}:n.after?{tone:"warn",title:`Opened ${fe(n.after)} instead of ${fe(n.before)??"the screen you were on"}`,detail:"The app doesn't restore the last screen after it's closed."}:{tone:"neutral",title:"Couldn't read the screen after reopening"};return i(Q,{children:h(p,{style:l.result,testID:"lifecycle-relaunch-report",children:[i(p,{testID:"lifecycle-relaunch-result",children:i(cn,{verdict:r})}),h(p,{style:l.resultButtons,children:[n.restored===false&&n.beforeHref?i(P,{onPress:()=>t("goBackToBeforeRelaunch"),testID:"lifecycle-relaunch-go-back",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:`Go to ${fe(n.before)}`})}):i(p,{}),i(P,{onPress:()=>t("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:i(u,{style:l.link,children:"Done"})})]})]})})}function Zo({snapshot:e,run:t}){let n=e.host?.appScheme,[r,o]=J(n?`${n}://`:""),a=e.batteryLibraries.length>0,c=e.recipes.filter(f=>f.id!=="dying-battery"||a),d=e.away!=null;return h(p,{children:[i(Ue,{children:"Test a moment"}),i(Q,{children:h(qe,{children:[c.map(f=>i(ei,{recipe:f,disabled:d,onPress:()=>t("runRecipe",{id:f.id})},f.id)),h(p,{style:l.stack,children:[i(u,{style:l.rowTitle,children:"Open a link"}),h(p,{style:l.inputRow,children:[i(ot,{testID:"lifecycle-url-input",accessibilityLabel:"Link to open",value:r,onChangeText:o,placeholder:"myapp://orders/42",placeholderTextColor:s.color.placeholder,autoCapitalize:"none",autoCorrect:false,keyboardType:"url",returnKeyType:"go",onSubmitEditing:()=>t("openUrl",{url:r}),style:l.input}),i(Ve,{label:"Open",size:"md",fullWidth:false,testID:"lifecycle-url-open",accessibilityLabel:"Open this link in the app",onPress:()=>t("openUrl",{url:r})})]}),e.listeners.deepLink===0?i(u,{style:l.warning,children:"Nothing in your app listens for links."}):null]},"link")]})})]})}function ei({recipe:e,disabled:t,onPress:n}){let r=t||!!e.unavailable;return h(P,{testID:`lifecycle-recipe-${e.id}`,accessibilityRole:"button",accessibilityLabel:e.title,accessibilityHint:e.unavailable??e.detail,accessibilityState:{disabled:r},disabled:r,activeOpacity:.6,onPress:n,style:[l.row,r?l.rowDisabled:null],children:[h(p,{style:l.rowText,children:[i(u,{style:l.rowTitle,children:e.title}),i(u,{style:l.detail,children:e.unavailable??e.detail})]}),e.unavailable?null:i(Vo,{size:16,color:s.color.accent})]})}function ti({snapshot:e,run:t}){let[n,r]=J(false),o=n?Fo:_o;return h(p,{children:[h(P,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:n},onPress:()=>r(a=>!a),style:l.disclosure,hitSlop:8,children:[i(u,{style:l.disclosureText,children:"Custom"}),i(o,{size:16,color:s.color.textSecondary})]}),n?h(p,{style:l.customBody,children:[i(ni,{snapshot:e,run:t}),i(oi,{snapshot:e,run:t}),i(Y,{children:"Only your app's JavaScript hears these events. Timers, requests and native code keep running, and a real event from the OS ends the simulation."})]}):null]})}function ni({snapshot:e,run:t}){let[n,r]=J("hold"),o=n==="hold"?null:Number(n),a=o!=null&&o>=Go,c=a&&e.clockAvailable,d=()=>({durationMs:o,skipWait:c}),f=e.platform==="android",y=e.away!=null;return h(p,{children:[i(Ue,{children:"Leave the app"}),h(Q,{children:[i(p,{style:l.segmentWrap,children:i(Ke,{tabs:Ko,activeKey:n,size:"sm",testIDPrefix:"lifecycle-duration",onChange:r})}),h(qe,{children:[i(ye,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:y,onPress:()=>t("background",d())},"background"),i(ye,{title:f?"Pull Down Notifications":"Take a Call",detail:f?"The app stays visible but loses focus":"The app stays visible but inactive, like with Control Center open",testID:"lifecycle-interrupt",disabled:y,onPress:()=>t("interrupt",d())},"interrupt")]})]}),a?i(Y,{children:e.clockAvailable?"Moves the app clock forward instead of waiting.":"Waits in real time. Install @buoy-gg/clock to skip the wait."}):null,e.listeners.appState===0?i(Y,{tone:"warning",children:"Nothing in your app listens for app state changes."}):null]})}var ri=[{key:"real",label:"Real"},{key:"100",label:"100%"},{key:"20",label:"20%"},{key:"5",label:"5%"}];function oi({snapshot:e,run:t}){let n=e.platform==="android",r=e.batteryLibraries.length>0,o=e.power,a=e.listeners.memoryWarning===0?"Nothing in your app listens for it":n?"Android never sends this, but your listeners will run":void 0;return h(p,{children:[i(Ue,{children:"Signals"}),i(Q,{children:h(qe,{children:[i(ye,{title:"Send Memory Warning",detail:a,warn:e.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>t("memoryWarning")},"memory"),h(p,{style:l.stack,children:[i(u,{style:l.rowTitle,children:"Appearance"}),i(Ke,{tabs:[{key:"system",label:"System"},{key:"light",label:"Light"},{key:"dark",label:"Dark"}],activeKey:e.scheme?.scheme??"system",size:"sm",testIDPrefix:"lifecycle-scheme",onChange:c=>t("setColorScheme",{scheme:c})})]},"scheme"),r?h(p,{style:l.stack,children:[i(u,{style:l.rowTitle,children:"Battery"}),i(Ke,{tabs:ri,activeKey:o?String(Math.round(o.level*100)):"real",size:"sm",testIDPrefix:"lifecycle-battery",onChange:c=>c==="real"?t("resetPower"):t("setPower",{level:Number(c)/100})}),h(p,{style:l.inlineRow,children:[i(u,{style:l.rowTitle,children:"Charging"}),i(rn,{value:o?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:c=>t("setPower",{state:c?"charging":"unplugged"})})]}),h(p,{style:l.inlineRow,children:[i(u,{style:l.rowTitle,children:"Low Power Mode"}),i(rn,{value:o?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:c=>t("setPower",{lowPowerMode:c})})]}),e.listeners.battery===0?i(u,{style:l.warning,children:"Nothing in your app listens for battery changes."}):null]},"battery"):null,n?i(ye,{title:"Press Back",detail:"Never closes the app. The result says if a real press would have.",testID:"lifecycle-back",onPress:()=>t("pressBack")},"back"):null]})}),r?null:i(Y,{children:"Battery needs expo-battery, react-native-device-info or @capacitor/device in your app."})]})}function ye({title:e,detail:t,warn:n,testID:r,disabled:o,onPress:a}){return i(P,{testID:r,accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{disabled:!!o},activeOpacity:.6,disabled:o,onPress:a,style:[l.row,o?l.rowDisabled:null],children:h(p,{style:l.rowText,children:[i(u,{style:l.actionTitle,children:e}),t?i(u,{style:n?l.warning:l.detail,children:t}):null]})})}var l=me.create({fill:{flex:1},content:{paddingHorizontal:s.gutter,paddingTop:8,gap:s.groupGap},waiting:{flex:1,alignItems:"center",justifyContent:"center",padding:24},status:{gap:12},intro:{color:s.color.textSecondary,fontSize:s.font.body,lineHeight:20,paddingHorizontal:s.labelInset,paddingTop:4},running:{alignItems:"center",paddingTop:12,gap:6},runningTitle:{color:an,fontSize:30,fontWeight:"300"},runningTimer:{color:s.color.textSecondary,fontSize:s.font.row,fontWeight:"500",fontVariant:["tabular-nums"]},runningButton:{alignSelf:"stretch",marginTop:10},runningWarning:{color:s.color.warning,fontSize:s.font.caption,textAlign:"center",marginTop:4},runningNote:{color:s.color.textTertiary,fontSize:s.font.caption,textAlign:"center",marginTop:4},simulatedLabel:{color:an,fontSize:s.font.micro,fontWeight:"600",textTransform:"uppercase",letterSpacing:.4},result:{paddingHorizontal:s.rowPadH,paddingVertical:14,gap:12},verdict:{flexDirection:"row",gap:10,alignItems:"flex-start"},verdictTitle:{fontSize:s.font.title,fontWeight:"600"},verdictDetail:{color:s.color.textSecondary,fontSize:s.font.caption,lineHeight:18},resultLabel:{color:s.color.textTertiary,fontSize:s.font.caption,fontVariant:["tabular-nums"]},resultButtons:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},link:{color:s.color.accent,fontSize:s.font.row,fontWeight:"500"},row:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:50,paddingHorizontal:s.rowPadH,paddingVertical:10},rowText:{flex:1,gap:2},rowDisabled:{opacity:.4},rowTitle:{color:s.color.text,fontSize:s.font.row},actionTitle:{color:s.color.accent,fontSize:s.font.row},detail:{color:s.color.textTertiary,fontSize:s.font.caption},warning:{color:s.color.warning,fontSize:s.font.caption},stack:{paddingHorizontal:s.rowPadH,paddingVertical:12,gap:10},segmentWrap:{paddingHorizontal:s.rowPadH,paddingTop:12,paddingBottom:4},inlineRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},inputRow:{flexDirection:"row",alignItems:"center",gap:8},input:{flex:1,color:s.color.text,fontFamily:on,fontSize:14,backgroundColor:s.color.bg,borderRadius:s.radius.input,borderWidth:1,borderColor:s.color.border,paddingHorizontal:12,paddingVertical:8},disclosure:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:s.labelInset},disclosureText:{color:s.color.textSecondary,fontSize:s.font.label,fontWeight:"600",textTransform:"uppercase",letterSpacing:.8},customBody:{gap:s.groupGap,marginTop:12},eventList:{gap:6},eventHeading:{color:s.color.textSecondary,fontSize:s.font.caption,fontWeight:"600"},event:{flexDirection:"row",gap:8,alignItems:"baseline"},eventSource:{width:56,color:s.color.textTertiary,fontSize:s.font.caption},eventTitle:{flex:1,color:s.color.text,fontSize:13,fontFamily:on},eventError:{color:s.color.danger},eventCount:{color:s.color.textSecondary,fontSize:s.font.caption,fontWeight:"600",fontVariant:["tabular-nums"]}});import{jsx as dn}from"react/jsx-runtime";var ii=_e.actions;async function ai(e,t){let n=ii[e];if(!n)throw new Error(`Unknown lifecycle action: ${e}`);return n(t)}var Qe=()=>_e.getSnapshot();function pn(){let[e,t]=Do(Qe),n=Wo(),r=Xt(false);Yt(()=>(ze(),Ct(),t(Qe()),ne(()=>t(Qe()))),[]);let o=e.away!=null,a=Xt(o);return Yt(()=>{let c=o&&!a.current;a.current=o,c&&!r.current?(r.current=true,n.minimize()):!o&&r.current&&(r.current=false,Bo("lifecycle"))},[o,n]),dn(Ro,{featureName:"Lifecycle Simulator",children:dn(sn,{snapshot:e,onAction:ai})})}import{jsx as li}from"react/jsx-runtime";var hn=Eo({id:"lifecycle",name:"LIFECYCLE",description:"See what your app does when people leave and come back",slot:"both",color:Mo,icon:({size:e,color:t})=>li(Lo,{size:e,color:t}),component:pn,modal:{subtitle:"what your app does when people leave"}}),si=Po(hn);import{LifecycleToolIcon as ci,LIFECYCLE_TOOL_ICON_COLOR as ui}from"@buoy-gg/shared-ui/web";var di=typeof navigator<"u"&&navigator.product==="ReactNative",pi=(()=>{try{return globalThis.Capacitor?.isNativePlatform?.()===true}catch{return false}})();(di||pi)&&(Ao(),(typeof tt<"u"&&tt||mt()?.pendingRelaunch)&&ze());export{he as LIFECYCLE_CHIP_ID,ui as LIFECYCLE_TOOL_ICON_COLOR,pn as LifecycleBody,Qt as LifecycleChip,ci as LifecycleToolIcon,sn as LifecycleToolView,re as RECIPES,ze as bootLifecycle,si as createLifecycleTool,m as getLifecycleSnapshot,Re as interrupt,_e as lifecycleSyncAdapter,hn as lifecycleToolPreset,Be as memoryWarning,Pt as openDeepLink,Fe as parseDurationMs,Dt as pressBack,Et as pressBackAsync,Ne as relaunchApp,Oe as resetLifecycle,Nt as resetPower,_ as returnToApp,tn as runRecipe,K as sendToBackground,Bt as setColorScheme,$e as setPower,ne as subscribeLifecycle};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/lifecycle",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.57",
|
|
4
4
|
"description": "Lifecycle and interruption simulator for React Native: see what your app does when people leave it and come back. Background, interruptions, memory warnings, deep links, appearance, battery and relaunch.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -17,16 +17,18 @@
|
|
|
17
17
|
"./lib/web/**/*.mjs"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@buoy-gg/shared-ui": "^7.0.
|
|
20
|
+
"@buoy-gg/shared-ui": "^7.0.57"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
+
"@buoy-gg/license": "7.0.57",
|
|
23
24
|
"react": "*"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"@types/react": "^19.1.0",
|
|
27
28
|
"@types/react-native": "^0.73.0",
|
|
28
29
|
"typescript": "~5.8.3",
|
|
29
|
-
"@buoy-gg/core": "^7.0.
|
|
30
|
+
"@buoy-gg/core": "^7.0.57",
|
|
31
|
+
"@buoy-gg/license": "^7.0.57"
|
|
30
32
|
},
|
|
31
33
|
"react-native-builder-bob": {
|
|
32
34
|
"source": "src",
|