@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
package/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ PROPRIETARY SOFTWARE LICENSE
2
+
3
+ Copyright (c) 2024-present Buoy. All rights reserved.
4
+
5
+ This software and its source code are proprietary and confidential.
6
+
7
+ NOTICE: This is NOT open source software. This software is licensed,
8
+ not sold, and is protected by copyright laws and international treaties.
9
+
10
+ TERMS AND CONDITIONS:
11
+
12
+ 1. LICENSE GRANT
13
+ Subject to the terms of this Agreement and payment of applicable fees,
14
+ Buoy grants you a limited, non-exclusive, non-transferable license
15
+ to use the compiled software packages in your applications.
16
+
17
+ 2. RESTRICTIONS
18
+ You may NOT:
19
+ - Copy, modify, or distribute the source code
20
+ - Reverse engineer, decompile, or disassemble the software
21
+ - Remove or alter any proprietary notices or labels
22
+ - Sublicense, rent, lease, or lend the software
23
+ - Use the software to create competing products
24
+ - Share access credentials with unauthorized parties
25
+
26
+ 3. OWNERSHIP
27
+ React Buoy retains all right, title, and interest in the software,
28
+ including all intellectual property rights. This license does not
29
+ grant you any rights to trademarks or service marks.
30
+
31
+ 4. TERMINATION
32
+ This license is effective until terminated. Your rights under this
33
+ license will terminate automatically without notice if you fail to
34
+ comply with any of its terms. Upon termination, you must cease all
35
+ use and destroy all copies of the software.
36
+
37
+ 5. DISCLAIMER OF WARRANTIES
38
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
39
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
41
+
42
+ 6. LIMITATION OF LIABILITY
43
+ IN NO EVENT SHALL BUOY BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
44
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN
45
+ CONNECTION WITH THIS LICENSE OR THE USE OF THE SOFTWARE.
46
+
47
+ 7. GOVERNING LAW
48
+ This Agreement shall be governed by and construed in accordance with
49
+ the laws of the United States, without regard to its conflict of
50
+ law provisions.
51
+
52
+ For licensing inquiries and subscription information:
53
+ - Website: https://buoy.gg
54
+ - Email: AustinLovesWorking@gmail.com
55
+
56
+ Unauthorized reproduction or distribution of this software, or any
57
+ portion of it, may result in severe civil and criminal penalties,
58
+ and will be prosecuted to the maximum extent possible under the law.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # @buoy-gg/images
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@buoy-gg/images?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/images) [![npm downloads](https://img.shields.io/npm/dm/@buoy-gg/images?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/images)
4
+
5
+ **See every image your app loads — where it came from, how long it took, what it cost, and why it failed.**
6
+
7
+ Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside your React Native app. Install it and it auto-appears in the floating menu from [`@buoy-gg/core`](https://www.npmjs.com/package/@buoy-gg/core).
8
+
9
+ Image HTTP requests never touch the JS network stack — network devtools are permanently blind to them. This tool is the visibility layer: a live registry of every RN `<Image>` and [`expo-image`](https://docs.expo.dev/versions/latest/sdk/image/) load, with cache verdicts, timings, and size auditing. Pure JS — works in Expo Go and release builds.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @buoy-gg/core @buoy-gg/images
15
+ ```
16
+
17
+ Then add the register import as the **first line** of your app entry file (`index.js` / `index.ts`):
18
+
19
+ ```ts
20
+ import "@buoy-gg/images/register";
21
+ ```
22
+
23
+ > Why first? RN core's `<Image>` instrumentation uses React Native's official component-decorator hook, which must be installed before the Image module first evaluates. expo-image capture has no such constraint — it works no matter when the tool loads. If you skip the import, the tool tells you what it's missing instead of sitting silently empty.
24
+
25
+ ## Quick start
26
+
27
+ ```tsx
28
+ import { FloatingDevTools } from "@buoy-gg/core";
29
+
30
+ export default function App() {
31
+ return (
32
+ <>
33
+ <YourApp />
34
+ <FloatingDevTools />
35
+ </>
36
+ );
37
+ }
38
+ ```
39
+
40
+ The IMAGES tool appears in the menu. Open it and browse every image the session has loaded.
41
+
42
+ ## What you get
43
+
44
+ - **Live image registry** — every RN `<Image>` and expo-image load: thumbnail, source, status, load time, decoded dimensions
45
+ - **Cache verdicts** — memory / disk / network per load (expo-image reports it directly; RN core is classified via `Image.queryCache`)
46
+ - **Oversize auditing** — decoded size vs displayed size × device pixel ratio, Lighthouse-style: green within 10%, red beyond 50%, with estimated wasted decoded memory and the exact size you should serve
47
+ - **Memory accounting** — estimated decoded-bitmap bytes per image and totals across the session (catch ballooning before the OOM)
48
+ - **Failure log** — every `onError` with the message, and on iOS the HTTP status code + response headers
49
+ - **Cache actions** — clear expo-image memory/disk caches from the detail view
50
+ - **Upscale detection** — tiny sources stretched into big boxes (blurry images) get flagged too
51
+
52
+ ## Desktop & AI
53
+
54
+ The same live session streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) (free, macOS/Windows/Linux) and to Claude Code or Cursor via the [Buoy MCP server](https://buoy.gg/buoy/latest/docs/mcp).
55
+
56
+ ## Free vs Pro
57
+
58
+ Every tool is free. [Pro](https://buoy.gg/pricing) unlocks production builds, the MCP server, and unlimited capture. Every weekend, Pro features unlock free for everyone.
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.dropActionState = dropActionState;
7
+ exports.evictExpoDiskEntry = evictExpoDiskEntry;
8
+ exports.getReloadNonce = getReloadNonce;
9
+ exports.getReloadRequest = getReloadRequest;
10
+ exports.hardReloadAllMounted = hardReloadAllMounted;
11
+ exports.hardReloadRecord = hardReloadRecord;
12
+ exports.registerExpoInstance = registerExpoInstance;
13
+ exports.retryRecord = retryRecord;
14
+ exports.settleReloadRequest = settleReloadRequest;
15
+ exports.subscribeActions = subscribeActions;
16
+ var _state = require("../state");
17
+ var _overrides = require("./overrides");
18
+ /**
19
+ * Per-image actions: hard reload (bypass cache) and retry.
20
+ *
21
+ * RN core path: the decorator wrapper owns every mounted <Image>'s props, so a
22
+ * reload request re-renders the wrapper with a bumped `key` (native remount →
23
+ * fresh load cycle) and, for cache-busting, `source.cache: 'reload'` injected
24
+ * — VERIFIED supported on BOTH platforms (iOS NSURLRequest policy;
25
+ * Android ReactImageView.kt reads source."cache" → Fresco full-fetch). The
26
+ * override stays applied until the load settles, then reverts lazily on the
27
+ * app's next natural re-render (avoids an extra cache round-trip).
28
+ *
29
+ * expo-image path: the patched class instance exposes the public
30
+ * `reloadAsync()`. Cache-busting first evicts the disk entry (cache path +
31
+ * expo-file-system delete) and clears expo's memory cache (global — no
32
+ * per-entry memory eviction exists), so the reload is a true refetch that
33
+ * rewrites both cache tiers.
34
+ */
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // RN reload-request bus (consumed by the decorator wrapper)
38
+ // ---------------------------------------------------------------------------
39
+
40
+ function subscribeActions(listener) {
41
+ const s = (0, _state.imagesState)();
42
+ s.actionListeners.add(listener);
43
+ return () => (0, _state.imagesState)().actionListeners.delete(listener);
44
+ }
45
+ function getReloadRequest(recordId) {
46
+ if (recordId == null) return undefined;
47
+ return (0, _state.imagesState)().reloadRequests.get(recordId);
48
+ }
49
+
50
+ /** Reload nonce for a record (0 = never requested). Snapshot for the wrapper. */
51
+ function getReloadNonce(recordId) {
52
+ return getReloadRequest(recordId)?.nonce ?? 0;
53
+ }
54
+ function requestRnReload(recordId, bust) {
55
+ const s = (0, _state.imagesState)();
56
+ const prev = s.reloadRequests.get(recordId);
57
+ s.reloadRequests.set(recordId, {
58
+ nonce: (prev?.nonce ?? 0) + 1,
59
+ bust
60
+ });
61
+ // touchRecord bumps the render version (the wrapper's snapshot) and emits.
62
+ (0, _overrides.touchRecord)(recordId);
63
+ }
64
+
65
+ /**
66
+ * Mark a request consumed once its load settles (called from the tracker on
67
+ * load/error). Silent — the wrapper reverts the prop override on the app's
68
+ * next natural re-render instead of forcing an immediate one.
69
+ */
70
+ function settleReloadRequest(recordId) {
71
+ const s = (0, _state.imagesState)();
72
+ const req = s.reloadRequests.get(recordId);
73
+ if (req?.bust) {
74
+ s.reloadRequests.set(recordId, {
75
+ nonce: req.nonce,
76
+ bust: false
77
+ });
78
+ }
79
+ }
80
+ function dropActionState(recordId) {
81
+ const s = (0, _state.imagesState)();
82
+ s.reloadRequests.delete(recordId);
83
+ s.expoInstances.delete(recordId);
84
+ s.overrides.delete(recordId);
85
+ s.flashUntil.delete(recordId);
86
+ s.recordVersions.delete(recordId);
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // expo instance registry (populated by the render patch)
91
+ // ---------------------------------------------------------------------------
92
+
93
+ function registerExpoInstance(recordId, instance) {
94
+ if (recordId == null) return;
95
+ (0, _state.imagesState)().expoInstances.set(recordId, instance);
96
+ }
97
+ function expoImageStatics() {
98
+ try {
99
+ return require("expo-image").Image ?? null;
100
+ } catch {
101
+ return null;
102
+ }
103
+ }
104
+ /**
105
+ * expo-file-system, legacy path first (v19+/SDK 54+ moved the function API
106
+ * there) then the main import — same pattern as shared-ui's persistentStorage.
107
+ */
108
+ function loadFileSystem() {
109
+ try {
110
+ const mod = require("expo-file-system/legacy");
111
+ const fs = mod?.default || mod;
112
+ if (fs?.deleteAsync) return fs;
113
+ } catch {
114
+ // try main import
115
+ }
116
+ try {
117
+ const mod = require("expo-file-system");
118
+ const fs = mod?.default || mod;
119
+ if (fs?.deleteAsync) return fs;
120
+ } catch {
121
+ // not installed
122
+ }
123
+ return null;
124
+ }
125
+
126
+ /**
127
+ * Delete an expo-image disk-cache entry (JS-only: cache path + file delete).
128
+ * Returns true if an entry existed and was deleted.
129
+ */
130
+ async function evictExpoDiskEntry(record) {
131
+ const statics = expoImageStatics();
132
+ const fileSystem = loadFileSystem();
133
+ if (!statics?.getCachePathAsync || !fileSystem?.deleteAsync || !record.uri) return false;
134
+ try {
135
+ const path = await statics.getCachePathAsync(record.uri);
136
+ if (!path) return false;
137
+ const uri = path.startsWith("file://") ? path : `file://${path}`;
138
+ await fileSystem.deleteAsync(uri, {
139
+ idempotent: true
140
+ });
141
+ return true;
142
+ } catch {
143
+ return false;
144
+ }
145
+ }
146
+
147
+ // ---------------------------------------------------------------------------
148
+ // High-level dispatchers (used by the detail view)
149
+ // ---------------------------------------------------------------------------
150
+
151
+ /** Fresh load attempt for a mounted image (no cache bypass). */
152
+ async function retryRecord(record) {
153
+ if (!record.mounted) {
154
+ return {
155
+ ok: false,
156
+ message: "Instance unmounted — cannot reload"
157
+ };
158
+ }
159
+ if (record.lib === "expo") {
160
+ const instance = (0, _state.imagesState)().expoInstances.get(record.id);
161
+ if (!instance?.reloadAsync) {
162
+ return {
163
+ ok: false,
164
+ message: "Live instance not reachable"
165
+ };
166
+ }
167
+ await instance.reloadAsync();
168
+ return {
169
+ ok: true,
170
+ message: "Reload requested"
171
+ };
172
+ }
173
+ requestRnReload(record.id, false);
174
+ return {
175
+ ok: true,
176
+ message: "Remounting image"
177
+ };
178
+ }
179
+
180
+ /** Hard-reload every mounted image (mass cache-bust). Returns count started. */
181
+ async function hardReloadAllMounted() {
182
+ const {
183
+ getSnapshot
184
+ } = require("../store/imageEventStore");
185
+ let count = 0;
186
+ for (const record of getSnapshot()) {
187
+ if (!record.mounted) continue;
188
+ const result = await hardReloadRecord(record);
189
+ if (result.ok) count++;
190
+ }
191
+ return {
192
+ ok: count > 0,
193
+ message: `Hard-reloading ${count} mounted image${count === 1 ? "" : "s"}`
194
+ };
195
+ }
196
+
197
+ /** Bypass-cache reload: refetches from network and rewrites the caches. */
198
+ async function hardReloadRecord(record) {
199
+ if (!record.mounted) {
200
+ return {
201
+ ok: false,
202
+ message: "Instance unmounted — cannot reload"
203
+ };
204
+ }
205
+ if (record.sourceKind !== "network") {
206
+ // Local/asset sources have no HTTP cache to bust — plain remount instead.
207
+ return retryRecord(record);
208
+ }
209
+ if (record.lib === "expo") {
210
+ const evicted = await evictExpoDiskEntry(record);
211
+ const statics = expoImageStatics();
212
+ // No per-entry memory eviction exists — global clear is the honest option.
213
+ await statics?.clearMemoryCache?.().catch?.(() => false);
214
+ const result = await retryRecord(record);
215
+ if (!result.ok) return result;
216
+ return {
217
+ ok: true,
218
+ message: evicted ? "Disk entry evicted, memory cache cleared, refetching" : "Memory cache cleared, refetching (no disk entry found)"
219
+ };
220
+ }
221
+ requestRnReload(record.id, true);
222
+ return {
223
+ ok: true,
224
+ message: "Refetching with cache bypassed"
225
+ };
226
+ }
227
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_state","require","_overrides","subscribeActions","listener","s","imagesState","actionListeners","add","delete","getReloadRequest","recordId","undefined","reloadRequests","get","getReloadNonce","nonce","requestRnReload","bust","prev","set","touchRecord","settleReloadRequest","req","dropActionState","expoInstances","overrides","flashUntil","recordVersions","registerExpoInstance","instance","expoImageStatics","Image","loadFileSystem","mod","fs","default","deleteAsync","evictExpoDiskEntry","record","statics","fileSystem","getCachePathAsync","uri","path","startsWith","idempotent","retryRecord","mounted","ok","message","lib","id","reloadAsync","hardReloadAllMounted","getSnapshot","count","result","hardReloadRecord","sourceKind","evicted","clearMemoryCache","catch"],"sourceRoot":"../../../src","sources":["capture/actions.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getCaptureStatus = getCaptureStatus;
7
+ exports.installImageCapture = installImageCapture;
8
+ var _state = require("../state");
9
+ var _installExpoImage = require("./installExpoImage");
10
+ var _installRnImage = require("./installRnImage");
11
+ /**
12
+ * installImageCapture — idempotent entry point for the capture layer.
13
+ *
14
+ * IMPORTANT (timing): the RN-core decorator only takes effect if this runs
15
+ * before anything evaluates the `Image` module from 'react-native'. The
16
+ * recommended integration is `import "@buoy-gg/images/register"` as the FIRST
17
+ * import of the app entry file. The expo-image patch has no such constraint.
18
+ *
19
+ * Idempotency is keyed on the globalThis singleton, so even if this package
20
+ * gets evaluated as two module instances, capture installs exactly once.
21
+ */
22
+
23
+ function installImageCapture() {
24
+ const s = (0, _state.imagesState)();
25
+ if (s.captureInstalled) return;
26
+ s.captureInstalled = true;
27
+ (0, _installRnImage.installRnImageInterceptor)();
28
+ (0, _installExpoImage.installExpoImageInterceptor)();
29
+ }
30
+ function getCaptureStatus() {
31
+ const rn = (0, _installRnImage.rnCaptureStatus)();
32
+ const expo = (0, _installExpoImage.expoCaptureStatus)();
33
+ return {
34
+ installed: (0, _state.imagesState)().captureInstalled,
35
+ rnDecoratorActive: rn.decoratorActive,
36
+ rnDecoratorTooLate: rn.tooLate,
37
+ expoPatched: expo.patched,
38
+ expoAvailable: expo.available
39
+ };
40
+ }
41
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_state","require","_installExpoImage","_installRnImage","installImageCapture","s","imagesState","captureInstalled","installRnImageInterceptor","installExpoImageInterceptor","getCaptureStatus","rn","rnCaptureStatus","expo","expoCaptureStatus","installed","rnDecoratorActive","decoratorActive","rnDecoratorTooLate","tooLate","expoPatched","patched","expoAvailable","available"],"sourceRoot":"../../../src","sources":["capture/install.ts"],"mappings":";;;;;;;AAYA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,iBAAA,GAAAD,OAAA;AACA,IAAAE,eAAA,GAAAF,OAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAOO,SAASG,mBAAmBA,CAAA,EAAS;EAC1C,MAAMC,CAAC,GAAG,IAAAC,kBAAW,EAAC,CAAC;EACvB,IAAID,CAAC,CAACE,gBAAgB,EAAE;EACxBF,CAAC,CAACE,gBAAgB,GAAG,IAAI;EACzB,IAAAC,yCAAyB,EAAC,CAAC;EAC3B,IAAAC,6CAA2B,EAAC,CAAC;AAC/B;AAEO,SAASC,gBAAgBA,CAAA,EAAkB;EAChD,MAAMC,EAAE,GAAG,IAAAC,+BAAe,EAAC,CAAC;EAC5B,MAAMC,IAAI,GAAG,IAAAC,mCAAiB,EAAC,CAAC;EAChC,OAAO;IACLC,SAAS,EAAE,IAAAT,kBAAW,EAAC,CAAC,CAACC,gBAAgB;IACzCS,iBAAiB,EAAEL,EAAE,CAACM,eAAe;IACrCC,kBAAkB,EAAEP,EAAE,CAACQ,OAAO;IAC9BC,WAAW,EAAEP,IAAI,CAACQ,OAAO;IACzBC,aAAa,EAAET,IAAI,CAACU;EACtB,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.expoCaptureStatus = expoCaptureStatus;
7
+ exports.installExpoImageInterceptor = installExpoImageInterceptor;
8
+ var _state = require("../state");
9
+ var _actions = require("./actions");
10
+ var _overrides = require("./overrides");
11
+ var _shared = require("./shared");
12
+ /**
13
+ * expo-image interception via class-prototype patch.
14
+ *
15
+ * expo-image's <Image> is a class component (React.PureComponent) whose
16
+ * render() reads `this.props`, so wrapping the prototype's render and swapping
17
+ * `this.props` for an instrumented copy for the duration of the original
18
+ * render is timing-immune (prototype methods are looked up dynamically — no
19
+ * import-order race like the RN core decorator). Props are restored in
20
+ * `finally`, so PureComponent's shouldComponentUpdate still compares the
21
+ * app's real props.
22
+ *
23
+ * Double-patch safety: install flags live on the globalThis singleton AND a
24
+ * marker is stamped on the prototype itself, so even two module instances of
25
+ * this package can't wrap render() twice.
26
+ *
27
+ * expo-image is an optional peer: if it isn't installed, this is a no-op.
28
+ */
29
+
30
+ const PATCH_MARKER = "__buoyImagesPatched";
31
+ const trackers = new WeakMap();
32
+ function trackerFor(instance) {
33
+ let tracker = trackers.get(instance);
34
+ if (!tracker) {
35
+ tracker = new _shared.ImageInstanceTracker("expo");
36
+ trackers.set(instance, tracker);
37
+ }
38
+ return tracker;
39
+ }
40
+ function installExpoImageInterceptor() {
41
+ const s = (0, _state.imagesState)();
42
+ if (s.expoInstalled) return;
43
+ s.expoInstalled = true;
44
+ let ImageClass;
45
+ try {
46
+ ImageClass = require("expo-image").Image;
47
+ } catch {
48
+ s.expoAvailable = false;
49
+ return; // expo-image not installed in this app
50
+ }
51
+ if (!ImageClass?.prototype?.render) {
52
+ s.expoAvailable = false;
53
+ return;
54
+ }
55
+ s.expoAvailable = true;
56
+ const proto = ImageClass.prototype;
57
+ if (proto[PATCH_MARKER]) {
58
+ s.expoPatched = true;
59
+ return; // already patched by another module instance of this package
60
+ }
61
+ proto[PATCH_MARKER] = true;
62
+ const originalRender = proto.render;
63
+ const originalUnmount = proto.componentWillUnmount;
64
+ proto.render = function buoyImagesRender() {
65
+ const originalProps = this.props;
66
+ if ((0, _shared.isInternalImage)(originalProps?.testID)) {
67
+ return originalRender.call(this);
68
+ }
69
+ const tracker = trackerFor(this);
70
+ tracker.syncSource(originalProps?.source);
71
+ tracker.noteA11y(Boolean(originalProps?.alt ?? originalProps?.accessibilityLabel));
72
+ // Keep the action layer pointed at the live instance (reloadAsync etc.).
73
+ (0, _actions.registerExpoInstance)(tracker.getRecordId(), this);
74
+ const wrapped = tracker.handlers(originalProps);
75
+ try {
76
+ // Simulation layer: global modes + per-record override + locate-flash.
77
+ this.props = (0, _overrides.applyOverrides)({
78
+ ...originalProps,
79
+ ...wrapped
80
+ }, tracker.getRecordId(), "expo");
81
+ return originalRender.call(this);
82
+ } finally {
83
+ this.props = originalProps;
84
+ }
85
+ };
86
+ proto.componentWillUnmount = function buoyImagesUnmount() {
87
+ trackers.get(this)?.unmount();
88
+ originalUnmount?.call(this);
89
+ };
90
+ s.expoPatched = true;
91
+ }
92
+ function expoCaptureStatus() {
93
+ const s = (0, _state.imagesState)();
94
+ return {
95
+ available: s.expoAvailable,
96
+ patched: s.expoPatched
97
+ };
98
+ }
99
+ //# sourceMappingURL=installExpoImage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_state","require","_actions","_overrides","_shared","PATCH_MARKER","trackers","WeakMap","trackerFor","instance","tracker","get","ImageInstanceTracker","set","installExpoImageInterceptor","s","imagesState","expoInstalled","ImageClass","Image","expoAvailable","prototype","render","proto","expoPatched","originalRender","originalUnmount","componentWillUnmount","buoyImagesRender","originalProps","props","isInternalImage","testID","call","syncSource","source","noteA11y","Boolean","alt","accessibilityLabel","registerExpoInstance","getRecordId","wrapped","handlers","applyOverrides","buoyImagesUnmount","unmount","expoCaptureStatus","available","patched"],"sourceRoot":"../../../src","sources":["capture/installExpoImage.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.installRnImageInterceptor = installRnImageInterceptor;
7
+ exports.rnCaptureStatus = rnCaptureStatus;
8
+ var React = _interopRequireWildcard(require("react"));
9
+ var _state = require("../state");
10
+ var _actions = require("./actions");
11
+ var _overrides = require("./overrides");
12
+ var _shared = require("./shared");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
+ /**
16
+ * RN core <Image> interception via the official injection hook.
17
+ *
18
+ * `unstable_setImageComponentDecorator` wraps EVERY RN <Image> app-wide — but
19
+ * the decorator is latched ONCE, at Image module evaluation
20
+ * (`Image.ios.js` / `Image.android.js` read it at module scope). So install
21
+ * order matters: this must run before anything touches `Image` from
22
+ * 'react-native' — hence the `@buoy-gg/images/register` first-import.
23
+ *
24
+ * Detection strategy: the decorator sets `decoratorInvoked` when RN's Image
25
+ * module applies it. `unstable_registerImageAttachedCallback` is a live Set
26
+ * (never latched), so image mounts are always visible — if mounts happen but
27
+ * the decorator never ran, we were too late and CaptureStatus reports it.
28
+ *
29
+ * All flags live on the globalThis singleton (../state.ts) so a second module
30
+ * instance of this package neither re-installs nor reports a stale status.
31
+ */
32
+
33
+ /** Wraps one RN Image render with capture instrumentation + reload actions. */
34
+ function useImageCapture(props) {
35
+ const trackerRef = React.useRef(null);
36
+ if (trackerRef.current == null) {
37
+ trackerRef.current = new _shared.ImageInstanceTracker("rn");
38
+ }
39
+ const tracker = trackerRef.current;
40
+ const internal = (0, _shared.isInternalImage)(props.testID);
41
+ if (!internal) {
42
+ tracker.syncSource(props.source);
43
+ tracker.noteA11y(Boolean(props.alt ?? props.accessibilityLabel ?? props["aria-label"]));
44
+ }
45
+
46
+ // Action/override bus: version bumps re-render just this instance (snapshot
47
+ // is per-record with a global floor, so unrelated actions don't invalidate
48
+ // other images but global-mode toggles reach everyone).
49
+ React.useSyncExternalStore(_actions.subscribeActions, () => (0, _overrides.getRenderVersion)(internal ? null : tracker.getRecordId()));
50
+ React.useEffect(() => {
51
+ if (internal) return undefined;
52
+ return () => tracker.unmount();
53
+ }, [tracker, internal]);
54
+ if (internal) return {
55
+ props,
56
+ reloadKey: 0
57
+ };
58
+ const recordId = tracker.getRecordId();
59
+ const wrapped = tracker.handlers(props);
60
+ const out = {
61
+ ...props,
62
+ ...wrapped
63
+ };
64
+
65
+ // While a bust request is pending (cleared when the load settles), refetch
66
+ // bypassing caches — VERIFIED both platforms honor source.cache: 'reload'.
67
+ const request = (0, _actions.getReloadRequest)(recordId);
68
+ if (request?.bust) {
69
+ out.source = (0, _overrides.patchSourceCache)(out.source, "reload");
70
+ }
71
+ // Simulation layer: global modes + per-record override + locate-flash.
72
+ (0, _overrides.applyOverrides)(out, recordId, "rn");
73
+ return {
74
+ props: out,
75
+ reloadKey: (0, _actions.getReloadNonce)(recordId)
76
+ };
77
+ }
78
+ function installRnImageInterceptor() {
79
+ const s = (0, _state.imagesState)();
80
+ if (s.rnInstalled) return;
81
+ s.rnInstalled = true;
82
+ try {
83
+ // Deep import: evaluates ONLY the injection module, never Image itself.
84
+ const injection = require("react-native/Libraries/Image/ImageInjection");
85
+ const setDecorator = injection.unstable_setImageComponentDecorator;
86
+ const registerAttached = injection.unstable_registerImageAttachedCallback;
87
+ if (typeof setDecorator === "function") {
88
+ setDecorator(BaseImage => {
89
+ (0, _state.imagesState)().decoratorInvoked = true;
90
+ const CapturedImage = /*#__PURE__*/React.forwardRef(function BuoyCapturedImage(props, ref) {
91
+ const {
92
+ props: instrumented,
93
+ reloadKey
94
+ } = useImageCapture(props);
95
+ // key bump forces a native remount → fresh load cycle (retry).
96
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(BaseImage, {
97
+ ...instrumented,
98
+ ref: ref
99
+ }, `buoy-r${reloadKey}`);
100
+ });
101
+ return CapturedImage;
102
+ });
103
+ s.decoratorRegistered = true;
104
+ }
105
+
106
+ // Live mount signal — works regardless of decorator timing. Used purely
107
+ // to detect the "decorator registered too late" condition.
108
+ if (typeof registerAttached === "function") {
109
+ registerAttached(() => {
110
+ (0, _state.imagesState)().attachSeen++;
111
+ });
112
+ }
113
+ } catch {
114
+ // Internal RN path moved (version drift) or non-RN platform — expo-image
115
+ // capture still works; status will report the decorator as inactive.
116
+ s.decoratorRegistered = false;
117
+ }
118
+ }
119
+ function rnCaptureStatus() {
120
+ const s = (0, _state.imagesState)();
121
+ return {
122
+ decoratorRegistered: s.decoratorRegistered,
123
+ decoratorActive: s.decoratorInvoked,
124
+ // Mounts observed but our wrapper never rendered → Image latched first.
125
+ tooLate: s.decoratorRegistered && !s.decoratorInvoked && s.attachSeen > 0
126
+ };
127
+ }
128
+ //# sourceMappingURL=installRnImage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","_interopRequireWildcard","require","_state","_actions","_overrides","_shared","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","useImageCapture","props","trackerRef","useRef","current","ImageInstanceTracker","tracker","internal","isInternalImage","testID","syncSource","source","noteA11y","Boolean","alt","accessibilityLabel","useSyncExternalStore","subscribeActions","getRenderVersion","getRecordId","useEffect","undefined","unmount","reloadKey","recordId","wrapped","handlers","out","request","getReloadRequest","bust","patchSourceCache","applyOverrides","getReloadNonce","installRnImageInterceptor","s","imagesState","rnInstalled","injection","setDecorator","unstable_setImageComponentDecorator","registerAttached","unstable_registerImageAttachedCallback","BaseImage","decoratorInvoked","CapturedImage","forwardRef","BuoyCapturedImage","ref","instrumented","jsx","decoratorRegistered","attachSeen","rnCaptureStatus","decoratorActive","tooLate"],"sourceRoot":"../../../src","sources":["capture/installRnImage.tsx"],"mappings":"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","ignoreList":[]}