@buoy-gg/lifecycle 7.0.62 → 7.0.64
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/LifecycleBody.js +1 -1
- package/lib/commonjs/components/LifecycleToolView.js +1 -1
- package/lib/commonjs/engine/lifecycleStore.js +1 -1
- package/lib/commonjs/engine/reportEvents.js +1 -0
- package/lib/module/components/LifecycleBody.js +1 -1
- package/lib/module/components/LifecycleToolView.js +1 -1
- package/lib/module/engine/lifecycleStore.js +1 -1
- package/lib/module/engine/reportEvents.js +1 -0
- package/lib/typescript/engine/lifecycleStore.d.ts +2 -0
- package/lib/typescript/engine/reportEvents.d.ts +9 -0
- package/lib/web/index.mjs +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.LifecycleBody=LifecycleBody;var _react=require("react");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _lifecycleStore=require("../engine/lifecycleStore");var _lifecycleSyncAdapter=require("../sync/lifecycleSyncAdapter");var _LifecycleToolView=require("./LifecycleToolView");var _jsxRuntime=require("react/jsx-runtime");const actions=_lifecycleSyncAdapter.lifecycleSyncAdapter.actions;async function runAction(e,t){const r=actions[e];if(!r)throw new Error(`Unknown lifecycle action: ${e}`);return r(t)}const read=()=>_lifecycleSyncAdapter.lifecycleSyncAdapter.getSnapshot();function LifecycleBody(){const[e,t]=(0,_react.useState)(read);const r=(0,_core.useToolHost)();const n=(0,_react.useRef)(false);(0,_react.useEffect)(()=>{(0,_lifecycleStore.bootLifecycle)();(0,_lifecycleStore.refreshSnapshot)();t(read());return(0,_lifecycleStore.subscribeLifecycle)(()=>t(read()))},[]);const c=e.away!=null;const
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.LifecycleBody=LifecycleBody;var _react=require("react");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _lifecycleStore=require("../engine/lifecycleStore");var _lifecycleSyncAdapter=require("../sync/lifecycleSyncAdapter");var _LifecycleToolView=require("./LifecycleToolView");var _jsxRuntime=require("react/jsx-runtime");const actions=_lifecycleSyncAdapter.lifecycleSyncAdapter.actions;async function runAction(e,t){const r=actions[e];if(!r)throw new Error(`Unknown lifecycle action: ${e}`);return r(t)}const read=()=>_lifecycleSyncAdapter.lifecycleSyncAdapter.getSnapshot();function LifecycleBody(){const[e,t]=(0,_react.useState)(read);const r=(0,_core.useToolHost)();const n=(0,_sharedUi.getUseIsPro)()();(0,_react.useEffect)(()=>n?(0,_lifecycleStore.warmReportSources)():void 0,[n]);const o=(0,_react.useRef)(false);(0,_react.useEffect)(()=>{(0,_lifecycleStore.bootLifecycle)();(0,_lifecycleStore.refreshSnapshot)();t(read());return(0,_lifecycleStore.subscribeLifecycle)(()=>t(read()))},[]);const c=e.away!=null;const i=(0,_react.useRef)(c);(0,_react.useEffect)(()=>{const s=c&&!i.current;i.current=c;if(s&&!o.current){o.current=true;r.minimize()}else if(!c&&o.current){o.current=false;(0,_sharedUi.openBuoyTool)("lifecycle")}},[c,r]);return(0,_jsxRuntime.jsx)(_sharedUi.FeatureGate,{featureName:"Lifecycle Simulator",children:(0,_jsxRuntime.jsx)(_LifecycleToolView.LifecycleToolView,{snapshot:e,onAction:runAction})})}
|
|
@@ -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, 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
|
+
"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[r,l]=(0,_react.useState)(null);const o=(c,s)=>{l(null);i.current?.scrollTo({y:0,animated:true});n(c,s).catch(a=>{l(a instanceof Error?a.message:String(a))})};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}),r?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"danger",centered:true,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"lifecycle-error",children:r})}):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 r=(0,_format.awayTitle)(i.kind,e.platform==="android");const l=e.report;const o=l?l.events.filter(c=>c.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: ${r} (simulated)`,children:r}),(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")})}),l?.finding?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.runningWarning,testID:"lifecycle-report-finding",children:l.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 r=useNow(i);const[l,o]=(0,_react.useState)(false);const c=(0,_format.verdict)(e,t);const s=t.events.filter(h=>h.whileAway);const a=t.events.filter(h=>!h.whileAway);const d=t.kind!=="signal";const u=i?Math.max(0,(t.collectingUntil??r)-r):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:c}),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:l}):null,a.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:d?"After returning":"What your app did",events:a,showAll:l}):null,!d&&s.length>0?(0,_jsxRuntime.jsx)(EventGroupList,{title:"What your app did",events:s,showAll:l}):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:l?"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 r=t?i:i.slice(0,PREVIEW_ROWS);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.eventList,testID:`lifecycle-events-${e}`,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventHeading,testID:`lifecycle-counts-${e}`,children:`${e} \xB7 ${(0,_format.countsLine)(n)}`}),r.map(l=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.event,testID:`lifecycle-event-${l.source}-${l.title}`,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventSource,children:(0,_format.sourceLabel)(l.source)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.eventTitle,l.error?styles.eventError:null],numberOfLines:1,children:l.title}),l.count>1?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.eventCount,testID:`lifecycle-event-${l.source}-${l.title}-count`,children:`\xD7${l.count}`}):null]},`${l.source}-${l.title}`)),i.length>r.length?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,children:`${i.length-r.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 r=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:r})}),(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,r]=(0,_react.useState)(t?`${t}://`:"");const l=e.batteryLibraries.length>0;const o=e.recipes.filter(s=>s.id!=="dying-battery"||l);const c=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:c,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:r,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 r=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(l=>!l),style:styles.disclosure,hitSlop:8,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.disclosureText,children:"Custom"}),(0,_jsxRuntime.jsx)(r,{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 r=t==="hold"?null:Number(t);const l=r!=null&&r>=SKIP_FROM_MS;const o=l&&e.clockAvailable;const c=()=>({durationMs:r,skipWait:o});const s=e.platform==="android";const a=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:a,onPress:()=>n("background",c())},"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:a,onPress:()=>n("interrupt",c())},"interrupt")]})]}),l?(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 r=e.power;const l=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:l,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:r?String(Math.round(r.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:r?.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:r?.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:r,onPress:l}){return(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:i,accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{disabled:!!r},activeOpacity:.6,disabled:r,onPress:l,style:[styles.row,r?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.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
|
+
"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;exports.warmReportSources=warmReportSources;var _reportEvents=require("./reportEvents");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 warmReportSources(){return loadWatchEvents()?.(REPORT_SOURCES,()=>{})??(()=>{})}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 u=()=>away?Number.MAX_SAFE_INTEGER:c;let c=Number.MAX_SAFE_INTEGER;markReturn=()=>{c=Date.now()};stopWatching=l(REPORT_SOURCES,f=>{if(!report||report.id!==i)return;const p=f.filter(a=>!(a.source.startsWith("react-query")&&a.status==="pending")).sort((a,g)=>a.timestamp-g.timestamp);const h=(0,_reportEvents.dedupeRouteEvents)(p);const d={};for(const a of h)d[a.source]=(d[a.source]??0)+1;const m=h.map(a=>({source:a.source,title:a.title,subtitle:a.subtitle,status:a.status,at:Math.max(0,a.timestamp-s),whileAway:a.timestamp<u()}));const v=m.filter(a=>a.whileAway&&a.source==="network"&&a.at>=FLUSH_GRACE_MS).length;report={...report,counts:d,events:m.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 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,u,c,f)=>{const p=(0,_native.wrapGetter)(u,c,f);if(p)restorePower.push(p);else if(typeof u[c]==="function")o.push(`${s} ${c}`)};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}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.dedupeRouteEvents=dedupeRouteEvents;function dedupeRouteEvents(r){return r.filter((t,u)=>{const e=r[u-1];return!e||t.source!=="route"||e.source!=="route"||t.title!==e.title||t.timestamp-e.timestamp>=250})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useEffect as
|
|
1
|
+
"use strict";import{useEffect as c,useRef as a,useState as p}from"react";import{FeatureGate as y,getUseIsPro as h,openBuoyTool as w}from"@buoy-gg/shared-ui";import{useToolHost as d}from"@buoy-gg/core";import{bootLifecycle as S,refreshSnapshot as L,subscribeLifecycle as A,warmReportSources as T}from"../engine/lifecycleStore";import{lifecycleSyncAdapter as u}from"../sync/lifecycleSyncAdapter";import{LifecycleToolView as b}from"./LifecycleToolView";import{jsx as l}from"react/jsx-runtime";const x=u.actions;async function g(e,r){const o=x[e];if(!o)throw new Error(`Unknown lifecycle action: ${e}`);return o(r)}const s=()=>u.getSnapshot();export function LifecycleBody(){const[e,r]=p(s);const o=d();const i=h()();c(()=>i?T():void 0,[i]);const n=a(false);c(()=>{S();L();r(s());return A(()=>r(s()))},[]);const t=e.away!=null;const f=a(t);c(()=>{const m=t&&!f.current;f.current=t;if(m&&!n.current){n.current=true;o.minimize()}else if(!t&&n.current){n.current=false;w("lifecycle")}},[t,o]);return l(y,{featureName:"Lifecycle Simulator",children:l(b,{snapshot:e,onAction:g})})}
|
|
@@ -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, 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
|
+
"use strict";import{useEffect as M,useRef as V,useState as w}from"react";import{ScrollView as O,StyleSheet as j,Text as s,TextInput as F,TouchableOpacity as g,View as u}from"react-native";import{AlertTriangle as _,CheckCircle as U,ChevronDown as K,ChevronRight as G,NightButton as I,NightCard as b,NightFootnote as m,NightRows as k,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 a,Fragment as te}from"react/jsx-runtime";const $="#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 B(t){const[r,i]=w(()=>C());M(()=>{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[d,c]=w(null);const y=(f,h)=>{c(null);o.current?.scrollTo({y:0,animated:true});r(f,h).catch(p=>{c(p instanceof Error?p.message:String(p))})};if(!t){return e(u,{style:n.waiting,testID:"lifecycle-waiting",children:e(m,{centered:true,children:"Waiting for the app\u2026"})})}return a(O,{ref:o,style:n.fill,contentContainerStyle:[n.content,{paddingBottom:i.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[e(ie,{snapshot:t,run:y}),d?e(m,{tone:"danger",centered:true,children:e(s,{testID:"lifecycle-error",children:d})}):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(s,{style:n.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."})}return a(u,{style:n.status,children:[o,i&&!t.away?e(b,{children:a(u,{style:n.row,children:[a(u,{style:n.rowText,children:[e(s,{style:n.simulatedLabel,children:"Simulated"}),e(s,{style:n.rowTitle,testID:"lifecycle-simulated",children:i})]}),e(I,{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=B(true);const o=t.away;const d=Q(o.kind,t.platform==="android");const c=t.report;const y=c?c.events.filter(f=>f.whileAway):[];return a(u,{style:n.running,children:[e(s,{style:n.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${d} (simulated)`,children:d}),e(s,{style:n.runningTimer,testID:"lifecycle-hero-status",children:J(t,i)}),e(u,{style:n.runningButton,children:e(I,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>r("returnToApp")})}),c?.finding?e(s,{style:n.runningWarning,testID:"lifecycle-report-finding",children:c.finding}):y.length>0?a(s,{style:n.runningNote,children:["So far: ",W(y)]}):null]})}function H({verdict:t}){const r=t.tone==="warn"?l.color.warning:t.tone==="good"?l.color.accent:l.color.text;return a(u,{style:n.verdict,children:[t.tone==="warn"?e(_,{size:20,color:r}):t.tone==="good"?e(U,{size:20,color:r}):null,a(u,{style:n.rowText,children:[e(s,{style:[n.verdictTitle,{color:r}],testID:"lifecycle-verdict",children:t.title}),t.detail?e(s,{style:n.verdictDetail,testID:"lifecycle-report-finding",children:t.detail}):null]})]})}const E=5;function oe({snapshot:t,run:r}){const i=t.report;const o=i.collectingUntil!=null;const d=B(o);const[c,y]=w(false);const f=ee(t,i);const h=i.events.filter(v=>v.whileAway);const p=i.events.filter(v=>!v.whileAway);const S=i.kind!=="signal";const R=o?Math.max(0,(i.collectingUntil??d)-d):0;return e(b,{children:a(u,{style:n.result,testID:"lifecycle-report",children:[e(H,{verdict:f}),S||o?e(s,{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(s,{style:n.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):a(te,{children:[S&&h.length>0?e(P,{title:"While away",events:h,showAll:c}):null,p.length>0?e(P,{title:S?"After returning":"What your app did",events:p,showAll:c}):null,!S&&h.length>0?e(P,{title:"What your app did",events:h,showAll:c}):null]}),a(u,{style:n.resultButtons,children:[N(i.events).length>E?e(g,{onPress:()=>y(v=>!v),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:e(s,{style:n.link,children:c?"Show Less":"Show All"})}):e(u,{}),e(g,{onPress:()=>r("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:e(s,{style:n.link,children:"Done"})})]})]})})}function P({title:t,events:r,showAll:i}){const o=N(r);const d=i?o:o.slice(0,E);return a(u,{style:n.eventList,testID:`lifecycle-events-${t}`,children:[e(s,{style:n.eventHeading,testID:`lifecycle-counts-${t}`,children:`${t} \xB7 ${W(r)}`}),d.map(c=>a(u,{style:n.event,testID:`lifecycle-event-${c.source}-${c.title}`,children:[e(s,{style:n.eventSource,children:Z(c.source)}),e(s,{style:[n.eventTitle,c.error?n.eventError:null],numberOfLines:1,children:c.title}),c.count>1?e(s,{style:n.eventCount,testID:`lifecycle-event-${c.source}-${c.title}-count`,children:`\xD7${c.count}`}):null]},`${c.source}-${c.title}`)),o.length>d.length?e(s,{style:n.detail,children:`${o.length-d.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 d=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:a(u,{style:n.result,testID:"lifecycle-relaunch-report",children:[e(u,{testID:"lifecycle-relaunch-result",children:e(H,{verdict:d})}),a(u,{style:n.resultButtons,children:[i.restored===false&&i.beforeHref?e(g,{onPress:()=>r("goBackToBeforeRelaunch"),testID:"lifecycle-relaunch-go-back",accessibilityRole:"button",hitSlop:8,children:e(s,{style:n.link,children:`Go to ${T(i.before)}`})}):e(u,{}),e(g,{onPress:()=>r("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:e(s,{style:n.link,children:"Done"})})]})]})})}function ae({snapshot:t,run:r}){const i=t.host?.appScheme;const[o,d]=w(i?`${i}://`:"");const c=t.batteryLibraries.length>0;const y=t.recipes.filter(h=>h.id!=="dying-battery"||c);const f=t.away!=null;return a(u,{children:[e(x,{children:"Test a moment"}),e(b,{children:a(k,{children:[y.map(h=>e(se,{recipe:h,disabled:f,onPress:()=>r("runRecipe",{id:h.id})},h.id)),a(u,{style:n.stack,children:[e(s,{style:n.rowTitle,children:"Open a link"}),a(u,{style:n.inputRow,children:[e(F,{testID:"lifecycle-url-input",accessibilityLabel:"Link to open",value:o,onChangeText:d,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(I,{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(s,{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 a(g,{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:[a(u,{style:n.rowText,children:[e(s,{style:n.rowTitle,children:t.title}),e(s,{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 d=i?K:G;return a(u,{children:[a(g,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:i},onPress:()=>o(c=>!c),style:n.disclosure,hitSlop:8,children:[e(s,{style:n.disclosureText,children:"Custom"}),e(d,{size:16,color:l.color.textSecondary})]}),i?a(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 d=i==="hold"?null:Number(i);const c=d!=null&&d>=le;const y=c&&t.clockAvailable;const f=()=>({durationMs:d,skipWait:y});const h=t.platform==="android";const p=t.away!=null;return a(u,{children:[e(x,{children:"Leave the app"}),a(b,{children:[e(u,{style:n.segmentWrap,children:e(z,{tabs:ne,activeKey:i,size:"sm",testIDPrefix:"lifecycle-duration",onChange:o})}),a(k,{children:[e(D,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:p,onPress:()=>r("background",f())},"background"),e(D,{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:p,onPress:()=>r("interrupt",f())},"interrupt")]})]}),c?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 d=t.power;const c=t.listeners.memoryWarning===0?"Nothing in your app listens for it":i?"Android never sends this, but your listeners will run":void 0;return a(u,{children:[e(x,{children:"Signals"}),e(b,{children:a(k,{children:[e(D,{title:"Send Memory Warning",detail:c,warn:t.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>r("memoryWarning")},"memory"),a(u,{style:n.stack,children:[e(s,{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?a(u,{style:n.stack,children:[e(s,{style:n.rowTitle,children:"Battery"}),e(z,{tabs:ye,activeKey:d?String(Math.round(d.level*100)):"real",size:"sm",testIDPrefix:"lifecycle-battery",onChange:y=>y==="real"?r("resetPower"):r("setPower",{level:Number(y)/100})}),a(u,{style:n.inlineRow,children:[e(s,{style:n.rowTitle,children:"Charging"}),e(L,{value:d?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:y=>r("setPower",{state:y?"charging":"unplugged"})})]}),a(u,{style:n.inlineRow,children:[e(s,{style:n.rowTitle,children:"Low Power Mode"}),e(L,{value:d?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:y=>r("setPower",{lowPowerMode:y})})]}),t.listeners.battery===0?e(s,{style:n.warning,children:"Nothing in your app listens for battery changes."}):null]},"battery"):null,i?e(D,{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 D({title:t,detail:r,warn:i,testID:o,disabled:d,onPress:c}){return e(g,{testID:o,accessibilityRole:"button",accessibilityLabel:t,accessibilityState:{disabled:!!d},activeOpacity:.6,disabled:d,onPress:c,style:[n.row,d?n.rowDisabled:null],children:a(u,{style:n.rowText,children:[e(s,{style:n.actionTitle,children:t}),r?e(s,{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:$,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:$,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 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
|
+
"use strict";import{dedupeRouteEvents as ge}from"./reportEvents";import{Appearance as M,BackHandler as ve}from"react-native";import{getRealAppState as Z,getSafeCurrentRoute as ee,getSafeRouter as be,realNow as g,reloadApp as Se,subscribeRealAppState as ke}from"@buoy-gg/shared-ui";import{loadToolModule as te}from"@buoy-gg/shared-ui/utils";import{appListenerCount as C,capacitorShell as p,deviceInfoModule as _,endSimulation as Ee,prepareColorScheme as Ae,emitAppState as x,emitDevice as w,emitFocus as re,expoListenerCount as Me,expoModule as k,getPlatform as v,wrapGetter as Re}from"./native";import{DEFAULT_SETTINGS as oe,readSavedAsync as Ce,readSavedSync as xe,writeSaved as G}from"./persistence";function ne(){const e=globalThis.__buoyRealTimers;return e??globalThis}function P(e,t){return ne().setTimeout(e,t)}function U(e){if(e!=null)ne().clearTimeout(e)}const Le=30;let d={...oe};let c=null;let y=null;let f=null;let a=null;let b=null;let D=[];let B=null;let $=null;let N=null;let S=[];let Te=0;let I=()=>{};const q=new Set;let R=null;function n(){R=null;for(const e of Array.from(q)){try{e()}catch{}}}function s(e){D=[{at:g(),text:e},...D].slice(0,Le)}function ae(){void G({v:1,settings:d,pendingRelaunch:null})}function _e(){const e=p?.host();if(e)return{...e,os:v(),appScheme:null};const t=k("ExpoDevice");const r=k("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:Pe()}}function Pe(){try{let e=k("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 H=null;function ie(){const e=[];if(k("ExpoBattery"))e.push("expo-battery");if(_())e.push("react-native-device-info");if(p?.battery.available())e.push("@capacitor/device");return e}function De(){let e=null;const t=o=>{if(o==null)return;e=(e??0)+o};const r=k("ExpoBattery");for(const o of Ne)t(Me(r,o));if(_())for(const o of Ie)t(C(o));return e}function le(){try{return te("@buoy-gg/clock")}catch{return null}}export function getLifecycleSnapshot(){if(R)return R;R={platform:v(),host:H??=_e(),realAppState:Z(),away:c,power:y,scheme:f,listeners:{appState:C("appStateDidChange"),focus:C("appStateFocusChange"),memoryWarning:C("memoryWarning"),deepLink:C("url"),battery:De()},batteryLibraries:ie(),clockAvailable:typeof le()?.shift==="function",report:a,relaunch:b,log:D,settings:d,active:c!=null||y!=null||f!=null};return R}export function refreshSnapshot(){n();return getLifecycleSnapshot()}export function subscribeLifecycle(e){q.add(e);return()=>q.delete(e)}export function getLifecycleSettings(){return d}const se=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"];const Be=40;export const FLUSH_GRACE_MS=1e3;function ce(){try{const e=te("@buoy-gg/events");return typeof e.watchEvents==="function"?e.watchEvents:null}catch{return null}}export function warmReportSources(){return ce()?.(se,()=>{})??(()=>{})}function W(){U($);$=null;N?.();N=null;if(a&&a.collectingUntil!=null){a={...a,collectingUntil:null};n()}}function ue(e,t,r,o){W();const i=g();const u=++Te;a={id:u,label:e,kind:t,signal:o,startedAt:i,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:r};const h=ce();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 L=()=>c?Number.MAX_SAFE_INTEGER:A;let A=Number.MAX_SAFE_INTEGER;I=()=>{A=Date.now()};N=h(se,F=>{if(!a||a.id!==u)return;const T=F.filter(l=>!(l.source.startsWith("react-query")&&l.status==="pending")).sort((l,we)=>l.timestamp-we.timestamp);const Y=ge(T);const O={};for(const l of Y)O[l.source]=(O[l.source]??0)+1;const K=Y.map(l=>({source:l.source,title:l.title,subtitle:l.subtitle,status:l.status,at:Math.max(0,l.timestamp-m),whileAway:l.timestamp<L()}));const Q=K.filter(l=>l.whileAway&&l.source==="network"&&l.at>=FLUSH_GRACE_MS).length;a={...a,counts:O,events:K.slice(0,Be),finding:Q>0&&a.kind==="background"?`The app kept making network requests in the background: ${Q} after its first second away.`:void 0};n()},m)}function X(){if(!a||a.collectingUntil==null||!N)return;const e=g()+d.reportWindowMs;a={...a,collectingUntil:e};U($);$=P(W,d.reportWindowMs)}function E(e,t,r){ue(e,"signal",r,t);I();X()}function j(){U(B);B=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 pe(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?le():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?` ${V(r)}`:"")+(t.skipWait?" (clock skipped)":"");ue(i,e);if(v()==="android"){re(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(`${i}: app ${e==="background"?"sent to the background":"interrupted"}`);if(t.skipWait&&r&&o?.shift){o.shift(r);s(`App clock moved ahead ${V(r)}`);return returnToApp()}if(c.returnAt!=null){B=P(()=>{B=null;if(c)returnToApp()},r)}n();return getLifecycleSnapshot()}export function sendToBackground(e){return pe("background",e)}export function interrupt(e){return pe("inactive",e)}export function returnToApp(){j();if(!c)return getLifecycleSnapshot();const e=c;c=null;if(v()==="android"){if(e.kind==="background")x("active");re(true)}else{x("active")}const t=e.skippedMs??g()-e.startedAt;s(`Returned to the app after ${V(t)}`);I();X();n();return getLifecycleSnapshot()}let fe=false;function $e(){if(fe)return;fe=true;ke(e=>{if(c){j();c=null;Ee();s(`The OS reported "${e}", which ended the simulation`);I();X()}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;E("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".')}E(`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.")}E("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=ve;const t=e.exitApp;let r=false;e.exitApp=()=>{r=true};E("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 de(){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".');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:de();E(`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:de();if(f?.mode==="native"&&t==="js")M.setColorScheme?.("unspecified");E(`Color scheme ${e}`,"colorScheme");if(t==="native"&&typeof M.setColorScheme==="function"){M.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 he(){if(!f)return;const e=f;f=null;if(p){p.colorScheme(null)}else if(e.mode==="native"&&typeof M.setColorScheme==="function"){M.setColorScheme("unspecified")}else if(e.previous){w("appearanceChanged",{colorScheme:e.previous})}s("Color scheme back to the system value")}export function resetColorScheme(){he();n();return getLifecycleSnapshot()}const Ne=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"];const Ie=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"];const z={unknown:0,unplugged:1,charging:2,full:3};function We(e,t){for(const m of S)m();S=[];const r=[];const o=[];const i=(m,L,A,F)=>{const T=Re(L,A,F);if(T)S.push(T);else if(typeof L[A]==="function")o.push(`${m} ${A}`)};const u=k("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(z[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:z[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=_();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=ie();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 z))throw new Error('state must be "unplugged", "charging", "full" or "unknown".');E(`Battery ${Math.round(o.level*100)}%${o.lowPowerMode?", low power":""}`,"battery");const{reached:i,realGetters:u}=We(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 me(){if(!y)return;for(const r of S)r();S=[];y=null;const e=k("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=_();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(){me();n();return getLifecycleSnapshot()}export async function relaunchApp(){await prepareRelaunch();P(()=>{void Se("auto","buoy lifecycle relaunch").catch(e=>{s(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`);ae();n()})},250);return getLifecycleSnapshot()}export async function prepareRelaunch(){const e=ee();const t={at:g(),pathname:e?.pathname??null,href:e?.href??null};s(`Relaunching from ${t.pathname??"an unknown screen"}`);ye(false);await G({v:1,settings:d,pendingRelaunch:t});n();return getLifecycleSnapshot()}const Fe=2500;function Oe(e){b={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null};n();P(()=>{const t=ee();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()},Fe)}export function goBackToBeforeRelaunch(){const e=b?.beforeHref;if(!e)throw new Error("There is no route to go back to.");const t=be();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 ye(e){if(c)returnToApp();me();he();if(e)s("Everything back to real")}export function resetLifecycle(){ye(true);n();return getLifecycleSnapshot()}export function clearReport(){W();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};ae();n();return getLifecycleSnapshot()}let J=false;export function bootLifecycle(){if(J)return;J=true;Ae();void p?.loadHost().then(()=>{H=null;n()});Z();$e();const e=r=>{if(!r)return;d=r.settings;if(r.pendingRelaunch){void G({v:1,settings:d,pendingRelaunch:null});Oe(r.pendingRelaunch)}n()};const t=xe();if(t!==void 0)e(t);else void Ce().then(e)}export function __resetLifecycleForTests(){j();W();for(const e of S)e();S=[];d={...oe};c=null;y=null;f=null;a=null;b=null;D=[];J=false;R=null;H=null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function dedupeRouteEvents(r){return r.filter((e,u)=>{const t=r[u-1];return!t||e.source!=="route"||t.source!=="route"||e.title!==t.title||e.timestamp-t.timestamp>=250})}
|
|
@@ -119,6 +119,8 @@ export declare function subscribeLifecycle(fn: () => void): () => void;
|
|
|
119
119
|
export declare function getLifecycleSettings(): LifecycleSettings;
|
|
120
120
|
/** Requests this soon after leaving count as a flush on the way out, not background work. */
|
|
121
121
|
export declare const FLUSH_GRACE_MS = 1000;
|
|
122
|
+
/** Keep sources ready while the panel is open, before the first signal. */
|
|
123
|
+
export declare function warmReportSources(): () => void;
|
|
122
124
|
export interface AwayOptions {
|
|
123
125
|
/** Return by itself after this many ms. Omit to stay away until returnToApp. */
|
|
124
126
|
durationMs?: number | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface TimedEvent {
|
|
2
|
+
source: string;
|
|
3
|
+
title: string;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
}
|
|
6
|
+
/** Router listeners can report the same navigation more than once. */
|
|
7
|
+
export declare function dedupeRouteEvents<T extends TimedEvent>(events: T[]): T[];
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=reportEvents.d.ts.map
|
package/lib/web/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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};
|
|
1
|
+
"use client";var tt=Object.defineProperty;var Sn=Object.getOwnPropertyDescriptor;var xn=Object.getOwnPropertyNames;var Cn=Object.prototype.hasOwnProperty;var Tn=(e,t)=>{for(var n in t)tt(e,n,{get:t[n],enumerable:true})},nt=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of xn(t))!Cn.call(e,o)&&o!==n&&tt(e,o,{get:()=>t[o],enumerable:!(r=Sn(t,o))||r.enumerable});return e},En=(e,t,n)=>(nt(e,t,"default"),n&&nt(n,t,"default"));var rt=(()=>{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);function An(e){return e.filter((t,n)=>{let r=e[n-1];return!r||t.source!=="route"||r.source!=="route"||t.title!==r.title||t.timestamp-r.timestamp>=250})}var ot={};Tn(ot,{AccessibilityInfo:()=>Mn,ActivityIndicator:()=>Lr,Alert:()=>Dr,Animated:()=>Dn,AppRegistry:()=>Rn,AppState:()=>$n,Appearance:()=>O,BackHandler:()=>it,Button:()=>Pr,CheckBox:()=>Jn,Clipboard:()=>Bn,DeviceEventEmitter:()=>pr,Dimensions:()=>Nn,Easing:()=>Wn,FlatList:()=>Qn,I18nManager:()=>On,Image:()=>Xn,ImageBackground:()=>Zn,InteractionManager:()=>jn,Keyboard:()=>zn,KeyboardAvoidingView:()=>er,LayoutAnimation:()=>Hn,Linking:()=>Fn,LogBox:()=>dr,Modal:()=>Ar,NativeEventEmitter:()=>_n,NativeModules:()=>Pn,PanResponder:()=>Vn,Picker:()=>tr,PixelRatio:()=>qn,Platform:()=>Un,Pressable:()=>Er,ProgressBar:()=>nr,RefreshControl:()=>rr,SafeAreaView:()=>or,ScrollView:()=>ut,SectionList:()=>ir,Share:()=>Kn,StatusBar:()=>ar,StyleSheet:()=>me,Switch:()=>Ir,Text:()=>p,TextInput:()=>ct,Touchable:()=>lr,TouchableHighlight:()=>Cr,TouchableNativeFeedback:()=>sr,TouchableOpacity:()=>P,TouchableWithoutFeedback:()=>Tr,UIManager:()=>Gn,Vibration:()=>Yn,View:()=>f,VirtualizedList:()=>cr,YellowBox:()=>ur,findNodeHandle:()=>Mr,unstable_createElement:()=>Ln,useColorScheme:()=>hr,useLocaleContext:()=>fr,useWindowDimensions:()=>yr});En(ot,In);import*as In from"react-native-web";import{unstable_createElement as Ln,NativeModules as Pn,AccessibilityInfo as Mn,Animated as Dn,Appearance as O,AppRegistry as Rn,AppState as $n,BackHandler as it,Clipboard as Bn,Dimensions as Nn,Easing as Wn,I18nManager as On,Keyboard as zn,InteractionManager as jn,LayoutAnimation as Hn,Linking as Fn,NativeEventEmitter as _n,PanResponder as Vn,PixelRatio as qn,Platform as Un,Share as Kn,StyleSheet as me,UIManager as Gn,Vibration as Yn,CheckBox as Jn,FlatList as Qn,Image as Xn,ImageBackground as Zn,KeyboardAvoidingView as er,Picker as tr,ProgressBar as nr,RefreshControl as rr,SafeAreaView as or,SectionList as ir,StatusBar as ar,Touchable as lr,TouchableNativeFeedback as sr,VirtualizedList as cr,YellowBox as ur,LogBox as dr,DeviceEventEmitter as pr,useColorScheme as hr,useLocaleContext as fr,useWindowDimensions as yr}from"react-native-web";import*as x from"react-native-web";import{createElement as be,forwardRef as at,useCallback as gr,useRef as mr}from"react";import{useEffect as br,useState as wr}from"react";import{createPortal as vr}from"react-dom";var kr='-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';import{jsx as Sr}from"react/jsx-runtime";var Q=Symbol.for("@buoy-gg/portal-host"),lt=e=>{if(!(e instanceof Element))return false;if(e.closest("input, textarea, select"))return true;let t=e.closest("[contenteditable]")?.getAttribute("contenteditable")?.toLowerCase();return t===""||t==="true"||t==="plaintext-only"};function st(){let e=document;if(e[Q])return e[Q].host;let t=document.createElement("div");t.dataset.buoyPortalHost="",Object.assign(t.style,{position:"fixed",inset:"0",zIndex:"2147483647",pointerEvents:"none",fontFamily:kr});let n=()=>{let u=document.fullscreenElement,E=u&&u.tagName!=="CANVAS"?u:document.body;t.parentElement!==E&&E.appendChild(t)},r=new Map,o=u=>{(!t.contains(u.target)||!lt(u.target))&&r.set(u.code||u.key,{key:u.key,code:u.code,location:u.location,keyCode:u.keyCode,which:u.which,altKey:u.altKey,ctrlKey:u.ctrlKey,metaKey:u.metaKey,shiftKey:u.shiftKey})},a=u=>{r.delete(u.code||u.key)},c=()=>r.clear(),d=()=>{let u=[...r.values()];r.clear();for(let E of u)document.dispatchEvent(new KeyboardEvent("keyup",{...E,bubbles:true}))},h=u=>{lt(u.target)&&u.stopPropagation()},g=u=>u.stopPropagation();return n(),document.addEventListener("fullscreenchange",n),document.addEventListener("keydown",o,true),document.addEventListener("keyup",a,true),window.addEventListener("blur",c),t.addEventListener("focusin",d),t.addEventListener("keydown",h),t.addEventListener("keyup",h),t.addEventListener("keypress",h),t.addEventListener("wheel",g,{passive:true}),e[Q]={host:t,users:0,dispose:()=>{document.removeEventListener("fullscreenchange",n),document.removeEventListener("keydown",o,true),document.removeEventListener("keyup",a,true),window.removeEventListener("blur",c),t.remove(),delete e[Q]}},t}function xr({children:e}){let[t,n]=wr(null);return br(()=>{let r=st(),o=document[Q];return o.users++,n(r),()=>{--o.users===0&&o.dispose()}},[]),t?vr(Sr("div",{"data-buoy-root":"",style:{display:"contents",pointerEvents:"auto"},children:e}),t):null}function A(e){let t=at((r,o)=>{let{accessibilityState:a,accessibilityValue:c,...d}=r;for(let h of["busy","checked","disabled","expanded","selected"])a?.[h]!==void 0&&d[`aria-${h}`]===void 0&&(d[`aria-${h}`]=a[h]);for(let[h,g]of Object.entries({min:"valuemin",max:"valuemax",now:"valuenow",text:"valuetext"}))c?.[h]!==void 0&&d[`aria-${g}`]===void 0&&(d[`aria-${g}`]=c[h]);return be(e,{...d,ref:o})}),n=e.State;return n&&Object.assign(t,{State:n}),t.displayName=e.displayName??e.name??"NativeWebView",t}var f=A(x.View),p=A(x.Text),ct=A(x.TextInput),P=A(x.TouchableOpacity),Cr=A(x.TouchableHighlight),Tr=A(x.TouchableWithoutFeedback),Er=A(x.Pressable),ut=A(x.ScrollView),dt=at((e,t)=>{let n=mr(null),r=gr(o=>{if(o){let a=o;for(;a.parentElement&&a.parentElement!==document.body;)a=a.parentElement;a.parentElement===document.body&&(n.current=a,Object.assign(a.style,{position:"relative",zIndex:"2147483647",pointerEvents:"auto"}),st().appendChild(a))}else n.current&&(document.body.appendChild(n.current),n.current=null);typeof t=="function"?t(o):t&&(t.current=o)},[t]);return be(xr,null,be(x.Modal,{...e,ref:r}))});dt.displayName="Modal";var Ar=A(dt),Ir=A(x.Switch),Lr=A(x.ActivityIndicator),Pr=A(x.Button),Mr=x.findNodeHandle,Dr={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 g=document.createElement("p");g.textContent=t,g.style.cssText="line-height:1.5;white-space:pre-wrap;margin:0 0 20px",o.appendChild(g)}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"}],h=()=>{o.close?.(),o.remove()};for(let g of d){let u=document.createElement("button");u.type="button",u.textContent=g.text??"OK",u.style.cssText=`padding:9px 14px;border:1px solid #64748b;border-radius:7px;color:white;background:${g.style==="destructive"?"#a52b38":"#283a4d"};cursor:pointer;font:inherit`,u.onclick=()=>{h(),g.onPress?.()},c.appendChild(u)}o.addEventListener("cancel",g=>{g.preventDefault(),r?.cancelable!==false&&(h(),r?.onDismiss?.())}),o.appendChild(c),document.body.appendChild(o),o.showModal?o.showModal():o.setAttribute("open","")}};import{getRealAppState as pt,getSafeCurrentRoute as ht,getSafeRouter as Rr,realNow as B,reloadApp as $r,subscribeRealAppState as Br}from"@buoy-gg/shared-ui/web";import{loadToolModule as ft}from"@buoy-gg/shared-ui/web/utils";import{capacitorListenerCount as yt,capacitorPlatform as gt,emitCapacitorEvent as X,hasCapacitorPlugin as Nr,installCapacitorBridge as Wr,interceptCapacitor as we,makeCapacitorCallbackId as Or,getCapacitorAppHost as zr,loadCapacitorAppHost as jr,colorSchemeQueryValue as Hr,getColorSchemeQueries as Fr}from"@buoy-gg/license/web";import{BUOY_SYNTHETIC_MARK as _r}from"@buoy-gg/shared-ui/web";function N(){return gt()??"web"}function z(){return gt()===null||!Wr()?false:(Vr(),true)}var mt=false;function Vr(){mt||(mt=true,we({plugin:"App",methods:["getState"],promise:(e,t)=>ie?t():{isActive:false}}))}function ve(){let e=globalThis.document;return e&&typeof e.dispatchEvent=="function"?e:null}function oe(e){let t=ve();if(!t)return;let n=globalThis.Event;if(!n)return;let r=new n(e);r[_r]=true,t.dispatchEvent(r)}function bt(e){let t=ve();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,V=false;function ke(e){ie!==e&&(ie=e,X("App","appStateChange",{isActive:e}))}function Z(e){if(z()){if(e==="inactive"){ke(false);return}if(e==="background"){ke(false),V||(V=true,X("App","pause",{}),oe("pause"),bt("hidden"));return}V&&(V=false,bt(null),X("App","resume",{}),oe("resume")),ke(true)}}function qr(){V&&Ur(null),V=false,ie=true}function Ur(e){let t=ve();!t||e!==null||(delete t.visibilityState,delete t.hidden)}function M(e,t){z()&&e==="url"&&X("App","appUrlOpen",t)}var Kr={appStateDidChange:["appStateChange","pause","resume"],url:["appUrlOpen"],hardwareBackPress:["backButton"]};function ee(e){if(!z())return null;let t=Kr[e];return t?t.reduce((n,r)=>n+yt("App",r),0):0}var Gr=400;function Yr(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(yt("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=we({plugin:"App",methods:["exitApp"],promise:()=>{n=true},callback:()=>(n=true,Or())});try{X("App","backButton",{canGoBack:t}),oe("backbutton"),await new Promise(o=>Yr(o,Gr))}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 zr()},loadHost(){return z()?jr():Promise.resolve(null)},colorScheme(e){if(!z())throw new Error("The color scheme needs a Capacitor app.");Jr();let t=Fr(),n=t.map(r=>r.matches);Se=e,t.forEach((r,o)=>{let a=r.matches;a!==n[o]&&Qr(r,a)})},battery:{available(){return z()&&Nr("Device")},set(e){te=e,e&&!kt&&(kt=true,we({plugin:"Device",methods:["getBatteryInfo"],promise:(t,n)=>te?{batteryLevel:te.level,isCharging:te.state==="charging"||te.state==="full"}:n()}))}}},Se=null,wt=false;function vt(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=Se?Hr(String(this.media??"")):null;return o?Se===o:r}}),true}function Jr(){if(wt)return;let e=globalThis.MediaQueryListEvent;vt(e?.prototype);let t=globalThis.MediaQueryList;vt(t?.prototype)&&(wt=true)}function Qr(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,kt=false;function j(e){return null}function Xr(e,t){return null}function ae(){return null}function Zr(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 eo,persistentStorage as St}from"@buoy-gg/shared-ui/web";function xt(){try{let e=globalThis.localStorage;return e?Tt(e.getItem(Ce)):void 0}catch{return}}var xe={showChip:true,reportWindowMs:5e3},Ce=eo.lifecycle.state();function to(e,t){return typeof e=="number"&&Number.isFinite(e)?e:t}function Ct(e){return typeof e=="string"?e:null}function Tt(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:xe.showChip,reportWindowMs:Math.min(6e4,Math.max(1e3,to(n.reportWindowMs,xe.reportWindowMs)))},pendingRelaunch:r&&typeof r.at=="number"?{at:r.at,pathname:Ct(r.pathname),href:Ct(r.href)}:null}}catch{return null}}async function no(){try{return Tt(await St.getItem(Ce))}catch{return null}}var Te=Promise.resolve();function Ee(e){let t=JSON.stringify(e);return Te=Te.then(()=>St.setItem(Ce,t)).catch(()=>{}),Te.then(()=>{})}function Et(){return globalThis.__buoyRealTimers??globalThis}function le(e,t){return Et().setTimeout(e,t)}function Ae(e){e!=null&&Et().clearTimeout(e)}var ro=30,L={...xe},T=null,D=null,I=null,w=null,H=null,Ie=[],se=null,ce=null,ue=null,q=[],oo=0,de=()=>{},Le=new Set,pe=null;function m(){pe=null;for(let e of Array.from(Le))try{e()}catch{}}function S(e){Ie=[{at:B(),text:e},...Ie].slice(0,ro)}function At(){Ee({v:1,settings:L,pendingRelaunch:null})}function io(){let e=C?.host();if(e)return{...e,os:N(),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)??N(),appScheme:ao()}}function ao(){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 Pe=null;function It(){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 lo(){let e=null,t=r=>{r!=null&&(e=(e??0)+r)},n=j("ExpoBattery");for(let r of fo)t(Xr(n,r));if(ae())for(let r of yo)t(ee(r));return e}function Lt(){try{return ft("@buoy-gg/clock")}catch{return null}}function b(){return pe||(pe={platform:N(),host:Pe??(Pe=io()),realAppState:pt(),away:T,power:D,scheme:I,listeners:{appState:ee("appStateDidChange"),focus:ee("appStateFocusChange"),memoryWarning:ee("memoryWarning"),deepLink:ee("url"),battery:lo()},batteryLibraries:It(),clockAvailable:typeof Lt()?.shift=="function",report:w,relaunch:H,log:Ie,settings:L,active:T!=null||D!=null||I!=null},pe)}function Pt(){return m(),b()}function ne(e){return Le.add(e),()=>Le.delete(e)}function so(){return L}var Mt=["network","react-query","react-query-query","react-query-mutation","route","storage-async","storage-mmkv","redux","zustand","jotai"],co=40,Dt=1e3;function Rt(){try{let e=ft("@buoy-gg/events");return typeof e.watchEvents=="function"?e.watchEvents:null}catch{return null}}function uo(){return Rt()?.(Mt,()=>{})??(()=>{})}function Me(){Ae(ce),ce=null,ue?.(),ue=null,w&&w.collectingUntil!=null&&(w={...w,collectingUntil:null},m())}function $t(e,t,n,r){Me();let o=B(),a=++oo;w={id:a,label:e,kind:t,signal:r,startedAt:o,collectingUntil:Number.MAX_SAFE_INTEGER,events:[],counts:{},note:n};let c=Rt();if(!c){w={...w,collectingUntil:null,unavailable:"Install @buoy-gg/events to see what the app did after a simulation."};return}let d=Date.now(),h=()=>T?Number.MAX_SAFE_INTEGER:g,g=Number.MAX_SAFE_INTEGER;de=()=>{g=Date.now()},ue=c(Mt,u=>{if(!w||w.id!==a)return;let E=u.filter(k=>!(k.source.startsWith("react-query")&&k.status==="pending")).sort((k,kn)=>k.timestamp-kn.timestamp),$=An(E),ge={};for(let k of $)ge[k.source]=(ge[k.source]??0)+1;let Ze=$.map(k=>({source:k.source,title:k.title,subtitle:k.subtitle,status:k.status,at:Math.max(0,k.timestamp-d),whileAway:k.timestamp<h()})),et=Ze.filter(k=>k.whileAway&&k.source==="network"&&k.at>=Dt).length;w={...w,counts:ge,events:Ze.slice(0,co),finding:et>0&&w.kind==="background"?`The app kept making network requests in the background: ${et} after its first second away.`:void 0},m()},d)}function De(){if(!w||w.collectingUntil==null||!ue)return;let e=B()+L.reportWindowMs;w={...w,collectingUntil:e},Ae(ce),ce=le(Me,L.reportWindowMs)}function F(e,t,n){$t(e,"signal",n,t),de(),De()}function Bt(){Ae(se),se=null}function Re(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 Nt(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?Lt():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?` ${Re(n)}`:"")+(t.skipWait?" (clock skipped)":"");return $t(o,e),N()==="android"?e==="background"&&Z("background"):(Z("inactive"),e==="background"&&Z("background")),T={kind:e,startedAt:B(),returnAt:n&&!t.skipWait?B()+n:null,skippedMs:t.skipWait?n:null},S(`${o}: app ${e==="background"?"sent to the background":"interrupted"}`),t.skipWait&&n&&r?.shift?(r.shift(n),S(`App clock moved ahead ${Re(n)}`),_()):(T.returnAt!=null&&(se=le(()=>{se=null,T&&_()},n)),m(),b())}function U(e){return Nt("background",e)}function $e(e){return Nt("inactive",e)}function _(){if(Bt(),!T)return b();let e=T;T=null,N()==="android"?(e.kind==="background"&&Z("active"),void 0):Z("active");let t=e.skippedMs??B()-e.startedAt;return S(`Returned to the app after ${Re(t)}`),de(),De(),m(),b()}var Wt=false;function po(){Wt||(Wt=true,Br(e=>{T&&(Bt(),T=null,qr(),S(`The OS reported "${e}", which ended the simulation`),de(),De()),m()}))}function Be(){if(C)throw new Error("Capacitor has no memory warning event, so there is nothing to send.");let e=N()==="android"?"Android never sends this event to React Native; only iOS does. Listeners ran anyway.":void 0;return F("Memory warning","memoryWarning",e),M("memoryWarning"),S("Memory warning sent"),m(),b()}function Ot(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"),M("url",{url:t}),S(`Deep link delivered: ${t}`),m(),b()}async function zt(){if(!C)return jt();if(N()!=="android")throw new Error("The hardware back button only exists on Android.");F("Back button","back");let e=await C.pressBack();return w&&(w={...w,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}`),m(),{handled:e.handled,snapshot:b()}}function jt(){if(N()!=="android")throw new Error("The hardware back button only exists on Android.");let e=it,t=e.exitApp,n=false;e.exitApp=()=>{n=true},F("Back button","back");try{M("hardwareBackPress")}finally{e.exitApp=t}return w&&(w={...w,note:n?"No screen handled back, so a real press would have left the app.":"A screen handled back."}),S(n?"Back pressed: nothing handled it":"Back pressed: handled by the app"),m(),{handled:!n,snapshot:b()}}function Ht(){try{let e=O.getColorScheme();return e==="light"||e==="dark"?e:null}catch{return null}}function Ft(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:Ht();return F(`Color scheme ${e}`,"colorScheme"),C.colorScheme(e),I={scheme:e,mode:t,previous:r},S(`Color scheme set to ${e}`),m(),b()}let n=I?I.previous:Ht();return I?.mode==="native"&&t==="js"&&O.setColorScheme?.("unspecified"),F(`Color scheme ${e}`,"colorScheme"),t==="native"&&typeof O.setColorScheme=="function"?O.setColorScheme(e):M("appearanceChanged",{colorScheme:e}),I={scheme:e,mode:t,previous:n},S(`Color scheme set to ${e}${t==="native"?" (native)":""}`),m(),b()}function _t(){if(!I)return;let e=I;I=null,C?C.colorScheme(null):e.mode==="native"&&typeof O.setColorScheme=="function"?O.setColorScheme("unspecified"):e.previous&&M("appearanceChanged",{colorScheme:e.previous}),S("Color scheme back to the system value")}function ho(){return _t(),m(),b()}var fo=["Expo.powerModeDidChange","Expo.batteryStateDidChange","Expo.batteryLevelDidChange"],yo=["RNDeviceInfo_powerStateDidChange","RNDeviceInfo_batteryLevelDidChange","RNDeviceInfo_batteryLevelIsLow"],Ne={unknown:0,unplugged:1,charging:2,full:3};function go(e,t){for(let d of q)d();q=[];let n=[],r=[],o=(d,h,g,u)=>{let E=Zr(h,g,u);E?q.push(E):typeof h[g]=="function"&&r.push(`${d} ${g}`)},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(Ne[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:Ne[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}),q.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"),M("RNDeviceInfo_powerStateDidChange",d()),e.level!==t?.level&&(M("RNDeviceInfo_batteryLevelDidChange",e.level),e.level<=.2&&M("RNDeviceInfo_batteryLevelIsLow",e.level))}return{reached:n,realGetters:r}}function We(e){if(It().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 Ne))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}=go(n,D);return D={...n,reached:r,realGetters:o},S(`Battery set to ${Math.round(n.level*100)}%, ${n.state}${n.lowPowerMode?", low power mode on":""}`),m(),b()}function Vt(){if(!D)return;for(let n of q)n();q=[],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=>M("RNDeviceInfo_powerStateDidChange",n)).catch(()=>{}),S("Battery back to the real values")}function qt(){return Vt(),m(),b()}async function Oe(){return await Ut(),le(()=>{$r("auto","buoy lifecycle relaunch").catch(e=>{S(`Relaunch failed: ${e instanceof Error?e.message:String(e)}`),At(),m()})},250),b()}async function Ut(){let e=ht(),t={at:B(),pathname:e?.pathname??null,href:e?.href??null};return S(`Relaunching from ${t.pathname??"an unknown screen"}`),Kt(false),await Ee({v:1,settings:L,pendingRelaunch:t}),m(),b()}var mo=2500;function bo(e){H={requestedAt:e.at,before:e.pathname,beforeHref:e.href,after:null,tookMs:null,restored:null},m(),le(()=>{let t=ht()?.pathname??null;H={...H,after:t,tookMs:B()-e.at,restored:e.pathname!=null&&t!=null?t===e.pathname:null},S(H.restored===true?`Relaunch restored ${t}`:`Relaunch landed on ${t??"an unknown screen"}${e.pathname?`, was on ${e.pathname}`:""}`),m()},mo)}function wo(){let e=H?.beforeHref;if(!e)throw new Error("There is no route to go back to.");let t=Rr();if(!t)throw new Error("Going back needs expo-router.");return(t.navigate??t.push)?.(e),S(`Went back to ${e}`),m(),b()}function vo(){return H=null,m(),b()}function Kt(e){T&&_(),Vt(),_t(),e&&S("Everything back to real")}function ze(){return Kt(true),m(),b()}function ko(){return Me(),w=null,m(),b()}function So(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},At(),m(),b()}var Gt=false;function je(){if(Gt)return;Gt=true,C?.loadHost().then(()=>{Pe=null,m()}),pt(),po();let e=n=>{n&&(L=n.settings,n.pendingRelaunch&&(Ee({v:1,settings:L,pendingRelaunch:null}),bo(n.pendingRelaunch)),m())},t=xt();t!==void 0?e(t):no().then(e)}import{useEffect as xo,useState as Co,useSyncExternalStore as To}from"react";import{FloatingTool as Eo,LifecycleToolIcon as Ao,dismissFloatingTool as Io,getFloatingTools as Lo,night as He,openFloatingTool as Po,realNow as Yt}from"@buoy-gg/shared-ui/web";function Jt(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 Qt(e,t){return e==="background"?"In the background":t?"Lost focus":"Interrupted"}function Xt(e,t){let n=e.away;if(!n)return"";let r=Jt(t-n.startedAt);return n.returnAt!=null?`${r} of ${Jt(n.returnAt-n.startedAt)}`:r}function Zt(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 Do(e,t){let[n,r]=Mo[e]??[e,e];return`${t} ${t===1?n:r}`}function en(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])=>Do(n,r)).join(", ")}function Ro(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 tn(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 $o={memoryWarning:"memory warnings",deepLink:"links",colorScheme:"color scheme changes",battery:"battery changes",back:"the back button"};function Bo(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 No(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 Wo(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}:Bo(e,t.signal)===0?{tone:"warn",title:`Nothing in your app listens for ${$o[t.signal]}`,detail:t.note}:{tone:"neutral",title:No(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>=Dt).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 nn}from"react/jsx-runtime";var he="lifecycle-chip",Oo={id:he,render:e=>R(on,{...e})},zo=()=>Lo().some(e=>e.id===he),rn=false;function jo(){if(rn)return;rn=true;let e=false,t=()=>{let n=b().active&&so().showChip;n&&!e?Po(Oo):!n&&zo()&&Io(he),e=n};ne(t),t()}function Ho(e){let[t,n]=Co(Yt);return xo(()=>{if(!e)return;let r=setInterval(()=>n(Yt()),1e3);return()=>clearInterval(r)},[e]),t}function on({id:e,revealToken:t}){let n=To(ne,b,b),r=Ho(n.away!=null),o=n.away,a=o?Qt(o.kind,n.platform==="android"):"Simulating",c=o?Xt(n,r):Zt(n);return R(Eo,{id:e,revealToken:t,variant:"strip",dragFromSurface:true,defaultPlacement:"top",accessibilityLabel:`Move or hide the lifecycle chip. ${a}`,children:nn(f,{style:W.row,children:[R(Ao,{size:18}),nn(f,{style:W.text,children:[R(p,{style:W.title,numberOfLines:1,testID:"lifecycle-chip-title",children:a}),R(p,{style:W.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:W.pill,hitSlop:{top:8,bottom:8,left:4,right:8},children:R(p,{style:W.pillText,children:"Return"})}):R(P,{testID:"lifecycle-chip-reset",accessibilityRole:"button",accessibilityLabel:"End every simulation",onPress:()=>ze(),style:W.pill,hitSlop:{top:8,bottom:8,left:4,right:8},children:R(p,{style:W.pillText,children:"Stop"})})]})})}var W=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:He.color.textSecondary,fontSize:11,fontVariant:["tabular-nums"]},pill:{paddingHorizontal:12,height:28,marginRight:4,borderRadius:14,alignItems:"center",justifyContent:"center",backgroundColor:He.color.accentFill},pillText:{color:He.color.accent,fontSize:13,fontWeight:"600"}});import{LifecycleToolIcon as Fo,LIFECYCLE_TOOL_ICON_COLOR as _o,createToolFactory as Vo,defineToolPreset as qo}from"@buoy-gg/shared-ui/web";import{useEffect as Fe,useRef as an,useState as Uo}from"react";import{FeatureGate as Ko,getUseIsPro as Go,openBuoyTool as Yo}from"@buoy-gg/shared-ui/web";import{useToolHost as Jo}from"@buoy-gg/core/web";import{createSyncAdapter as Qo}from"@buoy-gg/shared-ui/web";var ln=6e4,re=[{id:"phone-call",title:"Take a phone call",detail:"The app pauses for 20 seconds, then comes back",run:()=>$e({durationMs:2e4})},{id:"quick-switch",title:"Switch apps for a moment",detail:"Hidden for 5 seconds, then back",run:()=>U({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:()=>U({durationMs:31*ln,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:()=>U({durationMs:540*ln,skipWait:true})},{id:"low-memory",title:"Run low on memory",detail:"A memory warning, then 10 seconds in the background",run:()=>(Be(),U({durationMs:1e4}))},{id:"dying-battery",title:"Battery almost empty",detail:"5% with Low Power Mode on",needsBattery:true,run:()=>We({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:()=>Oe()}];function sn(e,t=b()){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 cn(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=sn(t);if(n)throw new Error(`${t.title}: ${n}.`);return t.run()}function K(e){return e&&typeof e=="object"?e:{}}function _e(e,t){let n=e[t];if(typeof n=="boolean")return n;if(n==="true")return true;if(n==="false")return false}var Xo={ms:1,s:1e3,m:6e4,min:6e4,h:36e5,d:864e5};function Ve(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])*Xo[(t[2]??"ms").toLowerCase()]}function un(e){let t=K(e);return{durationMs:Ve(t.duration??t.durationMs??t.for),skipWait:_e(t,"skipWait")??false}}function v(e=b()){return{...e,recipes:re.map(t=>({id:t.id,title:t.title,detail:t.detail,unavailable:sn(t,e)}))}}var qe=Qo({version:1,getSnapshot(){return v()},subscribe(e){return ne(e)},actions:{getState(){return v(Pt())},background(e){return v(U(un(e)))},interrupt(e){return v($e(un(e)))},returnToApp(){return v(_())},memoryWarning(){return v(Be())},openUrl(e){let t=K(e),n=t.url??t.link??t.href;if(typeof n!="string")throw new Error('openUrl needs `url`, like "myapp://orders/42".');return v(Ot(n))},async pressBack(){let e=await zt();return{...v(e.snapshot),handled:e.handled}},setColorScheme(e){let t=K(e),n=t.scheme??t.colorScheme;if(n==="system")return v(ho());if(n!=="light"&&n!=="dark")throw new Error('setColorScheme needs `scheme`: "light", "dark" or "system".');let r=t.mode==="native"?"native":"js";return v(Ft(n,r))},setPower(e){let t=K(e),n=t.level??t.batteryLevel;return v(We({lowPowerMode:_e(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(qt())},async relaunch(){return v(await Oe())},async prepareRelaunch(){return v(await Ut())},goBackToBeforeRelaunch(){return v(wo())},dismissRelaunchReport(){return v(vo())},async runRecipe(e){let t=K(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 cn(n))},clearReport(){return v(ko())},reset(){return v(ze())},updateSettings(e){let t=K(e),n=t.reportWindowMs??t.reportWindow;return v(So({showChip:_e(t,"showChip"),reportWindowMs:n!=null?Ve(n)??void 0:void 0}))}}});import{useEffect as Zo,useRef as ei,useState as G}from"react";import{AlertTriangle as ti,CheckCircle as ni,ChevronDown as ri,ChevronRight as oi,NightButton as Ue,NightCard as Y,NightFootnote as J,NightRows as Ke,NightSectionLabel as Ge,NightSegmented as Ye,NightSwitch as dn,Play as ii,monoFont as pn,night as s,realNow as Je,useSafeAreaInsets as ai}from"@buoy-gg/shared-ui/web";import{Fragment as li,jsx as i,jsxs as y}from"react/jsx-runtime";var hn="#A3E635",si=[{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"}],ci=6e4;function fn(e){let[t,n]=G(()=>Je());return Zo(()=>{if(!e)return;let r=setInterval(()=>n(Je()),1e3);return()=>clearInterval(r)},[e]),e?t:Je()}function yn({snapshot:e,onAction:t}){let n=ai({minBottom:16}),r=ei(null),[o,a]=G(null),c=(d,h)=>{a(null),r.current?.scrollTo({y:0,animated:true}),t(d,h).catch(g=>{a(g instanceof Error?g.message:String(g))})};return e?y(ut,{ref:r,style:l.fill,contentContainerStyle:[l.content,{paddingBottom:n.bottom}],testID:"lifecycle-scroll",keyboardShouldPersistTaps:"handled",children:[i(ui,{snapshot:e,run:c}),o?i(J,{tone:"danger",centered:true,children:i(p,{testID:"lifecycle-error",children:o})}):null,i(fi,{snapshot:e,run:c}),i(gi,{snapshot:e,run:c})]}):i(f,{style:l.waiting,testID:"lifecycle-waiting",children:i(J,{centered:true,children:"Waiting for the app\u2026"})})}function ui({snapshot:e,run:t}){let n=Zt(e),r;return e.away?r=i(di,{snapshot:e,run:t}):e.relaunch?r=i(hi,{snapshot:e,run:t}):e.report?r=i(pi,{snapshot:e,run:t}):r=i(p,{style:l.intro,testID:"lifecycle-intro",children:"Pick a moment below. Buoy plays it on your app, then shows what your code did."}),y(f,{style:l.status,children:[r,n&&!e.away?i(Y,{children:y(f,{style:l.row,children:[y(f,{style:l.rowText,children:[i(p,{style:l.simulatedLabel,children:"Simulated"}),i(p,{style:l.rowTitle,testID:"lifecycle-simulated",children:n})]}),i(Ue,{label:"Stop Simulating",size:"md",fullWidth:false,testID:"lifecycle-reset",accessibilityLabel:"End every simulation",onPress:()=>t("reset")})]})}):null]})}function di({snapshot:e,run:t}){let n=fn(true),r=e.away,o=Qt(r.kind,e.platform==="android"),a=e.report,c=a?a.events.filter(d=>d.whileAway):[];return y(f,{style:l.running,children:[i(p,{style:l.runningTitle,testID:"lifecycle-hero-state",accessibilityLabel:`App state: ${o} (simulated)`,children:o}),i(p,{style:l.runningTimer,testID:"lifecycle-hero-status",children:Xt(e,n)}),i(f,{style:l.runningButton,children:i(Ue,{label:"Return to App",variant:"primary",testID:"lifecycle-return",onPress:()=>t("returnToApp")})}),a?.finding?i(p,{style:l.runningWarning,testID:"lifecycle-report-finding",children:a.finding}):c.length>0?y(p,{style:l.runningNote,children:["So far: ",en(c)]}):null]})}function gn({verdict:e}){let t=e.tone==="warn"?s.color.warning:e.tone==="good"?s.color.accent:s.color.text;return y(f,{style:l.verdict,children:[e.tone==="warn"?i(ti,{size:20,color:t}):e.tone==="good"?i(ni,{size:20,color:t}):null,y(f,{style:l.rowText,children:[i(p,{style:[l.verdictTitle,{color:t}],testID:"lifecycle-verdict",children:e.title}),e.detail?i(p,{style:l.verdictDetail,testID:"lifecycle-report-finding",children:e.detail}):null]})]})}var mn=5;function pi({snapshot:e,run:t}){let n=e.report,r=n.collectingUntil!=null,o=fn(r),[a,c]=G(false),d=Wo(e,n),h=n.events.filter($=>$.whileAway),g=n.events.filter($=>!$.whileAway),u=n.kind!=="signal",E=r?Math.max(0,(n.collectingUntil??o)-o):0;return i(Y,{children:y(f,{style:l.result,testID:"lifecycle-report",children:[i(gn,{verdict:d}),u||r?i(p,{style:l.resultLabel,testID:"lifecycle-report-label",children:u?`${n.label}${r?` \xB7 watching ${Math.ceil(E/1e3)} s`:""}`:`Watching ${Math.ceil(E/1e3)} s`}):null,n.unavailable?null:n.events.length===0?r?null:i(p,{style:l.detail,testID:"lifecycle-report-empty",children:"Your app made no requests, route changes, query updates or store writes."}):y(li,{children:[u&&h.length>0?i(Qe,{title:"While away",events:h,showAll:a}):null,g.length>0?i(Qe,{title:u?"After returning":"What your app did",events:g,showAll:a}):null,!u&&h.length>0?i(Qe,{title:"What your app did",events:h,showAll:a}):null]}),y(f,{style:l.resultButtons,children:[tn(n.events).length>mn?i(P,{onPress:()=>c($=>!$),testID:"lifecycle-report-show-all",accessibilityRole:"button",hitSlop:8,children:i(p,{style:l.link,children:a?"Show Less":"Show All"})}):i(f,{}),i(P,{onPress:()=>t("clearReport"),testID:"lifecycle-report-clear",accessibilityRole:"button",hitSlop:8,children:i(p,{style:l.link,children:"Done"})})]})]})})}function Qe({title:e,events:t,showAll:n}){let r=tn(t),o=n?r:r.slice(0,mn);return y(f,{style:l.eventList,testID:`lifecycle-events-${e}`,children:[i(p,{style:l.eventHeading,testID:`lifecycle-counts-${e}`,children:`${e} \xB7 ${en(t)}`}),o.map(a=>y(f,{style:l.event,testID:`lifecycle-event-${a.source}-${a.title}`,children:[i(p,{style:l.eventSource,children:Ro(a.source)}),i(p,{style:[l.eventTitle,a.error?l.eventError:null],numberOfLines:1,children:a.title}),a.count>1?i(p,{style:l.eventCount,testID:`lifecycle-event-${a.source}-${a.title}-count`,children:`\xD7${a.count}`}):null]},`${a.source}-${a.title}`)),r.length>o.length?i(p,{style:l.detail,children:`${r.length-o.length} more`}):null]})}var fe=e=>e==="/"?"the home screen":e;function hi({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(Y,{children:y(f,{style:l.result,testID:"lifecycle-relaunch-report",children:[i(f,{testID:"lifecycle-relaunch-result",children:i(gn,{verdict:r})}),y(f,{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(p,{style:l.link,children:`Go to ${fe(n.before)}`})}):i(f,{}),i(P,{onPress:()=>t("dismissRelaunchReport"),testID:"lifecycle-relaunch-dismiss",accessibilityRole:"button",hitSlop:8,children:i(p,{style:l.link,children:"Done"})})]})]})})}function fi({snapshot:e,run:t}){let n=e.host?.appScheme,[r,o]=G(n?`${n}://`:""),a=e.batteryLibraries.length>0,c=e.recipes.filter(h=>h.id!=="dying-battery"||a),d=e.away!=null;return y(f,{children:[i(Ge,{children:"Test a moment"}),i(Y,{children:y(Ke,{children:[c.map(h=>i(yi,{recipe:h,disabled:d,onPress:()=>t("runRecipe",{id:h.id})},h.id)),y(f,{style:l.stack,children:[i(p,{style:l.rowTitle,children:"Open a link"}),y(f,{style:l.inputRow,children:[i(ct,{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(Ue,{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(p,{style:l.warning,children:"Nothing in your app listens for links."}):null]},"link")]})})]})}function yi({recipe:e,disabled:t,onPress:n}){let r=t||!!e.unavailable;return y(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:[y(f,{style:l.rowText,children:[i(p,{style:l.rowTitle,children:e.title}),i(p,{style:l.detail,children:e.unavailable??e.detail})]}),e.unavailable?null:i(ii,{size:16,color:s.color.accent})]})}function gi({snapshot:e,run:t}){let[n,r]=G(false),o=n?ri:oi;return y(f,{children:[y(P,{testID:"lifecycle-custom",accessibilityRole:"button",accessibilityState:{expanded:n},onPress:()=>r(a=>!a),style:l.disclosure,hitSlop:8,children:[i(p,{style:l.disclosureText,children:"Custom"}),i(o,{size:16,color:s.color.textSecondary})]}),n?y(f,{style:l.customBody,children:[i(mi,{snapshot:e,run:t}),i(wi,{snapshot:e,run:t}),i(J,{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 mi({snapshot:e,run:t}){let[n,r]=G("hold"),o=n==="hold"?null:Number(n),a=o!=null&&o>=ci,c=a&&e.clockAvailable,d=()=>({durationMs:o,skipWait:c}),h=e.platform==="android",g=e.away!=null;return y(f,{children:[i(Ge,{children:"Leave the app"}),y(Y,{children:[i(f,{style:l.segmentWrap,children:i(Ye,{tabs:si,activeKey:n,size:"sm",testIDPrefix:"lifecycle-duration",onChange:r})}),y(Ke,{children:[i(ye,{title:"Switch to Another App",detail:"The app goes to the background",testID:"lifecycle-background",disabled:g,onPress:()=>t("background",d())},"background"),i(ye,{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:()=>t("interrupt",d())},"interrupt")]})]}),a?i(J,{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(J,{tone:"warning",children:"Nothing in your app listens for app state changes."}):null]})}var bi=[{key:"real",label:"Real"},{key:"100",label:"100%"},{key:"20",label:"20%"},{key:"5",label:"5%"}];function wi({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 y(f,{children:[i(Ge,{children:"Signals"}),i(Y,{children:y(Ke,{children:[i(ye,{title:"Send Memory Warning",detail:a,warn:e.listeners.memoryWarning===0,testID:"lifecycle-memory-warning",onPress:()=>t("memoryWarning")},"memory"),y(f,{style:l.stack,children:[i(p,{style:l.rowTitle,children:"Appearance"}),i(Ye,{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?y(f,{style:l.stack,children:[i(p,{style:l.rowTitle,children:"Battery"}),i(Ye,{tabs:bi,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})}),y(f,{style:l.inlineRow,children:[i(p,{style:l.rowTitle,children:"Charging"}),i(dn,{value:o?.state==="charging",testID:"lifecycle-battery-charging",accessibilityLabel:"Charging",onValueChange:c=>t("setPower",{state:c?"charging":"unplugged"})})]}),y(f,{style:l.inlineRow,children:[i(p,{style:l.rowTitle,children:"Low Power Mode"}),i(dn,{value:o?.lowPowerMode??false,testID:"lifecycle-low-power",accessibilityLabel:"Low Power Mode",onValueChange:c=>t("setPower",{lowPowerMode:c})})]}),e.listeners.battery===0?i(p,{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(J,{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:y(f,{style:l.rowText,children:[i(p,{style:l.actionTitle,children:e}),t?i(p,{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:hn,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:hn,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:pn,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:pn},eventError:{color:s.color.danger},eventCount:{color:s.color.textSecondary,fontSize:s.font.caption,fontWeight:"600",fontVariant:["tabular-nums"]}});import{jsx as bn}from"react/jsx-runtime";var vi=qe.actions;async function ki(e,t){let n=vi[e];if(!n)throw new Error(`Unknown lifecycle action: ${e}`);return n(t)}var Xe=()=>qe.getSnapshot();function wn(){let[e,t]=Uo(Xe),n=Jo(),r=Go()();Fe(()=>r?uo():void 0,[r]);let o=an(false);Fe(()=>(je(),Pt(),t(Xe()),ne(()=>t(Xe()))),[]);let a=e.away!=null,c=an(a);return Fe(()=>{let d=a&&!c.current;c.current=a,d&&!o.current?(o.current=true,n.minimize()):!a&&o.current&&(o.current=false,Yo("lifecycle"))},[a,n]),bn(Ko,{featureName:"Lifecycle Simulator",children:bn(yn,{snapshot:e,onAction:ki})})}import{jsx as Si}from"react/jsx-runtime";var vn=qo({id:"lifecycle",name:"LIFECYCLE",description:"See what your app does when people leave and come back",slot:"both",color:_o,icon:({size:e,color:t})=>Si(Fo,{size:e,color:t}),component:wn,modal:{subtitle:"what your app does when people leave"}}),xi=Vo(vn);import{LifecycleToolIcon as Ci,LIFECYCLE_TOOL_ICON_COLOR as Ti}from"@buoy-gg/shared-ui/web";var Ei=typeof navigator<"u"&&navigator.product==="ReactNative",Ai=(()=>{try{return globalThis.Capacitor?.isNativePlatform?.()===true}catch{return false}})();(Ei||Ai)&&(jo(),(typeof rt<"u"&&rt||xt()?.pendingRelaunch)&&je());export{he as LIFECYCLE_CHIP_ID,Ti as LIFECYCLE_TOOL_ICON_COLOR,wn as LifecycleBody,on as LifecycleChip,Ci as LifecycleToolIcon,yn as LifecycleToolView,re as RECIPES,je as bootLifecycle,xi as createLifecycleTool,b as getLifecycleSnapshot,$e as interrupt,qe as lifecycleSyncAdapter,vn as lifecycleToolPreset,Be as memoryWarning,Ot as openDeepLink,Ve as parseDurationMs,jt as pressBack,zt as pressBackAsync,Oe as relaunchApp,ze as resetLifecycle,qt as resetPower,_ as returnToApp,cn as runRecipe,U as sendToBackground,Ft as setColorScheme,We 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.64",
|
|
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,18 +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.64"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@buoy-gg/license": "7.0.
|
|
23
|
+
"@buoy-gg/license": "7.0.64",
|
|
24
24
|
"react": "*"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/react": "^19.1.0",
|
|
28
28
|
"@types/react-native": "^0.73.0",
|
|
29
29
|
"typescript": "~5.8.3",
|
|
30
|
-
"@buoy-gg/
|
|
31
|
-
"@buoy-gg/
|
|
30
|
+
"@buoy-gg/core": "^7.0.64",
|
|
31
|
+
"@buoy-gg/license": "^7.0.64"
|
|
32
32
|
},
|
|
33
33
|
"react-native-builder-bob": {
|
|
34
34
|
"source": "src",
|