@buoy-gg/images 7.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +58 -0
  3. package/lib/commonjs/capture/actions.js +227 -0
  4. package/lib/commonjs/capture/actions.js.map +1 -0
  5. package/lib/commonjs/capture/install.js +41 -0
  6. package/lib/commonjs/capture/install.js.map +1 -0
  7. package/lib/commonjs/capture/installExpoImage.js +99 -0
  8. package/lib/commonjs/capture/installExpoImage.js.map +1 -0
  9. package/lib/commonjs/capture/installRnImage.js +128 -0
  10. package/lib/commonjs/capture/installRnImage.js.map +1 -0
  11. package/lib/commonjs/capture/overrides.js +286 -0
  12. package/lib/commonjs/capture/overrides.js.map +1 -0
  13. package/lib/commonjs/capture/savings.js +193 -0
  14. package/lib/commonjs/capture/savings.js.map +1 -0
  15. package/lib/commonjs/capture/shared.js +367 -0
  16. package/lib/commonjs/capture/shared.js.map +1 -0
  17. package/lib/commonjs/components/ImageDetail.js +444 -0
  18. package/lib/commonjs/components/ImageDetail.js.map +1 -0
  19. package/lib/commonjs/components/ImageDetailFooter.js +232 -0
  20. package/lib/commonjs/components/ImageDetailFooter.js.map +1 -0
  21. package/lib/commonjs/components/ImageRow.js +164 -0
  22. package/lib/commonjs/components/ImageRow.js.map +1 -0
  23. package/lib/commonjs/components/ImagesHeader.js +63 -0
  24. package/lib/commonjs/components/ImagesHeader.js.map +1 -0
  25. package/lib/commonjs/components/ImagesIcon.js +59 -0
  26. package/lib/commonjs/components/ImagesIcon.js.map +1 -0
  27. package/lib/commonjs/components/ImagesListFooter.js +194 -0
  28. package/lib/commonjs/components/ImagesListFooter.js.map +1 -0
  29. package/lib/commonjs/components/ImagesModal.js +173 -0
  30. package/lib/commonjs/components/ImagesModal.js.map +1 -0
  31. package/lib/commonjs/components/ImagesRoot.js +24 -0
  32. package/lib/commonjs/components/ImagesRoot.js.map +1 -0
  33. package/lib/commonjs/components/InsightsBar.js +59 -0
  34. package/lib/commonjs/components/InsightsBar.js.map +1 -0
  35. package/lib/commonjs/export.js +81 -0
  36. package/lib/commonjs/export.js.map +1 -0
  37. package/lib/commonjs/format.js +117 -0
  38. package/lib/commonjs/format.js.map +1 -0
  39. package/lib/commonjs/hooks/useImageRecords.js +20 -0
  40. package/lib/commonjs/hooks/useImageRecords.js.map +1 -0
  41. package/lib/commonjs/index.js +236 -0
  42. package/lib/commonjs/index.js.map +1 -0
  43. package/lib/commonjs/package.json +1 -0
  44. package/lib/commonjs/preset.js +45 -0
  45. package/lib/commonjs/preset.js.map +1 -0
  46. package/lib/commonjs/register.js +19 -0
  47. package/lib/commonjs/register.js.map +1 -0
  48. package/lib/commonjs/state.js +54 -0
  49. package/lib/commonjs/state.js.map +1 -0
  50. package/lib/commonjs/store/imageEventStore.js +160 -0
  51. package/lib/commonjs/store/imageEventStore.js.map +1 -0
  52. package/lib/commonjs/store/insights.js +76 -0
  53. package/lib/commonjs/store/insights.js.map +1 -0
  54. package/lib/commonjs/sync/imagesSyncAdapter.js +315 -0
  55. package/lib/commonjs/sync/imagesSyncAdapter.js.map +1 -0
  56. package/lib/commonjs/types.js +2 -0
  57. package/lib/commonjs/types.js.map +1 -0
  58. package/lib/module/capture/actions.js +214 -0
  59. package/lib/module/capture/actions.js.map +1 -0
  60. package/lib/module/capture/install.js +36 -0
  61. package/lib/module/capture/install.js.map +1 -0
  62. package/lib/module/capture/installExpoImage.js +94 -0
  63. package/lib/module/capture/installExpoImage.js.map +1 -0
  64. package/lib/module/capture/installRnImage.js +122 -0
  65. package/lib/module/capture/installRnImage.js.map +1 -0
  66. package/lib/module/capture/overrides.js +269 -0
  67. package/lib/module/capture/overrides.js.map +1 -0
  68. package/lib/module/capture/savings.js +189 -0
  69. package/lib/module/capture/savings.js.map +1 -0
  70. package/lib/module/capture/shared.js +359 -0
  71. package/lib/module/capture/shared.js.map +1 -0
  72. package/lib/module/components/ImageDetail.js +440 -0
  73. package/lib/module/components/ImageDetail.js.map +1 -0
  74. package/lib/module/components/ImageDetailFooter.js +228 -0
  75. package/lib/module/components/ImageDetailFooter.js.map +1 -0
  76. package/lib/module/components/ImageRow.js +160 -0
  77. package/lib/module/components/ImageRow.js.map +1 -0
  78. package/lib/module/components/ImagesHeader.js +59 -0
  79. package/lib/module/components/ImagesHeader.js.map +1 -0
  80. package/lib/module/components/ImagesIcon.js +55 -0
  81. package/lib/module/components/ImagesIcon.js.map +1 -0
  82. package/lib/module/components/ImagesListFooter.js +190 -0
  83. package/lib/module/components/ImagesListFooter.js.map +1 -0
  84. package/lib/module/components/ImagesModal.js +169 -0
  85. package/lib/module/components/ImagesModal.js.map +1 -0
  86. package/lib/module/components/ImagesRoot.js +20 -0
  87. package/lib/module/components/ImagesRoot.js.map +1 -0
  88. package/lib/module/components/InsightsBar.js +55 -0
  89. package/lib/module/components/InsightsBar.js.map +1 -0
  90. package/lib/module/export.js +76 -0
  91. package/lib/module/export.js.map +1 -0
  92. package/lib/module/format.js +108 -0
  93. package/lib/module/format.js.map +1 -0
  94. package/lib/module/hooks/useImageRecords.js +16 -0
  95. package/lib/module/hooks/useImageRecords.js.map +1 -0
  96. package/lib/module/index.js +73 -0
  97. package/lib/module/index.js.map +1 -0
  98. package/lib/module/preset.js +40 -0
  99. package/lib/module/preset.js.map +1 -0
  100. package/lib/module/register.js +19 -0
  101. package/lib/module/register.js.map +1 -0
  102. package/lib/module/state.js +50 -0
  103. package/lib/module/state.js.map +1 -0
  104. package/lib/module/store/imageEventStore.js +146 -0
  105. package/lib/module/store/imageEventStore.js.map +1 -0
  106. package/lib/module/store/insights.js +71 -0
  107. package/lib/module/store/insights.js.map +1 -0
  108. package/lib/module/sync/imagesSyncAdapter.js +311 -0
  109. package/lib/module/sync/imagesSyncAdapter.js.map +1 -0
  110. package/lib/module/types.js +2 -0
  111. package/lib/module/types.js.map +1 -0
  112. package/lib/typescript/capture/actions.d.ts +49 -0
  113. package/lib/typescript/capture/actions.d.ts.map +1 -0
  114. package/lib/typescript/capture/install.d.ts +15 -0
  115. package/lib/typescript/capture/install.d.ts.map +1 -0
  116. package/lib/typescript/capture/installExpoImage.d.ts +23 -0
  117. package/lib/typescript/capture/installExpoImage.d.ts.map +1 -0
  118. package/lib/typescript/capture/installRnImage.d.ts +24 -0
  119. package/lib/typescript/capture/installRnImage.d.ts.map +1 -0
  120. package/lib/typescript/capture/overrides.d.ts +83 -0
  121. package/lib/typescript/capture/overrides.d.ts.map +1 -0
  122. package/lib/typescript/capture/savings.d.ts +37 -0
  123. package/lib/typescript/capture/savings.d.ts.map +1 -0
  124. package/lib/typescript/capture/shared.d.ts +61 -0
  125. package/lib/typescript/capture/shared.d.ts.map +1 -0
  126. package/lib/typescript/components/ImageDetail.d.ts +13 -0
  127. package/lib/typescript/components/ImageDetail.d.ts.map +1 -0
  128. package/lib/typescript/components/ImageDetailFooter.d.ts +19 -0
  129. package/lib/typescript/components/ImageDetailFooter.d.ts.map +1 -0
  130. package/lib/typescript/components/ImageRow.d.ts +15 -0
  131. package/lib/typescript/components/ImageRow.d.ts.map +1 -0
  132. package/lib/typescript/components/ImagesHeader.d.ts +25 -0
  133. package/lib/typescript/components/ImagesHeader.d.ts.map +1 -0
  134. package/lib/typescript/components/ImagesIcon.d.ts +13 -0
  135. package/lib/typescript/components/ImagesIcon.d.ts.map +1 -0
  136. package/lib/typescript/components/ImagesListFooter.d.ts +8 -0
  137. package/lib/typescript/components/ImagesListFooter.d.ts.map +1 -0
  138. package/lib/typescript/components/ImagesModal.d.ts +17 -0
  139. package/lib/typescript/components/ImagesModal.d.ts.map +1 -0
  140. package/lib/typescript/components/ImagesRoot.d.ts +11 -0
  141. package/lib/typescript/components/ImagesRoot.d.ts.map +1 -0
  142. package/lib/typescript/components/InsightsBar.d.ts +13 -0
  143. package/lib/typescript/components/InsightsBar.d.ts.map +1 -0
  144. package/lib/typescript/export.d.ts +12 -0
  145. package/lib/typescript/export.d.ts.map +1 -0
  146. package/lib/typescript/format.d.ts +26 -0
  147. package/lib/typescript/format.d.ts.map +1 -0
  148. package/lib/typescript/hooks/useImageRecords.d.ts +11 -0
  149. package/lib/typescript/hooks/useImageRecords.d.ts.map +1 -0
  150. package/lib/typescript/index.d.ts +33 -0
  151. package/lib/typescript/index.d.ts.map +1 -0
  152. package/lib/typescript/preset.d.ts +38 -0
  153. package/lib/typescript/preset.d.ts.map +1 -0
  154. package/lib/typescript/register.d.ts +15 -0
  155. package/lib/typescript/register.d.ts.map +1 -0
  156. package/lib/typescript/state.d.ts +54 -0
  157. package/lib/typescript/state.d.ts.map +1 -0
  158. package/lib/typescript/store/imageEventStore.d.ts +34 -0
  159. package/lib/typescript/store/imageEventStore.d.ts.map +1 -0
  160. package/lib/typescript/store/insights.d.ts +11 -0
  161. package/lib/typescript/store/insights.d.ts.map +1 -0
  162. package/lib/typescript/sync/imagesSyncAdapter.d.ts +205 -0
  163. package/lib/typescript/sync/imagesSyncAdapter.d.ts.map +1 -0
  164. package/lib/typescript/types.d.ts +121 -0
  165. package/lib/typescript/types.d.ts.map +1 -0
  166. package/package.json +67 -0
  167. package/register.d.ts +1 -0
  168. package/register.js +15 -0
  169. package/src/capture/actions.ts +206 -0
  170. package/src/capture/install.ts +36 -0
  171. package/src/capture/installExpoImage.ts +115 -0
  172. package/src/capture/installRnImage.tsx +133 -0
  173. package/src/capture/overrides.ts +282 -0
  174. package/src/capture/savings.ts +193 -0
  175. package/src/capture/shared.ts +387 -0
  176. package/src/components/ImageDetail.tsx +456 -0
  177. package/src/components/ImageDetailFooter.tsx +270 -0
  178. package/src/components/ImageRow.tsx +148 -0
  179. package/src/components/ImagesHeader.tsx +77 -0
  180. package/src/components/ImagesIcon.tsx +66 -0
  181. package/src/components/ImagesListFooter.tsx +193 -0
  182. package/src/components/ImagesModal.tsx +195 -0
  183. package/src/components/ImagesRoot.tsx +18 -0
  184. package/src/components/InsightsBar.tsx +51 -0
  185. package/src/export.ts +100 -0
  186. package/src/format.ts +85 -0
  187. package/src/hooks/useImageRecords.ts +24 -0
  188. package/src/index.tsx +108 -0
  189. package/src/preset.tsx +35 -0
  190. package/src/register.ts +17 -0
  191. package/src/state.ts +88 -0
  192. package/src/store/imageEventStore.ts +162 -0
  193. package/src/store/insights.ts +66 -0
  194. package/src/sync/imagesSyncAdapter.ts +261 -0
  195. package/src/types.ts +111 -0
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Formatting + verdict helpers shared by list rows and the detail view.
5
+ */
6
+
7
+ import { macOSColors } from "@buoy-gg/shared-ui";
8
+ import { oversizeFactor } from "./store/imageEventStore";
9
+ export function formatBytes(bytes) {
10
+ if (bytes <= 0) return "0 B";
11
+ if (bytes < 1024) return `${bytes} B`;
12
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
13
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
14
+ }
15
+ export function formatMs(ms) {
16
+ if (ms == null) return "—";
17
+ if (ms < 1000) return `${Math.round(ms)}ms`;
18
+ return `${(ms / 1000).toFixed(2)}s`;
19
+ }
20
+
21
+ /** Last path segment of a URI, for compact row display. */
22
+ export function uriTail(uri) {
23
+ if (!uri) return "(no source)";
24
+ // Metro dev-server asset URLs put the real path in ?unstable_path=…
25
+ const unstable = uri.match(/[?&]unstable_path=([^&?]+)/);
26
+ const effective = unstable ? decodeURIComponent(unstable[1]) : uri;
27
+ const withoutQuery = effective.split("?")[0] ?? effective;
28
+ const segments = withoutQuery.split("/").filter(Boolean);
29
+ return segments[segments.length - 1] ?? effective;
30
+ }
31
+ /**
32
+ * Fresco-style fit verdict: green within 10%, yellow within 50%, red beyond.
33
+ * Undersized sources (upscaled, likely blurry) get their own callout.
34
+ */
35
+ export function sizeVerdict(record) {
36
+ const factor = oversizeFactor(record);
37
+ if (factor == null) return {
38
+ label: "",
39
+ color: macOSColors.text.muted,
40
+ factor
41
+ };
42
+ if (factor < 0.9) {
43
+ return {
44
+ label: `${factor.toFixed(1)}× upscaled`,
45
+ color: macOSColors.semantic.info,
46
+ factor
47
+ };
48
+ }
49
+ if (factor <= 1.1) {
50
+ return {
51
+ label: "right-sized",
52
+ color: macOSColors.semantic.success,
53
+ factor
54
+ };
55
+ }
56
+ if (factor <= 1.5) {
57
+ return {
58
+ label: `${factor.toFixed(1)}× oversized`,
59
+ color: macOSColors.semantic.warning,
60
+ factor
61
+ };
62
+ }
63
+ return {
64
+ label: `${factor.toFixed(1)}× oversized`,
65
+ color: macOSColors.semantic.error,
66
+ factor
67
+ };
68
+ }
69
+ export function statusColor(record) {
70
+ switch (record.status) {
71
+ case "loaded":
72
+ return macOSColors.semantic.success;
73
+ case "error":
74
+ return macOSColors.semantic.error;
75
+ case "loading":
76
+ return macOSColors.semantic.warning;
77
+ default:
78
+ return macOSColors.text.muted;
79
+ }
80
+ }
81
+
82
+ /** Cache verdict badge text + tint (memory=green, disk=yellow, network=red). */
83
+ export function cacheBadge(record) {
84
+ const verdict = record.cacheVerdict;
85
+ if (verdict === "memory" || verdict === "disk/memory") {
86
+ return {
87
+ label: verdict.toUpperCase(),
88
+ color: macOSColors.semantic.success
89
+ };
90
+ }
91
+ if (verdict === "disk") {
92
+ return {
93
+ label: "DISK",
94
+ color: macOSColors.semantic.warning
95
+ };
96
+ }
97
+ if (verdict === "none" || record.progressSeen) {
98
+ return {
99
+ label: "NETWORK",
100
+ color: macOSColors.semantic.error
101
+ };
102
+ }
103
+ return {
104
+ label: "?",
105
+ color: macOSColors.text.muted
106
+ };
107
+ }
108
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["macOSColors","oversizeFactor","formatBytes","bytes","toFixed","formatMs","ms","Math","round","uriTail","uri","unstable","match","effective","decodeURIComponent","withoutQuery","split","segments","filter","Boolean","length","sizeVerdict","record","factor","label","color","text","muted","semantic","info","success","warning","error","statusColor","status","cacheBadge","verdict","cacheVerdict","toUpperCase","progressSeen"],"sourceRoot":"../../src","sources":["format.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * React bindings for the image event store.
5
+ */
6
+
7
+ import { useMemo, useSyncExternalStore } from "react";
8
+ import { computeStats, getSnapshot, subscribe } from "../store/imageEventStore";
9
+ export function useImageRecords() {
10
+ const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
11
+ return useMemo(() => ({
12
+ records: [...snapshot].reverse(),
13
+ stats: computeStats(snapshot)
14
+ }), [snapshot]);
15
+ }
16
+ //# sourceMappingURL=useImageRecords.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useMemo","useSyncExternalStore","computeStats","getSnapshot","subscribe","useImageRecords","snapshot","records","reverse","stats"],"sourceRoot":"../../../src","sources":["hooks/useImageRecords.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,SAASA,OAAO,EAAEC,oBAAoB,QAAQ,OAAO;AACrD,SAASC,YAAY,EAAEC,WAAW,EAAEC,SAAS,QAAQ,0BAA0B;AAS/E,OAAO,SAASC,eAAeA,CAAA,EAA0B;EACvD,MAAMC,QAAQ,GAAGL,oBAAoB,CAACG,SAAS,EAAED,WAAW,EAAEA,WAAW,CAAC;EAC1E,OAAOH,OAAO,CACZ,OAAO;IACLO,OAAO,EAAE,CAAC,GAAGD,QAAQ,CAAC,CAACE,OAAO,CAAC,CAAC;IAChCC,KAAK,EAAEP,YAAY,CAACI,QAAQ;EAC9B,CAAC,CAAC,EACF,CAACA,QAAQ,CACX,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * @buoy-gg/images
5
+ *
6
+ * Image debugger for React Native: a live registry of every image the app
7
+ * loads — RN core <Image> (via the official component-decorator hook) and
8
+ * expo-image (via a timing-immune class patch) — with cache verdicts
9
+ * (memory/disk/network), load timings, decoded-vs-displayed oversize checks,
10
+ * estimated decoded/wasted memory, and a failure log with HTTP details where
11
+ * the platform provides them.
12
+ *
13
+ * Image HTTP traffic never touches the JS network stack, so network devtools
14
+ * cannot see it — this tool is the visibility layer for images.
15
+ */
16
+
17
+ // Side-effect: install capture as early as this package is imported. For full
18
+ // RN-core coverage, import "@buoy-gg/images/register" FIRST in your entry file
19
+ // (the RN decorator must beat React Native's Image module evaluation).
20
+ import "./register";
21
+
22
+ // =============================================================================
23
+ // PRESET (Primary entry point — pass to <FloatingDevTools apps={[...]} />)
24
+ // =============================================================================
25
+ export { imagesToolPreset, createImagesTool } from "./preset";
26
+
27
+ // =============================================================================
28
+ // ROOT (optional; capture also auto-installs on package import)
29
+ // =============================================================================
30
+ export { ImagesRoot } from "./components/ImagesRoot";
31
+
32
+ // =============================================================================
33
+ // COMPONENTS
34
+ // =============================================================================
35
+ export { ImagesModal } from "./components/ImagesModal";
36
+ export { ImagesIcon, IMAGES_ICON_COLOR } from "./components/ImagesIcon";
37
+
38
+ // =============================================================================
39
+ // CAPTURE
40
+ // =============================================================================
41
+ export { installImageCapture, getCaptureStatus } from "./capture/install";
42
+
43
+ // =============================================================================
44
+ // ACTIONS
45
+ // =============================================================================
46
+ export { hardReloadRecord, retryRecord, evictExpoDiskEntry } from "./capture/actions";
47
+ // =============================================================================
48
+ // SIMULATION OVERRIDES
49
+ // =============================================================================
50
+ export { setOverride, clearOverride, getOverride, flashRecord, setNetworkMode, setBlankImages, getGlobalModes, setOverrideForAllMounted, clearAllOverrides, flashAllMounted } from "./capture/overrides";
51
+ export { hardReloadAllMounted } from "./capture/actions";
52
+ // =============================================================================
53
+ // SAVINGS PROVER + INSIGHTS
54
+ // =============================================================================
55
+ export { proveSavings } from "./capture/savings";
56
+ export { computeInsights, insightChips } from "./store/insights";
57
+ export { formatRecordMarkdown, formatRegistryMarkdown } from "./export";
58
+
59
+ // =============================================================================
60
+ // EXTERNAL SYNC (device → desktop dashboard / MCP)
61
+ // =============================================================================
62
+ export { imagesSyncAdapter } from "./sync/imagesSyncAdapter";
63
+
64
+ // =============================================================================
65
+ // STORE + HOOKS
66
+ // =============================================================================
67
+ export { useImageRecords } from "./hooks/useImageRecords";
68
+ export { clearRecords, getSnapshot as getImageRecords, subscribe as subscribeImageRecords, computeStats, oversizeFactor, estDecodedBytes, estWastedBytes } from "./store/imageEventStore";
69
+
70
+ // =============================================================================
71
+ // TYPES
72
+ // =============================================================================
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["imagesToolPreset","createImagesTool","ImagesRoot","ImagesModal","ImagesIcon","IMAGES_ICON_COLOR","installImageCapture","getCaptureStatus","hardReloadRecord","retryRecord","evictExpoDiskEntry","setOverride","clearOverride","getOverride","flashRecord","setNetworkMode","setBlankImages","getGlobalModes","setOverrideForAllMounted","clearAllOverrides","flashAllMounted","hardReloadAllMounted","proveSavings","computeInsights","insightChips","formatRecordMarkdown","formatRegistryMarkdown","imagesSyncAdapter","useImageRecords","clearRecords","getSnapshot","getImageRecords","subscribe","subscribeImageRecords","computeStats","oversizeFactor","estDecodedBytes","estWastedBytes"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO,YAAY;;AAEnB;AACA;AACA;AACA,SAASA,gBAAgB,EAAEC,gBAAgB,QAAQ,UAAU;;AAE7D;AACA;AACA;AACA,SAASC,UAAU,QAAQ,yBAAyB;;AAEpD;AACA;AACA;AACA,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,UAAU,EAAEC,iBAAiB,QAAQ,yBAAyB;;AAEvE;AACA;AACA;AACA,SAASC,mBAAmB,EAAEC,gBAAgB,QAAQ,mBAAmB;;AAEzE;AACA;AACA;AACA,SACEC,gBAAgB,EAChBC,WAAW,EACXC,kBAAkB,QACb,mBAAmB;AAG1B;AACA;AACA;AACA,SACEC,WAAW,EACXC,aAAa,EACbC,WAAW,EACXC,WAAW,EACXC,cAAc,EACdC,cAAc,EACdC,cAAc,EACdC,wBAAwB,EACxBC,iBAAiB,EACjBC,eAAe,QACV,qBAAqB;AAC5B,SAASC,oBAAoB,QAAQ,mBAAmB;AAGxD;AACA;AACA;AACA,SAASC,YAAY,QAAQ,mBAAmB;AAEhD,SAASC,eAAe,EAAEC,YAAY,QAAQ,kBAAkB;AAChE,SAASC,oBAAoB,EAAEC,sBAAsB,QAAQ,UAAU;;AAEvE;AACA;AACA;AACA,SAASC,iBAAiB,QAAQ,0BAA0B;;AAE5D;AACA;AACA;AACA,SAASC,eAAe,QAAQ,yBAAyB;AACzD,SACEC,YAAY,EACZC,WAAW,IAAIC,eAAe,EAC9BC,SAAS,IAAIC,qBAAqB,EAClCC,YAAY,EACZC,cAAc,EACdC,eAAe,EACfC,cAAc,QACT,yBAAyB;;AAEhC;AACA;AACA","ignoreList":[]}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Pre-configured Images tool for FloatingDevTools.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { imagesToolPreset } from '@buoy-gg/images';
9
+ *
10
+ * <FloatingDevTools apps={[imagesToolPreset]} />
11
+ * ```
12
+ */
13
+
14
+ import { ImagesIcon, IMAGES_ICON_COLOR } from "./components/ImagesIcon";
15
+ import { ImagesModal } from "./components/ImagesModal";
16
+ import { jsx as _jsx } from "react/jsx-runtime";
17
+ export const imagesToolPreset = {
18
+ id: "images",
19
+ name: "IMAGES",
20
+ description: "Image loads, caching, failures, and oversize checks",
21
+ slot: "both",
22
+ icon: ({
23
+ size,
24
+ color
25
+ }) => /*#__PURE__*/_jsx(ImagesIcon, {
26
+ size: size,
27
+ color: color || IMAGES_ICON_COLOR
28
+ }),
29
+ component: ImagesModal
30
+ };
31
+
32
+ /** Create a custom Images tool configuration. */
33
+ export function createImagesTool(options = {}) {
34
+ return {
35
+ ...imagesToolPreset,
36
+ name: options.name ?? imagesToolPreset.name,
37
+ description: options.description ?? imagesToolPreset.description
38
+ };
39
+ }
40
+ //# sourceMappingURL=preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["ImagesIcon","IMAGES_ICON_COLOR","ImagesModal","jsx","_jsx","imagesToolPreset","id","name","description","slot","icon","size","color","component","createImagesTool","options"],"sourceRoot":"../../src","sources":["preset.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,UAAU,EAAEC,iBAAiB,QAAQ,yBAAyB;AACvE,SAASC,WAAW,QAAQ,0BAA0B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEvD,OAAO,MAAMC,gBAAgB,GAAG;EAC9BC,EAAE,EAAE,QAAQ;EACZC,IAAI,EAAE,QAAQ;EACdC,WAAW,EAAE,qDAAqD;EAClEC,IAAI,EAAE,MAAe;EACrBC,IAAI,EAAEA,CAAC;IAAEC,IAAI;IAAEC;EAAwC,CAAC,kBACtDR,IAAA,CAACJ,UAAU;IAACW,IAAI,EAAEA,IAAK;IAACC,KAAK,EAAEA,KAAK,IAAIX;EAAkB,CAAE,CAC7D;EACDY,SAAS,EAAEX;AACb,CAAC;;AAED;AACA,OAAO,SAASY,gBAAgBA,CAC9BC,OAAgD,GAAG,CAAC,CAAC,EACrD;EACA,OAAO;IACL,GAAGV,gBAAgB;IACnBE,IAAI,EAAEQ,OAAO,CAACR,IAAI,IAAIF,gBAAgB,CAACE,IAAI;IAC3CC,WAAW,EAAEO,OAAO,CAACP,WAAW,IAAIH,gBAAgB,CAACG;EACvD,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Side-effect entry: installs image capture on import.
5
+ *
6
+ * Import this FIRST in your app entry file so the RN-core <Image> decorator
7
+ * lands before React Native's Image module is evaluated:
8
+ *
9
+ * ```ts
10
+ * import "@buoy-gg/images/register";
11
+ * ```
12
+ *
13
+ * This module intentionally imports nothing that touches react-native's Image
14
+ * (directly or transitively) before installing.
15
+ */
16
+
17
+ import { installImageCapture } from "./capture/install";
18
+ installImageCapture();
19
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["installImageCapture"],"sourceRoot":"../../src","sources":["register.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,mBAAmB,QAAQ,mBAAmB;AAEvDA,mBAAmB,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Global singleton state for the Images tool.
5
+ *
6
+ * The package can get evaluated twice as two separate module instances (e.g.
7
+ * the `/register` entry shim resolving to one copy while the package root
8
+ * import resolves to another — lib vs src). If capture state lived in module
9
+ * scope, the early copy would install the RN decorator and collect records
10
+ * while the UI copy read an empty store and a false "decorator never ran"
11
+ * flag. Keying all mutable state on globalThis under a well-known symbol makes
12
+ * every copy operate on the same data.
13
+ */
14
+
15
+ const KEY = Symbol.for("buoy.images.globalState.v1");
16
+ export function imagesState() {
17
+ const g = globalThis;
18
+ if (!g[KEY]) {
19
+ g[KEY] = {
20
+ records: [],
21
+ byId: new Map(),
22
+ nextId: 1,
23
+ listeners: new Set(),
24
+ snapshot: [],
25
+ emitScheduled: false,
26
+ captureInstalled: false,
27
+ rnInstalled: false,
28
+ expoInstalled: false,
29
+ decoratorRegistered: false,
30
+ decoratorInvoked: false,
31
+ attachSeen: 0,
32
+ expoAvailable: false,
33
+ expoPatched: false,
34
+ reloadRequests: new Map(),
35
+ actionListeners: new Set(),
36
+ expoInstances: new Map(),
37
+ overrides: new Map(),
38
+ flashUntil: new Map(),
39
+ recordVersions: new Map(),
40
+ globalVersion: 0,
41
+ versionCounter: 0,
42
+ globalModes: {
43
+ network: "normal",
44
+ blank: false
45
+ }
46
+ };
47
+ }
48
+ return g[KEY];
49
+ }
50
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["KEY","Symbol","for","imagesState","g","globalThis","records","byId","Map","nextId","listeners","Set","snapshot","emitScheduled","captureInstalled","rnInstalled","expoInstalled","decoratorRegistered","decoratorInvoked","attachSeen","expoAvailable","expoPatched","reloadRequests","actionListeners","expoInstances","overrides","flashUntil","recordVersions","globalVersion","versionCounter","globalModes","network","blank"],"sourceRoot":"../../src","sources":["state.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA6CA,MAAMA,GAAG,GAAGC,MAAM,CAACC,GAAG,CAAC,4BAA4B,CAAC;AAEpD,OAAO,SAASC,WAAWA,CAAA,EAAsB;EAC/C,MAAMC,CAAC,GAAGC,UAA2D;EACrE,IAAI,CAACD,CAAC,CAACJ,GAAG,CAAC,EAAE;IACXI,CAAC,CAACJ,GAAG,CAAC,GAAG;MACPM,OAAO,EAAE,EAAE;MACXC,IAAI,EAAE,IAAIC,GAAG,CAAC,CAAC;MACfC,MAAM,EAAE,CAAC;MACTC,SAAS,EAAE,IAAIC,GAAG,CAAC,CAAC;MACpBC,QAAQ,EAAE,EAAE;MACZC,aAAa,EAAE,KAAK;MACpBC,gBAAgB,EAAE,KAAK;MACvBC,WAAW,EAAE,KAAK;MAClBC,aAAa,EAAE,KAAK;MACpBC,mBAAmB,EAAE,KAAK;MAC1BC,gBAAgB,EAAE,KAAK;MACvBC,UAAU,EAAE,CAAC;MACbC,aAAa,EAAE,KAAK;MACpBC,WAAW,EAAE,KAAK;MAClBC,cAAc,EAAE,IAAId,GAAG,CAAC,CAAC;MACzBe,eAAe,EAAE,IAAIZ,GAAG,CAAC,CAAC;MAC1Ba,aAAa,EAAE,IAAIhB,GAAG,CAAC,CAAC;MACxBiB,SAAS,EAAE,IAAIjB,GAAG,CAAC,CAAC;MACpBkB,UAAU,EAAE,IAAIlB,GAAG,CAAC,CAAC;MACrBmB,cAAc,EAAE,IAAInB,GAAG,CAAC,CAAC;MACzBoB,aAAa,EAAE,CAAC;MAChBC,cAAc,EAAE,CAAC;MACjBC,WAAW,EAAE;QAAEC,OAAO,EAAE,QAAQ;QAAEC,KAAK,EAAE;MAAM;IACjD,CAAC;EACH;EACA,OAAO5B,CAAC,CAACJ,GAAG,CAAC;AACf","ignoreList":[]}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * imageEventStore
5
+ *
6
+ * Bounded buffer of ImageRecords fed by the capture layer (installRnImage /
7
+ * installExpoImage). Follows the console tool's store shape — Set of
8
+ * listeners, frame-coalesced emit so bursty image grids don't turn every
9
+ * event into its own React commit — but ALL mutable state lives on the
10
+ * globalThis singleton (see ../state.ts) so a dual module instance of this
11
+ * package still reads/writes one shared store.
12
+ */
13
+
14
+ import { PixelRatio } from "react-native";
15
+ import { imagesState } from "../state";
16
+ /** Max records retained before the oldest are dropped. */
17
+ const MAX_RECORDS = 500;
18
+ function emit() {
19
+ const s = imagesState();
20
+ if (s.emitScheduled) return;
21
+ s.emitScheduled = true;
22
+ requestAnimationFrame(() => {
23
+ s.emitScheduled = false;
24
+ for (const listener of s.listeners) listener();
25
+ });
26
+ }
27
+
28
+ /** Snapshot identity only changes on emit, so useSyncExternalStore stays cheap. */
29
+ function invalidate() {
30
+ const s = imagesState();
31
+ s.snapshot = [...s.records];
32
+ emit();
33
+ }
34
+ export function createRecord(partial) {
35
+ const s = imagesState();
36
+ const record = {
37
+ ...partial,
38
+ id: s.nextId++,
39
+ createdAt: Date.now(),
40
+ status: "pending",
41
+ mounted: true,
42
+ loadCount: 0
43
+ };
44
+ s.records.push(record);
45
+ s.byId.set(record.id, record);
46
+ if (s.records.length > MAX_RECORDS) {
47
+ const dropped = s.records.splice(0, s.records.length - MAX_RECORDS);
48
+ for (const d of dropped) s.byId.delete(d.id);
49
+ }
50
+ invalidate();
51
+ return record;
52
+ }
53
+
54
+ /** Mutate a record in place (records are owned by the store) and notify. */
55
+ export function updateRecord(id, patch) {
56
+ const s = imagesState();
57
+ const record = s.byId.get(id);
58
+ if (!record) return undefined;
59
+ Object.assign(record, patch);
60
+ invalidate();
61
+ return record;
62
+ }
63
+ export function getRecord(id) {
64
+ return imagesState().byId.get(id);
65
+ }
66
+ export function getSnapshot() {
67
+ return imagesState().snapshot;
68
+ }
69
+ export function subscribe(listener) {
70
+ const s = imagesState();
71
+ s.listeners.add(listener);
72
+ return () => imagesState().listeners.delete(listener);
73
+ }
74
+ export function clearRecords() {
75
+ const s = imagesState();
76
+ // Keep records still actively loading so in-flight events don't orphan.
77
+ s.records = s.records.filter(r => r.mounted && r.status !== "loaded" && r.status !== "error");
78
+ s.byId = new Map(s.records.map(r => [r.id, r]));
79
+ invalidate();
80
+ }
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // Derived math (shared by rows, detail view, and stats)
84
+ // ---------------------------------------------------------------------------
85
+
86
+ /** Physical pixels actually needed to fill the laid-out view 1:1. */
87
+ export function neededPixels(record) {
88
+ if (!record.layout || record.layout.width <= 0 || record.layout.height <= 0) return null;
89
+ const scale = PixelRatio.get();
90
+ return {
91
+ width: Math.round(record.layout.width * scale),
92
+ height: Math.round(record.layout.height * scale)
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Linear oversize factor: how many times larger (per axis, area-normalized)
98
+ * the decoded bitmap is vs what the view needs. 1 = perfect, 2 = 4× the pixels.
99
+ */
100
+ export function oversizeFactor(record) {
101
+ const needed = neededPixels(record);
102
+ if (!needed || !record.intrinsic) return null;
103
+ const neededArea = needed.width * needed.height;
104
+ const intrinsicArea = record.intrinsic.width * record.intrinsic.height;
105
+ if (neededArea <= 0 || intrinsicArea <= 0) return null;
106
+ return Math.sqrt(intrinsicArea / neededArea);
107
+ }
108
+
109
+ /** Estimated decoded-bitmap memory for a loaded record (RGBA8888). */
110
+ export function estDecodedBytes(record) {
111
+ if (!record.intrinsic) return 0;
112
+ return record.intrinsic.width * record.intrinsic.height * 4;
113
+ }
114
+
115
+ /** Decoded bytes beyond what the laid-out size needs (0 if not oversized). */
116
+ export function estWastedBytes(record) {
117
+ const needed = neededPixels(record);
118
+ if (!needed || !record.intrinsic) return 0;
119
+ const wasted = (record.intrinsic.width * record.intrinsic.height - needed.width * needed.height) * 4;
120
+ return Math.max(0, wasted);
121
+ }
122
+ export function computeStats(list) {
123
+ const stats = {
124
+ total: list.length,
125
+ loading: 0,
126
+ loaded: 0,
127
+ errors: 0,
128
+ networkLoads: 0,
129
+ estDecodedBytes: 0,
130
+ estWastedBytes: 0
131
+ };
132
+ for (const r of list) {
133
+ // Unmounted in-flight records are stale (the instance died mid-load) —
134
+ // they must not count as live in-flight work.
135
+ if ((r.status === "loading" || r.status === "pending") && r.mounted) stats.loading++;
136
+ if (r.status === "loaded") stats.loaded++;
137
+ if (r.status === "error") stats.errors++;
138
+ if (r.progressSeen || r.cacheVerdict === "none") stats.networkLoads++;
139
+ if (r.mounted && r.status === "loaded") {
140
+ stats.estDecodedBytes += estDecodedBytes(r);
141
+ stats.estWastedBytes += estWastedBytes(r);
142
+ }
143
+ }
144
+ return stats;
145
+ }
146
+ //# sourceMappingURL=imageEventStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["PixelRatio","imagesState","MAX_RECORDS","emit","s","emitScheduled","requestAnimationFrame","listener","listeners","invalidate","snapshot","records","createRecord","partial","record","id","nextId","createdAt","Date","now","status","mounted","loadCount","push","byId","set","length","dropped","splice","d","delete","updateRecord","patch","get","undefined","Object","assign","getRecord","getSnapshot","subscribe","add","clearRecords","filter","r","Map","map","neededPixels","layout","width","height","scale","Math","round","oversizeFactor","needed","intrinsic","neededArea","intrinsicArea","sqrt","estDecodedBytes","estWastedBytes","wasted","max","computeStats","list","stats","total","loading","loaded","errors","networkLoads","progressSeen","cacheVerdict"],"sourceRoot":"../../../src","sources":["store/imageEventStore.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Cross-record insights — findings computed purely from data the registry
5
+ * already holds (no extra instrumentation): duplicate simultaneous loads,
6
+ * retry storms, iOS image-queue saturation, missing alt text, and
7
+ * layout-shifting images.
8
+ */
9
+
10
+ /** loadCount at/above this flags render-thrash reload storms. */
11
+ const RETRY_STORM_THRESHOLD = 5;
12
+ /** RCTImageLoader allows 4 concurrent loading tasks on iOS. */
13
+ const IOS_CONCURRENT_LOAD_LIMIT = 4;
14
+ export function computeInsights(records) {
15
+ const byUri = new Map();
16
+ const retryStorms = [];
17
+ const layoutShifters = [];
18
+ let missingAlt = 0;
19
+ let rnLoading = 0;
20
+ for (const r of records) {
21
+ if (r.mounted && r.uri) {
22
+ byUri.set(r.uri, (byUri.get(r.uri) ?? 0) + 1);
23
+ }
24
+ if (r.loadCount >= RETRY_STORM_THRESHOLD) {
25
+ retryStorms.push({
26
+ id: r.id,
27
+ uri: r.uri,
28
+ loadCount: r.loadCount
29
+ });
30
+ }
31
+ if ((r.layoutShifts ?? 0) > 0) {
32
+ layoutShifters.push({
33
+ id: r.id,
34
+ uri: r.uri,
35
+ shifts: r.layoutShifts ?? 0
36
+ });
37
+ }
38
+ if (r.mounted && r.hasAltText === false) missingAlt++;
39
+ if (r.lib === "rn" && r.mounted && r.status === "loading") rnLoading++;
40
+ }
41
+ const duplicates = [...byUri.entries()].filter(([, count]) => count > 1).map(([uri, count]) => ({
42
+ uri,
43
+ count
44
+ })).sort((a, b) => b.count - a.count);
45
+ return {
46
+ duplicates,
47
+ retryStorms: retryStorms.sort((a, b) => b.loadCount - a.loadCount),
48
+ queueSaturated: rnLoading > IOS_CONCURRENT_LOAD_LIMIT,
49
+ missingAlt,
50
+ layoutShifters
51
+ };
52
+ }
53
+
54
+ /** Compact one-line chips for UI/MCP surfacing. Empty array = all clear. */
55
+ export function insightChips(insights) {
56
+ const chips = [];
57
+ if (insights.duplicates.length > 0) {
58
+ const extra = insights.duplicates.reduce((n, d) => n + d.count - 1, 0);
59
+ chips.push(`${insights.duplicates.length} duplicate URL${insights.duplicates.length > 1 ? "s" : ""} (${extra} redundant loads)`);
60
+ }
61
+ if (insights.retryStorms.length > 0) {
62
+ chips.push(`${insights.retryStorms.length} retry storm${insights.retryStorms.length > 1 ? "s" : ""}`);
63
+ }
64
+ if (insights.queueSaturated) chips.push("iOS image queue saturated (>4 loading)");
65
+ if (insights.missingAlt > 0) chips.push(`${insights.missingAlt} missing alt text`);
66
+ if (insights.layoutShifters.length > 0) {
67
+ chips.push(`${insights.layoutShifters.length} layout-shifting image${insights.layoutShifters.length > 1 ? "s" : ""}`);
68
+ }
69
+ return chips;
70
+ }
71
+ //# sourceMappingURL=insights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["RETRY_STORM_THRESHOLD","IOS_CONCURRENT_LOAD_LIMIT","computeInsights","records","byUri","Map","retryStorms","layoutShifters","missingAlt","rnLoading","r","mounted","uri","set","get","loadCount","push","id","layoutShifts","shifts","hasAltText","lib","status","duplicates","entries","filter","count","map","sort","a","b","queueSaturated","insightChips","insights","chips","length","extra","reduce","n","d"],"sourceRoot":"../../../src","sources":["store/insights.ts"],"mappings":"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","ignoreList":[]}