@buoy-gg/images 7.0.67 → 7.0.69

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.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImageDetail=ImageDetail;var _nativeImageModules=require("../capture/nativeImageModules");var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _overrides=require("../capture/overrides");var _savings=require("../capture/savings");var _remote=require("../remote");var _imageEventStore=require("../store/imageEventStore");var _format=require("../format");var _jsxRuntime=require("react/jsx-runtime");function Section({title:e,children:l}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionTitle,children:e}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.sectionBody,children:l})]})}function Row({label:e,value:l,color:i}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.kvRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.kvLabel,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.kvValue,i?{color:i}:null],selectable:true,children:l})]})}function clearExpoCache(e){const l=(0,_remote.remoteImagesDispatch)();if(l){void l("clearExpoCaches",{memory:e==="memory",disk:e==="disk"});return}try{const i=(0,_nativeImageModules.loadExpoImage)();if(e==="memory")void i.Image.clearMemoryCache();else void i.Image.clearDiskCache()}catch{}}function SwapUrlSection({record:e}){const[l,i]=(0,_react.useState)(e.uri);const t=l.trim();const a=e.mounted&&t.length>0&&t!==e.uri;return(0,_jsxRuntime.jsxs)(Section,{title:"SWAP SOURCE URL",children:[(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.urlInput,value:l,onChangeText:i,placeholder:"https://\u2026",placeholderTextColor:_sharedUi.night.color.placeholder,autoCapitalize:"none",autoCorrect:false,multiline:true}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actionsRow,children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:[styles.actionButton,!a&&styles.actionDisabled],disabled:!a,onPress:()=>(0,_overrides.setOverride)(e.id,{source:{type:"url",uri:t},label:"URL swapped"}),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Apply"})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>i(e.uri),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Reset field"})})]})]})}function SavingsSection({record:e}){const[l,i]=(0,_react.useState)(false);const[t,a]=(0,_react.useState)(null);const s=()=>{i(true);(0,_savings.proveSavings)(e).then(a).catch(o=>a({ok:false,message:String(o?.message??o)})).finally(()=>i(false))};return(0,_jsxRuntime.jsx)(Section,{title:"PROVE SAVINGS (re-encode on device)",children:t==null?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.actionsRow,children:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:s,disabled:l,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:l?"Re-encoding\u2026":"Re-encode at displayed size (WebP)"})})}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(Row,{label:"Result",value:t.message||(t.ok?"done":"failed"),color:t.ok?_sharedUi.macOSColors.semantic.success:_sharedUi.macOSColors.semantic.error}),t.originalBytes!=null?(0,_jsxRuntime.jsx)(Row,{label:"Original",value:`${(0,_format.formatBytes)(t.originalBytes)} (${t.originalBytesSource})`}):null,t.optimizedBytes!=null?(0,_jsxRuntime.jsx)(Row,{label:"Optimized",value:`${(0,_format.formatBytes)(t.optimizedBytes)} \u2014 ${t.optimizedDims?.width}\xD7${t.optimizedDims?.height} WebP`,color:_sharedUi.macOSColors.semantic.success}):null,t.savedBytes!=null?(0,_jsxRuntime.jsx)(Row,{label:"Saved",value:`${(0,_format.formatBytes)(t.savedBytes)} (${t.savedPct}%)`,color:_sharedUi.macOSColors.semantic.success}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actionsRow,children:[t.ok&&t.optimizedUri&&e.mounted?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>(0,_overrides.setOverride)(e.id,{source:{type:"url",uri:t.optimizedUri},label:"Optimized preview"}),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Preview in place"})}):null,(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:s,disabled:l,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:l?"Re-encoding\u2026":"Re-run"})})]})]})})}function ImageDetail({record:e}){const l=(0,_format.sizeVerdict)(e);const i=(0,_format.cacheBadge)(e);const t=(0,_imageEventStore.neededPixels)(e);const a=(0,_imageEventStore.estDecodedBytes)(e);const s=(0,_imageEventStore.estWastedBytes)(e);return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.container,contentContainerStyle:styles.content,children:[e.overrideLabel?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.overrideBanner,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.overrideText,children:["Simulation active: ",e.overrideLabel," \u2014 stats below describe the override, not the original source."]}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>(0,_overrides.clearOverride)(e.id),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.overrideRestore,children:"RESTORE"})})]}):null,e.uri&&e.sourceKind!=="data"?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.previewBox,children:(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-images-preview",source:{uri:e.uri},style:styles.preview,resizeMode:"contain"})}):null,(0,_jsxRuntime.jsxs)(Section,{title:"SOURCE",children:[(0,_jsxRuntime.jsx)(Row,{label:"URI",value:e.uri||"(none)"}),(0,_jsxRuntime.jsx)(Row,{label:"Kind",value:e.sourceKind}),(0,_jsxRuntime.jsx)(Row,{label:"Library",value:e.lib==="web"?"Browser <img>":e.lib==="expo"?"expo-image":"RN <Image>"}),e.hasAltText===false?(0,_jsxRuntime.jsx)(Row,{label:"Alt text",value:"missing \u2014 add alt/accessibilityLabel",color:_sharedUi.macOSColors.semantic.warning}):null,e.mediaType!=null?(0,_jsxRuntime.jsx)(Row,{label:"Media type",value:String(e.mediaType)}):null,e.isAnimated!=null?(0,_jsxRuntime.jsx)(Row,{label:"Animated",value:e.isAnimated?"yes":"no"}):null]}),(0,_jsxRuntime.jsxs)(Section,{title:"LOAD",children:[(0,_jsxRuntime.jsx)(Row,{label:"Status",value:e.status,color:e.status==="error"?_sharedUi.macOSColors.semantic.error:e.status==="loaded"?_sharedUi.macOSColors.semantic.success:_sharedUi.macOSColors.semantic.warning}),(0,_jsxRuntime.jsx)(Row,{label:"Duration",value:(0,_format.formatMs)(e.durationMs)}),e.displayedAt&&e.loadedAt?(0,_jsxRuntime.jsx)(Row,{label:"Decode \u2192 display",value:(0,_format.formatMs)(Math.max(0,e.displayedAt-e.loadedAt))}):null,(0,_jsxRuntime.jsx)(Row,{label:"Cache",value:`${i.label}`,color:i.color}),e.cacheVerdictSource?(0,_jsxRuntime.jsx)(Row,{label:"Cache source",value:e.cacheVerdictSource==="event"?"reported by expo-image onLoad":"Image.queryCache after load"}):null,e.progressSeen?(0,_jsxRuntime.jsx)(Row,{label:"Downloaded",value:e.bytesTotal?`${(0,_format.formatBytes)(e.bytesLoaded??0)} / ${(0,_format.formatBytes)(e.bytesTotal)}`:"network transfer observed"}):null,(0,_jsxRuntime.jsx)(Row,{label:"Load cycles",value:String(e.loadCount)}),(0,_jsxRuntime.jsx)(Row,{label:"Still mounted",value:e.mounted?"yes":"no"})]}),(0,_jsxRuntime.jsxs)(Section,{title:"DIMENSIONS",children:[e.intrinsic?(0,_jsxRuntime.jsx)(Row,{label:"Decoded",value:`${e.intrinsic.width}\xD7${e.intrinsic.height} px`}):(0,_jsxRuntime.jsx)(Row,{label:"Decoded",value:"unknown"}),e.layout?(0,_jsxRuntime.jsx)(Row,{label:"Displayed",value:`${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)} dp (needs ${t?`${t.width}\xD7${t.height}`:"?"} px @${Math.round((0,_imageEventStore.effectivePixelRatio)()*100)/100}x)`}):(0,_jsxRuntime.jsx)(Row,{label:"Displayed",value:"no layout yet"}),l.label?(0,_jsxRuntime.jsx)(Row,{label:"Verdict",value:l.label,color:l.color}):null,a>0?(0,_jsxRuntime.jsx)(Row,{label:"Est. decoded memory",value:(0,_format.formatBytes)(a)}):null,s>0?(0,_jsxRuntime.jsx)(Row,{label:"Est. wasted",value:`${(0,_format.formatBytes)(s)} \u2014 resize the source to ${t?`${t.width}\xD7${t.height}`:"the displayed size"}`,color:_sharedUi.macOSColors.semantic.warning}):null,(e.layoutShifts??0)>0?(0,_jsxRuntime.jsx)(Row,{label:"Layout shifts",value:`${e.layoutShifts} \u2014 box resized after load; reserve explicit width/height`,color:_sharedUi.macOSColors.semantic.warning}):null]}),e.sourceKind==="network"||e.sourceKind==="asset"?(0,_jsxRuntime.jsx)(SavingsSection,{record:e},`savings-${e.id}`):null,e.status==="error"?(0,_jsxRuntime.jsxs)(Section,{title:"ERROR",children:[(0,_jsxRuntime.jsx)(Row,{label:"Message",value:e.error??"unknown",color:_sharedUi.macOSColors.semantic.error}),e.errorCode!=null?(0,_jsxRuntime.jsx)(Row,{label:"HTTP status",value:String(e.errorCode)}):null,e.errorHeaders?Object.entries(e.errorHeaders).map(([o,n])=>(0,_jsxRuntime.jsx)(Row,{label:o,value:String(n)},o)):null]}):null,e.sourceKind==="network"&&e.mounted?(0,_jsxRuntime.jsx)(SwapUrlSection,{record:e},e.id):null,e.lib==="expo"?(0,_jsxRuntime.jsx)(Section,{title:"CACHE ACTIONS (expo-image, global)",children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actionsRow,children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>clearExpoCache("memory"),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Clear memory cache"})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>clearExpoCache("disk"),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Clear disk cache"})})]})}):null]})}const styles=_reactNative.StyleSheet.create({container:{flex:1},content:{padding:12,gap:12},previewBox:{height:140,borderRadius:8,backgroundColor:_sharedUi.night.color.bg,overflow:"hidden"},preview:{width:"100%",height:"100%"},section:{gap:6},sectionTitle:{color:_sharedUi.night.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.8},sectionBody:{backgroundColor:_sharedUi.night.color.surface,borderRadius:8,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,paddingHorizontal:10,paddingVertical:4},kvRow:{flexDirection:"row",paddingVertical:5,gap:12},kvLabel:{color:_sharedUi.night.color.textSecondary,fontSize:11,width:110},kvValue:{color:_sharedUi.night.color.text,fontSize:11,flex:1},actionsRow:{flexDirection:"row",gap:8,paddingVertical:8},actionButton:{backgroundColor:_sharedUi.night.color.surfaceElevated,borderRadius:6,paddingHorizontal:10,paddingVertical:6,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border},actionText:{color:_sharedUi.night.color.text,fontSize:11,fontWeight:"600"},actionDisabled:{opacity:.4},urlInput:{color:_sharedUi.night.color.text,fontSize:11,fontFamily:_sharedUi.monoFont,backgroundColor:_sharedUi.night.color.surfaceElevated,borderRadius:6,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,paddingHorizontal:8,paddingVertical:6,marginTop:8},overrideBanner:{flexDirection:"row",alignItems:"center",gap:10,padding:10,borderRadius:8,backgroundColor:_sharedUi.night.color.warningSoft},overrideText:{flex:1,color:_sharedUi.night.color.warning,fontSize:11,lineHeight:15},overrideRestore:{color:_sharedUi.night.color.warning,fontSize:11,fontWeight:"700",letterSpacing:.5}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImageDetail=ImageDetail;var _nativeImageModules=require("../capture/nativeImageModules");var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _overrides=require("../capture/overrides");var _savings=require("../capture/savings");var _remote=require("../remote");var _imageEventStore=require("../store/imageEventStore");var _format=require("../format");var _jsxRuntime=require("react/jsx-runtime");function Section({title:e,children:l}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.section,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionTitle,children:e}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.sectionBody,children:l})]})}function rowTestID(e){return`buoy-images-detail-${e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}`}function Row({label:e,value:l,color:i}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.kvRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.kvLabel,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:rowTestID(e),style:[styles.kvValue,i?{color:i}:null],selectable:true,children:l})]})}function clearExpoCache(e){const l=(0,_remote.remoteImagesDispatch)();if(l){void l("clearExpoCaches",{memory:e==="memory",disk:e==="disk"});return}try{const i=(0,_nativeImageModules.loadExpoImage)();if(e==="memory")void i.Image.clearMemoryCache();else void i.Image.clearDiskCache()}catch{}}function SwapUrlSection({record:e}){const[l,i]=(0,_react.useState)(e.uri);const t=l.trim();const a=e.mounted&&t.length>0&&t!==e.uri;return(0,_jsxRuntime.jsxs)(Section,{title:"SWAP SOURCE URL",children:[(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.urlInput,value:l,onChangeText:i,placeholder:"https://\u2026",placeholderTextColor:_sharedUi.night.color.placeholder,autoCapitalize:"none",autoCorrect:false,multiline:true}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actionsRow,children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:[styles.actionButton,!a&&styles.actionDisabled],disabled:!a,onPress:()=>(0,_overrides.setOverride)(e.id,{source:{type:"url",uri:t},label:"URL swapped"}),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Apply"})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>i(e.uri),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Reset field"})})]})]})}function SavingsSection({record:e}){const[l,i]=(0,_react.useState)(false);const[t,a]=(0,_react.useState)(null);const s=()=>{i(true);(0,_savings.proveSavings)(e).then(a).catch(o=>a({ok:false,message:String(o?.message??o)})).finally(()=>i(false))};return(0,_jsxRuntime.jsx)(Section,{title:"PROVE SAVINGS (re-encode on device)",children:t==null?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.actionsRow,children:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:s,disabled:l,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:l?"Re-encoding\u2026":"Re-encode at displayed size (WebP)"})})}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(Row,{label:"Result",value:t.message||(t.ok?"done":"failed"),color:t.ok?_sharedUi.macOSColors.semantic.success:_sharedUi.macOSColors.semantic.error}),t.originalBytes!=null?(0,_jsxRuntime.jsx)(Row,{label:"Original",value:`${(0,_format.formatBytes)(t.originalBytes)} (${t.originalBytesSource})`}):null,t.optimizedBytes!=null?(0,_jsxRuntime.jsx)(Row,{label:"Optimized",value:`${(0,_format.formatBytes)(t.optimizedBytes)} \u2014 ${t.optimizedDims?.width}\xD7${t.optimizedDims?.height} WebP`,color:_sharedUi.macOSColors.semantic.success}):null,t.savedBytes!=null?(0,_jsxRuntime.jsx)(Row,{label:"Saved",value:`${(0,_format.formatBytes)(t.savedBytes)} (${t.savedPct}%)`,color:_sharedUi.macOSColors.semantic.success}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actionsRow,children:[t.ok&&t.optimizedUri&&e.mounted?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>(0,_overrides.setOverride)(e.id,{source:{type:"url",uri:t.optimizedUri},label:"Optimized preview"}),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Preview in place"})}):null,(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:s,disabled:l,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:l?"Re-encoding\u2026":"Re-run"})})]})]})})}function ImageDetail({record:e}){const l=(0,_format.sizeVerdict)(e);const i=(0,_format.cacheBadge)(e);const t=(0,_imageEventStore.neededPixels)(e);const a=(0,_imageEventStore.estDecodedBytes)(e);const s=(0,_imageEventStore.estWastedBytes)(e);return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.container,contentContainerStyle:styles.content,children:[e.overrideLabel?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.overrideBanner,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.overrideText,children:["Simulation active: ",e.overrideLabel," \u2014 stats below describe the override, not the original source."]}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>(0,_overrides.clearOverride)(e.id),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.overrideRestore,children:"RESTORE"})})]}):null,e.uri&&e.sourceKind!=="data"?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.previewBox,children:(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-images-preview",source:{uri:e.uri},style:styles.preview,resizeMode:"contain"})}):null,(0,_jsxRuntime.jsxs)(Section,{title:"SOURCE",children:[(0,_jsxRuntime.jsx)(Row,{label:"URI",value:e.uri||"(none)"}),(0,_jsxRuntime.jsx)(Row,{label:"Kind",value:e.sourceKind}),(0,_jsxRuntime.jsx)(Row,{label:"Library",value:e.lib==="web"?"Browser <img>":e.lib==="expo"?"expo-image":"RN <Image>"}),e.hasAltText===false?(0,_jsxRuntime.jsx)(Row,{label:"Alt text",value:"missing \u2014 add alt/accessibilityLabel",color:_sharedUi.macOSColors.semantic.warning}):null,e.mediaType!=null?(0,_jsxRuntime.jsx)(Row,{label:"Media type",value:String(e.mediaType)}):null,e.isAnimated!=null?(0,_jsxRuntime.jsx)(Row,{label:"Animated",value:e.isAnimated?"yes":"no"}):null]}),(0,_jsxRuntime.jsxs)(Section,{title:"LOAD",children:[(0,_jsxRuntime.jsx)(Row,{label:"Status",value:e.status,color:e.status==="error"?_sharedUi.macOSColors.semantic.error:e.status==="loaded"?_sharedUi.macOSColors.semantic.success:_sharedUi.macOSColors.semantic.warning}),(0,_jsxRuntime.jsx)(Row,{label:"Duration",value:(0,_format.formatMs)(e.durationMs)}),e.displayedAt&&e.loadedAt?(0,_jsxRuntime.jsx)(Row,{label:"Decode \u2192 display",value:(0,_format.formatMs)(Math.max(0,e.displayedAt-e.loadedAt))}):null,(0,_jsxRuntime.jsx)(Row,{label:"Cache",value:`${i.label}`,color:i.color}),e.cacheVerdictSource?(0,_jsxRuntime.jsx)(Row,{label:"Cache source",value:e.cacheVerdictSource==="event"?"reported by expo-image onLoad":"Image.queryCache after load"}):null,e.progressSeen?(0,_jsxRuntime.jsx)(Row,{label:"Downloaded",value:e.bytesTotal?`${(0,_format.formatBytes)(e.bytesLoaded??0)} / ${(0,_format.formatBytes)(e.bytesTotal)}`:"network transfer observed"}):null,(0,_jsxRuntime.jsx)(Row,{label:"Load cycles",value:String(e.loadCount)}),(0,_jsxRuntime.jsx)(Row,{label:"Still mounted",value:e.mounted?"yes":"no"})]}),(0,_jsxRuntime.jsxs)(Section,{title:"DIMENSIONS",children:[e.intrinsic?(0,_jsxRuntime.jsx)(Row,{label:"Decoded",value:`${e.intrinsic.width}\xD7${e.intrinsic.height} px`}):(0,_jsxRuntime.jsx)(Row,{label:"Decoded",value:"unknown"}),e.layout?(0,_jsxRuntime.jsx)(Row,{label:"Displayed",value:`${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)} dp (needs ${t?`${t.width}\xD7${t.height}`:"?"} px @${Math.round((0,_imageEventStore.effectivePixelRatio)()*100)/100}x)`}):(0,_jsxRuntime.jsx)(Row,{label:"Displayed",value:"no layout yet"}),l.label?(0,_jsxRuntime.jsx)(Row,{label:"Verdict",value:l.label,color:l.color}):null,a>0?(0,_jsxRuntime.jsx)(Row,{label:"Est. decoded memory",value:(0,_format.formatBytes)(a)}):null,s>0?(0,_jsxRuntime.jsx)(Row,{label:"Est. wasted",value:`${(0,_format.formatBytes)(s)} \u2014 resize the source to ${t?`${t.width}\xD7${t.height}`:"the displayed size"}`,color:_sharedUi.macOSColors.semantic.warning}):null,(e.layoutShifts??0)>0?(0,_jsxRuntime.jsx)(Row,{label:"Layout shifts",value:`${e.layoutShifts} \u2014 box resized after load; reserve explicit width/height`,color:_sharedUi.macOSColors.semantic.warning}):null]}),e.sourceKind==="network"||e.sourceKind==="asset"?(0,_jsxRuntime.jsx)(SavingsSection,{record:e},`savings-${e.id}`):null,e.status==="error"?(0,_jsxRuntime.jsxs)(Section,{title:"ERROR",children:[(0,_jsxRuntime.jsx)(Row,{label:"Message",value:e.error??"unknown",color:_sharedUi.macOSColors.semantic.error}),e.errorCode!=null?(0,_jsxRuntime.jsx)(Row,{label:"HTTP status",value:String(e.errorCode)}):null,e.errorHeaders?Object.entries(e.errorHeaders).map(([o,n])=>(0,_jsxRuntime.jsx)(Row,{label:o,value:String(n)},o)):null]}):null,e.sourceKind==="network"&&e.mounted?(0,_jsxRuntime.jsx)(SwapUrlSection,{record:e},e.id):null,e.lib==="expo"?(0,_jsxRuntime.jsx)(Section,{title:"CACHE ACTIONS (expo-image, global)",children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actionsRow,children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>clearExpoCache("memory"),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Clear memory cache"})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.actionButton,onPress:()=>clearExpoCache("disk"),children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Clear disk cache"})})]})}):null]})}const styles=_reactNative.StyleSheet.create({container:{flex:1},content:{padding:12,gap:12},previewBox:{height:140,borderRadius:8,backgroundColor:_sharedUi.night.color.bg,overflow:"hidden"},preview:{width:"100%",height:"100%"},section:{gap:6},sectionTitle:{color:_sharedUi.night.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.8},sectionBody:{backgroundColor:_sharedUi.night.color.surface,borderRadius:8,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,paddingHorizontal:10,paddingVertical:4},kvRow:{flexDirection:"row",paddingVertical:5,gap:12},kvLabel:{color:_sharedUi.night.color.textSecondary,fontSize:11,width:110},kvValue:{color:_sharedUi.night.color.text,fontSize:11,flex:1},actionsRow:{flexDirection:"row",gap:8,paddingVertical:8},actionButton:{backgroundColor:_sharedUi.night.color.surfaceElevated,borderRadius:6,paddingHorizontal:10,paddingVertical:6,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border},actionText:{color:_sharedUi.night.color.text,fontSize:11,fontWeight:"600"},actionDisabled:{opacity:.4},urlInput:{color:_sharedUi.night.color.text,fontSize:11,fontFamily:_sharedUi.monoFont,backgroundColor:_sharedUi.night.color.surfaceElevated,borderRadius:6,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,paddingHorizontal:8,paddingVertical:6,marginTop:8},overrideBanner:{flexDirection:"row",alignItems:"center",gap:10,padding:10,borderRadius:8,backgroundColor:_sharedUi.night.color.warningSoft},overrideText:{flex:1,color:_sharedUi.night.color.warning,fontSize:11,lineHeight:15},overrideRestore:{color:_sharedUi.night.color.warning,fontSize:11,fontWeight:"700",letterSpacing:.5}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImageDetailFooter=ImageDetailFooter;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _actions=require("../capture/actions");var _overrides=require("../capture/overrides");var _jsxRuntime=require("react/jsx-runtime");function ImageDetailFooter({record:e,hasPrevious:s,hasNext:a,onPrevious:i,onNext:u}){const[d,o]=(0,_react.useState)(null);const c=l=>{o("\u2026");l().then(r=>o(r.message)).catch(r=>o(String(r?.message??r)))};const t=!e.mounted;const b=e.overrideLabel!=null;const n=(l,r)=>{(0,_overrides.setOverride)(e.id,{source:l,label:r});o(`${r} \u2014 Restore to undo`)};return(0,_jsxRuntime.jsxs)(_sharedUi.ToolFooter,{children:[d?(0,_jsxRuntime.jsx)(_sharedUi.FooterMessage,{children:d}):t?(0,_jsxRuntime.jsx)(_sharedUi.FooterMessage,{tone:"muted",children:"Instance unmounted \u2014 reload actions need the image on screen."}):null,(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{style:{gap:8},children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:i,disabled:!s,style:[styles.navButton,!s&&styles.disabled],activeOpacity:.7,accessibilityLabel:"Previous image",children:(0,_jsxRuntime.jsx)(_sharedUi.ChevronLeft,{size:20,color:s?_sharedUi.night.color.accent:_sharedUi.night.color.textTertiary})}),(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:"Hard reload",size:"md",disabled:t,icon:(0,_jsxRuntime.jsx)(_sharedUi.RefreshCw,{size:13,color:t?_sharedUi.night.color.textTertiary:_sharedUi.night.color.info}),onPress:()=>c(()=>(0,_actions.hardReloadRecord)(e))}),(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:e.status==="error"?"Retry":"Reload",size:"md",disabled:t,onPress:()=>c(()=>(0,_actions.retryRecord)(e))}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:u,disabled:!a,style:[styles.navButton,!a&&styles.disabled],activeOpacity:.7,accessibilityLabel:"Next image",children:(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:20,color:a?_sharedUi.night.color.accent:_sharedUi.night.color.textTertiary})})]}),(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{style:{gap:8},children:[(0,_jsxRuntime.jsx)(SimButton,{label:"Error",disabled:t,onPress:()=>n({type:"error"},"Forced error")}),(0,_jsxRuntime.jsx)(SimButton,{label:"Loading",disabled:t,onPress:()=>n({type:"hang"},"Forced loading")}),(0,_jsxRuntime.jsx)(SimButton,{label:"Blank",disabled:t,onPress:()=>n({type:"blank"},"Blanked")}),(0,_jsxRuntime.jsx)(SimButton,{label:"Find",disabled:t,onPress:()=>{(0,_overrides.flashRecord)(e.id);o("Flashing a red border on the image (2.5s)")}}),(0,_jsxRuntime.jsx)(SimButton,{label:"Restore",accent:true,disabled:!b,onPress:()=>{(0,_overrides.clearOverride)(e.id);o("Override removed \u2014 original source restored")}})]})]})}function SimButton({label:e,onPress:s,disabled:a,accent:i}){return(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:e,onPress:s,disabled:a,accent:i,style:{paddingVertical:7}})}const styles=_reactNative.StyleSheet.create({navButton:{paddingHorizontal:10,paddingVertical:8,borderRadius:6,backgroundColor:_sharedUi.night.color.button,alignItems:"center",justifyContent:"center"},disabled:{opacity:.4}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImageDetailFooter=ImageDetailFooter;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _actions=require("../capture/actions");var _overrides=require("../capture/overrides");var _jsxRuntime=require("react/jsx-runtime");function ImageDetailFooter({record:e,hasPrevious:o,hasNext:a,onPrevious:i,onNext:u}){const[d,s]=(0,_react.useState)(null);const c=l=>{s("\u2026");l().then(r=>s(r.message)).catch(r=>s(String(r?.message??r)))};const t=!e.mounted;const g=e.overrideLabel!=null;const n=(l,r)=>{(0,_overrides.setOverride)(e.id,{source:l,label:r});s(`${r} \u2014 Restore to undo`)};return(0,_jsxRuntime.jsxs)(_sharedUi.ToolFooter,{children:[d?(0,_jsxRuntime.jsx)(_sharedUi.FooterMessage,{testID:"buoy-images-detail-footer-message",children:d}):t?(0,_jsxRuntime.jsx)(_sharedUi.FooterMessage,{tone:"muted",children:"Instance unmounted \u2014 reload actions need the image on screen."}):null,(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{style:{gap:8},children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:i,disabled:!o,style:[styles.navButton,!o&&styles.disabled],activeOpacity:.7,testID:"buoy-images-detail-previous",accessibilityLabel:"Previous image",children:(0,_jsxRuntime.jsx)(_sharedUi.ChevronLeft,{size:20,color:o?_sharedUi.night.color.accent:_sharedUi.night.color.textTertiary})}),(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:"Hard reload",size:"md",testID:"buoy-images-detail-hard-reload",disabled:t,icon:(0,_jsxRuntime.jsx)(_sharedUi.RefreshCw,{size:13,color:t?_sharedUi.night.color.textTertiary:_sharedUi.night.color.info}),onPress:()=>c(()=>(0,_actions.hardReloadRecord)(e))}),(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:e.status==="error"?"Retry":"Reload",size:"md",testID:"buoy-images-detail-reload",disabled:t,onPress:()=>c(()=>(0,_actions.retryRecord)(e))}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:u,disabled:!a,style:[styles.navButton,!a&&styles.disabled],activeOpacity:.7,testID:"buoy-images-detail-next",accessibilityLabel:"Next image",children:(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:20,color:a?_sharedUi.night.color.accent:_sharedUi.night.color.textTertiary})})]}),(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{style:{gap:8},children:[(0,_jsxRuntime.jsx)(SimButton,{label:"Error",disabled:t,onPress:()=>n({type:"error"},"Forced error")}),(0,_jsxRuntime.jsx)(SimButton,{label:"Loading",disabled:t,onPress:()=>n({type:"hang"},"Forced loading")}),(0,_jsxRuntime.jsx)(SimButton,{label:"Blank",disabled:t,onPress:()=>n({type:"blank"},"Blanked")}),(0,_jsxRuntime.jsx)(SimButton,{label:"Find",disabled:t,onPress:()=>{(0,_overrides.flashRecord)(e.id);s("Flashing a red border on the image (2.5s)")}}),(0,_jsxRuntime.jsx)(SimButton,{label:"Restore",accent:true,disabled:!g,onPress:()=>{(0,_overrides.clearOverride)(e.id);s("Override removed \u2014 original source restored")}})]})]})}function SimButton({label:e,onPress:o,disabled:a,accent:i}){return(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:e,onPress:o,disabled:a,accent:i,testID:`buoy-images-sim-${e.toLowerCase()}`,style:{paddingVertical:7}})}const styles=_reactNative.StyleSheet.create({navButton:{paddingHorizontal:10,paddingVertical:8,borderRadius:6,backgroundColor:_sharedUi.night.color.button,alignItems:"center",justifyContent:"center"},disabled:{opacity:.4}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImageRow=ImageRow;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _format=require("../format");var _jsxRuntime=require("react/jsx-runtime");function ImageRow({record:t,onPress:o}){const e=(0,_format.sizeVerdict)(t);const i=(0,_format.cacheBadge)(t);const r=t.sourceKind==="network"||t.sourceKind==="asset"||t.sourceKind==="file";return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.row,testID:`buoy-image-row-${t.id}`,onPress:()=>o(t.id),children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.thumbBox,children:[r&&t.uri?(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-images-thumb",source:{uri:t.uri},style:styles.thumb,resizeMode:"cover"}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.thumbFallback,children:"?"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.statusDot,{backgroundColor:(0,_format.statusColor)(t)}]})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.main,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.name,numberOfLines:1,children:(0,_format.uriTail)(t.uri)}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.metaRow,children:[(0,_jsxRuntime.jsx)(_sharedUi.Pill,{variant:"text",label:t.lib==="web"?"WEB":t.lib==="expo"?"EXPO":"RN",color:_sharedUi.night.color.textTertiary}),(0,_jsxRuntime.jsx)(_sharedUi.Pill,{variant:"text",label:i.label,color:i.color}),t.overrideLabel?(0,_jsxRuntime.jsx)(_sharedUi.Pill,{variant:"text",label:"SIM",color:_sharedUi.night.color.warning}):null,(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.meta,children:(0,_format.formatMs)(t.durationMs)}),t.intrinsic?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.meta,children:[t.intrinsic.width,"\xD7",t.intrinsic.height]}):null]})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.right,children:t.status==="error"?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.verdict,{color:_sharedUi.macOSColors.semantic.error}],children:"FAILED"}):e.label?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.verdict,{color:e.color}],children:e.label}):null})]})}const styles=_reactNative.StyleSheet.create({row:{flexDirection:"row",alignItems:"center",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:_reactNative.StyleSheet.hairlineWidth,borderBottomColor:_sharedUi.night.color.border,gap:10},thumbBox:{width:40,height:40,borderRadius:6,backgroundColor:_sharedUi.night.color.bg,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:40,height:40},thumbFallback:{color:_sharedUi.night.color.textTertiary,fontSize:16,fontWeight:"700"},statusDot:{position:"absolute",right:2,bottom:2,width:8,height:8,borderRadius:4,borderWidth:1,borderColor:_sharedUi.night.color.bg},main:{flex:1,gap:2},name:{color:_sharedUi.night.color.text,fontSize:12,fontWeight:"600"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:_sharedUi.night.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end"},verdict:{fontSize:10,fontWeight:"700"}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImageRow=ImageRow;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _format=require("../format");var _jsxRuntime=require("react/jsx-runtime");function ImageRow({record:t,onPress:r}){const i=(0,_format.sizeVerdict)(t);const o=(0,_format.cacheBadge)(t);const s=t.sourceKind==="network"||t.sourceKind==="asset"||t.sourceKind==="file";const e=`buoy-image-row-${t.id}`;return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.row,testID:e,onPress:()=>r(t.id),children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.thumbBox,children:[s&&t.uri?(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-images-thumb",source:{uri:t.uri},style:styles.thumb,resizeMode:"cover"}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.thumbFallback,children:"?"}),(0,_jsxRuntime.jsx)(_reactNative.View,{testID:`${e}-status`,accessibilityLabel:t.status,style:[styles.statusDot,{backgroundColor:(0,_format.statusColor)(t)}]})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.main,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.name,numberOfLines:1,testID:`${e}-name`,children:(0,_format.uriTail)(t.uri)}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.metaRow,children:[(0,_jsxRuntime.jsx)(_sharedUi.Pill,{variant:"text",label:t.lib==="web"?"WEB":t.lib==="expo"?"EXPO":"RN",color:_sharedUi.night.color.textTertiary}),(0,_jsxRuntime.jsx)(_sharedUi.Pill,{variant:"text",label:o.label,color:o.color,testID:`${e}-cache`}),t.overrideLabel?(0,_jsxRuntime.jsx)(_sharedUi.Pill,{variant:"text",label:"SIM",color:_sharedUi.night.color.warning,testID:`${e}-sim`}):null,(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.meta,children:(0,_format.formatMs)(t.durationMs)}),t.intrinsic?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.meta,testID:`${e}-size`,children:[t.intrinsic.width,"\xD7",t.intrinsic.height]}):null]})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.right,children:t.status==="error"?(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:`${e}-verdict`,style:[styles.verdict,{color:_sharedUi.macOSColors.semantic.error}],children:"FAILED"}):i.label?(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:`${e}-verdict`,style:[styles.verdict,{color:i.color}],children:i.label}):null})]})}const styles=_reactNative.StyleSheet.create({row:{flexDirection:"row",alignItems:"center",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:_reactNative.StyleSheet.hairlineWidth,borderBottomColor:_sharedUi.night.color.border,gap:10},thumbBox:{width:40,height:40,borderRadius:6,backgroundColor:_sharedUi.night.color.bg,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:40,height:40},thumbFallback:{color:_sharedUi.night.color.textTertiary,fontSize:16,fontWeight:"700"},statusDot:{position:"absolute",right:2,bottom:2,width:8,height:8,borderRadius:4,borderWidth:1,borderColor:_sharedUi.night.color.bg},main:{flex:1,gap:2},name:{color:_sharedUi.night.color.text,fontSize:12,fontWeight:"600"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:_sharedUi.night.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end"},verdict:{fontSize:10,fontWeight:"700"}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImagesHeader=ImagesHeader;var _sharedUi=require("@buoy-gg/shared-ui");var _format=require("../format");var _jsxRuntime=require("react/jsx-runtime");function ImagesHeader({stats:e,detailOpen:d,detailIndex:r=-1,detailTotal:t=0,onCloseDetail:i,onClear:n,getReport:a,onBack:o}){if(d){const l=r>=0&&t>0?`${r+1} of ${t}`:void 0;return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:i}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Image detail",subtitle:l}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Actions,{children:(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:a})})]})}const s=[`${e.total} images`,`${e.errors} failed`,`\u2248${(0,_format.formatBytes)(e.estDecodedBytes)} decoded`];if(e.estWastedBytes>0){s.push(`${(0,_format.formatBytes)(e.estWastedBytes)} wasted`)}return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[o?(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:o}):null,(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Images",subtitle:s.join(" \xB7 ")}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:a}),(0,_jsxRuntime.jsx)(_sharedUi.ToolbarClearButton,{onPress:n})]})]})}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImagesHeader=ImagesHeader;var _sharedUi=require("@buoy-gg/shared-ui");var _format=require("../format");var _jsxRuntime=require("react/jsx-runtime");function ImagesHeader({stats:e,detailOpen:d,detailIndex:t=-1,detailTotal:r=0,onCloseDetail:i,onClear:l,getReport:a,onBack:s}){if(d){const n=t>=0&&r>0?`${t+1} of ${r}`:void 0;return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:i}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Image detail",subtitle:n,testID:"buoy-images-detail-title"}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Actions,{children:(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:a})})]})}const o=[`${e.total} images`,`${e.errors} failed`,`\u2248${(0,_format.formatBytes)(e.estDecodedBytes)} decoded`];if(e.estWastedBytes>0){o.push(`${(0,_format.formatBytes)(e.estWastedBytes)} wasted`)}return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[s?(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:s}):null,(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Images",subtitle:o.join(" \xB7 "),testID:"buoy-images-title"}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:a}),(0,_jsxRuntime.jsx)(_sharedUi.ToolbarClearButton,{onPress:l,testID:"buoy-images-clear"})]})]})}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImagesListFooter=ImagesListFooter;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _actions=require("../capture/actions");var _overrides=require("../capture/overrides");var _jsxRuntime=require("react/jsx-runtime");const NETWORK_MODES=[{key:"normal",label:"Normal"},{key:"offline",label:"Offline"},{key:"cold",label:"Cold"}];function ImagesListFooter(){const[r,t]=(0,_react.useState)(null);const s=(0,_react.useSyncExternalStore)(_actions.subscribeActions,()=>(0,_overrides.getGlobalModes)().network);const a=(e,o)=>{const n=(0,_overrides.setOverrideForAllMounted)(e,o);t(n>0?`${o} on ${n} image${n===1?"":"s"} \u2014 Restore all to undo`:"No mounted images")};return(0,_jsxRuntime.jsxs)(_sharedUi.ToolFooter,{paddingBottom:10,style:{paddingTop:8},children:[r?(0,_jsxRuntime.jsx)(_sharedUi.FooterMessage,{children:r}):(0,_jsxRuntime.jsx)(_sharedUi.FooterCaption,{children:"MASS ACTIONS \u2014 every image on screen"}),(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{children:[(0,_jsxRuntime.jsx)(MassButton,{label:"Error",onPress:()=>a({type:"error"},"Forced error")}),(0,_jsxRuntime.jsx)(MassButton,{label:"Loading",onPress:()=>a({type:"hang"},"Forced loading")}),(0,_jsxRuntime.jsx)(MassButton,{label:"Blank",onPress:()=>a({type:"blank"},"Blanked")}),(0,_jsxRuntime.jsx)(MassButton,{label:"Reload",onPress:()=>{t("\u2026");(0,_actions.hardReloadAllMounted)().then(e=>t(e.message))}}),(0,_jsxRuntime.jsx)(MassButton,{label:"Find",onPress:()=>{const e=(0,_overrides.flashAllMounted)();t(`Flashing ${e} image${e===1?"":"s"} (2.5s)`)}}),(0,_jsxRuntime.jsx)(MassButton,{label:"Restore",accent:true,onPress:()=>{const e=(0,_overrides.clearAllOverrides)();t(e>0?`Restored ${e} image${e===1?"":"s"}`:"No overrides active")}})]}),(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.netLabel,children:"NET"}),NETWORK_MODES.map(e=>{const o=s===e.key;return(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:e.label,active:o,style:{paddingVertical:6},onPress:()=>{(0,_overrides.setNetworkMode)(e.key);t(e.key==="normal"?"Network simulation off \u2014 tap RELOAD to load normally again":e.key==="offline"?"Offline: network images FAIL (bundled assets still load) \u2014 tap RELOAD to apply to on-screen images":"Cold (bypass caches) \u2014 tap RELOAD: everything refetches like first launch")}},e.key)})]})]})}function MassButton({label:r,onPress:t,accent:s}){return(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:r,onPress:t,accent:s})}const styles=_reactNative.StyleSheet.create({netLabel:{color:_sharedUi.night.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.8,alignSelf:"center",marginRight:2}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImagesListFooter=ImagesListFooter;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _actions=require("../capture/actions");var _overrides=require("../capture/overrides");var _jsxRuntime=require("react/jsx-runtime");const NETWORK_MODES=[{key:"normal",label:"Normal"},{key:"offline",label:"Offline"},{key:"cold",label:"Cold"}];function ImagesListFooter(){const[s,t]=(0,_react.useState)(null);const o=(0,_react.useSyncExternalStore)(_actions.subscribeActions,()=>(0,_overrides.getGlobalModes)().network);const a=(e,r)=>{const n=(0,_overrides.setOverrideForAllMounted)(e,r);t(n>0?`${r} on ${n} image${n===1?"":"s"} \u2014 Restore all to undo`:"No mounted images")};return(0,_jsxRuntime.jsxs)(_sharedUi.ToolFooter,{paddingBottom:10,style:{paddingTop:8},children:[s?(0,_jsxRuntime.jsx)(_sharedUi.FooterMessage,{testID:"buoy-images-message",children:s}):(0,_jsxRuntime.jsx)(_sharedUi.FooterCaption,{children:"MASS ACTIONS \u2014 every image on screen"}),(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{children:[(0,_jsxRuntime.jsx)(MassButton,{label:"Error",onPress:()=>a({type:"error"},"Forced error")}),(0,_jsxRuntime.jsx)(MassButton,{label:"Loading",onPress:()=>a({type:"hang"},"Forced loading")}),(0,_jsxRuntime.jsx)(MassButton,{label:"Blank",onPress:()=>a({type:"blank"},"Blanked")}),(0,_jsxRuntime.jsx)(MassButton,{label:"Reload",onPress:()=>{t("\u2026");(0,_actions.hardReloadAllMounted)().then(e=>t(e.message))}}),(0,_jsxRuntime.jsx)(MassButton,{label:"Find",onPress:()=>{const e=(0,_overrides.flashAllMounted)();t(`Flashing ${e} image${e===1?"":"s"} (2.5s)`)}}),(0,_jsxRuntime.jsx)(MassButton,{label:"Restore",accent:true,onPress:()=>{const e=(0,_overrides.clearAllOverrides)();t(e>0?`Restored ${e} image${e===1?"":"s"}`:"No overrides active")}})]}),(0,_jsxRuntime.jsxs)(_sharedUi.FooterRow,{children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.netLabel,children:"NET"}),NETWORK_MODES.map(e=>{const r=o===e.key;return(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:e.label,active:r,testID:`buoy-images-net-${e.key}`,style:{paddingVertical:6},onPress:()=>{(0,_overrides.setNetworkMode)(e.key);t(e.key==="normal"?"Network simulation off \u2014 tap RELOAD to load normally again":e.key==="offline"?"Offline: network images FAIL (bundled assets still load) \u2014 tap RELOAD to apply to on-screen images":"Cold (bypass caches) \u2014 tap RELOAD: everything refetches like first launch")}},e.key)})]})]})}function MassButton({label:s,onPress:t,accent:o}){return(0,_jsxRuntime.jsx)(_sharedUi.FooterButton,{label:s,onPress:t,accent:o,testID:`buoy-images-mass-${s.toLowerCase()}`})}const styles=_reactNative.StyleSheet.create({netLabel:{color:_sharedUi.night.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.8,alignSelf:"center",marginRight:2}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImagesModal=ImagesModal;exports.ImagesToolView=ImagesToolView;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _install=require("../capture/install");var _overrides=require("../capture/overrides");var _export=require("../export");var _useImageRecords=require("../hooks/useImageRecords");var _remote=require("../remote");var _imageEventStore=require("../store/imageEventStore");var _ImageDetail=require("./ImageDetail");var _ImageDetailFooter=require("./ImageDetailFooter");var _ImageRow=require("./ImageRow");var _ImagesHeader=require("./ImagesHeader");var _ImagesListFooter=require("./ImagesListFooter");var _InsightsBar=require("./InsightsBar");var _insights=require("../store/insights");var _jsxRuntime=require("react/jsx-runtime");function CaptureNotice(){const r=(0,_install.getCaptureStatus)();const i=[];if(r.rnDecoratorTooLate){i.push('RN <Image> instrumentation missed the module-load race \u2014 add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.')}if(!r.browserObserverActive&&!r.expoAvailable&&!r.rnDecoratorActive&&!r.rnDecoratorTooLate){i.push("Waiting for images\u2026 render some <Image> components to populate the list.")}if(i.length===0)return null;return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.notice,children:i.map(n=>(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.noticeText,children:n},n))})}function EmptyState(){return(0,_jsxRuntime.jsx)(_sharedUi.ToolEmptyState,{testID:"buoy-images-empty",otto:"listening",title:"No images captured yet",message:"Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."})}function ImagesModal({visible:r,onClose:i,onBack:n,onMinimize:h,persistenceKey:x,inline:I=false}){(0,_install.installImageCapture)();const{records:o,stats:c}=(0,_useImageRecords.useImageRecords)();const[u,d]=(0,_react.useState)(null);const e=u!=null?(0,_imageEventStore.getRecord)(u):void 0;const l=e?.status==="error"&&e.errorHeaders==null?e.id:null;(0,_react.useEffect)(()=>{const t=(0,_remote.remoteImagesDispatch)();if(l==null||!t)return;let s=false;t("getDetail",{id:l}).then(f=>{if(s)return;const y=f?.errorHeaders;(0,_imageEventStore.updateRecord)(l,{errorHeaders:y??{}})}).catch(()=>{});return()=>{s=true}},[l]);const a=e?o.findIndex(t=>t.id===e.id):-1;const g=t=>{const s=o[t];if(s)d(s.id)};const v=()=>e?(0,_export.formatRecordMarkdown)(e):(0,_export.formatRegistryMarkdown)(o,c,(0,_insights.computeInsights)(o),(0,_install.getCaptureStatus)(),(0,_overrides.getGlobalModes)());const m=(0,_jsxRuntime.jsx)(_ImagesHeader.ImagesHeader,{stats:c,detailOpen:e!=null,detailIndex:a,detailTotal:o.length,onCloseDetail:()=>d(null),onClear:_imageEventStore.clearRecords,getReport:v,onBack:n});const p=e?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.detailContainer,children:[(0,_jsxRuntime.jsx)(_ImageDetail.ImageDetail,{record:e}),(0,_jsxRuntime.jsx)(_ImageDetailFooter.ImageDetailFooter,{record:e,hasPrevious:a>0,hasNext:a>=0&&a<o.length-1,onPrevious:()=>g(a-1),onNext:()=>g(a+1)},e.id)]}):(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.listContainer,children:[(0,_jsxRuntime.jsx)(_InsightsBar.InsightsBar,{insights:(0,_insights.computeInsights)(o)}),(0,_jsxRuntime.jsx)(CaptureNotice,{}),(0,_jsxRuntime.jsx)(_reactNative.FlatList,{data:o,keyExtractor:t=>String(t.id),renderItem:({item:t})=>(0,_jsxRuntime.jsx)(_ImageRow.ImageRow,{record:t,onPress:d}),ListEmptyComponent:(0,_jsxRuntime.jsx)(EmptyState,{})}),(0,_jsxRuntime.jsx)(_ImagesListFooter.ImagesListFooter,{})]});if(I){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRoot,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.inlineHeader,..._sharedUi.windowDragProps,children:m}),p]})}return(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:r,onClose:i,onMinimize:h,persistenceKey:x,header:{showToggleButton:true,customContent:m},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:p})}function ImagesToolView(r={}){return(0,_jsxRuntime.jsx)(ImagesModal,{...r,inline:true,visible:true,onClose:()=>{}})}const styles=_reactNative.StyleSheet.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:_sharedUi.macOSColors.border.default,backgroundColor:"transparent"},listContainer:{flex:1},detailContainer:{flex:1},notice:{margin:10,padding:10,borderRadius:8,backgroundColor:_sharedUi.night.color.warningSoft,gap:4},noticeText:{color:_sharedUi.night.color.warning,fontSize:11},empty:{alignItems:"center",padding:32,gap:8},emptyTitle:{color:_sharedUi.night.color.text,fontSize:13,fontWeight:"600"},emptyText:{color:_sharedUi.night.color.textSecondary,fontSize:11,textAlign:"center",lineHeight:16}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ImagesModal=ImagesModal;exports.ImagesToolView=ImagesToolView;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _install=require("../capture/install");var _overrides=require("../capture/overrides");var _export=require("../export");var _useImageRecords=require("../hooks/useImageRecords");var _remote=require("../remote");var _imageEventStore=require("../store/imageEventStore");var _ImageDetail=require("./ImageDetail");var _ImageDetailFooter=require("./ImageDetailFooter");var _ImageRow=require("./ImageRow");var _ImagesHeader=require("./ImagesHeader");var _ImagesListFooter=require("./ImagesListFooter");var _InsightsBar=require("./InsightsBar");var _insights=require("../store/insights");var _jsxRuntime=require("react/jsx-runtime");function CaptureNotice(){const r=(0,_install.getCaptureStatus)();const i=[];if(r.rnDecoratorTooLate){i.push('RN <Image> instrumentation missed the module-load race \u2014 add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.')}if(!r.browserObserverActive&&!r.expoAvailable&&!r.rnDecoratorActive&&!r.rnDecoratorTooLate){i.push("Waiting for images\u2026 render some <Image> components to populate the list.")}if(i.length===0)return null;return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.notice,children:i.map(n=>(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.noticeText,children:n},n))})}function EmptyState(){return(0,_jsxRuntime.jsx)(_sharedUi.ToolEmptyState,{testID:"buoy-images-empty",otto:"listening",title:"No images captured yet",message:"Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."})}function ImagesModal({visible:r,onClose:i,onBack:n,onMinimize:h,persistenceKey:x,inline:I=false}){(0,_install.installImageCapture)();const{records:o,stats:c}=(0,_useImageRecords.useImageRecords)();const[u,d]=(0,_react.useState)(null);const e=u!=null?(0,_imageEventStore.getRecord)(u):void 0;const l=e?.status==="error"&&e.errorHeaders==null?e.id:null;(0,_react.useEffect)(()=>{const t=(0,_remote.remoteImagesDispatch)();if(l==null||!t)return;let s=false;t("getDetail",{id:l}).then(f=>{if(s)return;const y=f?.errorHeaders;(0,_imageEventStore.updateRecord)(l,{errorHeaders:y??{}})}).catch(()=>{});return()=>{s=true}},[l]);const a=e?o.findIndex(t=>t.id===e.id):-1;const g=t=>{const s=o[t];if(s)d(s.id)};const v=()=>e?(0,_export.formatRecordMarkdown)(e):(0,_export.formatRegistryMarkdown)(o,c,(0,_insights.computeInsights)(o),(0,_install.getCaptureStatus)(),(0,_overrides.getGlobalModes)());const m=(0,_jsxRuntime.jsx)(_ImagesHeader.ImagesHeader,{stats:c,detailOpen:e!=null,detailIndex:a,detailTotal:o.length,onCloseDetail:()=>d(null),onClear:_imageEventStore.clearRecords,getReport:v,onBack:n});const p=e?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.detailContainer,children:[(0,_jsxRuntime.jsx)(_ImageDetail.ImageDetail,{record:e}),(0,_jsxRuntime.jsx)(_ImageDetailFooter.ImageDetailFooter,{record:e,hasPrevious:a>0,hasNext:a>=0&&a<o.length-1,onPrevious:()=>g(a-1),onNext:()=>g(a+1)},e.id)]}):(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.listContainer,children:[(0,_jsxRuntime.jsx)(_InsightsBar.InsightsBar,{insights:(0,_insights.computeInsights)(o)}),(0,_jsxRuntime.jsx)(CaptureNotice,{}),(0,_jsxRuntime.jsx)(_reactNative.FlatList,{testID:"buoy-images-list",data:o,keyExtractor:t=>String(t.id),renderItem:({item:t})=>(0,_jsxRuntime.jsx)(_ImageRow.ImageRow,{record:t,onPress:d}),ListEmptyComponent:(0,_jsxRuntime.jsx)(EmptyState,{})}),(0,_jsxRuntime.jsx)(_ImagesListFooter.ImagesListFooter,{})]});if(I){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRoot,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.inlineHeader,..._sharedUi.windowDragProps,children:m}),p]})}return(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:r,onClose:i,onMinimize:h,persistenceKey:x,header:{showToggleButton:true,customContent:m},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:p})}function ImagesToolView(r={}){return(0,_jsxRuntime.jsx)(ImagesModal,{...r,inline:true,visible:true,onClose:()=>{}})}const styles=_reactNative.StyleSheet.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:_sharedUi.macOSColors.border.default,backgroundColor:"transparent"},listContainer:{flex:1},detailContainer:{flex:1},notice:{margin:10,padding:10,borderRadius:8,backgroundColor:_sharedUi.night.color.warningSoft,gap:4},noticeText:{color:_sharedUi.night.color.warning,fontSize:11},empty:{alignItems:"center",padding:32,gap:8},emptyTitle:{color:_sharedUi.night.color.text,fontSize:13,fontWeight:"600"},emptyText:{color:_sharedUi.night.color.textSecondary,fontSize:11,textAlign:"center",lineHeight:16}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.InsightsBar=InsightsBar;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _insights=require("../store/insights");var _jsxRuntime=require("react/jsx-runtime");function InsightsBar({insights:t}){const e=(0,_insights.insightChips)(t);if(e.length===0)return null;return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.bar,children:e.map(r=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.chip,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.chipText,children:r})},r))})}const styles=_reactNative.StyleSheet.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8,borderBottomWidth:_reactNative.StyleSheet.hairlineWidth,borderBottomColor:_sharedUi.night.color.border},chip:{backgroundColor:_sharedUi.night.color.warningSoft,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{color:_sharedUi.night.color.warning,fontSize:10,fontWeight:"600",lineHeight:13}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.InsightsBar=InsightsBar;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _insights=require("../store/insights");var _jsxRuntime=require("react/jsx-runtime");function InsightsBar({insights:t}){const r=(0,_insights.insightChipEntries)(t);if(r.length===0)return null;return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.bar,children:r.map(e=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.chip,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.chipText,testID:`buoy-images-insight-${e.key}`,children:e.text})},e.key))})}const styles=_reactNative.StyleSheet.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8,borderBottomWidth:_reactNative.StyleSheet.hairlineWidth,borderBottomColor:_sharedUi.night.color.border},chip:{backgroundColor:_sharedUi.night.color.warningSoft,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{color:_sharedUi.night.color.warning,fontSize:10,fontWeight:"600",lineHeight:13}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.computeInsights=computeInsights;exports.insightChips=insightChips;const RETRY_STORM_THRESHOLD=5;const IOS_CONCURRENT_LOAD_LIMIT=4;function computeInsights(e){const u=new Map;const r=[];const s=[];let i=0;let l=0;for(const t of e){if(t.mounted&&t.uri){u.set(t.uri,(u.get(t.uri)??0)+1)}if(t.loadCount>=RETRY_STORM_THRESHOLD){r.push({id:t.id,uri:t.uri,loadCount:t.loadCount})}if((t.layoutShifts??0)>0){s.push({id:t.id,uri:t.uri,shifts:t.layoutShifts??0})}if(t.mounted&&t.hasAltText===false)i++;if(t.lib==="rn"&&t.mounted&&t.status==="loading")l++}const n=[...u.entries()].filter(([,t])=>t>1).map(([t,o])=>({uri:t,count:o})).sort((t,o)=>o.count-t.count);return{duplicates:n,retryStorms:r.sort((t,o)=>o.loadCount-t.loadCount),queueSaturated:l>IOS_CONCURRENT_LOAD_LIMIT,missingAlt:i,layoutShifters:s}}function insightChips(e){const u=[];if(e.duplicates.length>0){const r=e.duplicates.reduce((s,i)=>s+i.count-1,0);u.push(`${e.duplicates.length} duplicate URL${e.duplicates.length>1?"s":""} (${r} redundant loads)`)}if(e.retryStorms.length>0){u.push(`${e.retryStorms.length} retry storm${e.retryStorms.length>1?"s":""}`)}if(e.queueSaturated)u.push("iOS image queue saturated (>4 loading)");if(e.missingAlt>0)u.push(`${e.missingAlt} missing alt text`);if(e.layoutShifters.length>0){u.push(`${e.layoutShifters.length} layout-shifting image${e.layoutShifters.length>1?"s":""}`)}return u}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.computeInsights=computeInsights;exports.insightChipEntries=insightChipEntries;exports.insightChips=insightChips;const RETRY_STORM_THRESHOLD=5;const IOS_CONCURRENT_LOAD_LIMIT=4;function computeInsights(e){const u=new Map;const o=[];const s=[];let i=0;let n=0;for(const t of e){if(t.mounted&&t.uri){u.set(t.uri,(u.get(t.uri)??0)+1)}if(t.loadCount>=RETRY_STORM_THRESHOLD){o.push({id:t.id,uri:t.uri,loadCount:t.loadCount})}if((t.layoutShifts??0)>0){s.push({id:t.id,uri:t.uri,shifts:t.layoutShifts??0})}if(t.mounted&&t.hasAltText===false)i++;if(t.lib==="rn"&&t.mounted&&t.status==="loading")n++}const l=[...u.entries()].filter(([,t])=>t>1).map(([t,r])=>({uri:t,count:r})).sort((t,r)=>r.count-t.count);return{duplicates:l,retryStorms:o.sort((t,r)=>r.loadCount-t.loadCount),queueSaturated:n>IOS_CONCURRENT_LOAD_LIMIT,missingAlt:i,layoutShifters:s}}function insightChipEntries(e){const u=[];if(e.duplicates.length>0){const o=e.duplicates.reduce((s,i)=>s+i.count-1,0);u.push({key:"duplicates",text:`${e.duplicates.length} duplicate URL${e.duplicates.length>1?"s":""} (${o} redundant loads)`})}if(e.retryStorms.length>0){u.push({key:"retry",text:`${e.retryStorms.length} retry storm${e.retryStorms.length>1?"s":""}`})}if(e.queueSaturated)u.push({key:"queue",text:"iOS image queue saturated (>4 loading)"});if(e.missingAlt>0)u.push({key:"alt",text:`${e.missingAlt} missing alt text`});if(e.layoutShifters.length>0){u.push({key:"shift",text:`${e.layoutShifters.length} layout-shifting image${e.layoutShifters.length>1?"s":""}`})}return u}function insightChips(e){return insightChipEntries(e).map(u=>u.text)}
@@ -1 +1 @@
1
- "use strict";import{loadExpoImage as C}from"../capture/nativeImageModules";import{useState as f}from"react";import{Image as T,ScrollView as B,StyleSheet as v,Text as c,TextInput as z,TouchableOpacity as m,View as u}from"react-native";import{macOSColors as d,night as a,monoFont as $}from"@buoy-gg/shared-ui";import{clearOverride as k,setOverride as x}from"../capture/overrides";import{proveSavings as D}from"../capture/savings";import{remoteImagesDispatch as I}from"../remote";import{effectivePixelRatio as P,estDecodedBytes as A,estWastedBytes as O,neededPixels as E}from"../store/imageEventStore";import{cacheBadge as V,formatBytes as y,formatMs as w,sizeVerdict as L}from"../format";import{jsx as l,jsxs as r,Fragment as W}from"react/jsx-runtime";function p({title:e,children:n}){return r(u,{style:t.section,children:[l(c,{style:t.sectionTitle,children:e}),l(u,{style:t.sectionBody,children:n})]})}function i({label:e,value:n,color:s}){return r(u,{style:t.kvRow,children:[l(c,{style:t.kvLabel,children:e}),l(c,{style:[t.kvValue,s?{color:s}:null],selectable:true,children:n})]})}function S(e){const n=I();if(n){void n("clearExpoCaches",{memory:e==="memory",disk:e==="disk"});return}try{const s=C();if(e==="memory")void s.Image.clearMemoryCache();else void s.Image.clearDiskCache()}catch{}}function M({record:e}){const[n,s]=f(e.uri);const o=n.trim();const h=e.mounted&&o.length>0&&o!==e.uri;return r(p,{title:"SWAP SOURCE URL",children:[l(z,{style:t.urlInput,value:n,onChangeText:s,placeholder:"https://\u2026",placeholderTextColor:a.color.placeholder,autoCapitalize:"none",autoCorrect:false,multiline:true}),r(u,{style:t.actionsRow,children:[l(m,{style:[t.actionButton,!h&&t.actionDisabled],disabled:!h,onPress:()=>x(e.id,{source:{type:"url",uri:o},label:"URL swapped"}),children:l(c,{style:t.actionText,children:"Apply"})}),l(m,{style:t.actionButton,onPress:()=>s(e.uri),children:l(c,{style:t.actionText,children:"Reset field"})})]})]})}function U({record:e}){const[n,s]=f(false);const[o,h]=f(null);const b=()=>{s(true);D(e).then(h).catch(g=>h({ok:false,message:String(g?.message??g)})).finally(()=>s(false))};return l(p,{title:"PROVE SAVINGS (re-encode on device)",children:o==null?l(u,{style:t.actionsRow,children:l(m,{style:t.actionButton,onPress:b,disabled:n,children:l(c,{style:t.actionText,children:n?"Re-encoding\u2026":"Re-encode at displayed size (WebP)"})})}):r(W,{children:[l(i,{label:"Result",value:o.message||(o.ok?"done":"failed"),color:o.ok?d.semantic.success:d.semantic.error}),o.originalBytes!=null?l(i,{label:"Original",value:`${y(o.originalBytes)} (${o.originalBytesSource})`}):null,o.optimizedBytes!=null?l(i,{label:"Optimized",value:`${y(o.optimizedBytes)} \u2014 ${o.optimizedDims?.width}\xD7${o.optimizedDims?.height} WebP`,color:d.semantic.success}):null,o.savedBytes!=null?l(i,{label:"Saved",value:`${y(o.savedBytes)} (${o.savedPct}%)`,color:d.semantic.success}):null,r(u,{style:t.actionsRow,children:[o.ok&&o.optimizedUri&&e.mounted?l(m,{style:t.actionButton,onPress:()=>x(e.id,{source:{type:"url",uri:o.optimizedUri},label:"Optimized preview"}),children:l(c,{style:t.actionText,children:"Preview in place"})}):null,l(m,{style:t.actionButton,onPress:b,disabled:n,children:l(c,{style:t.actionText,children:n?"Re-encoding\u2026":"Re-run"})})]})]})})}export function ImageDetail({record:e}){const n=L(e);const s=V(e);const o=E(e);const h=A(e);const b=O(e);return r(B,{style:t.container,contentContainerStyle:t.content,children:[e.overrideLabel?r(u,{style:t.overrideBanner,children:[r(c,{style:t.overrideText,children:["Simulation active: ",e.overrideLabel," \u2014 stats below describe the override, not the original source."]}),l(m,{onPress:()=>k(e.id),children:l(c,{style:t.overrideRestore,children:"RESTORE"})})]}):null,e.uri&&e.sourceKind!=="data"?l(u,{style:t.previewBox,children:l(T,{testID:"buoy-internal-images-preview",source:{uri:e.uri},style:t.preview,resizeMode:"contain"})}):null,r(p,{title:"SOURCE",children:[l(i,{label:"URI",value:e.uri||"(none)"}),l(i,{label:"Kind",value:e.sourceKind}),l(i,{label:"Library",value:e.lib==="web"?"Browser <img>":e.lib==="expo"?"expo-image":"RN <Image>"}),e.hasAltText===false?l(i,{label:"Alt text",value:"missing \u2014 add alt/accessibilityLabel",color:d.semantic.warning}):null,e.mediaType!=null?l(i,{label:"Media type",value:String(e.mediaType)}):null,e.isAnimated!=null?l(i,{label:"Animated",value:e.isAnimated?"yes":"no"}):null]}),r(p,{title:"LOAD",children:[l(i,{label:"Status",value:e.status,color:e.status==="error"?d.semantic.error:e.status==="loaded"?d.semantic.success:d.semantic.warning}),l(i,{label:"Duration",value:w(e.durationMs)}),e.displayedAt&&e.loadedAt?l(i,{label:"Decode \u2192 display",value:w(Math.max(0,e.displayedAt-e.loadedAt))}):null,l(i,{label:"Cache",value:`${s.label}`,color:s.color}),e.cacheVerdictSource?l(i,{label:"Cache source",value:e.cacheVerdictSource==="event"?"reported by expo-image onLoad":"Image.queryCache after load"}):null,e.progressSeen?l(i,{label:"Downloaded",value:e.bytesTotal?`${y(e.bytesLoaded??0)} / ${y(e.bytesTotal)}`:"network transfer observed"}):null,l(i,{label:"Load cycles",value:String(e.loadCount)}),l(i,{label:"Still mounted",value:e.mounted?"yes":"no"})]}),r(p,{title:"DIMENSIONS",children:[e.intrinsic?l(i,{label:"Decoded",value:`${e.intrinsic.width}\xD7${e.intrinsic.height} px`}):l(i,{label:"Decoded",value:"unknown"}),e.layout?l(i,{label:"Displayed",value:`${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)} dp (needs ${o?`${o.width}\xD7${o.height}`:"?"} px @${Math.round(P()*100)/100}x)`}):l(i,{label:"Displayed",value:"no layout yet"}),n.label?l(i,{label:"Verdict",value:n.label,color:n.color}):null,h>0?l(i,{label:"Est. decoded memory",value:y(h)}):null,b>0?l(i,{label:"Est. wasted",value:`${y(b)} \u2014 resize the source to ${o?`${o.width}\xD7${o.height}`:"the displayed size"}`,color:d.semantic.warning}):null,(e.layoutShifts??0)>0?l(i,{label:"Layout shifts",value:`${e.layoutShifts} \u2014 box resized after load; reserve explicit width/height`,color:d.semantic.warning}):null]}),e.sourceKind==="network"||e.sourceKind==="asset"?l(U,{record:e},`savings-${e.id}`):null,e.status==="error"?r(p,{title:"ERROR",children:[l(i,{label:"Message",value:e.error??"unknown",color:d.semantic.error}),e.errorCode!=null?l(i,{label:"HTTP status",value:String(e.errorCode)}):null,e.errorHeaders?Object.entries(e.errorHeaders).map(([g,R])=>l(i,{label:g,value:String(R)},g)):null]}):null,e.sourceKind==="network"&&e.mounted?l(M,{record:e},e.id):null,e.lib==="expo"?l(p,{title:"CACHE ACTIONS (expo-image, global)",children:r(u,{style:t.actionsRow,children:[l(m,{style:t.actionButton,onPress:()=>S("memory"),children:l(c,{style:t.actionText,children:"Clear memory cache"})}),l(m,{style:t.actionButton,onPress:()=>S("disk"),children:l(c,{style:t.actionText,children:"Clear disk cache"})})]})}):null]})}const t=v.create({container:{flex:1},content:{padding:12,gap:12},previewBox:{height:140,borderRadius:8,backgroundColor:a.color.bg,overflow:"hidden"},preview:{width:"100%",height:"100%"},section:{gap:6},sectionTitle:{color:a.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.8},sectionBody:{backgroundColor:a.color.surface,borderRadius:8,borderWidth:v.hairlineWidth,borderColor:a.color.border,paddingHorizontal:10,paddingVertical:4},kvRow:{flexDirection:"row",paddingVertical:5,gap:12},kvLabel:{color:a.color.textSecondary,fontSize:11,width:110},kvValue:{color:a.color.text,fontSize:11,flex:1},actionsRow:{flexDirection:"row",gap:8,paddingVertical:8},actionButton:{backgroundColor:a.color.surfaceElevated,borderRadius:6,paddingHorizontal:10,paddingVertical:6,borderWidth:v.hairlineWidth,borderColor:a.color.border},actionText:{color:a.color.text,fontSize:11,fontWeight:"600"},actionDisabled:{opacity:.4},urlInput:{color:a.color.text,fontSize:11,fontFamily:$,backgroundColor:a.color.surfaceElevated,borderRadius:6,borderWidth:v.hairlineWidth,borderColor:a.color.border,paddingHorizontal:8,paddingVertical:6,marginTop:8},overrideBanner:{flexDirection:"row",alignItems:"center",gap:10,padding:10,borderRadius:8,backgroundColor:a.color.warningSoft},overrideText:{flex:1,color:a.color.warning,fontSize:11,lineHeight:15},overrideRestore:{color:a.color.warning,fontSize:11,fontWeight:"700",letterSpacing:.5}});
1
+ "use strict";import{loadExpoImage as C}from"../capture/nativeImageModules";import{useState as f}from"react";import{Image as T,ScrollView as B,StyleSheet as v,Text as c,TextInput as z,TouchableOpacity as m,View as u}from"react-native";import{macOSColors as d,night as n,monoFont as $}from"@buoy-gg/shared-ui";import{clearOverride as D,setOverride as w}from"../capture/overrides";import{proveSavings as k}from"../capture/savings";import{remoteImagesDispatch as I}from"../remote";import{effectivePixelRatio as P,estDecodedBytes as A,estWastedBytes as O,neededPixels as E}from"../store/imageEventStore";import{cacheBadge as V,formatBytes as y,formatMs as x,sizeVerdict as L}from"../format";import{jsx as t,jsxs as r,Fragment as W}from"react/jsx-runtime";function p({title:e,children:a}){return r(u,{style:l.section,children:[t(c,{style:l.sectionTitle,children:e}),t(u,{style:l.sectionBody,children:a})]})}function M(e){return`buoy-images-detail-${e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}`}function i({label:e,value:a,color:s}){return r(u,{style:l.kvRow,children:[t(c,{style:l.kvLabel,children:e}),t(c,{testID:M(e),style:[l.kvValue,s?{color:s}:null],selectable:true,children:a})]})}function S(e){const a=I();if(a){void a("clearExpoCaches",{memory:e==="memory",disk:e==="disk"});return}try{const s=C();if(e==="memory")void s.Image.clearMemoryCache();else void s.Image.clearDiskCache()}catch{}}function U({record:e}){const[a,s]=f(e.uri);const o=a.trim();const h=e.mounted&&o.length>0&&o!==e.uri;return r(p,{title:"SWAP SOURCE URL",children:[t(z,{style:l.urlInput,value:a,onChangeText:s,placeholder:"https://\u2026",placeholderTextColor:n.color.placeholder,autoCapitalize:"none",autoCorrect:false,multiline:true}),r(u,{style:l.actionsRow,children:[t(m,{style:[l.actionButton,!h&&l.actionDisabled],disabled:!h,onPress:()=>w(e.id,{source:{type:"url",uri:o},label:"URL swapped"}),children:t(c,{style:l.actionText,children:"Apply"})}),t(m,{style:l.actionButton,onPress:()=>s(e.uri),children:t(c,{style:l.actionText,children:"Reset field"})})]})]})}function H({record:e}){const[a,s]=f(false);const[o,h]=f(null);const g=()=>{s(true);k(e).then(h).catch(b=>h({ok:false,message:String(b?.message??b)})).finally(()=>s(false))};return t(p,{title:"PROVE SAVINGS (re-encode on device)",children:o==null?t(u,{style:l.actionsRow,children:t(m,{style:l.actionButton,onPress:g,disabled:a,children:t(c,{style:l.actionText,children:a?"Re-encoding\u2026":"Re-encode at displayed size (WebP)"})})}):r(W,{children:[t(i,{label:"Result",value:o.message||(o.ok?"done":"failed"),color:o.ok?d.semantic.success:d.semantic.error}),o.originalBytes!=null?t(i,{label:"Original",value:`${y(o.originalBytes)} (${o.originalBytesSource})`}):null,o.optimizedBytes!=null?t(i,{label:"Optimized",value:`${y(o.optimizedBytes)} \u2014 ${o.optimizedDims?.width}\xD7${o.optimizedDims?.height} WebP`,color:d.semantic.success}):null,o.savedBytes!=null?t(i,{label:"Saved",value:`${y(o.savedBytes)} (${o.savedPct}%)`,color:d.semantic.success}):null,r(u,{style:l.actionsRow,children:[o.ok&&o.optimizedUri&&e.mounted?t(m,{style:l.actionButton,onPress:()=>w(e.id,{source:{type:"url",uri:o.optimizedUri},label:"Optimized preview"}),children:t(c,{style:l.actionText,children:"Preview in place"})}):null,t(m,{style:l.actionButton,onPress:g,disabled:a,children:t(c,{style:l.actionText,children:a?"Re-encoding\u2026":"Re-run"})})]})]})})}export function ImageDetail({record:e}){const a=L(e);const s=V(e);const o=E(e);const h=A(e);const g=O(e);return r(B,{style:l.container,contentContainerStyle:l.content,children:[e.overrideLabel?r(u,{style:l.overrideBanner,children:[r(c,{style:l.overrideText,children:["Simulation active: ",e.overrideLabel," \u2014 stats below describe the override, not the original source."]}),t(m,{onPress:()=>D(e.id),children:t(c,{style:l.overrideRestore,children:"RESTORE"})})]}):null,e.uri&&e.sourceKind!=="data"?t(u,{style:l.previewBox,children:t(T,{testID:"buoy-internal-images-preview",source:{uri:e.uri},style:l.preview,resizeMode:"contain"})}):null,r(p,{title:"SOURCE",children:[t(i,{label:"URI",value:e.uri||"(none)"}),t(i,{label:"Kind",value:e.sourceKind}),t(i,{label:"Library",value:e.lib==="web"?"Browser <img>":e.lib==="expo"?"expo-image":"RN <Image>"}),e.hasAltText===false?t(i,{label:"Alt text",value:"missing \u2014 add alt/accessibilityLabel",color:d.semantic.warning}):null,e.mediaType!=null?t(i,{label:"Media type",value:String(e.mediaType)}):null,e.isAnimated!=null?t(i,{label:"Animated",value:e.isAnimated?"yes":"no"}):null]}),r(p,{title:"LOAD",children:[t(i,{label:"Status",value:e.status,color:e.status==="error"?d.semantic.error:e.status==="loaded"?d.semantic.success:d.semantic.warning}),t(i,{label:"Duration",value:x(e.durationMs)}),e.displayedAt&&e.loadedAt?t(i,{label:"Decode \u2192 display",value:x(Math.max(0,e.displayedAt-e.loadedAt))}):null,t(i,{label:"Cache",value:`${s.label}`,color:s.color}),e.cacheVerdictSource?t(i,{label:"Cache source",value:e.cacheVerdictSource==="event"?"reported by expo-image onLoad":"Image.queryCache after load"}):null,e.progressSeen?t(i,{label:"Downloaded",value:e.bytesTotal?`${y(e.bytesLoaded??0)} / ${y(e.bytesTotal)}`:"network transfer observed"}):null,t(i,{label:"Load cycles",value:String(e.loadCount)}),t(i,{label:"Still mounted",value:e.mounted?"yes":"no"})]}),r(p,{title:"DIMENSIONS",children:[e.intrinsic?t(i,{label:"Decoded",value:`${e.intrinsic.width}\xD7${e.intrinsic.height} px`}):t(i,{label:"Decoded",value:"unknown"}),e.layout?t(i,{label:"Displayed",value:`${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)} dp (needs ${o?`${o.width}\xD7${o.height}`:"?"} px @${Math.round(P()*100)/100}x)`}):t(i,{label:"Displayed",value:"no layout yet"}),a.label?t(i,{label:"Verdict",value:a.label,color:a.color}):null,h>0?t(i,{label:"Est. decoded memory",value:y(h)}):null,g>0?t(i,{label:"Est. wasted",value:`${y(g)} \u2014 resize the source to ${o?`${o.width}\xD7${o.height}`:"the displayed size"}`,color:d.semantic.warning}):null,(e.layoutShifts??0)>0?t(i,{label:"Layout shifts",value:`${e.layoutShifts} \u2014 box resized after load; reserve explicit width/height`,color:d.semantic.warning}):null]}),e.sourceKind==="network"||e.sourceKind==="asset"?t(H,{record:e},`savings-${e.id}`):null,e.status==="error"?r(p,{title:"ERROR",children:[t(i,{label:"Message",value:e.error??"unknown",color:d.semantic.error}),e.errorCode!=null?t(i,{label:"HTTP status",value:String(e.errorCode)}):null,e.errorHeaders?Object.entries(e.errorHeaders).map(([b,R])=>t(i,{label:b,value:String(R)},b)):null]}):null,e.sourceKind==="network"&&e.mounted?t(U,{record:e},e.id):null,e.lib==="expo"?t(p,{title:"CACHE ACTIONS (expo-image, global)",children:r(u,{style:l.actionsRow,children:[t(m,{style:l.actionButton,onPress:()=>S("memory"),children:t(c,{style:l.actionText,children:"Clear memory cache"})}),t(m,{style:l.actionButton,onPress:()=>S("disk"),children:t(c,{style:l.actionText,children:"Clear disk cache"})})]})}):null]})}const l=v.create({container:{flex:1},content:{padding:12,gap:12},previewBox:{height:140,borderRadius:8,backgroundColor:n.color.bg,overflow:"hidden"},preview:{width:"100%",height:"100%"},section:{gap:6},sectionTitle:{color:n.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.8},sectionBody:{backgroundColor:n.color.surface,borderRadius:8,borderWidth:v.hairlineWidth,borderColor:n.color.border,paddingHorizontal:10,paddingVertical:4},kvRow:{flexDirection:"row",paddingVertical:5,gap:12},kvLabel:{color:n.color.textSecondary,fontSize:11,width:110},kvValue:{color:n.color.text,fontSize:11,flex:1},actionsRow:{flexDirection:"row",gap:8,paddingVertical:8},actionButton:{backgroundColor:n.color.surfaceElevated,borderRadius:6,paddingHorizontal:10,paddingVertical:6,borderWidth:v.hairlineWidth,borderColor:n.color.border},actionText:{color:n.color.text,fontSize:11,fontWeight:"600"},actionDisabled:{opacity:.4},urlInput:{color:n.color.text,fontSize:11,fontFamily:$,backgroundColor:n.color.surfaceElevated,borderRadius:6,borderWidth:v.hairlineWidth,borderColor:n.color.border,paddingHorizontal:8,paddingVertical:6,marginTop:8},overrideBanner:{flexDirection:"row",alignItems:"center",gap:10,padding:10,borderRadius:8,backgroundColor:n.color.warningSoft},overrideText:{flex:1,color:n.color.warning,fontSize:11,lineHeight:15},overrideRestore:{color:n.color.warning,fontSize:11,fontWeight:"700",letterSpacing:.5}});
@@ -1 +1 @@
1
- "use strict";import{useState as P}from"react";import{StyleSheet as x,TouchableOpacity as h}from"react-native";import{ChevronLeft as B,ChevronRight as z,FooterButton as u,FooterMessage as f,FooterRow as v,RefreshCw as O,ToolFooter as j,night as s}from"@buoy-gg/shared-ui";import{hardReloadRecord as C,retryRecord as L}from"../capture/actions";import{clearOverride as S,flashRecord as T,setOverride as k}from"../capture/overrides";import{jsx as e,jsxs as g}from"react/jsx-runtime";export function ImageDetailFooter({record:t,hasPrevious:i,hasNext:n,onPrevious:c,onNext:R}){const[y,a]=P(null);const p=m=>{a("\u2026");m().then(r=>a(r.message)).catch(r=>a(String(r?.message??r)))};const o=!t.mounted;const F=t.overrideLabel!=null;const b=(m,r)=>{k(t.id,{source:m,label:r});a(`${r} \u2014 Restore to undo`)};return g(j,{children:[y?e(f,{children:y}):o?e(f,{tone:"muted",children:"Instance unmounted \u2014 reload actions need the image on screen."}):null,g(v,{style:{gap:8},children:[e(h,{onPress:c,disabled:!i,style:[d.navButton,!i&&d.disabled],activeOpacity:.7,accessibilityLabel:"Previous image",children:e(B,{size:20,color:i?s.color.accent:s.color.textTertiary})}),e(u,{label:"Hard reload",size:"md",disabled:o,icon:e(O,{size:13,color:o?s.color.textTertiary:s.color.info}),onPress:()=>p(()=>C(t))}),e(u,{label:t.status==="error"?"Retry":"Reload",size:"md",disabled:o,onPress:()=>p(()=>L(t))}),e(h,{onPress:R,disabled:!n,style:[d.navButton,!n&&d.disabled],activeOpacity:.7,accessibilityLabel:"Next image",children:e(z,{size:20,color:n?s.color.accent:s.color.textTertiary})})]}),g(v,{style:{gap:8},children:[e(l,{label:"Error",disabled:o,onPress:()=>b({type:"error"},"Forced error")}),e(l,{label:"Loading",disabled:o,onPress:()=>b({type:"hang"},"Forced loading")}),e(l,{label:"Blank",disabled:o,onPress:()=>b({type:"blank"},"Blanked")}),e(l,{label:"Find",disabled:o,onPress:()=>{T(t.id);a("Flashing a red border on the image (2.5s)")}}),e(l,{label:"Restore",accent:true,disabled:!F,onPress:()=>{S(t.id);a("Override removed \u2014 original source restored")}})]})]})}function l({label:t,onPress:i,disabled:n,accent:c}){return e(u,{label:t,onPress:i,disabled:n,accent:c,style:{paddingVertical:7}})}const d=x.create({navButton:{paddingHorizontal:10,paddingVertical:8,borderRadius:6,backgroundColor:s.color.button,alignItems:"center",justifyContent:"center"},disabled:{opacity:.4}});
1
+ "use strict";import{useState as I}from"react";import{StyleSheet as P,TouchableOpacity as h}from"react-native";import{ChevronLeft as x,ChevronRight as D,FooterButton as u,FooterMessage as f,FooterRow as v,RefreshCw as B,ToolFooter as z,night as r}from"@buoy-gg/shared-ui";import{hardReloadRecord as C,retryRecord as L}from"../capture/actions";import{clearOverride as O,flashRecord as j,setOverride as S}from"../capture/overrides";import{jsx as e,jsxs as g}from"react/jsx-runtime";export function ImageDetailFooter({record:t,hasPrevious:i,hasNext:l,onPrevious:c,onNext:R}){const[y,a]=I(null);const p=m=>{a("\u2026");m().then(s=>a(s.message)).catch(s=>a(String(s?.message??s)))};const o=!t.mounted;const F=t.overrideLabel!=null;const b=(m,s)=>{S(t.id,{source:m,label:s});a(`${s} \u2014 Restore to undo`)};return g(z,{children:[y?e(f,{testID:"buoy-images-detail-footer-message",children:y}):o?e(f,{tone:"muted",children:"Instance unmounted \u2014 reload actions need the image on screen."}):null,g(v,{style:{gap:8},children:[e(h,{onPress:c,disabled:!i,style:[d.navButton,!i&&d.disabled],activeOpacity:.7,testID:"buoy-images-detail-previous",accessibilityLabel:"Previous image",children:e(x,{size:20,color:i?r.color.accent:r.color.textTertiary})}),e(u,{label:"Hard reload",size:"md",testID:"buoy-images-detail-hard-reload",disabled:o,icon:e(B,{size:13,color:o?r.color.textTertiary:r.color.info}),onPress:()=>p(()=>C(t))}),e(u,{label:t.status==="error"?"Retry":"Reload",size:"md",testID:"buoy-images-detail-reload",disabled:o,onPress:()=>p(()=>L(t))}),e(h,{onPress:R,disabled:!l,style:[d.navButton,!l&&d.disabled],activeOpacity:.7,testID:"buoy-images-detail-next",accessibilityLabel:"Next image",children:e(D,{size:20,color:l?r.color.accent:r.color.textTertiary})})]}),g(v,{style:{gap:8},children:[e(n,{label:"Error",disabled:o,onPress:()=>b({type:"error"},"Forced error")}),e(n,{label:"Loading",disabled:o,onPress:()=>b({type:"hang"},"Forced loading")}),e(n,{label:"Blank",disabled:o,onPress:()=>b({type:"blank"},"Blanked")}),e(n,{label:"Find",disabled:o,onPress:()=>{j(t.id);a("Flashing a red border on the image (2.5s)")}}),e(n,{label:"Restore",accent:true,disabled:!F,onPress:()=>{O(t.id);a("Override removed \u2014 original source restored")}})]})]})}function n({label:t,onPress:i,disabled:l,accent:c}){return e(u,{label:t,onPress:i,disabled:l,accent:c,testID:`buoy-images-sim-${t.toLowerCase()}`,style:{paddingVertical:7}})}const d=P.create({navButton:{paddingHorizontal:10,paddingVertical:8,borderRadius:6,backgroundColor:r.color.button,alignItems:"center",justifyContent:"center"},disabled:{opacity:.4}});
@@ -1 +1 @@
1
- "use strict";import{Image as b,StyleSheet as h,Text as l,TouchableOpacity as d,View as r}from"react-native";import{macOSColors as g,night as o,Pill as s}from"@buoy-gg/shared-ui";import{cacheBadge as f,formatMs as y,sizeVerdict as x,statusColor as w,uriTail as p}from"../format";import{jsx as i,jsxs as n}from"react/jsx-runtime";export function ImageRow({record:t,onPress:m}){const a=x(t);const c=f(t);const u=t.sourceKind==="network"||t.sourceKind==="asset"||t.sourceKind==="file";return n(d,{style:e.row,testID:`buoy-image-row-${t.id}`,onPress:()=>m(t.id),children:[n(r,{style:e.thumbBox,children:[u&&t.uri?i(b,{testID:"buoy-internal-images-thumb",source:{uri:t.uri},style:e.thumb,resizeMode:"cover"}):i(l,{style:e.thumbFallback,children:"?"}),i(r,{style:[e.statusDot,{backgroundColor:w(t)}]})]}),n(r,{style:e.main,children:[i(l,{style:e.name,numberOfLines:1,children:p(t.uri)}),n(r,{style:e.metaRow,children:[i(s,{variant:"text",label:t.lib==="web"?"WEB":t.lib==="expo"?"EXPO":"RN",color:o.color.textTertiary}),i(s,{variant:"text",label:c.label,color:c.color}),t.overrideLabel?i(s,{variant:"text",label:"SIM",color:o.color.warning}):null,i(l,{style:e.meta,children:y(t.durationMs)}),t.intrinsic?n(l,{style:e.meta,children:[t.intrinsic.width,"\xD7",t.intrinsic.height]}):null]})]}),i(r,{style:e.right,children:t.status==="error"?i(l,{style:[e.verdict,{color:g.semantic.error}],children:"FAILED"}):a.label?i(l,{style:[e.verdict,{color:a.color}],children:a.label}):null})]})}const e=h.create({row:{flexDirection:"row",alignItems:"center",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:h.hairlineWidth,borderBottomColor:o.color.border,gap:10},thumbBox:{width:40,height:40,borderRadius:6,backgroundColor:o.color.bg,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:40,height:40},thumbFallback:{color:o.color.textTertiary,fontSize:16,fontWeight:"700"},statusDot:{position:"absolute",right:2,bottom:2,width:8,height:8,borderRadius:4,borderWidth:1,borderColor:o.color.bg},main:{flex:1,gap:2},name:{color:o.color.text,fontSize:12,fontWeight:"600"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:o.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end"},verdict:{fontSize:10,fontWeight:"700"}});
1
+ "use strict";import{Image as d,StyleSheet as m,Text as r,TouchableOpacity as g,View as s}from"react-native";import{macOSColors as y,night as l,Pill as c}from"@buoy-gg/shared-ui";import{cacheBadge as f,formatMs as x,sizeVerdict as w,statusColor as I,uriTail as D}from"../format";import{jsx as i,jsxs as n}from"react/jsx-runtime";export function ImageRow({record:t,onPress:u}){const a=w(t);const h=f(t);const b=t.sourceKind==="network"||t.sourceKind==="asset"||t.sourceKind==="file";const o=`buoy-image-row-${t.id}`;return n(g,{style:e.row,testID:o,onPress:()=>u(t.id),children:[n(s,{style:e.thumbBox,children:[b&&t.uri?i(d,{testID:"buoy-internal-images-thumb",source:{uri:t.uri},style:e.thumb,resizeMode:"cover"}):i(r,{style:e.thumbFallback,children:"?"}),i(s,{testID:`${o}-status`,accessibilityLabel:t.status,style:[e.statusDot,{backgroundColor:I(t)}]})]}),n(s,{style:e.main,children:[i(r,{style:e.name,numberOfLines:1,testID:`${o}-name`,children:D(t.uri)}),n(s,{style:e.metaRow,children:[i(c,{variant:"text",label:t.lib==="web"?"WEB":t.lib==="expo"?"EXPO":"RN",color:l.color.textTertiary}),i(c,{variant:"text",label:h.label,color:h.color,testID:`${o}-cache`}),t.overrideLabel?i(c,{variant:"text",label:"SIM",color:l.color.warning,testID:`${o}-sim`}):null,i(r,{style:e.meta,children:x(t.durationMs)}),t.intrinsic?n(r,{style:e.meta,testID:`${o}-size`,children:[t.intrinsic.width,"\xD7",t.intrinsic.height]}):null]})]}),i(s,{style:e.right,children:t.status==="error"?i(r,{testID:`${o}-verdict`,style:[e.verdict,{color:y.semantic.error}],children:"FAILED"}):a.label?i(r,{testID:`${o}-verdict`,style:[e.verdict,{color:a.color}],children:a.label}):null})]})}const e=m.create({row:{flexDirection:"row",alignItems:"center",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:m.hairlineWidth,borderBottomColor:l.color.border,gap:10},thumbBox:{width:40,height:40,borderRadius:6,backgroundColor:l.color.bg,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:40,height:40},thumbFallback:{color:l.color.textTertiary,fontSize:16,fontWeight:"700"},statusDot:{position:"absolute",right:2,bottom:2,width:8,height:8,borderRadius:4,borderWidth:1,borderColor:l.color.bg},main:{flex:1,gap:2},name:{color:l.color.text,fontSize:12,fontWeight:"600"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:l.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end"},verdict:{fontSize:10,fontWeight:"700"}});
@@ -1 +1 @@
1
- "use strict";import{ModalHeader as e,ToolbarClearButton as $,ToolbarCopyButton as d}from"@buoy-gg/shared-ui";import{formatBytes as u}from"../format";import{jsx as t,jsxs as r}from"react/jsx-runtime";export function ImagesHeader({stats:o,detailOpen:c,detailIndex:s=-1,detailTotal:n=0,onCloseDetail:m,onClear:f,getReport:i,onBack:a}){if(c){const B=s>=0&&n>0?`${s+1} of ${n}`:void 0;return r(e,{children:[t(e.Navigation,{onBack:m}),t(e.Content,{title:"Image detail",subtitle:B}),t(e.Actions,{children:t(d,{value:i})})]})}const l=[`${o.total} images`,`${o.errors} failed`,`\u2248${u(o.estDecodedBytes)} decoded`];if(o.estWastedBytes>0){l.push(`${u(o.estWastedBytes)} wasted`)}return r(e,{children:[a?t(e.Navigation,{onBack:a}):null,t(e.Content,{title:"Images",subtitle:l.join(" \xB7 ")}),r(e.Actions,{children:[t(d,{value:i}),t($,{onPress:f})]})]})}
1
+ "use strict";import{ModalHeader as e,ToolbarClearButton as g,ToolbarCopyButton as u}from"@buoy-gg/shared-ui";import{formatBytes as d}from"../format";import{jsx as t,jsxs as s}from"react/jsx-runtime";export function ImagesHeader({stats:o,detailOpen:c,detailIndex:i=-1,detailTotal:r=0,onCloseDetail:m,onClear:f,getReport:n,onBack:a}){if(c){const b=i>=0&&r>0?`${i+1} of ${r}`:void 0;return s(e,{children:[t(e.Navigation,{onBack:m}),t(e.Content,{title:"Image detail",subtitle:b,testID:"buoy-images-detail-title"}),t(e.Actions,{children:t(u,{value:n})})]})}const l=[`${o.total} images`,`${o.errors} failed`,`\u2248${d(o.estDecodedBytes)} decoded`];if(o.estWastedBytes>0){l.push(`${d(o.estWastedBytes)} wasted`)}return s(e,{children:[a?t(e.Navigation,{onBack:a}):null,t(e.Content,{title:"Images",subtitle:l.join(" \xB7 "),testID:"buoy-images-title"}),s(e.Actions,{children:[t(u,{value:n}),t(g,{onPress:f,testID:"buoy-images-clear"})]})]})}
@@ -1 +1 @@
1
- "use strict";import{useState as m,useSyncExternalStore as u}from"react";import{StyleSheet as f,Text as p}from"react-native";import{FooterButton as d,FooterCaption as y,FooterMessage as b,FooterRow as g,ToolFooter as h,night as k}from"@buoy-gg/shared-ui";import{hardReloadAllMounted as F,subscribeActions as S}from"../capture/actions";import{clearAllOverrides as A,flashAllMounted as O,getGlobalModes as R,setNetworkMode as M,setOverrideForAllMounted as v}from"../capture/overrides";import{jsx as o,jsxs as c}from"react/jsx-runtime";const x=[{key:"normal",label:"Normal"},{key:"offline",label:"Offline"},{key:"cold",label:"Cold"}];export function ImagesListFooter(){const[s,t]=m(null);const l=u(S,()=>R().network);const a=(e,n)=>{const i=v(e,n);t(i>0?`${n} on ${i} image${i===1?"":"s"} \u2014 Restore all to undo`:"No mounted images")};return c(h,{paddingBottom:10,style:{paddingTop:8},children:[s?o(b,{children:s}):o(y,{children:"MASS ACTIONS \u2014 every image on screen"}),c(g,{children:[o(r,{label:"Error",onPress:()=>a({type:"error"},"Forced error")}),o(r,{label:"Loading",onPress:()=>a({type:"hang"},"Forced loading")}),o(r,{label:"Blank",onPress:()=>a({type:"blank"},"Blanked")}),o(r,{label:"Reload",onPress:()=>{t("\u2026");F().then(e=>t(e.message))}}),o(r,{label:"Find",onPress:()=>{const e=O();t(`Flashing ${e} image${e===1?"":"s"} (2.5s)`)}}),o(r,{label:"Restore",accent:true,onPress:()=>{const e=A();t(e>0?`Restored ${e} image${e===1?"":"s"}`:"No overrides active")}})]}),c(g,{children:[o(p,{style:E.netLabel,children:"NET"}),x.map(e=>{const n=l===e.key;return o(d,{label:e.label,active:n,style:{paddingVertical:6},onPress:()=>{M(e.key);t(e.key==="normal"?"Network simulation off \u2014 tap RELOAD to load normally again":e.key==="offline"?"Offline: network images FAIL (bundled assets still load) \u2014 tap RELOAD to apply to on-screen images":"Cold (bypass caches) \u2014 tap RELOAD: everything refetches like first launch")}},e.key)})]})]})}function r({label:s,onPress:t,accent:l}){return o(d,{label:s,onPress:t,accent:l})}const E=f.create({netLabel:{color:k.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.8,alignSelf:"center",marginRight:2}});
1
+ "use strict";import{useState as m,useSyncExternalStore as u}from"react";import{StyleSheet as y,Text as f}from"react-native";import{FooterButton as d,FooterCaption as p,FooterMessage as b,FooterRow as g,ToolFooter as h,night as k}from"@buoy-gg/shared-ui";import{hardReloadAllMounted as F,subscribeActions as S}from"../capture/actions";import{clearAllOverrides as A,flashAllMounted as O,getGlobalModes as R,setNetworkMode as M,setOverrideForAllMounted as v}from"../capture/overrides";import{jsx as t,jsxs as c}from"react/jsx-runtime";const L=[{key:"normal",label:"Normal"},{key:"offline",label:"Offline"},{key:"cold",label:"Cold"}];export function ImagesListFooter(){const[r,o]=m(null);const l=u(S,()=>R().network);const a=(e,n)=>{const i=v(e,n);o(i>0?`${n} on ${i} image${i===1?"":"s"} \u2014 Restore all to undo`:"No mounted images")};return c(h,{paddingBottom:10,style:{paddingTop:8},children:[r?t(b,{testID:"buoy-images-message",children:r}):t(p,{children:"MASS ACTIONS \u2014 every image on screen"}),c(g,{children:[t(s,{label:"Error",onPress:()=>a({type:"error"},"Forced error")}),t(s,{label:"Loading",onPress:()=>a({type:"hang"},"Forced loading")}),t(s,{label:"Blank",onPress:()=>a({type:"blank"},"Blanked")}),t(s,{label:"Reload",onPress:()=>{o("\u2026");F().then(e=>o(e.message))}}),t(s,{label:"Find",onPress:()=>{const e=O();o(`Flashing ${e} image${e===1?"":"s"} (2.5s)`)}}),t(s,{label:"Restore",accent:true,onPress:()=>{const e=A();o(e>0?`Restored ${e} image${e===1?"":"s"}`:"No overrides active")}})]}),c(g,{children:[t(f,{style:$.netLabel,children:"NET"}),L.map(e=>{const n=l===e.key;return t(d,{label:e.label,active:n,testID:`buoy-images-net-${e.key}`,style:{paddingVertical:6},onPress:()=>{M(e.key);o(e.key==="normal"?"Network simulation off \u2014 tap RELOAD to load normally again":e.key==="offline"?"Offline: network images FAIL (bundled assets still load) \u2014 tap RELOAD to apply to on-screen images":"Cold (bypass caches) \u2014 tap RELOAD: everything refetches like first launch")}},e.key)})]})]})}function s({label:r,onPress:o,accent:l}){return t(d,{label:r,onPress:o,accent:l,testID:`buoy-images-mass-${r.toLowerCase()}`})}const $=y.create({netLabel:{color:k.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.8,alignSelf:"center",marginRight:2}});
@@ -1 +1 @@
1
- "use strict";import{useEffect as H,useState as k}from"react";import{FlatList as M,StyleSheet as z,Text as E,View as d}from"react-native";import{JsModal as N,macOSColors as B,night as g,windowDragProps as F,ToolEmptyState as L}from"@buoy-gg/shared-ui";import{getCaptureStatus as b,installImageCapture as P}from"../capture/install";import{getGlobalModes as j}from"../capture/overrides";import{formatRecordMarkdown as A,formatRegistryMarkdown as W}from"../export";import{useImageRecords as O}from"../hooks/useImageRecords";import{remoteImagesDispatch as V}from"../remote";import{clearRecords as _,getRecord as G,updateRecord as J}from"../store/imageEventStore";import{ImageDetail as K}from"./ImageDetail";import{ImageDetailFooter as q}from"./ImageDetailFooter";import{ImageRow as Q}from"./ImageRow";import{ImagesHeader as U}from"./ImagesHeader";import{ImagesListFooter as X}from"./ImagesListFooter";import{InsightsBar as Y}from"./InsightsBar";import{computeInsights as C}from"../store/insights";import{jsx as e,jsxs as u}from"react/jsx-runtime";function Z(){const r=b();const i=[];if(r.rnDecoratorTooLate){i.push('RN <Image> instrumentation missed the module-load race \u2014 add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.')}if(!r.browserObserverActive&&!r.expoAvailable&&!r.rnDecoratorActive&&!r.rnDecoratorTooLate){i.push("Waiting for images\u2026 render some <Image> components to populate the list.")}if(i.length===0)return null;return e(d,{style:s.notice,children:i.map(c=>e(E,{style:s.noticeText,children:c},c))})}function $(){return e(L,{testID:"buoy-images-empty",otto:"listening",title:"No images captured yet",message:"Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."})}export function ImagesModal({visible:r,onClose:i,onBack:c,onMinimize:S,persistenceKey:R,inline:w=false}){P();const{records:n,stats:f}=O();const[h,p]=k(null);const t=h!=null?G(h):void 0;const m=t?.status==="error"&&t.errorHeaders==null?t.id:null;H(()=>{const o=V();if(m==null||!o)return;let l=false;o("getDetail",{id:m}).then(v=>{if(l)return;const D=v?.errorHeaders;J(m,{errorHeaders:D??{}})}).catch(()=>{});return()=>{l=true}},[m]);const a=t?n.findIndex(o=>o.id===t.id):-1;const y=o=>{const l=n[o];if(l)p(l.id)};const T=()=>t?A(t):W(n,f,C(n),b(),j());const x=e(U,{stats:f,detailOpen:t!=null,detailIndex:a,detailTotal:n.length,onCloseDetail:()=>p(null),onClear:_,getReport:T,onBack:c});const I=t?u(d,{style:s.detailContainer,children:[e(K,{record:t}),e(q,{record:t,hasPrevious:a>0,hasNext:a>=0&&a<n.length-1,onPrevious:()=>y(a-1),onNext:()=>y(a+1)},t.id)]}):u(d,{style:s.listContainer,children:[e(Y,{insights:C(n)}),e(Z,{}),e(M,{data:n,keyExtractor:o=>String(o.id),renderItem:({item:o})=>e(Q,{record:o,onPress:p}),ListEmptyComponent:e($,{})}),e(X,{})]});if(w){return u(d,{style:s.inlineRoot,children:[e(d,{style:s.inlineHeader,...F,children:x}),I]})}return e(N,{visible:r,onClose:i,onMinimize:S,persistenceKey:R,header:{showToggleButton:true,customContent:x},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:I})}export function ImagesToolView(r={}){return e(ImagesModal,{...r,inline:true,visible:true,onClose:()=>{}})}const s=z.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:B.border.default,backgroundColor:"transparent"},listContainer:{flex:1},detailContainer:{flex:1},notice:{margin:10,padding:10,borderRadius:8,backgroundColor:g.color.warningSoft,gap:4},noticeText:{color:g.color.warning,fontSize:11},empty:{alignItems:"center",padding:32,gap:8},emptyTitle:{color:g.color.text,fontSize:13,fontWeight:"600"},emptyText:{color:g.color.textSecondary,fontSize:11,textAlign:"center",lineHeight:16}});
1
+ "use strict";import{useEffect as H,useState as k}from"react";import{FlatList as M,StyleSheet as z,Text as E,View as d}from"react-native";import{JsModal as N,macOSColors as B,night as g,windowDragProps as F,ToolEmptyState as L}from"@buoy-gg/shared-ui";import{getCaptureStatus as b,installImageCapture as P}from"../capture/install";import{getGlobalModes as j}from"../capture/overrides";import{formatRecordMarkdown as A,formatRegistryMarkdown as W}from"../export";import{useImageRecords as O}from"../hooks/useImageRecords";import{remoteImagesDispatch as V}from"../remote";import{clearRecords as _,getRecord as G,updateRecord as J}from"../store/imageEventStore";import{ImageDetail as K}from"./ImageDetail";import{ImageDetailFooter as q}from"./ImageDetailFooter";import{ImageRow as Q}from"./ImageRow";import{ImagesHeader as U}from"./ImagesHeader";import{ImagesListFooter as X}from"./ImagesListFooter";import{InsightsBar as Y}from"./InsightsBar";import{computeInsights as C}from"../store/insights";import{jsx as e,jsxs as u}from"react/jsx-runtime";function Z(){const r=b();const n=[];if(r.rnDecoratorTooLate){n.push('RN <Image> instrumentation missed the module-load race \u2014 add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.')}if(!r.browserObserverActive&&!r.expoAvailable&&!r.rnDecoratorActive&&!r.rnDecoratorTooLate){n.push("Waiting for images\u2026 render some <Image> components to populate the list.")}if(n.length===0)return null;return e(d,{style:a.notice,children:n.map(c=>e(E,{style:a.noticeText,children:c},c))})}function $(){return e(L,{testID:"buoy-images-empty",otto:"listening",title:"No images captured yet",message:"Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."})}export function ImagesModal({visible:r,onClose:n,onBack:c,onMinimize:S,persistenceKey:R,inline:w=false}){P();const{records:i,stats:f}=O();const[h,p]=k(null);const t=h!=null?G(h):void 0;const m=t?.status==="error"&&t.errorHeaders==null?t.id:null;H(()=>{const o=V();if(m==null||!o)return;let l=false;o("getDetail",{id:m}).then(v=>{if(l)return;const D=v?.errorHeaders;J(m,{errorHeaders:D??{}})}).catch(()=>{});return()=>{l=true}},[m]);const s=t?i.findIndex(o=>o.id===t.id):-1;const y=o=>{const l=i[o];if(l)p(l.id)};const T=()=>t?A(t):W(i,f,C(i),b(),j());const I=e(U,{stats:f,detailOpen:t!=null,detailIndex:s,detailTotal:i.length,onCloseDetail:()=>p(null),onClear:_,getReport:T,onBack:c});const x=t?u(d,{style:a.detailContainer,children:[e(K,{record:t}),e(q,{record:t,hasPrevious:s>0,hasNext:s>=0&&s<i.length-1,onPrevious:()=>y(s-1),onNext:()=>y(s+1)},t.id)]}):u(d,{style:a.listContainer,children:[e(Y,{insights:C(i)}),e(Z,{}),e(M,{testID:"buoy-images-list",data:i,keyExtractor:o=>String(o.id),renderItem:({item:o})=>e(Q,{record:o,onPress:p}),ListEmptyComponent:e($,{})}),e(X,{})]});if(w){return u(d,{style:a.inlineRoot,children:[e(d,{style:a.inlineHeader,...F,children:I}),x]})}return e(N,{visible:r,onClose:n,onMinimize:S,persistenceKey:R,header:{showToggleButton:true,customContent:I},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:x})}export function ImagesToolView(r={}){return e(ImagesModal,{...r,inline:true,visible:true,onClose:()=>{}})}const a=z.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:B.border.default,backgroundColor:"transparent"},listContainer:{flex:1},detailContainer:{flex:1},notice:{margin:10,padding:10,borderRadius:8,backgroundColor:g.color.warningSoft,gap:4},noticeText:{color:g.color.warning,fontSize:11},empty:{alignItems:"center",padding:32,gap:8},emptyTitle:{color:g.color.text,fontSize:13,fontWeight:"600"},emptyText:{color:g.color.textSecondary,fontSize:11,textAlign:"center",lineHeight:16}});
@@ -1 +1 @@
1
- "use strict";import{StyleSheet as n,Text as c,View as l}from"react-native";import{night as r}from"@buoy-gg/shared-ui";import{insightChips as d}from"../store/insights";import{jsx as o}from"react/jsx-runtime";export function InsightsBar({insights:a}){const i=d(a);if(i.length===0)return null;return o(l,{style:t.bar,children:i.map(e=>o(l,{style:t.chip,children:o(c,{style:t.chipText,children:e})},e))})}const t=n.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8,borderBottomWidth:n.hairlineWidth,borderBottomColor:r.color.border},chip:{backgroundColor:r.color.warningSoft,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{color:r.color.warning,fontSize:10,fontWeight:"600",lineHeight:13}});
1
+ "use strict";import{StyleSheet as n,Text as s,View as l}from"react-native";import{night as t}from"@buoy-gg/shared-ui";import{insightChipEntries as c}from"../store/insights";import{jsx as i}from"react/jsx-runtime";export function InsightsBar({insights:a}){const e=c(a);if(e.length===0)return null;return i(l,{style:o.bar,children:e.map(r=>i(l,{style:o.chip,children:i(s,{style:o.chipText,testID:`buoy-images-insight-${r.key}`,children:r.text})},r.key))})}const o=n.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8,borderBottomWidth:n.hairlineWidth,borderBottomColor:t.color.border},chip:{backgroundColor:t.color.warningSoft,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{color:t.color.warning,fontSize:10,fontWeight:"600",lineHeight:13}});
@@ -1 +1 @@
1
- "use strict";const i=5;const d=4;export function computeInsights(e){const u=new Map;const r=[];const l=[];let s=0;let n=0;for(const t of e){if(t.mounted&&t.uri){u.set(t.uri,(u.get(t.uri)??0)+1)}if(t.loadCount>=i){r.push({id:t.id,uri:t.uri,loadCount:t.loadCount})}if((t.layoutShifts??0)>0){l.push({id:t.id,uri:t.uri,shifts:t.layoutShifts??0})}if(t.mounted&&t.hasAltText===false)s++;if(t.lib==="rn"&&t.mounted&&t.status==="loading")n++}const a=[...u.entries()].filter(([,t])=>t>1).map(([t,o])=>({uri:t,count:o})).sort((t,o)=>o.count-t.count);return{duplicates:a,retryStorms:r.sort((t,o)=>o.loadCount-t.loadCount),queueSaturated:n>d,missingAlt:s,layoutShifters:l}}export function insightChips(e){const u=[];if(e.duplicates.length>0){const r=e.duplicates.reduce((l,s)=>l+s.count-1,0);u.push(`${e.duplicates.length} duplicate URL${e.duplicates.length>1?"s":""} (${r} redundant loads)`)}if(e.retryStorms.length>0){u.push(`${e.retryStorms.length} retry storm${e.retryStorms.length>1?"s":""}`)}if(e.queueSaturated)u.push("iOS image queue saturated (>4 loading)");if(e.missingAlt>0)u.push(`${e.missingAlt} missing alt text`);if(e.layoutShifters.length>0){u.push(`${e.layoutShifters.length} layout-shifting image${e.layoutShifters.length>1?"s":""}`)}return u}
1
+ "use strict";const a=5;const d=4;export function computeInsights(e){const u=new Map;const o=[];const i=[];let n=0;let s=0;for(const t of e){if(t.mounted&&t.uri){u.set(t.uri,(u.get(t.uri)??0)+1)}if(t.loadCount>=a){o.push({id:t.id,uri:t.uri,loadCount:t.loadCount})}if((t.layoutShifts??0)>0){i.push({id:t.id,uri:t.uri,shifts:t.layoutShifts??0})}if(t.mounted&&t.hasAltText===false)n++;if(t.lib==="rn"&&t.mounted&&t.status==="loading")s++}const l=[...u.entries()].filter(([,t])=>t>1).map(([t,r])=>({uri:t,count:r})).sort((t,r)=>r.count-t.count);return{duplicates:l,retryStorms:o.sort((t,r)=>r.loadCount-t.loadCount),queueSaturated:s>d,missingAlt:n,layoutShifters:i}}export function insightChipEntries(e){const u=[];if(e.duplicates.length>0){const o=e.duplicates.reduce((i,n)=>i+n.count-1,0);u.push({key:"duplicates",text:`${e.duplicates.length} duplicate URL${e.duplicates.length>1?"s":""} (${o} redundant loads)`})}if(e.retryStorms.length>0){u.push({key:"retry",text:`${e.retryStorms.length} retry storm${e.retryStorms.length>1?"s":""}`})}if(e.queueSaturated)u.push({key:"queue",text:"iOS image queue saturated (>4 loading)"});if(e.missingAlt>0)u.push({key:"alt",text:`${e.missingAlt} missing alt text`});if(e.layoutShifters.length>0){u.push({key:"shift",text:`${e.layoutShifters.length} layout-shifting image${e.layoutShifters.length>1?"s":""}`})}return u}export function insightChips(e){return insightChipEntries(e).map(u=>u.text)}
@@ -7,5 +7,10 @@
7
7
  import type { ImageInsights, ImageRecord } from "../types";
8
8
  export declare function computeInsights(records: ImageRecord[]): ImageInsights;
9
9
  /** Compact one-line chips for UI/MCP surfacing. Empty array = all clear. */
10
+ /** The insight chips, each with a stable key (duplicates, retry, queue, alt, shift). */
11
+ export declare function insightChipEntries(insights: ImageInsights): {
12
+ key: string;
13
+ text: string;
14
+ }[];
10
15
  export declare function insightChips(insights: ImageInsights): string[];
11
16
  //# sourceMappingURL=insights.d.ts.map
package/lib/web/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- "use client";import{A as re,B as ye,C as oe,D as ae,E as be,F as mt,G as z,H as gt,I as H,J as ie,K as pt,L as G,M as fe,N as ve,O as xe,P as we,Q as qe,R as j,S as Ge,T as yt,U as _,a as bt,b as y,c as m,d as g,e as ft,f as C,g as vt,h as xt,i as R,j as wt,k as _e,l as E,m as le,n as $t,o as kt,p as V,q as $e,r as J,s as St,t as Je,u as ne,v as ke,w as Se,x as Ct,y as Rt,z as Bt}from"./chunks/chunk-6UR26VMI.mjs";y();y();y();y();import{ImagesIcon as Qe,IMAGES_ICON_COLOR as Xe}from"@buoy-gg/shared-ui/web";y();E();import{useEffect as It,useState as Tt}from"react";import{JsModal as Mt,macOSColors as zt,night as se,windowDragProps as Dt,ToolEmptyState as At}from"@buoy-gg/shared-ui/web";y();E();z();y();function de(e){let t=new Map,r=[],o=[],i=0,n=0;for(let a of e)a.mounted&&a.uri&&t.set(a.uri,(t.get(a.uri)??0)+1),a.loadCount>=5&&r.push({id:a.id,uri:a.uri,loadCount:a.loadCount}),(a.layoutShifts??0)>0&&o.push({id:a.id,uri:a.uri,shifts:a.layoutShifts??0}),a.mounted&&a.hasAltText===false&&i++,a.lib==="rn"&&a.mounted&&a.status==="loading"&&n++;return{duplicates:[...t.entries()].filter(([,a])=>a>1).map(([a,s])=>({uri:a,count:s})).sort((a,s)=>s.count-a.count),retryStorms:r.sort((a,s)=>s.loadCount-a.loadCount),queueSaturated:n>4,missingAlt:i,layoutShifters:o}}function Ce(e){let t=[];if(e.duplicates.length>0){let r=e.duplicates.reduce((o,i)=>o+i.count-1,0);t.push(`${e.duplicates.length} duplicate URL${e.duplicates.length>1?"s":""} (${r} redundant loads)`)}return e.retryStorms.length>0&&t.push(`${e.retryStorms.length} retry storm${e.retryStorms.length>1?"s":""}`),e.queueSaturated&&t.push("iOS image queue saturated (>4 loading)"),e.missingAlt>0&&t.push(`${e.missingAlt} missing alt text`),e.layoutShifters.length>0&&t.push(`${e.layoutShifters.length} layout-shifting image${e.layoutShifters.length>1?"s":""}`),t}y();z();import{macOSColors as D,night as Re}from"@buoy-gg/shared-ui/web";function x(e){return e<=0?"0 B":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Q(e){return e==null?"\u2014":e<1e3?`${Math.round(e)}ms`:`${(e/1e3).toFixed(2)}s`}function Be(e){if(!e)return"(no source)";let t=e.match(/[?&]unstable_path=([^&?]+)/),r=t?decodeURIComponent(t[1]):e,o=(r.split("?")[0]??r).split("/").filter(Boolean);return o[o.length-1]??r}function ce(e){let t=ye(e);return t==null?{label:"",color:Re.color.textTertiary,factor:t}:t<.9?{label:`${t.toFixed(1)}\xD7 upscaled`,color:D.semantic.info,factor:t}:t<=1.1?{label:"right-sized",color:D.semantic.success,factor:t}:t<=1.5?{label:`${t.toFixed(1)}\xD7 oversized`,color:D.semantic.warning,factor:t}:{label:`${t.toFixed(1)}\xD7 oversized`,color:D.semantic.error,factor:t}}function Pt(e){switch(e.status){case"loaded":return D.semantic.success;case"error":return D.semantic.error;case"loading":return D.semantic.warning;default:return Re.color.textTertiary}}function ue(e){let t=e.cacheVerdict;return t==="memory"||t==="disk/memory"?{label:t.toUpperCase(),color:D.semantic.success}:t==="disk"?{label:"DISK",color:D.semantic.warning}:t==="none"||e.progressSeen?{label:"NETWORK",color:D.semantic.error}:{label:"?",color:Re.color.textTertiary}}function Ye(e){let t=ce(e),r=ue(e),o=re(e),i=oe(e),n=ae(e),a=[];return a.push(`## Image report \u2014 ${Be(e.uri)}`),a.push(""),a.push(`- URI: ${e.uri||"(none)"}`),a.push(`- Library: ${e.lib==="expo"?"expo-image":"RN <Image>"} \xB7 kind: ${e.sourceKind} \xB7 mounted: ${e.mounted?"yes":"no"}`),a.push(`- Status: ${e.status}${e.errorCode?` (HTTP ${e.errorCode})`:""} \xB7 load cycles: ${e.loadCount}`),a.push(`- Cache: ${r.label}${e.cacheVerdictSource?` (via ${e.cacheVerdictSource==="event"?"expo onLoad":"Image.queryCache"})`:""}`),a.push(`- Load time: ${Q(e.durationMs)}${e.displayedAt&&e.loadedAt?` \xB7 decode\u2192display ${Q(Math.max(0,e.displayedAt-e.loadedAt))}`:""}`),e.intrinsic&&a.push(`- Decoded: ${e.intrinsic.width}\xD7${e.intrinsic.height}px${e.mediaType?` (${e.mediaType})`:""}${e.isAnimated?" animated":""} \u2248 ${x(i)} decoded memory`),e.layout&&a.push(`- Displayed: ${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)}dp @${xt.get()}x (needs ${o?`${o.width}\xD7${o.height}px`:"?"})`),t.label&&a.push(`- Size verdict: ${t.label}${n>0&&o?` \u2014 wasting \u2248${x(n)}; serve ${o.width}\xD7${o.height}`:""}`),e.progressSeen&&a.push(`- Network transfer: ${e.bytesTotal?x(e.bytesTotal):"observed"}`),e.hasAltText===false&&a.push("- Accessibility: MISSING alt/accessibilityLabel"),(e.layoutShifts??0)>0&&a.push(`- Layout shifts after load: ${e.layoutShifts} (reserve explicit dimensions)`),e.error&&(a.push(`- Error: ${e.error}`),e.errorHeaders&&a.push(`- Response headers: ${JSON.stringify(e.errorHeaders)}`)),e.overrideLabel&&a.push(`- Simulation active: ${e.overrideLabel}`),a.join(`
2
- `)}function Ze(e,t,r,o,i){let n=[];n.push(`## Buoy Images registry (${t.total} records)`),n.push(""),n.push(`${t.loaded} loaded \xB7 ${t.errors} failed \xB7 ${t.loading} in flight \xB7 \u2248${x(t.estDecodedBytes)} decoded`+(t.estWastedBytes>0?` \xB7 ${x(t.estWastedBytes)} wasted on oversized sources`:""));let a=Ce(r);a.length>0&&n.push(`Insights: ${a.join(" \xB7 ")}`),(i.network!=="normal"||i.blank)&&n.push(`Simulation active: network=${i.network}${i.blank?", blank images":""}`),o.rnDecoratorTooLate&&n.push("\u26A0 RN <Image> capture inactive (register import too late)"),n.push(""),n.push("| image | lib | status | cache | ms | decoded px | shown dp | verdict | notes |"),n.push("|---|---|---|---|---|---|---|---|---|");for(let s of e){let u=ce(s),S=ue(s),h=s.intrinsic?`${s.intrinsic.width}\xD7${s.intrinsic.height}`:"\u2013",$=s.layout?`${Math.round(s.layout.width)}\xD7${Math.round(s.layout.height)}`:"\u2013",p=[s.error?`error: ${s.error}`:null,s.overrideLabel?`sim: ${s.overrideLabel}`:null,s.hasAltText===false?"no alt":null,(s.layoutShifts??0)>0?`${s.layoutShifts} layout shifts`:null,s.mounted?null:"unmounted"].filter(Boolean).join("; ");n.push(`| ${Be(s.uri)} | ${s.lib} | ${s.status} | ${S.label} | ${s.durationMs!=null?Math.round(s.durationMs):"\u2013"} | ${h} | ${$} | ${u.label||"\u2013"} | ${p||"\u2013"} |`)}return n.join(`
3
- `)}y();z();import{useMemo as Lt,useSyncExternalStore as Ot}from"react";function et(){let e=Ot(ke,ne,ne);return Lt(()=>({records:[...e].reverse(),stats:be(e)}),[e])}J();z();y();y();function Ie(){return null}function Et(){return null}function Ft(){return null}E();import{useState as Te}from"react";import{macOSColors as B,night as b,monoFont as Wt}from"@buoy-gg/shared-ui/web";y();J();z();import{buoyFetch as Nt}from"@buoy-gg/shared-ui/web";var X=new Map;async function Me(e){let t=V();if(t)return await t("proveSavings",{id:e.id});let r=re(e);if(!r)return{ok:false,message:"Measure the displayed image before optimizing it."};try{let o=await Nt(e.uri);if(!o.ok)throw new Error(`Image download returned HTTP ${o.status}.`);let i=await o.blob(),n=await createImageBitmap(i),a=document.createElement("canvas");a.width=Math.max(1,Math.min(n.width,Math.round(r.width))),a.height=Math.max(1,Math.min(n.height,Math.round(r.height)));let s=a.getContext("2d");if(!s)throw n.close(),new Error("Canvas is unavailable.");s.drawImage(n,0,0,a.width,a.height),n.close();let u=await new Promise((p,N)=>a.toBlob(te=>te?p(te):N(new Error("Image encoding failed.")),"image/webp",.8));if(u.type!=="image/webp")return{ok:false,message:"This browser cannot encode WebP images."};let S=X.get(e.id);S&&URL.revokeObjectURL(S);let h=URL.createObjectURL(u);for(X.set(e.id,h);X.size>30;){let[p,N]=X.entries().next().value;URL.revokeObjectURL(N),X.delete(p)}let $=i.size-u.size;return{ok:true,message:"WebP preview created.",originalBytes:i.size,originalBytesSource:"download",optimizedBytes:u.size,optimizedUri:h,optimizedDims:{width:a.width,height:a.height},savedBytes:$,savedPct:i.size?$/i.size*100:0}}catch(o){return{ok:false,message:`Image optimization failed: ${o instanceof Error?o.message:String(o)}`}}}J();z();import{Fragment as Ht,jsx as l,jsxs as w}from"react/jsx-runtime";function F({title:e,children:t}){return w(m,{style:d.section,children:[l(g,{style:d.sectionTitle,children:e}),l(m,{style:d.sectionBody,children:t})]})}function c({label:e,value:t,color:r}){return w(m,{style:d.kvRow,children:[l(g,{style:d.kvLabel,children:e}),l(g,{style:[d.kvValue,r?{color:r}:null],selectable:true,children:t})]})}function tt(e){let t=V();if(t){t("clearExpoCaches",{memory:e==="memory",disk:e==="disk"});return}try{let r=Ie();e==="memory"?r.Image.clearMemoryCache():r.Image.clearDiskCache()}catch{}}function jt({record:e}){let[t,r]=Te(e.uri),o=t.trim(),i=e.mounted&&o.length>0&&o!==e.uri;return w(F,{title:"SWAP SOURCE URL",children:[l(ft,{style:d.urlInput,value:t,onChangeText:r,placeholder:"https://\u2026",placeholderTextColor:b.color.placeholder,autoCapitalize:"none",autoCorrect:false,multiline:true}),w(m,{style:d.actionsRow,children:[l(C,{style:[d.actionButton,!i&&d.actionDisabled],disabled:!i,onPress:()=>H(e.id,{source:{type:"url",uri:o},label:"URL swapped"}),children:l(g,{style:d.actionText,children:"Apply"})}),l(C,{style:d.actionButton,onPress:()=>r(e.uri),children:l(g,{style:d.actionText,children:"Reset field"})})]})]})}function Vt({record:e}){let[t,r]=Te(false),[o,i]=Te(null),n=()=>{r(true),Me(e).then(i).catch(a=>i({ok:false,message:String(a?.message??a)})).finally(()=>r(false))};return l(F,{title:"PROVE SAVINGS (re-encode on device)",children:o==null?l(m,{style:d.actionsRow,children:l(C,{style:d.actionButton,onPress:n,disabled:t,children:l(g,{style:d.actionText,children:t?"Re-encoding\u2026":"Re-encode at displayed size (WebP)"})})}):w(Ht,{children:[l(c,{label:"Result",value:o.message||(o.ok?"done":"failed"),color:o.ok?B.semantic.success:B.semantic.error}),o.originalBytes!=null?l(c,{label:"Original",value:`${x(o.originalBytes)} (${o.originalBytesSource})`}):null,o.optimizedBytes!=null?l(c,{label:"Optimized",value:`${x(o.optimizedBytes)} \u2014 ${o.optimizedDims?.width}\xD7${o.optimizedDims?.height} WebP`,color:B.semantic.success}):null,o.savedBytes!=null?l(c,{label:"Saved",value:`${x(o.savedBytes)} (${o.savedPct}%)`,color:B.semantic.success}):null,w(m,{style:d.actionsRow,children:[o.ok&&o.optimizedUri&&e.mounted?l(C,{style:d.actionButton,onPress:()=>H(e.id,{source:{type:"url",uri:o.optimizedUri},label:"Optimized preview"}),children:l(g,{style:d.actionText,children:"Preview in place"})}):null,l(C,{style:d.actionButton,onPress:n,disabled:t,children:l(g,{style:d.actionText,children:t?"Re-encoding\u2026":"Re-run"})})]})]})})}function Ut({record:e}){let t=ce(e),r=ue(e),o=re(e),i=oe(e),n=ae(e);return w(vt,{style:d.container,contentContainerStyle:d.content,children:[e.overrideLabel?w(m,{style:d.overrideBanner,children:[w(g,{style:d.overrideText,children:["Simulation active: ",e.overrideLabel," \u2014 stats below describe the override, not the original source."]}),l(C,{onPress:()=>ie(e.id),children:l(g,{style:d.overrideRestore,children:"RESTORE"})})]}):null,e.uri&&e.sourceKind!=="data"?l(m,{style:d.previewBox,children:l(_e,{testID:"buoy-internal-images-preview",source:{uri:e.uri},style:d.preview,resizeMode:"contain"})}):null,w(F,{title:"SOURCE",children:[l(c,{label:"URI",value:e.uri||"(none)"}),l(c,{label:"Kind",value:e.sourceKind}),l(c,{label:"Library",value:e.lib==="web"?"Browser <img>":e.lib==="expo"?"expo-image":"RN <Image>"}),e.hasAltText===false?l(c,{label:"Alt text",value:"missing \u2014 add alt/accessibilityLabel",color:B.semantic.warning}):null,e.mediaType!=null?l(c,{label:"Media type",value:String(e.mediaType)}):null,e.isAnimated!=null?l(c,{label:"Animated",value:e.isAnimated?"yes":"no"}):null]}),w(F,{title:"LOAD",children:[l(c,{label:"Status",value:e.status,color:e.status==="error"?B.semantic.error:e.status==="loaded"?B.semantic.success:B.semantic.warning}),l(c,{label:"Duration",value:Q(e.durationMs)}),e.displayedAt&&e.loadedAt?l(c,{label:"Decode \u2192 display",value:Q(Math.max(0,e.displayedAt-e.loadedAt))}):null,l(c,{label:"Cache",value:`${r.label}`,color:r.color}),e.cacheVerdictSource?l(c,{label:"Cache source",value:e.cacheVerdictSource==="event"?"reported by expo-image onLoad":"Image.queryCache after load"}):null,e.progressSeen?l(c,{label:"Downloaded",value:e.bytesTotal?`${x(e.bytesLoaded??0)} / ${x(e.bytesTotal)}`:"network transfer observed"}):null,l(c,{label:"Load cycles",value:String(e.loadCount)}),l(c,{label:"Still mounted",value:e.mounted?"yes":"no"})]}),w(F,{title:"DIMENSIONS",children:[e.intrinsic?l(c,{label:"Decoded",value:`${e.intrinsic.width}\xD7${e.intrinsic.height} px`}):l(c,{label:"Decoded",value:"unknown"}),e.layout?l(c,{label:"Displayed",value:`${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)} dp (needs ${o?`${o.width}\xD7${o.height}`:"?"} px @${Math.round(Bt()*100)/100}x)`}):l(c,{label:"Displayed",value:"no layout yet"}),t.label?l(c,{label:"Verdict",value:t.label,color:t.color}):null,i>0?l(c,{label:"Est. decoded memory",value:x(i)}):null,n>0?l(c,{label:"Est. wasted",value:`${x(n)} \u2014 resize the source to ${o?`${o.width}\xD7${o.height}`:"the displayed size"}`,color:B.semantic.warning}):null,(e.layoutShifts??0)>0?l(c,{label:"Layout shifts",value:`${e.layoutShifts} \u2014 box resized after load; reserve explicit width/height`,color:B.semantic.warning}):null]}),e.sourceKind==="network"||e.sourceKind==="asset"?l(Vt,{record:e},`savings-${e.id}`):null,e.status==="error"?w(F,{title:"ERROR",children:[l(c,{label:"Message",value:e.error??"unknown",color:B.semantic.error}),e.errorCode!=null?l(c,{label:"HTTP status",value:String(e.errorCode)}):null,e.errorHeaders?Object.entries(e.errorHeaders).map(([a,s])=>l(c,{label:a,value:String(s)},a)):null]}):null,e.sourceKind==="network"&&e.mounted?l(jt,{record:e},e.id):null,e.lib==="expo"?l(F,{title:"CACHE ACTIONS (expo-image, global)",children:w(m,{style:d.actionsRow,children:[l(C,{style:d.actionButton,onPress:()=>tt("memory"),children:l(g,{style:d.actionText,children:"Clear memory cache"})}),l(C,{style:d.actionButton,onPress:()=>tt("disk"),children:l(g,{style:d.actionText,children:"Clear disk cache"})})]})}):null]})}var d=R.create({container:{flex:1},content:{padding:12,gap:12},previewBox:{height:140,borderRadius:8,backgroundColor:b.color.bg,overflow:"hidden"},preview:{width:"100%",height:"100%"},section:{gap:6},sectionTitle:{color:b.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.8},sectionBody:{backgroundColor:b.color.surface,borderRadius:8,borderWidth:R.hairlineWidth,borderColor:b.color.border,paddingHorizontal:10,paddingVertical:4},kvRow:{flexDirection:"row",paddingVertical:5,gap:12},kvLabel:{color:b.color.textSecondary,fontSize:11,width:110},kvValue:{color:b.color.text,fontSize:11,flex:1},actionsRow:{flexDirection:"row",gap:8,paddingVertical:8},actionButton:{backgroundColor:b.color.surfaceElevated,borderRadius:6,paddingHorizontal:10,paddingVertical:6,borderWidth:R.hairlineWidth,borderColor:b.color.border},actionText:{color:b.color.text,fontSize:11,fontWeight:"600"},actionDisabled:{opacity:.4},urlInput:{color:b.color.text,fontSize:11,fontFamily:Wt,backgroundColor:b.color.surfaceElevated,borderRadius:6,borderWidth:R.hairlineWidth,borderColor:b.color.border,paddingHorizontal:8,paddingVertical:6,marginTop:8},overrideBanner:{flexDirection:"row",alignItems:"center",gap:10,padding:10,borderRadius:8,backgroundColor:b.color.warningSoft},overrideText:{flex:1,color:b.color.warning,fontSize:11,lineHeight:15},overrideRestore:{color:b.color.warning,fontSize:11,fontWeight:"700",letterSpacing:.5}});y();E();import{useState as Kt}from"react";import{ChevronLeft as qt,ChevronRight as Gt,FooterButton as ze,FooterMessage as rt,FooterRow as ot,RefreshCw as _t,ToolFooter as Jt,night as W}from"@buoy-gg/shared-ui/web";y();J();$t();function Qt(e){return le().actionListeners.add(e),()=>le().actionListeners.delete(e)}function at(e,t){let r=le(),o=r.reloadRequests.get(e);r.reloadRequests.set(e,{nonce:(o?.nonce??0)+1,bust:t}),gt(e)}function it(){try{return Ie().Image??null}catch{return null}}function Xt(){try{let e=Et(),t=e?.default||e;if(t?.deleteAsync)return t}catch{}try{let e=Ft(),t=e?.default||e;if(t?.deleteAsync)return t}catch{}return null}async function De(e){let t=it(),r=Xt();if(!t?.getCachePathAsync||!r?.deleteAsync||!e.uri)return false;try{let o=await t.getCachePathAsync(e.uri);if(!o)return false;let i=o.startsWith("file://")?o:`file://${o}`;return await r.deleteAsync(i,{idempotent:true}),true}catch{return false}}async function Y(e){let t=V();if(t)return $e(t("retry",{id:e.id}));if(!e.mounted)return{ok:false,message:"Instance unmounted \u2014 cannot reload"};if(e.lib==="expo"){let r=le().expoInstances.get(e.id);return r?.reloadAsync?(await r.reloadAsync(),{ok:true,message:"Reload requested"}):{ok:false,message:"Live instance not reachable"}}return at(e.id,false),{ok:true,message:"Remounting image"}}async function Ae(){let e=V();if(e)return $e(e("massAction",{kind:"reload"}));let{getSnapshot:t}=(z(),bt(mt)),r=0;for(let o of t()){if(!o.mounted)continue;(await he(o)).ok&&r++}return{ok:r>0,message:`Hard-reloading ${r} mounted image${r===1?"":"s"}`}}async function he(e){let t=V();if(t)return $e(t("hardReload",{id:e.id}));if(!e.mounted)return{ok:false,message:"Instance unmounted \u2014 cannot reload"};if(e.sourceKind!=="network")return Y(e);if(e.lib==="expo"){let r=await De(e);await it()?.clearMemoryCache?.().catch?.(()=>false);let o=await Y(e);return o.ok?{ok:true,message:r?"Disk entry evicted, memory cache cleared, refetching":"Memory cache cleared, refetching (no disk entry found)"}:o}return at(e.id,true),{ok:true,message:"Refetching with cache bypassed"}}import{jsx as f,jsxs as Pe}from"react/jsx-runtime";function Yt({record:e,hasPrevious:t,hasNext:r,onPrevious:o,onNext:i}){let[n,a]=Kt(null),s=$=>{a("\u2026"),$().then(p=>a(p.message)).catch(p=>a(String(p?.message??p)))},u=!e.mounted,S=e.overrideLabel!=null,h=($,p)=>{H(e.id,{source:$,label:p}),a(`${p} \u2014 Restore to undo`)};return Pe(Jt,{children:[n?f(rt,{children:n}):u?f(rt,{tone:"muted",children:"Instance unmounted \u2014 reload actions need the image on screen."}):null,Pe(ot,{style:{gap:8},children:[f(C,{onPress:o,disabled:!t,style:[me.navButton,!t&&me.disabled],activeOpacity:.7,accessibilityLabel:"Previous image",children:f(qt,{size:20,color:t?W.color.accent:W.color.textTertiary})}),f(ze,{label:"Hard reload",size:"md",disabled:u,icon:f(_t,{size:13,color:u?W.color.textTertiary:W.color.info}),onPress:()=>s(()=>he(e))}),f(ze,{label:e.status==="error"?"Retry":"Reload",size:"md",disabled:u,onPress:()=>s(()=>Y(e))}),f(C,{onPress:i,disabled:!r,style:[me.navButton,!r&&me.disabled],activeOpacity:.7,accessibilityLabel:"Next image",children:f(Gt,{size:20,color:r?W.color.accent:W.color.textTertiary})})]}),Pe(ot,{style:{gap:8},children:[f(Z,{label:"Error",disabled:u,onPress:()=>h({type:"error"},"Forced error")}),f(Z,{label:"Loading",disabled:u,onPress:()=>h({type:"hang"},"Forced loading")}),f(Z,{label:"Blank",disabled:u,onPress:()=>h({type:"blank"},"Blanked")}),f(Z,{label:"Find",disabled:u,onPress:()=>{xe(e.id),a("Flashing a red border on the image (2.5s)")}}),f(Z,{label:"Restore",accent:true,disabled:!S,onPress:()=>{ie(e.id),a("Override removed \u2014 original source restored")}})]})]})}function Z({label:e,onPress:t,disabled:r,accent:o}){return f(ze,{label:e,onPress:t,disabled:r,accent:o,style:{paddingVertical:7}})}var me=R.create({navButton:{paddingHorizontal:10,paddingVertical:8,borderRadius:6,backgroundColor:W.color.button,alignItems:"center",justifyContent:"center"},disabled:{opacity:.4}});y();E();import{macOSColors as Zt,night as A,Pill as Le}from"@buoy-gg/shared-ui/web";import{jsx as I,jsxs as ee}from"react/jsx-runtime";function er({record:e,onPress:t}){let r=ce(e),o=ue(e),i=e.sourceKind==="network"||e.sourceKind==="asset"||e.sourceKind==="file";return ee(C,{style:k.row,testID:`buoy-image-row-${e.id}`,onPress:()=>t(e.id),children:[ee(m,{style:k.thumbBox,children:[i&&e.uri?I(_e,{testID:"buoy-internal-images-thumb",source:{uri:e.uri},style:k.thumb,resizeMode:"cover"}):I(g,{style:k.thumbFallback,children:"?"}),I(m,{style:[k.statusDot,{backgroundColor:Pt(e)}]})]}),ee(m,{style:k.main,children:[I(g,{style:k.name,numberOfLines:1,children:Be(e.uri)}),ee(m,{style:k.metaRow,children:[I(Le,{variant:"text",label:e.lib==="web"?"WEB":e.lib==="expo"?"EXPO":"RN",color:A.color.textTertiary}),I(Le,{variant:"text",label:o.label,color:o.color}),e.overrideLabel?I(Le,{variant:"text",label:"SIM",color:A.color.warning}):null,I(g,{style:k.meta,children:Q(e.durationMs)}),e.intrinsic?ee(g,{style:k.meta,children:[e.intrinsic.width,"\xD7",e.intrinsic.height]}):null]})]}),I(m,{style:k.right,children:e.status==="error"?I(g,{style:[k.verdict,{color:Zt.semantic.error}],children:"FAILED"}):r.label?I(g,{style:[k.verdict,{color:r.color}],children:r.label}):null})]})}var k=R.create({row:{flexDirection:"row",alignItems:"center",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:R.hairlineWidth,borderBottomColor:A.color.border,gap:10},thumbBox:{width:40,height:40,borderRadius:6,backgroundColor:A.color.bg,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:40,height:40},thumbFallback:{color:A.color.textTertiary,fontSize:16,fontWeight:"700"},statusDot:{position:"absolute",right:2,bottom:2,width:8,height:8,borderRadius:4,borderWidth:1,borderColor:A.color.bg},main:{flex:1,gap:2},name:{color:A.color.text,fontSize:12,fontWeight:"600"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:A.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end"},verdict:{fontSize:10,fontWeight:"700"}});y();import{ModalHeader as P,ToolbarClearButton as tr,ToolbarCopyButton as lt}from"@buoy-gg/shared-ui/web";import{jsx as L,jsxs as Oe}from"react/jsx-runtime";function rr({stats:e,detailOpen:t,detailIndex:r=-1,detailTotal:o=0,onCloseDetail:i,onClear:n,getReport:a,onBack:s}){if(t){let S=r>=0&&o>0?`${r+1} of ${o}`:void 0;return Oe(P,{children:[L(P.Navigation,{onBack:i}),L(P.Content,{title:"Image detail",subtitle:S}),L(P.Actions,{children:L(lt,{value:a})})]})}let u=[`${e.total} images`,`${e.errors} failed`,`\u2248${x(e.estDecodedBytes)} decoded`];return e.estWastedBytes>0&&u.push(`${x(e.estWastedBytes)} wasted`),Oe(P,{children:[s?L(P.Navigation,{onBack:s}):null,L(P.Content,{title:"Images",subtitle:u.join(" \xB7 ")}),Oe(P.Actions,{children:[L(lt,{value:a}),L(tr,{onPress:n})]})]})}y();E();import{useState as or,useSyncExternalStore as ar}from"react";import{FooterButton as nt,FooterCaption as ir,FooterMessage as lr,FooterRow as st,ToolFooter as nr,night as sr}from"@buoy-gg/shared-ui/web";import{jsx as T,jsxs as Ee}from"react/jsx-runtime";var dr=[{key:"normal",label:"Normal"},{key:"offline",label:"Offline"},{key:"cold",label:"Cold"}];function cr(){let[e,t]=or(null),r=ar(Qt,()=>j().network),o=(i,n)=>{let a=G(i,n);t(a>0?`${n} on ${a} image${a===1?"":"s"} \u2014 Restore all to undo`:"No mounted images")};return Ee(nr,{paddingBottom:10,style:{paddingTop:8},children:[e?T(lr,{children:e}):T(ir,{children:"MASS ACTIONS \u2014 every image on screen"}),Ee(st,{children:[T(U,{label:"Error",onPress:()=>o({type:"error"},"Forced error")}),T(U,{label:"Loading",onPress:()=>o({type:"hang"},"Forced loading")}),T(U,{label:"Blank",onPress:()=>o({type:"blank"},"Blanked")}),T(U,{label:"Reload",onPress:()=>{t("\u2026"),Ae().then(i=>t(i.message))}}),T(U,{label:"Find",onPress:()=>{let i=ve();t(`Flashing ${i} image${i===1?"":"s"} (2.5s)`)}}),T(U,{label:"Restore",accent:true,onPress:()=>{let i=fe();t(i>0?`Restored ${i} image${i===1?"":"s"}`:"No overrides active")}})]}),Ee(st,{children:[T(g,{style:ur.netLabel,children:"NET"}),dr.map(i=>{let n=r===i.key;return T(nt,{label:i.label,active:n,style:{paddingVertical:6},onPress:()=>{we(i.key),t(i.key==="normal"?"Network simulation off \u2014 tap RELOAD to load normally again":i.key==="offline"?"Offline: network images FAIL (bundled assets still load) \u2014 tap RELOAD to apply to on-screen images":"Cold (bypass caches) \u2014 tap RELOAD: everything refetches like first launch")}},i.key)})]})]})}function U({label:e,onPress:t,accent:r}){return T(nt,{label:e,onPress:t,accent:r})}var ur=R.create({netLabel:{color:sr.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.8,alignSelf:"center",marginRight:2}});y();E();import{night as Fe}from"@buoy-gg/shared-ui/web";import{jsx as We}from"react/jsx-runtime";function hr({insights:e}){let t=Ce(e);return t.length===0?null:We(m,{style:Ne.bar,children:t.map(r=>We(m,{style:Ne.chip,children:We(g,{style:Ne.chipText,children:r})},r))})}var Ne=R.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8,borderBottomWidth:R.hairlineWidth,borderBottomColor:Fe.color.border},chip:{backgroundColor:Fe.color.warningSoft,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{color:Fe.color.warning,fontSize:10,fontWeight:"600",lineHeight:13}});import{jsx as v,jsxs as He}from"react/jsx-runtime";function mr(){let e=_(),t=[];return e.rnDecoratorTooLate&&t.push('RN <Image> instrumentation missed the module-load race \u2014 add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.'),!e.browserObserverActive&&!e.expoAvailable&&!e.rnDecoratorActive&&!e.rnDecoratorTooLate&&t.push("Waiting for images\u2026 render some <Image> components to populate the list."),t.length===0?null:v(m,{style:K.notice,children:t.map(r=>v(g,{style:K.noticeText,children:r},r))})}function gr(){return v(At,{testID:"buoy-images-empty",otto:"listening",title:"No images captured yet",message:"Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."})}function je({visible:e,onClose:t,onBack:r,onMinimize:o,persistenceKey:i,inline:n=false}){Ge();let{records:a,stats:s}=et(),[u,S]=Tt(null),h=u!=null?Je(u):void 0,$=h?.status==="error"&&h.errorHeaders==null?h.id:null;It(()=>{let M=V();if($==null||!M)return;let q=false;return M("getDetail",{id:$}).then(ut=>{if(q)return;let ht=ut?.errorHeaders;St($,{errorHeaders:ht??{}})}).catch(()=>{}),()=>{q=true}},[$]);let p=h?a.findIndex(M=>M.id===h.id):-1,N=M=>{let q=a[M];q&&S(q.id)},te=()=>h?Ye(h):Ze(a,s,de(a),_(),j()),Ue=v(rr,{stats:s,detailOpen:h!=null,detailIndex:p,detailTotal:a.length,onCloseDetail:()=>S(null),onClear:Se,getReport:te,onBack:r}),Ke=h?He(m,{style:K.detailContainer,children:[v(Ut,{record:h}),v(Yt,{record:h,hasPrevious:p>0,hasNext:p>=0&&p<a.length-1,onPrevious:()=>N(p-1),onNext:()=>N(p+1)},h.id)]}):He(m,{style:K.listContainer,children:[v(hr,{insights:de(a)}),v(mr,{}),v(wt,{data:a,keyExtractor:M=>String(M.id),renderItem:({item:M})=>v(er,{record:M,onPress:S}),ListEmptyComponent:v(gr,{})}),v(cr,{})]});return n?He(m,{style:K.inlineRoot,children:[v(m,{style:K.inlineHeader,...Dt,children:Ue}),Ke]}):v(Mt,{visible:e,onClose:t,onMinimize:o,persistenceKey:i,header:{showToggleButton:true,customContent:Ue},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:Ke})}function pr(e={}){return v(je,{...e,inline:true,visible:true,onClose:()=>{}})}var K=R.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:zt.border.default,backgroundColor:"transparent"},listContainer:{flex:1},detailContainer:{flex:1},notice:{margin:10,padding:10,borderRadius:8,backgroundColor:se.color.warningSoft,gap:4},noticeText:{color:se.color.warning,fontSize:11},empty:{alignItems:"center",padding:32,gap:8},emptyTitle:{color:se.color.text,fontSize:13,fontWeight:"600"},emptyText:{color:se.color.textSecondary,fontSize:11,textAlign:"center",lineHeight:16}});import{createToolFactory as yr,defineToolPreset as br}from"@buoy-gg/shared-ui/web";import{jsx as fr}from"react/jsx-runtime";var dt=br({id:"images",name:"IMAGES",description:"Image loads, caching, failures, and oversize checks",slot:"both",icon:({size:e,color:t})=>fr(Qe,{size:e,color:t||Xe}),component:je}),vr=yr(dt);y();import{useEffect as xr}from"react";function wr(){return xr(yt,[]),null}y();z();var ge=2*1024;function pe(e){if(!e)return e;if(e.startsWith("data:")){let t=e.indexOf(","),r=t>=0?e.slice(0,Math.min(t+1,64)):"data:",o=t>=0?e.slice(t+1):e,i=o.length>16?`${o.slice(0,8)}\u2026${o.slice(-8)}`:o;return`${r}[${e.length} chars ${i}]`}return e.length<=ge?e:`${e.slice(0,ge)}\u2026 [${e.length-ge} more]`}function $r(e,t=ge){return e?e.length<=t?e:`${e.slice(0,t)}\u2026 [${e.length-t} more]`:null}function kr(e){return{...e,duplicates:e.duplicates.map(t=>({...t,uri:pe(t.uri)})),retryStorms:e.retryStorms.map(t=>({...t,uri:pe(t.uri)})),layoutShifters:e.layoutShifters.map(t=>({...t,uri:pe(t.uri)}))}}function Ve(e){let t=ye(e);return{id:e.id,lib:e.lib,uri:pe(e.uri),kind:e.sourceKind,status:e.status,mounted:e.mounted,cache:e.cacheVerdict??null,cacheSource:e.cacheVerdictSource??null,ms:e.durationMs!=null?Math.round(e.durationMs):null,intrinsic:e.intrinsic??null,layout:e.layout?{width:Math.round(e.layout.width),height:Math.round(e.layout.height)}:null,neededPx:re(e),oversizeFactor:t!=null?Math.round(t*100)/100:null,decodedKB:Math.round(oe(e)/1024),wastedKB:Math.round(ae(e)/1024),progressSeen:e.progressSeen===true,bytesTotal:e.bytesTotal??null,error:$r(e.error),errorCode:e.errorCode??null,loadCount:e.loadCount,overrideLabel:e.overrideLabel??null,hasAltText:e.hasAltText??null,layoutShifts:e.layoutShifts??0,ageMs:Date.now()-e.createdAt}}function O(e){let t=e?.id;if(typeof t!="number")throw new Error("Missing numeric `id` param");let r=Je(t);if(!r)throw new Error(`Image record ${t} not found (cleared or evicted) \u2014 re-run the list action for current ids.`);return r}function ct(){let e=ne();return{stats:be(e),captureStatus:_(),globalModes:j(),insights:kr(de(e)),records:[...e].reverse()}}var Sr={version:1,getSnapshot:()=>{let{records:e,...t}=ct();return{...t,records:e.slice(0,100).map(Ve)}},subscribe:e=>ke(e),actions:{list:e=>{let t=e??{},r=Math.min(Math.max(t.limit??50,1),200),{records:o,...i}=ct(),n=t.status?o.filter(a=>a.status===t.status):o;return{...i,total:n.length,records:n.slice(0,r).map(Ve)}},getDetail:e=>{let t=O(e);return{...Ve(t),errorHeaders:t.errorHeaders??null}},hardReload:e=>he(O(e)),proveSavings:e=>Me(O(e)),retry:e=>Y(O(e)),evictDisk:async e=>{let t=O(e),r=await De(t);return{ok:r,message:r?"Disk cache entry deleted":"No disk entry found (expo-image + expo-file-system required)"}},flash:e=>(xe(O(e).id),{ok:true,message:"Flashing for 2.5s"}),setOverride:e=>{let t=O(e),r=e,o={error:{source:{type:"error"},label:"Forced error"},hang:{source:{type:"hang"},label:"Forced loading"},blank:{source:{type:"blank"},label:"Blanked"}};if(r.kind==="url"){if(!r.uri)throw new Error("kind 'url' requires a `uri` param");return H(t.id,{source:{type:"url",uri:r.uri},label:"URL swapped"}),{ok:true,message:`Source overridden to ${r.uri}`}}let i=r.kind?o[r.kind]:void 0;if(!i)throw new Error(`Unknown override kind: ${String(r.kind)}`);return t.mounted?(H(t.id,i),{ok:true,message:`${i.label} applied`}):{ok:false,message:"Instance unmounted \u2014 overrides need the image on screen"}},clearOverride:e=>(ie(O(e).id),{ok:true,message:"Override removed \u2014 original source restored"}),massAction:async e=>{let t=e?.kind;switch(t){case"error":{let r=G({type:"error"},"Forced error");return{ok:r>0,message:`Forced error on ${r} images`}}case"loading":{let r=G({type:"hang"},"Forced loading");return{ok:r>0,message:`Forced loading on ${r} images`}}case"blank":{let r=G({type:"blank"},"Blanked");return{ok:r>0,message:`Blanked ${r} images`}}case"reload":return Ae();case"flash":{let r=ve();return{ok:r>0,message:`Flashing ${r} images`}}case"restore":return{ok:true,message:`Restored ${fe()} images`};default:throw new Error(`Unknown mass kind: ${String(t)}`)}},setNetworkMode:e=>{let t=e?.mode;if(t!=="normal"&&t!=="offline"&&t!=="cold")throw new Error("mode must be 'normal' | 'offline' | 'cold'");return we(t),{ok:true,modes:j()}},setBlankImages:e=>(qe(e?.enabled===true),{ok:true,modes:j()}),clearRecords:()=>(Se(),{ok:true,message:"Registry cleared"}),clearExpoCaches:async e=>{let t=e??{},r=t.memory!==false,o=t.disk!==false;try{let i=Ie(),n=[];return r&&(await i.Image.clearMemoryCache(),n.push("memory")),o&&(await i.Image.clearDiskCache(),n.push("disk")),{ok:true,message:`Cleared expo-image ${n.join(" + ")} cache`}}catch{return{ok:false,message:"expo-image not installed"}}},getCaptureStatus:()=>_()}};z();J();z();export{Xe as IMAGES_ICON_COLOR,Qe as ImagesIcon,je as ImagesModal,wr as ImagesRoot,pr as ImagesToolView,fe as clearAllOverrides,ie as clearOverride,Se as clearRecords,de as computeInsights,be as computeStats,vr as createImagesTool,Ct as disableImagesCapture,oe as estDecodedBytes,ae as estWastedBytes,De as evictExpoDiskEntry,ve as flashAllMounted,xe as flashRecord,Ye as formatRecordMarkdown,Ze as formatRegistryMarkdown,_ as getCaptureStatus,j as getGlobalModes,ne as getImageRecords,pt as getOverride,Ae as hardReloadAllMounted,he as hardReloadRecord,Sr as imagesSyncAdapter,dt as imagesToolPreset,Ce as insightChips,Ge as installImageCapture,ye as oversizeFactor,Me as proveSavings,Rt as replaceImagesFromSnapshot,Y as retryRecord,qe as setBlankImages,we as setNetworkMode,H as setOverride,G as setOverrideForAllMounted,kt as setRemoteImagesHandler,ke as subscribeImageRecords,et as useImageRecords};
1
+ "use client";import{A as re,B as ye,C as oe,D as ae,E as be,F as gt,G as M,H as pt,I as H,J as ie,K as yt,L as G,M as fe,N as ve,O as xe,P as we,Q as Ke,R as j,S as qe,T as bt,U as _,a as ft,b as y,c as m,d as g,e as vt,f as C,g as xt,h as wt,i as I,j as $t,k as Ge,l as E,m as le,n as kt,o as St,p as V,q as $e,r as J,s as Ct,t as _e,u as ne,v as ke,w as Se,x as It,y as Rt,z as Dt}from"./chunks/chunk-6UR26VMI.mjs";y();y();y();y();import{ImagesIcon as Je,IMAGES_ICON_COLOR as Qe}from"@buoy-gg/shared-ui/web";y();E();import{useEffect as Bt,useState as Tt}from"react";import{JsModal as Mt,macOSColors as zt,night as se,windowDragProps as At,ToolEmptyState as Lt}from"@buoy-gg/shared-ui/web";y();E();M();y();function de(e){let t=new Map,r=[],o=[],i=0,l=0;for(let a of e)a.mounted&&a.uri&&t.set(a.uri,(t.get(a.uri)??0)+1),a.loadCount>=5&&r.push({id:a.id,uri:a.uri,loadCount:a.loadCount}),(a.layoutShifts??0)>0&&o.push({id:a.id,uri:a.uri,shifts:a.layoutShifts??0}),a.mounted&&a.hasAltText===false&&i++,a.lib==="rn"&&a.mounted&&a.status==="loading"&&l++;return{duplicates:[...t.entries()].filter(([,a])=>a>1).map(([a,s])=>({uri:a,count:s})).sort((a,s)=>s.count-a.count),retryStorms:r.sort((a,s)=>s.loadCount-a.loadCount),queueSaturated:l>4,missingAlt:i,layoutShifters:o}}function Xe(e){let t=[];if(e.duplicates.length>0){let r=e.duplicates.reduce((o,i)=>o+i.count-1,0);t.push({key:"duplicates",text:`${e.duplicates.length} duplicate URL${e.duplicates.length>1?"s":""} (${r} redundant loads)`})}return e.retryStorms.length>0&&t.push({key:"retry",text:`${e.retryStorms.length} retry storm${e.retryStorms.length>1?"s":""}`}),e.queueSaturated&&t.push({key:"queue",text:"iOS image queue saturated (>4 loading)"}),e.missingAlt>0&&t.push({key:"alt",text:`${e.missingAlt} missing alt text`}),e.layoutShifters.length>0&&t.push({key:"shift",text:`${e.layoutShifters.length} layout-shifting image${e.layoutShifters.length>1?"s":""}`}),t}function Ye(e){return Xe(e).map(t=>t.text)}y();M();import{macOSColors as z,night as Ce}from"@buoy-gg/shared-ui/web";function x(e){return e<=0?"0 B":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Q(e){return e==null?"\u2014":e<1e3?`${Math.round(e)}ms`:`${(e/1e3).toFixed(2)}s`}function Ie(e){if(!e)return"(no source)";let t=e.match(/[?&]unstable_path=([^&?]+)/),r=t?decodeURIComponent(t[1]):e,o=(r.split("?")[0]??r).split("/").filter(Boolean);return o[o.length-1]??r}function ce(e){let t=ye(e);return t==null?{label:"",color:Ce.color.textTertiary,factor:t}:t<.9?{label:`${t.toFixed(1)}\xD7 upscaled`,color:z.semantic.info,factor:t}:t<=1.1?{label:"right-sized",color:z.semantic.success,factor:t}:t<=1.5?{label:`${t.toFixed(1)}\xD7 oversized`,color:z.semantic.warning,factor:t}:{label:`${t.toFixed(1)}\xD7 oversized`,color:z.semantic.error,factor:t}}function Pt(e){switch(e.status){case"loaded":return z.semantic.success;case"error":return z.semantic.error;case"loading":return z.semantic.warning;default:return Ce.color.textTertiary}}function ue(e){let t=e.cacheVerdict;return t==="memory"||t==="disk/memory"?{label:t.toUpperCase(),color:z.semantic.success}:t==="disk"?{label:"DISK",color:z.semantic.warning}:t==="none"||e.progressSeen?{label:"NETWORK",color:z.semantic.error}:{label:"?",color:Ce.color.textTertiary}}function Ze(e){let t=ce(e),r=ue(e),o=re(e),i=oe(e),l=ae(e),a=[];return a.push(`## Image report \u2014 ${Ie(e.uri)}`),a.push(""),a.push(`- URI: ${e.uri||"(none)"}`),a.push(`- Library: ${e.lib==="expo"?"expo-image":"RN <Image>"} \xB7 kind: ${e.sourceKind} \xB7 mounted: ${e.mounted?"yes":"no"}`),a.push(`- Status: ${e.status}${e.errorCode?` (HTTP ${e.errorCode})`:""} \xB7 load cycles: ${e.loadCount}`),a.push(`- Cache: ${r.label}${e.cacheVerdictSource?` (via ${e.cacheVerdictSource==="event"?"expo onLoad":"Image.queryCache"})`:""}`),a.push(`- Load time: ${Q(e.durationMs)}${e.displayedAt&&e.loadedAt?` \xB7 decode\u2192display ${Q(Math.max(0,e.displayedAt-e.loadedAt))}`:""}`),e.intrinsic&&a.push(`- Decoded: ${e.intrinsic.width}\xD7${e.intrinsic.height}px${e.mediaType?` (${e.mediaType})`:""}${e.isAnimated?" animated":""} \u2248 ${x(i)} decoded memory`),e.layout&&a.push(`- Displayed: ${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)}dp @${wt.get()}x (needs ${o?`${o.width}\xD7${o.height}px`:"?"})`),t.label&&a.push(`- Size verdict: ${t.label}${l>0&&o?` \u2014 wasting \u2248${x(l)}; serve ${o.width}\xD7${o.height}`:""}`),e.progressSeen&&a.push(`- Network transfer: ${e.bytesTotal?x(e.bytesTotal):"observed"}`),e.hasAltText===false&&a.push("- Accessibility: MISSING alt/accessibilityLabel"),(e.layoutShifts??0)>0&&a.push(`- Layout shifts after load: ${e.layoutShifts} (reserve explicit dimensions)`),e.error&&(a.push(`- Error: ${e.error}`),e.errorHeaders&&a.push(`- Response headers: ${JSON.stringify(e.errorHeaders)}`)),e.overrideLabel&&a.push(`- Simulation active: ${e.overrideLabel}`),a.join(`
2
+ `)}function et(e,t,r,o,i){let l=[];l.push(`## Buoy Images registry (${t.total} records)`),l.push(""),l.push(`${t.loaded} loaded \xB7 ${t.errors} failed \xB7 ${t.loading} in flight \xB7 \u2248${x(t.estDecodedBytes)} decoded`+(t.estWastedBytes>0?` \xB7 ${x(t.estWastedBytes)} wasted on oversized sources`:""));let a=Ye(r);a.length>0&&l.push(`Insights: ${a.join(" \xB7 ")}`),(i.network!=="normal"||i.blank)&&l.push(`Simulation active: network=${i.network}${i.blank?", blank images":""}`),o.rnDecoratorTooLate&&l.push("\u26A0 RN <Image> capture inactive (register import too late)"),l.push(""),l.push("| image | lib | status | cache | ms | decoded px | shown dp | verdict | notes |"),l.push("|---|---|---|---|---|---|---|---|---|");for(let s of e){let u=ce(s),S=ue(s),h=s.intrinsic?`${s.intrinsic.width}\xD7${s.intrinsic.height}`:"\u2013",$=s.layout?`${Math.round(s.layout.width)}\xD7${Math.round(s.layout.height)}`:"\u2013",p=[s.error?`error: ${s.error}`:null,s.overrideLabel?`sim: ${s.overrideLabel}`:null,s.hasAltText===false?"no alt":null,(s.layoutShifts??0)>0?`${s.layoutShifts} layout shifts`:null,s.mounted?null:"unmounted"].filter(Boolean).join("; ");l.push(`| ${Ie(s.uri)} | ${s.lib} | ${s.status} | ${S.label} | ${s.durationMs!=null?Math.round(s.durationMs):"\u2013"} | ${h} | ${$} | ${u.label||"\u2013"} | ${p||"\u2013"} |`)}return l.join(`
3
+ `)}y();M();import{useMemo as Ot,useSyncExternalStore as Et}from"react";function tt(){let e=Et(ke,ne,ne);return Ot(()=>({records:[...e].reverse(),stats:be(e)}),[e])}J();M();y();y();function Re(){return null}function Ft(){return null}function Wt(){return null}E();import{useState as De}from"react";import{macOSColors as R,night as b,monoFont as Nt}from"@buoy-gg/shared-ui/web";y();J();M();import{buoyFetch as Ht}from"@buoy-gg/shared-ui/web";var X=new Map;async function Be(e){let t=V();if(t)return await t("proveSavings",{id:e.id});let r=re(e);if(!r)return{ok:false,message:"Measure the displayed image before optimizing it."};try{let o=await Ht(e.uri);if(!o.ok)throw new Error(`Image download returned HTTP ${o.status}.`);let i=await o.blob(),l=await createImageBitmap(i),a=document.createElement("canvas");a.width=Math.max(1,Math.min(l.width,Math.round(r.width))),a.height=Math.max(1,Math.min(l.height,Math.round(r.height)));let s=a.getContext("2d");if(!s)throw l.close(),new Error("Canvas is unavailable.");s.drawImage(l,0,0,a.width,a.height),l.close();let u=await new Promise((p,N)=>a.toBlob(te=>te?p(te):N(new Error("Image encoding failed.")),"image/webp",.8));if(u.type!=="image/webp")return{ok:false,message:"This browser cannot encode WebP images."};let S=X.get(e.id);S&&URL.revokeObjectURL(S);let h=URL.createObjectURL(u);for(X.set(e.id,h);X.size>30;){let[p,N]=X.entries().next().value;URL.revokeObjectURL(N),X.delete(p)}let $=i.size-u.size;return{ok:true,message:"WebP preview created.",originalBytes:i.size,originalBytesSource:"download",optimizedBytes:u.size,optimizedUri:h,optimizedDims:{width:a.width,height:a.height},savedBytes:$,savedPct:i.size?$/i.size*100:0}}catch(o){return{ok:false,message:`Image optimization failed: ${o instanceof Error?o.message:String(o)}`}}}J();M();import{Fragment as jt,jsx as n,jsxs as w}from"react/jsx-runtime";function F({title:e,children:t}){return w(m,{style:d.section,children:[n(g,{style:d.sectionTitle,children:e}),n(m,{style:d.sectionBody,children:t})]})}function Vt(e){return`buoy-images-detail-${e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}`}function c({label:e,value:t,color:r}){return w(m,{style:d.kvRow,children:[n(g,{style:d.kvLabel,children:e}),n(g,{testID:Vt(e),style:[d.kvValue,r?{color:r}:null],selectable:true,children:t})]})}function rt(e){let t=V();if(t){t("clearExpoCaches",{memory:e==="memory",disk:e==="disk"});return}try{let r=Re();e==="memory"?r.Image.clearMemoryCache():r.Image.clearDiskCache()}catch{}}function Ut({record:e}){let[t,r]=De(e.uri),o=t.trim(),i=e.mounted&&o.length>0&&o!==e.uri;return w(F,{title:"SWAP SOURCE URL",children:[n(vt,{style:d.urlInput,value:t,onChangeText:r,placeholder:"https://\u2026",placeholderTextColor:b.color.placeholder,autoCapitalize:"none",autoCorrect:false,multiline:true}),w(m,{style:d.actionsRow,children:[n(C,{style:[d.actionButton,!i&&d.actionDisabled],disabled:!i,onPress:()=>H(e.id,{source:{type:"url",uri:o},label:"URL swapped"}),children:n(g,{style:d.actionText,children:"Apply"})}),n(C,{style:d.actionButton,onPress:()=>r(e.uri),children:n(g,{style:d.actionText,children:"Reset field"})})]})]})}function Kt({record:e}){let[t,r]=De(false),[o,i]=De(null),l=()=>{r(true),Be(e).then(i).catch(a=>i({ok:false,message:String(a?.message??a)})).finally(()=>r(false))};return n(F,{title:"PROVE SAVINGS (re-encode on device)",children:o==null?n(m,{style:d.actionsRow,children:n(C,{style:d.actionButton,onPress:l,disabled:t,children:n(g,{style:d.actionText,children:t?"Re-encoding\u2026":"Re-encode at displayed size (WebP)"})})}):w(jt,{children:[n(c,{label:"Result",value:o.message||(o.ok?"done":"failed"),color:o.ok?R.semantic.success:R.semantic.error}),o.originalBytes!=null?n(c,{label:"Original",value:`${x(o.originalBytes)} (${o.originalBytesSource})`}):null,o.optimizedBytes!=null?n(c,{label:"Optimized",value:`${x(o.optimizedBytes)} \u2014 ${o.optimizedDims?.width}\xD7${o.optimizedDims?.height} WebP`,color:R.semantic.success}):null,o.savedBytes!=null?n(c,{label:"Saved",value:`${x(o.savedBytes)} (${o.savedPct}%)`,color:R.semantic.success}):null,w(m,{style:d.actionsRow,children:[o.ok&&o.optimizedUri&&e.mounted?n(C,{style:d.actionButton,onPress:()=>H(e.id,{source:{type:"url",uri:o.optimizedUri},label:"Optimized preview"}),children:n(g,{style:d.actionText,children:"Preview in place"})}):null,n(C,{style:d.actionButton,onPress:l,disabled:t,children:n(g,{style:d.actionText,children:t?"Re-encoding\u2026":"Re-run"})})]})]})})}function qt({record:e}){let t=ce(e),r=ue(e),o=re(e),i=oe(e),l=ae(e);return w(xt,{style:d.container,contentContainerStyle:d.content,children:[e.overrideLabel?w(m,{style:d.overrideBanner,children:[w(g,{style:d.overrideText,children:["Simulation active: ",e.overrideLabel," \u2014 stats below describe the override, not the original source."]}),n(C,{onPress:()=>ie(e.id),children:n(g,{style:d.overrideRestore,children:"RESTORE"})})]}):null,e.uri&&e.sourceKind!=="data"?n(m,{style:d.previewBox,children:n(Ge,{testID:"buoy-internal-images-preview",source:{uri:e.uri},style:d.preview,resizeMode:"contain"})}):null,w(F,{title:"SOURCE",children:[n(c,{label:"URI",value:e.uri||"(none)"}),n(c,{label:"Kind",value:e.sourceKind}),n(c,{label:"Library",value:e.lib==="web"?"Browser <img>":e.lib==="expo"?"expo-image":"RN <Image>"}),e.hasAltText===false?n(c,{label:"Alt text",value:"missing \u2014 add alt/accessibilityLabel",color:R.semantic.warning}):null,e.mediaType!=null?n(c,{label:"Media type",value:String(e.mediaType)}):null,e.isAnimated!=null?n(c,{label:"Animated",value:e.isAnimated?"yes":"no"}):null]}),w(F,{title:"LOAD",children:[n(c,{label:"Status",value:e.status,color:e.status==="error"?R.semantic.error:e.status==="loaded"?R.semantic.success:R.semantic.warning}),n(c,{label:"Duration",value:Q(e.durationMs)}),e.displayedAt&&e.loadedAt?n(c,{label:"Decode \u2192 display",value:Q(Math.max(0,e.displayedAt-e.loadedAt))}):null,n(c,{label:"Cache",value:`${r.label}`,color:r.color}),e.cacheVerdictSource?n(c,{label:"Cache source",value:e.cacheVerdictSource==="event"?"reported by expo-image onLoad":"Image.queryCache after load"}):null,e.progressSeen?n(c,{label:"Downloaded",value:e.bytesTotal?`${x(e.bytesLoaded??0)} / ${x(e.bytesTotal)}`:"network transfer observed"}):null,n(c,{label:"Load cycles",value:String(e.loadCount)}),n(c,{label:"Still mounted",value:e.mounted?"yes":"no"})]}),w(F,{title:"DIMENSIONS",children:[e.intrinsic?n(c,{label:"Decoded",value:`${e.intrinsic.width}\xD7${e.intrinsic.height} px`}):n(c,{label:"Decoded",value:"unknown"}),e.layout?n(c,{label:"Displayed",value:`${Math.round(e.layout.width)}\xD7${Math.round(e.layout.height)} dp (needs ${o?`${o.width}\xD7${o.height}`:"?"} px @${Math.round(Dt()*100)/100}x)`}):n(c,{label:"Displayed",value:"no layout yet"}),t.label?n(c,{label:"Verdict",value:t.label,color:t.color}):null,i>0?n(c,{label:"Est. decoded memory",value:x(i)}):null,l>0?n(c,{label:"Est. wasted",value:`${x(l)} \u2014 resize the source to ${o?`${o.width}\xD7${o.height}`:"the displayed size"}`,color:R.semantic.warning}):null,(e.layoutShifts??0)>0?n(c,{label:"Layout shifts",value:`${e.layoutShifts} \u2014 box resized after load; reserve explicit width/height`,color:R.semantic.warning}):null]}),e.sourceKind==="network"||e.sourceKind==="asset"?n(Kt,{record:e},`savings-${e.id}`):null,e.status==="error"?w(F,{title:"ERROR",children:[n(c,{label:"Message",value:e.error??"unknown",color:R.semantic.error}),e.errorCode!=null?n(c,{label:"HTTP status",value:String(e.errorCode)}):null,e.errorHeaders?Object.entries(e.errorHeaders).map(([a,s])=>n(c,{label:a,value:String(s)},a)):null]}):null,e.sourceKind==="network"&&e.mounted?n(Ut,{record:e},e.id):null,e.lib==="expo"?n(F,{title:"CACHE ACTIONS (expo-image, global)",children:w(m,{style:d.actionsRow,children:[n(C,{style:d.actionButton,onPress:()=>rt("memory"),children:n(g,{style:d.actionText,children:"Clear memory cache"})}),n(C,{style:d.actionButton,onPress:()=>rt("disk"),children:n(g,{style:d.actionText,children:"Clear disk cache"})})]})}):null]})}var d=I.create({container:{flex:1},content:{padding:12,gap:12},previewBox:{height:140,borderRadius:8,backgroundColor:b.color.bg,overflow:"hidden"},preview:{width:"100%",height:"100%"},section:{gap:6},sectionTitle:{color:b.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.8},sectionBody:{backgroundColor:b.color.surface,borderRadius:8,borderWidth:I.hairlineWidth,borderColor:b.color.border,paddingHorizontal:10,paddingVertical:4},kvRow:{flexDirection:"row",paddingVertical:5,gap:12},kvLabel:{color:b.color.textSecondary,fontSize:11,width:110},kvValue:{color:b.color.text,fontSize:11,flex:1},actionsRow:{flexDirection:"row",gap:8,paddingVertical:8},actionButton:{backgroundColor:b.color.surfaceElevated,borderRadius:6,paddingHorizontal:10,paddingVertical:6,borderWidth:I.hairlineWidth,borderColor:b.color.border},actionText:{color:b.color.text,fontSize:11,fontWeight:"600"},actionDisabled:{opacity:.4},urlInput:{color:b.color.text,fontSize:11,fontFamily:Nt,backgroundColor:b.color.surfaceElevated,borderRadius:6,borderWidth:I.hairlineWidth,borderColor:b.color.border,paddingHorizontal:8,paddingVertical:6,marginTop:8},overrideBanner:{flexDirection:"row",alignItems:"center",gap:10,padding:10,borderRadius:8,backgroundColor:b.color.warningSoft},overrideText:{flex:1,color:b.color.warning,fontSize:11,lineHeight:15},overrideRestore:{color:b.color.warning,fontSize:11,fontWeight:"700",letterSpacing:.5}});y();E();import{useState as Gt}from"react";import{ChevronLeft as _t,ChevronRight as Jt,FooterButton as Te,FooterMessage as ot,FooterRow as at,RefreshCw as Qt,ToolFooter as Xt,night as W}from"@buoy-gg/shared-ui/web";y();J();kt();function Yt(e){return le().actionListeners.add(e),()=>le().actionListeners.delete(e)}function it(e,t){let r=le(),o=r.reloadRequests.get(e);r.reloadRequests.set(e,{nonce:(o?.nonce??0)+1,bust:t}),pt(e)}function lt(){try{return Re().Image??null}catch{return null}}function Zt(){try{let e=Ft(),t=e?.default||e;if(t?.deleteAsync)return t}catch{}try{let e=Wt(),t=e?.default||e;if(t?.deleteAsync)return t}catch{}return null}async function Me(e){let t=lt(),r=Zt();if(!t?.getCachePathAsync||!r?.deleteAsync||!e.uri)return false;try{let o=await t.getCachePathAsync(e.uri);if(!o)return false;let i=o.startsWith("file://")?o:`file://${o}`;return await r.deleteAsync(i,{idempotent:true}),true}catch{return false}}async function Y(e){let t=V();if(t)return $e(t("retry",{id:e.id}));if(!e.mounted)return{ok:false,message:"Instance unmounted \u2014 cannot reload"};if(e.lib==="expo"){let r=le().expoInstances.get(e.id);return r?.reloadAsync?(await r.reloadAsync(),{ok:true,message:"Reload requested"}):{ok:false,message:"Live instance not reachable"}}return it(e.id,false),{ok:true,message:"Remounting image"}}async function ze(){let e=V();if(e)return $e(e("massAction",{kind:"reload"}));let{getSnapshot:t}=(M(),ft(gt)),r=0;for(let o of t()){if(!o.mounted)continue;(await he(o)).ok&&r++}return{ok:r>0,message:`Hard-reloading ${r} mounted image${r===1?"":"s"}`}}async function he(e){let t=V();if(t)return $e(t("hardReload",{id:e.id}));if(!e.mounted)return{ok:false,message:"Instance unmounted \u2014 cannot reload"};if(e.sourceKind!=="network")return Y(e);if(e.lib==="expo"){let r=await Me(e);await lt()?.clearMemoryCache?.().catch?.(()=>false);let o=await Y(e);return o.ok?{ok:true,message:r?"Disk entry evicted, memory cache cleared, refetching":"Memory cache cleared, refetching (no disk entry found)"}:o}return it(e.id,true),{ok:true,message:"Refetching with cache bypassed"}}import{jsx as f,jsxs as Ae}from"react/jsx-runtime";function er({record:e,hasPrevious:t,hasNext:r,onPrevious:o,onNext:i}){let[l,a]=Gt(null),s=$=>{a("\u2026"),$().then(p=>a(p.message)).catch(p=>a(String(p?.message??p)))},u=!e.mounted,S=e.overrideLabel!=null,h=($,p)=>{H(e.id,{source:$,label:p}),a(`${p} \u2014 Restore to undo`)};return Ae(Xt,{children:[l?f(ot,{testID:"buoy-images-detail-footer-message",children:l}):u?f(ot,{tone:"muted",children:"Instance unmounted \u2014 reload actions need the image on screen."}):null,Ae(at,{style:{gap:8},children:[f(C,{onPress:o,disabled:!t,style:[me.navButton,!t&&me.disabled],activeOpacity:.7,testID:"buoy-images-detail-previous",accessibilityLabel:"Previous image",children:f(_t,{size:20,color:t?W.color.accent:W.color.textTertiary})}),f(Te,{label:"Hard reload",size:"md",testID:"buoy-images-detail-hard-reload",disabled:u,icon:f(Qt,{size:13,color:u?W.color.textTertiary:W.color.info}),onPress:()=>s(()=>he(e))}),f(Te,{label:e.status==="error"?"Retry":"Reload",size:"md",testID:"buoy-images-detail-reload",disabled:u,onPress:()=>s(()=>Y(e))}),f(C,{onPress:i,disabled:!r,style:[me.navButton,!r&&me.disabled],activeOpacity:.7,testID:"buoy-images-detail-next",accessibilityLabel:"Next image",children:f(Jt,{size:20,color:r?W.color.accent:W.color.textTertiary})})]}),Ae(at,{style:{gap:8},children:[f(Z,{label:"Error",disabled:u,onPress:()=>h({type:"error"},"Forced error")}),f(Z,{label:"Loading",disabled:u,onPress:()=>h({type:"hang"},"Forced loading")}),f(Z,{label:"Blank",disabled:u,onPress:()=>h({type:"blank"},"Blanked")}),f(Z,{label:"Find",disabled:u,onPress:()=>{xe(e.id),a("Flashing a red border on the image (2.5s)")}}),f(Z,{label:"Restore",accent:true,disabled:!S,onPress:()=>{ie(e.id),a("Override removed \u2014 original source restored")}})]})]})}function Z({label:e,onPress:t,disabled:r,accent:o}){return f(Te,{label:e,onPress:t,disabled:r,accent:o,testID:`buoy-images-sim-${e.toLowerCase()}`,style:{paddingVertical:7}})}var me=I.create({navButton:{paddingHorizontal:10,paddingVertical:8,borderRadius:6,backgroundColor:W.color.button,alignItems:"center",justifyContent:"center"},disabled:{opacity:.4}});y();E();import{macOSColors as tr,night as A,Pill as Le}from"@buoy-gg/shared-ui/web";import{jsx as D,jsxs as ee}from"react/jsx-runtime";function rr({record:e,onPress:t}){let r=ce(e),o=ue(e),i=e.sourceKind==="network"||e.sourceKind==="asset"||e.sourceKind==="file",l=`buoy-image-row-${e.id}`;return ee(C,{style:k.row,testID:l,onPress:()=>t(e.id),children:[ee(m,{style:k.thumbBox,children:[i&&e.uri?D(Ge,{testID:"buoy-internal-images-thumb",source:{uri:e.uri},style:k.thumb,resizeMode:"cover"}):D(g,{style:k.thumbFallback,children:"?"}),D(m,{testID:`${l}-status`,accessibilityLabel:e.status,style:[k.statusDot,{backgroundColor:Pt(e)}]})]}),ee(m,{style:k.main,children:[D(g,{style:k.name,numberOfLines:1,testID:`${l}-name`,children:Ie(e.uri)}),ee(m,{style:k.metaRow,children:[D(Le,{variant:"text",label:e.lib==="web"?"WEB":e.lib==="expo"?"EXPO":"RN",color:A.color.textTertiary}),D(Le,{variant:"text",label:o.label,color:o.color,testID:`${l}-cache`}),e.overrideLabel?D(Le,{variant:"text",label:"SIM",color:A.color.warning,testID:`${l}-sim`}):null,D(g,{style:k.meta,children:Q(e.durationMs)}),e.intrinsic?ee(g,{style:k.meta,testID:`${l}-size`,children:[e.intrinsic.width,"\xD7",e.intrinsic.height]}):null]})]}),D(m,{style:k.right,children:e.status==="error"?D(g,{testID:`${l}-verdict`,style:[k.verdict,{color:tr.semantic.error}],children:"FAILED"}):r.label?D(g,{testID:`${l}-verdict`,style:[k.verdict,{color:r.color}],children:r.label}):null})]})}var k=I.create({row:{flexDirection:"row",alignItems:"center",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:I.hairlineWidth,borderBottomColor:A.color.border,gap:10},thumbBox:{width:40,height:40,borderRadius:6,backgroundColor:A.color.bg,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:40,height:40},thumbFallback:{color:A.color.textTertiary,fontSize:16,fontWeight:"700"},statusDot:{position:"absolute",right:2,bottom:2,width:8,height:8,borderRadius:4,borderWidth:1,borderColor:A.color.bg},main:{flex:1,gap:2},name:{color:A.color.text,fontSize:12,fontWeight:"600"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:A.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end"},verdict:{fontSize:10,fontWeight:"700"}});y();import{ModalHeader as L,ToolbarClearButton as or,ToolbarCopyButton as nt}from"@buoy-gg/shared-ui/web";import{jsx as P,jsxs as Pe}from"react/jsx-runtime";function ar({stats:e,detailOpen:t,detailIndex:r=-1,detailTotal:o=0,onCloseDetail:i,onClear:l,getReport:a,onBack:s}){if(t){let S=r>=0&&o>0?`${r+1} of ${o}`:void 0;return Pe(L,{children:[P(L.Navigation,{onBack:i}),P(L.Content,{title:"Image detail",subtitle:S,testID:"buoy-images-detail-title"}),P(L.Actions,{children:P(nt,{value:a})})]})}let u=[`${e.total} images`,`${e.errors} failed`,`\u2248${x(e.estDecodedBytes)} decoded`];return e.estWastedBytes>0&&u.push(`${x(e.estWastedBytes)} wasted`),Pe(L,{children:[s?P(L.Navigation,{onBack:s}):null,P(L.Content,{title:"Images",subtitle:u.join(" \xB7 "),testID:"buoy-images-title"}),Pe(L.Actions,{children:[P(nt,{value:a}),P(or,{onPress:l,testID:"buoy-images-clear"})]})]})}y();E();import{useState as ir,useSyncExternalStore as lr}from"react";import{FooterButton as st,FooterCaption as nr,FooterMessage as sr,FooterRow as dt,ToolFooter as dr,night as cr}from"@buoy-gg/shared-ui/web";import{jsx as B,jsxs as Oe}from"react/jsx-runtime";var ur=[{key:"normal",label:"Normal"},{key:"offline",label:"Offline"},{key:"cold",label:"Cold"}];function hr(){let[e,t]=ir(null),r=lr(Yt,()=>j().network),o=(i,l)=>{let a=G(i,l);t(a>0?`${l} on ${a} image${a===1?"":"s"} \u2014 Restore all to undo`:"No mounted images")};return Oe(dr,{paddingBottom:10,style:{paddingTop:8},children:[e?B(sr,{testID:"buoy-images-message",children:e}):B(nr,{children:"MASS ACTIONS \u2014 every image on screen"}),Oe(dt,{children:[B(U,{label:"Error",onPress:()=>o({type:"error"},"Forced error")}),B(U,{label:"Loading",onPress:()=>o({type:"hang"},"Forced loading")}),B(U,{label:"Blank",onPress:()=>o({type:"blank"},"Blanked")}),B(U,{label:"Reload",onPress:()=>{t("\u2026"),ze().then(i=>t(i.message))}}),B(U,{label:"Find",onPress:()=>{let i=ve();t(`Flashing ${i} image${i===1?"":"s"} (2.5s)`)}}),B(U,{label:"Restore",accent:true,onPress:()=>{let i=fe();t(i>0?`Restored ${i} image${i===1?"":"s"}`:"No overrides active")}})]}),Oe(dt,{children:[B(g,{style:mr.netLabel,children:"NET"}),ur.map(i=>{let l=r===i.key;return B(st,{label:i.label,active:l,testID:`buoy-images-net-${i.key}`,style:{paddingVertical:6},onPress:()=>{we(i.key),t(i.key==="normal"?"Network simulation off \u2014 tap RELOAD to load normally again":i.key==="offline"?"Offline: network images FAIL (bundled assets still load) \u2014 tap RELOAD to apply to on-screen images":"Cold (bypass caches) \u2014 tap RELOAD: everything refetches like first launch")}},i.key)})]})]})}function U({label:e,onPress:t,accent:r}){return B(st,{label:e,onPress:t,accent:r,testID:`buoy-images-mass-${e.toLowerCase()}`})}var mr=I.create({netLabel:{color:cr.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.8,alignSelf:"center",marginRight:2}});y();E();import{night as Ee}from"@buoy-gg/shared-ui/web";import{jsx as Fe}from"react/jsx-runtime";function gr({insights:e}){let t=Xe(e);return t.length===0?null:Fe(m,{style:We.bar,children:t.map(r=>Fe(m,{style:We.chip,children:Fe(g,{style:We.chipText,testID:`buoy-images-insight-${r.key}`,children:r.text})},r.key))})}var We=I.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8,borderBottomWidth:I.hairlineWidth,borderBottomColor:Ee.color.border},chip:{backgroundColor:Ee.color.warningSoft,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{color:Ee.color.warning,fontSize:10,fontWeight:"600",lineHeight:13}});import{jsx as v,jsxs as Ne}from"react/jsx-runtime";function pr(){let e=_(),t=[];return e.rnDecoratorTooLate&&t.push('RN <Image> instrumentation missed the module-load race \u2014 add `import "@buoy-gg/images/register"` as the FIRST import of your entry file.'),!e.browserObserverActive&&!e.expoAvailable&&!e.rnDecoratorActive&&!e.rnDecoratorTooLate&&t.push("Waiting for images\u2026 render some <Image> components to populate the list."),t.length===0?null:v(m,{style:K.notice,children:t.map(r=>v(g,{style:K.noticeText,children:r},r))})}function yr(){return v(Lt,{testID:"buoy-images-empty",otto:"listening",title:"No images captured yet",message:"Every RN <Image> and expo-image load is recorded here with cache verdicts, timings, and oversize checks."})}function He({visible:e,onClose:t,onBack:r,onMinimize:o,persistenceKey:i,inline:l=false}){qe();let{records:a,stats:s}=tt(),[u,S]=Tt(null),h=u!=null?_e(u):void 0,$=h?.status==="error"&&h.errorHeaders==null?h.id:null;Bt(()=>{let T=V();if($==null||!T)return;let q=false;return T("getDetail",{id:$}).then(ht=>{if(q)return;let mt=ht?.errorHeaders;Ct($,{errorHeaders:mt??{}})}).catch(()=>{}),()=>{q=true}},[$]);let p=h?a.findIndex(T=>T.id===h.id):-1,N=T=>{let q=a[T];q&&S(q.id)},te=()=>h?Ze(h):et(a,s,de(a),_(),j()),Ve=v(ar,{stats:s,detailOpen:h!=null,detailIndex:p,detailTotal:a.length,onCloseDetail:()=>S(null),onClear:Se,getReport:te,onBack:r}),Ue=h?Ne(m,{style:K.detailContainer,children:[v(qt,{record:h}),v(er,{record:h,hasPrevious:p>0,hasNext:p>=0&&p<a.length-1,onPrevious:()=>N(p-1),onNext:()=>N(p+1)},h.id)]}):Ne(m,{style:K.listContainer,children:[v(gr,{insights:de(a)}),v(pr,{}),v($t,{testID:"buoy-images-list",data:a,keyExtractor:T=>String(T.id),renderItem:({item:T})=>v(rr,{record:T,onPress:S}),ListEmptyComponent:v(yr,{})}),v(hr,{})]});return l?Ne(m,{style:K.inlineRoot,children:[v(m,{style:K.inlineHeader,...At,children:Ve}),Ue]}):v(Mt,{visible:e,onClose:t,onMinimize:o,persistenceKey:i,header:{showToggleButton:true,customContent:Ve},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:Ue})}function br(e={}){return v(He,{...e,inline:true,visible:true,onClose:()=>{}})}var K=I.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:zt.border.default,backgroundColor:"transparent"},listContainer:{flex:1},detailContainer:{flex:1},notice:{margin:10,padding:10,borderRadius:8,backgroundColor:se.color.warningSoft,gap:4},noticeText:{color:se.color.warning,fontSize:11},empty:{alignItems:"center",padding:32,gap:8},emptyTitle:{color:se.color.text,fontSize:13,fontWeight:"600"},emptyText:{color:se.color.textSecondary,fontSize:11,textAlign:"center",lineHeight:16}});import{createToolFactory as fr,defineToolPreset as vr}from"@buoy-gg/shared-ui/web";import{jsx as xr}from"react/jsx-runtime";var ct=vr({id:"images",name:"IMAGES",description:"Image loads, caching, failures, and oversize checks",slot:"both",icon:({size:e,color:t})=>xr(Je,{size:e,color:t||Qe}),component:He}),wr=fr(ct);y();import{useEffect as $r}from"react";function kr(){return $r(bt,[]),null}y();M();var ge=2*1024;function pe(e){if(!e)return e;if(e.startsWith("data:")){let t=e.indexOf(","),r=t>=0?e.slice(0,Math.min(t+1,64)):"data:",o=t>=0?e.slice(t+1):e,i=o.length>16?`${o.slice(0,8)}\u2026${o.slice(-8)}`:o;return`${r}[${e.length} chars ${i}]`}return e.length<=ge?e:`${e.slice(0,ge)}\u2026 [${e.length-ge} more]`}function Sr(e,t=ge){return e?e.length<=t?e:`${e.slice(0,t)}\u2026 [${e.length-t} more]`:null}function Cr(e){return{...e,duplicates:e.duplicates.map(t=>({...t,uri:pe(t.uri)})),retryStorms:e.retryStorms.map(t=>({...t,uri:pe(t.uri)})),layoutShifters:e.layoutShifters.map(t=>({...t,uri:pe(t.uri)}))}}function je(e){let t=ye(e);return{id:e.id,lib:e.lib,uri:pe(e.uri),kind:e.sourceKind,status:e.status,mounted:e.mounted,cache:e.cacheVerdict??null,cacheSource:e.cacheVerdictSource??null,ms:e.durationMs!=null?Math.round(e.durationMs):null,intrinsic:e.intrinsic??null,layout:e.layout?{width:Math.round(e.layout.width),height:Math.round(e.layout.height)}:null,neededPx:re(e),oversizeFactor:t!=null?Math.round(t*100)/100:null,decodedKB:Math.round(oe(e)/1024),wastedKB:Math.round(ae(e)/1024),progressSeen:e.progressSeen===true,bytesTotal:e.bytesTotal??null,error:Sr(e.error),errorCode:e.errorCode??null,loadCount:e.loadCount,overrideLabel:e.overrideLabel??null,hasAltText:e.hasAltText??null,layoutShifts:e.layoutShifts??0,ageMs:Date.now()-e.createdAt}}function O(e){let t=e?.id;if(typeof t!="number")throw new Error("Missing numeric `id` param");let r=_e(t);if(!r)throw new Error(`Image record ${t} not found (cleared or evicted) \u2014 re-run the list action for current ids.`);return r}function ut(){let e=ne();return{stats:be(e),captureStatus:_(),globalModes:j(),insights:Cr(de(e)),records:[...e].reverse()}}var Ir={version:1,getSnapshot:()=>{let{records:e,...t}=ut();return{...t,records:e.slice(0,100).map(je)}},subscribe:e=>ke(e),actions:{list:e=>{let t=e??{},r=Math.min(Math.max(t.limit??50,1),200),{records:o,...i}=ut(),l=t.status?o.filter(a=>a.status===t.status):o;return{...i,total:l.length,records:l.slice(0,r).map(je)}},getDetail:e=>{let t=O(e);return{...je(t),errorHeaders:t.errorHeaders??null}},hardReload:e=>he(O(e)),proveSavings:e=>Be(O(e)),retry:e=>Y(O(e)),evictDisk:async e=>{let t=O(e),r=await Me(t);return{ok:r,message:r?"Disk cache entry deleted":"No disk entry found (expo-image + expo-file-system required)"}},flash:e=>(xe(O(e).id),{ok:true,message:"Flashing for 2.5s"}),setOverride:e=>{let t=O(e),r=e,o={error:{source:{type:"error"},label:"Forced error"},hang:{source:{type:"hang"},label:"Forced loading"},blank:{source:{type:"blank"},label:"Blanked"}};if(r.kind==="url"){if(!r.uri)throw new Error("kind 'url' requires a `uri` param");return H(t.id,{source:{type:"url",uri:r.uri},label:"URL swapped"}),{ok:true,message:`Source overridden to ${r.uri}`}}let i=r.kind?o[r.kind]:void 0;if(!i)throw new Error(`Unknown override kind: ${String(r.kind)}`);return t.mounted?(H(t.id,i),{ok:true,message:`${i.label} applied`}):{ok:false,message:"Instance unmounted \u2014 overrides need the image on screen"}},clearOverride:e=>(ie(O(e).id),{ok:true,message:"Override removed \u2014 original source restored"}),massAction:async e=>{let t=e?.kind;switch(t){case"error":{let r=G({type:"error"},"Forced error");return{ok:r>0,message:`Forced error on ${r} images`}}case"loading":{let r=G({type:"hang"},"Forced loading");return{ok:r>0,message:`Forced loading on ${r} images`}}case"blank":{let r=G({type:"blank"},"Blanked");return{ok:r>0,message:`Blanked ${r} images`}}case"reload":return ze();case"flash":{let r=ve();return{ok:r>0,message:`Flashing ${r} images`}}case"restore":return{ok:true,message:`Restored ${fe()} images`};default:throw new Error(`Unknown mass kind: ${String(t)}`)}},setNetworkMode:e=>{let t=e?.mode;if(t!=="normal"&&t!=="offline"&&t!=="cold")throw new Error("mode must be 'normal' | 'offline' | 'cold'");return we(t),{ok:true,modes:j()}},setBlankImages:e=>(Ke(e?.enabled===true),{ok:true,modes:j()}),clearRecords:()=>(Se(),{ok:true,message:"Registry cleared"}),clearExpoCaches:async e=>{let t=e??{},r=t.memory!==false,o=t.disk!==false;try{let i=Re(),l=[];return r&&(await i.Image.clearMemoryCache(),l.push("memory")),o&&(await i.Image.clearDiskCache(),l.push("disk")),{ok:true,message:`Cleared expo-image ${l.join(" + ")} cache`}}catch{return{ok:false,message:"expo-image not installed"}}},getCaptureStatus:()=>_()}};M();J();M();export{Qe as IMAGES_ICON_COLOR,Je as ImagesIcon,He as ImagesModal,kr as ImagesRoot,br as ImagesToolView,fe as clearAllOverrides,ie as clearOverride,Se as clearRecords,de as computeInsights,be as computeStats,wr as createImagesTool,It as disableImagesCapture,oe as estDecodedBytes,ae as estWastedBytes,Me as evictExpoDiskEntry,ve as flashAllMounted,xe as flashRecord,Ze as formatRecordMarkdown,et as formatRegistryMarkdown,_ as getCaptureStatus,j as getGlobalModes,ne as getImageRecords,yt as getOverride,ze as hardReloadAllMounted,he as hardReloadRecord,Ir as imagesSyncAdapter,ct as imagesToolPreset,Ye as insightChips,qe as installImageCapture,ye as oversizeFactor,Be as proveSavings,Rt as replaceImagesFromSnapshot,Y as retryRecord,Ke as setBlankImages,we as setNetworkMode,H as setOverride,G as setOverrideForAllMounted,St as setRemoteImagesHandler,ke as subscribeImageRecords,tt as useImageRecords};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/images",
3
- "version": "7.0.67",
3
+ "version": "7.0.69",
4
4
  "description": "Inspect instrumented React Native Image and expo-image loads, available cache and timing data, failures, and image-size estimates.",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -19,7 +19,7 @@
19
19
  "**/autoCapture.*"
20
20
  ],
21
21
  "dependencies": {
22
- "@buoy-gg/shared-ui": "^7.0.67"
22
+ "@buoy-gg/shared-ui": "^7.0.69"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": "*"