@buoy-gg/images 7.0.41 → 7.0.42

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 (194) hide show
  1. package/README.md +11 -70
  2. package/lib/commonjs/autoCapture.js +1 -4
  3. package/lib/commonjs/autoCapture.web.js +1 -6
  4. package/lib/commonjs/capture/actions.js +1 -243
  5. package/lib/commonjs/capture/install.js +1 -45
  6. package/lib/commonjs/capture/install.web.js +1 -250
  7. package/lib/commonjs/capture/installExpoImage.js +1 -99
  8. package/lib/commonjs/capture/installRnImage.js +1 -132
  9. package/lib/commonjs/capture/nativeImageModules.js +1 -30
  10. package/lib/commonjs/capture/nativeImageModules.web.js +1 -18
  11. package/lib/commonjs/capture/overrides.js +1 -346
  12. package/lib/commonjs/capture/rnDecoratorEarly.js +1 -55
  13. package/lib/commonjs/capture/savings.js +1 -209
  14. package/lib/commonjs/capture/savings.web.js +1 -71
  15. package/lib/commonjs/capture/shared.js +1 -378
  16. package/lib/commonjs/components/ImageDetail.js +1 -455
  17. package/lib/commonjs/components/ImageDetailFooter.js +1 -158
  18. package/lib/commonjs/components/ImageRow.js +1 -156
  19. package/lib/commonjs/components/ImagesHeader.js +1 -63
  20. package/lib/commonjs/components/ImagesIcon.js +1 -19
  21. package/lib/commonjs/components/ImagesListFooter.js +1 -126
  22. package/lib/commonjs/components/ImagesModal.js +1 -240
  23. package/lib/commonjs/components/ImagesRoot.js +1 -24
  24. package/lib/commonjs/components/ImagesRoot.web.js +1 -13
  25. package/lib/commonjs/components/InsightsBar.js +1 -59
  26. package/lib/commonjs/export.js +1 -81
  27. package/lib/commonjs/format.js +1 -117
  28. package/lib/commonjs/hooks/useImageRecords.js +1 -20
  29. package/lib/commonjs/index.js +1 -261
  30. package/lib/commonjs/preset.js +1 -39
  31. package/lib/commonjs/register.js +1 -19
  32. package/lib/commonjs/registerEarly.js +1 -14
  33. package/lib/commonjs/remote.js +1 -42
  34. package/lib/commonjs/state.js +1 -58
  35. package/lib/commonjs/store/imageEventStore.js +1 -238
  36. package/lib/commonjs/store/insights.js +1 -76
  37. package/lib/commonjs/sync/imagesSyncAdapter.js +1 -361
  38. package/lib/commonjs/types.js +0 -1
  39. package/lib/module/autoCapture.js +1 -4
  40. package/lib/module/autoCapture.web.js +1 -5
  41. package/lib/module/capture/actions.js +1 -230
  42. package/lib/module/capture/install.js +1 -40
  43. package/lib/module/capture/install.web.js +1 -243
  44. package/lib/module/capture/installExpoImage.js +1 -94
  45. package/lib/module/capture/installRnImage.js +1 -125
  46. package/lib/module/capture/nativeImageModules.js +1 -24
  47. package/lib/module/capture/nativeImageModules.web.js +1 -12
  48. package/lib/module/capture/overrides.js +1 -329
  49. package/lib/module/capture/rnDecoratorEarly.js +1 -50
  50. package/lib/module/capture/savings.js +1 -205
  51. package/lib/module/capture/savings.web.js +1 -67
  52. package/lib/module/capture/shared.js +1 -369
  53. package/lib/module/components/ImageDetail.js +1 -451
  54. package/lib/module/components/ImageDetailFooter.js +1 -154
  55. package/lib/module/components/ImageRow.js +1 -152
  56. package/lib/module/components/ImagesHeader.js +1 -59
  57. package/lib/module/components/ImagesIcon.js +1 -12
  58. package/lib/module/components/ImagesListFooter.js +1 -122
  59. package/lib/module/components/ImagesModal.js +1 -235
  60. package/lib/module/components/ImagesRoot.js +1 -20
  61. package/lib/module/components/ImagesRoot.web.js +1 -9
  62. package/lib/module/components/InsightsBar.js +1 -55
  63. package/lib/module/export.js +1 -76
  64. package/lib/module/format.js +1 -108
  65. package/lib/module/hooks/useImageRecords.js +1 -16
  66. package/lib/module/index.js +1 -79
  67. package/lib/module/preset.js +1 -35
  68. package/lib/module/register.js +1 -19
  69. package/lib/module/registerEarly.js +1 -14
  70. package/lib/module/remote.js +1 -36
  71. package/lib/module/state.js +1 -54
  72. package/lib/module/store/imageEventStore.js +1 -221
  73. package/lib/module/store/insights.js +1 -71
  74. package/lib/module/sync/imagesSyncAdapter.js +1 -356
  75. package/lib/module/types.js +0 -1
  76. package/lib/web/chunks/chunk-TTS5EH4R.mjs +1 -2
  77. package/lib/web/index.mjs +3 -4
  78. package/lib/web/register.mjs +1 -2
  79. package/package.json +2 -2
  80. package/register.js +1 -15
  81. package/lib/commonjs/autoCapture.js.map +0 -1
  82. package/lib/commonjs/autoCapture.web.js.map +0 -1
  83. package/lib/commonjs/capture/actions.js.map +0 -1
  84. package/lib/commonjs/capture/install.js.map +0 -1
  85. package/lib/commonjs/capture/install.web.js.map +0 -1
  86. package/lib/commonjs/capture/installExpoImage.js.map +0 -1
  87. package/lib/commonjs/capture/installRnImage.js.map +0 -1
  88. package/lib/commonjs/capture/nativeImageModules.js.map +0 -1
  89. package/lib/commonjs/capture/nativeImageModules.web.js.map +0 -1
  90. package/lib/commonjs/capture/overrides.js.map +0 -1
  91. package/lib/commonjs/capture/rnDecoratorEarly.js.map +0 -1
  92. package/lib/commonjs/capture/savings.js.map +0 -1
  93. package/lib/commonjs/capture/savings.web.js.map +0 -1
  94. package/lib/commonjs/capture/shared.js.map +0 -1
  95. package/lib/commonjs/components/ImageDetail.js.map +0 -1
  96. package/lib/commonjs/components/ImageDetailFooter.js.map +0 -1
  97. package/lib/commonjs/components/ImageRow.js.map +0 -1
  98. package/lib/commonjs/components/ImagesHeader.js.map +0 -1
  99. package/lib/commonjs/components/ImagesIcon.js.map +0 -1
  100. package/lib/commonjs/components/ImagesListFooter.js.map +0 -1
  101. package/lib/commonjs/components/ImagesModal.js.map +0 -1
  102. package/lib/commonjs/components/ImagesRoot.js.map +0 -1
  103. package/lib/commonjs/components/ImagesRoot.web.js.map +0 -1
  104. package/lib/commonjs/components/InsightsBar.js.map +0 -1
  105. package/lib/commonjs/export.js.map +0 -1
  106. package/lib/commonjs/format.js.map +0 -1
  107. package/lib/commonjs/hooks/useImageRecords.js.map +0 -1
  108. package/lib/commonjs/index.js.map +0 -1
  109. package/lib/commonjs/preset.js.map +0 -1
  110. package/lib/commonjs/register.js.map +0 -1
  111. package/lib/commonjs/registerEarly.js.map +0 -1
  112. package/lib/commonjs/remote.js.map +0 -1
  113. package/lib/commonjs/state.js.map +0 -1
  114. package/lib/commonjs/store/imageEventStore.js.map +0 -1
  115. package/lib/commonjs/store/insights.js.map +0 -1
  116. package/lib/commonjs/sync/imagesSyncAdapter.js.map +0 -1
  117. package/lib/commonjs/types.js.map +0 -1
  118. package/lib/module/autoCapture.js.map +0 -1
  119. package/lib/module/autoCapture.web.js.map +0 -1
  120. package/lib/module/capture/actions.js.map +0 -1
  121. package/lib/module/capture/install.js.map +0 -1
  122. package/lib/module/capture/install.web.js.map +0 -1
  123. package/lib/module/capture/installExpoImage.js.map +0 -1
  124. package/lib/module/capture/installRnImage.js.map +0 -1
  125. package/lib/module/capture/nativeImageModules.js.map +0 -1
  126. package/lib/module/capture/nativeImageModules.web.js.map +0 -1
  127. package/lib/module/capture/overrides.js.map +0 -1
  128. package/lib/module/capture/rnDecoratorEarly.js.map +0 -1
  129. package/lib/module/capture/savings.js.map +0 -1
  130. package/lib/module/capture/savings.web.js.map +0 -1
  131. package/lib/module/capture/shared.js.map +0 -1
  132. package/lib/module/components/ImageDetail.js.map +0 -1
  133. package/lib/module/components/ImageDetailFooter.js.map +0 -1
  134. package/lib/module/components/ImageRow.js.map +0 -1
  135. package/lib/module/components/ImagesHeader.js.map +0 -1
  136. package/lib/module/components/ImagesIcon.js.map +0 -1
  137. package/lib/module/components/ImagesListFooter.js.map +0 -1
  138. package/lib/module/components/ImagesModal.js.map +0 -1
  139. package/lib/module/components/ImagesRoot.js.map +0 -1
  140. package/lib/module/components/ImagesRoot.web.js.map +0 -1
  141. package/lib/module/components/InsightsBar.js.map +0 -1
  142. package/lib/module/export.js.map +0 -1
  143. package/lib/module/format.js.map +0 -1
  144. package/lib/module/hooks/useImageRecords.js.map +0 -1
  145. package/lib/module/index.js.map +0 -1
  146. package/lib/module/preset.js.map +0 -1
  147. package/lib/module/register.js.map +0 -1
  148. package/lib/module/registerEarly.js.map +0 -1
  149. package/lib/module/remote.js.map +0 -1
  150. package/lib/module/state.js.map +0 -1
  151. package/lib/module/store/imageEventStore.js.map +0 -1
  152. package/lib/module/store/insights.js.map +0 -1
  153. package/lib/module/sync/imagesSyncAdapter.js.map +0 -1
  154. package/lib/module/types.js.map +0 -1
  155. package/lib/typescript/autoCapture.d.ts.map +0 -1
  156. package/lib/typescript/autoCapture.web.d.ts.map +0 -1
  157. package/lib/typescript/capture/actions.d.ts.map +0 -1
  158. package/lib/typescript/capture/install.d.ts.map +0 -1
  159. package/lib/typescript/capture/install.web.d.ts.map +0 -1
  160. package/lib/typescript/capture/installExpoImage.d.ts.map +0 -1
  161. package/lib/typescript/capture/installRnImage.d.ts.map +0 -1
  162. package/lib/typescript/capture/nativeImageModules.d.ts.map +0 -1
  163. package/lib/typescript/capture/nativeImageModules.web.d.ts.map +0 -1
  164. package/lib/typescript/capture/overrides.d.ts.map +0 -1
  165. package/lib/typescript/capture/rnDecoratorEarly.d.ts.map +0 -1
  166. package/lib/typescript/capture/savings.d.ts.map +0 -1
  167. package/lib/typescript/capture/savings.web.d.ts.map +0 -1
  168. package/lib/typescript/capture/shared.d.ts.map +0 -1
  169. package/lib/typescript/components/ImageDetail.d.ts.map +0 -1
  170. package/lib/typescript/components/ImageDetailFooter.d.ts.map +0 -1
  171. package/lib/typescript/components/ImageRow.d.ts.map +0 -1
  172. package/lib/typescript/components/ImagesHeader.d.ts.map +0 -1
  173. package/lib/typescript/components/ImagesIcon.d.ts.map +0 -1
  174. package/lib/typescript/components/ImagesListFooter.d.ts.map +0 -1
  175. package/lib/typescript/components/ImagesModal.d.ts.map +0 -1
  176. package/lib/typescript/components/ImagesRoot.d.ts.map +0 -1
  177. package/lib/typescript/components/ImagesRoot.web.d.ts.map +0 -1
  178. package/lib/typescript/components/InsightsBar.d.ts.map +0 -1
  179. package/lib/typescript/export.d.ts.map +0 -1
  180. package/lib/typescript/format.d.ts.map +0 -1
  181. package/lib/typescript/hooks/useImageRecords.d.ts.map +0 -1
  182. package/lib/typescript/index.d.ts.map +0 -1
  183. package/lib/typescript/preset.d.ts.map +0 -1
  184. package/lib/typescript/register.d.ts.map +0 -1
  185. package/lib/typescript/registerEarly.d.ts.map +0 -1
  186. package/lib/typescript/remote.d.ts.map +0 -1
  187. package/lib/typescript/state.d.ts.map +0 -1
  188. package/lib/typescript/store/imageEventStore.d.ts.map +0 -1
  189. package/lib/typescript/store/insights.d.ts.map +0 -1
  190. package/lib/typescript/sync/imagesSyncAdapter.d.ts.map +0 -1
  191. package/lib/typescript/types.d.ts.map +0 -1
  192. package/lib/web/chunks/chunk-7CWLRQ2L.mjs +0 -2
  193. package/lib/web/chunks/chunk-B5A6CYSS.mjs +0 -2
  194. package/lib/web/chunks/chunk-LKTR6X2V.mjs +0 -2
@@ -1,243 +1 @@
1
- "use strict";
2
-
3
- import { imagesState } from '../state';
4
- import { createRecord, getRecord, updateRecord } from '../store/imageEventStore';
5
- import { getOverride, getGlobalModes } from './overrides';
6
- const tracked = new Map();
7
- let detach;
8
- let leases = 0;
9
- const EMPTY_IMAGE = 'data:image/png;base64,';
10
- function apply(item) {
11
- const record = getRecord(item.id);
12
- if (!record) return;
13
- const state = imagesState();
14
- const override = getOverride(item.id);
15
- const modes = getGlobalModes();
16
- let source = item.source;
17
- if (modes.network === 'offline' && record.sourceKind === 'network') source = EMPTY_IMAGE;
18
- if (override?.source) {
19
- const next = override.source;
20
- if (next.type === 'url') source = next.uri;else if (next.type === 'error') source = EMPTY_IMAGE;else source = null;
21
- if (next.type === 'hang') updateRecord(item.id, {
22
- status: 'loading'
23
- });
24
- }
25
- const request = state.reloadRequests.get(item.id);
26
- const reload = request && request.nonce !== item.nonce;
27
- if (reload) {
28
- item.nonce = request.nonce;
29
- if (request.bust && source && /^https?:/.test(new URL(source, document.baseURI).href)) {
30
- const url = new URL(source, document.baseURI);
31
- url.searchParams.set('__buoy_reload', String(Date.now()));
32
- source = url.href;
33
- }
34
- item.image.removeAttribute('src');
35
- updateRecord(item.id, {
36
- status: 'loading',
37
- startedAt: Date.now(),
38
- loadCount: record.loadCount + 1
39
- });
40
- }
41
- if (modes.network === 'cold' && source && /^https?:/.test(new URL(source, document.baseURI).href)) {
42
- if (item.coldSource !== source || !item.coldURL || reload) {
43
- item.coldSource = source;
44
- const url = new URL(source, document.baseURI);
45
- url.searchParams.set('__buoy_reload', `${Date.now()}-${item.nonce}`);
46
- item.coldURL = url.href;
47
- }
48
- source = item.coldURL;
49
- } else {
50
- item.coldSource = undefined;
51
- item.coldURL = undefined;
52
- }
53
- item.appliedSource = source;
54
- item.appliedSrcset = source !== item.source ? null : item.srcset;
55
- if (item.appliedSrcset === null) item.image.removeAttribute('srcset');else if (item.image.getAttribute('srcset') !== item.appliedSrcset) item.image.setAttribute('srcset', item.appliedSrcset);
56
- if (source === null) item.image.removeAttribute('src');else if (item.image.getAttribute('src') !== source) item.image.setAttribute('src', source);
57
- const style = document.createElement('span').style;
58
- style.cssText = item.style ?? '';
59
- const fit = override?.extraProps?.contentFit ?? override?.extraProps?.resizeMode;
60
- if (typeof fit === 'string') style.objectFit = {
61
- stretch: 'fill',
62
- center: 'none'
63
- }[fit] ?? fit;
64
- if (modes.blank || override?.source?.type === 'blank') style.opacity = '0';
65
- for (const [key, value] of Object.entries(override?.style ?? {})) {
66
- const css = key.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
67
- style.setProperty(css, typeof value === 'number' && !['opacity', 'zIndex', 'flex', 'flexGrow', 'flexShrink'].includes(key) ? `${value}px` : String(value));
68
- }
69
- if ((state.flashUntil.get(item.id) ?? 0) > Date.now()) style.outline = '3px solid #ff453a';
70
- item.appliedStyle = style.cssText || null;
71
- if (item.image.getAttribute('style') !== item.appliedStyle) {
72
- if (item.appliedStyle === null) item.image.removeAttribute('style');else item.image.setAttribute('style', item.appliedStyle);
73
- }
74
- }
75
- function track(image) {
76
- if (tracked.has(image) || image.closest('[data-buoy-root]')) return;
77
- const uri = image.currentSrc || image.src;
78
- if (!uri) return;
79
- const record = createRecord({
80
- lib: 'web',
81
- uri,
82
- sourceKind: uri.startsWith('data:') ? 'data' : uri.startsWith('blob:') ? 'file' : 'network',
83
- hasAltText: image.hasAttribute('alt') || image.hasAttribute('aria-label')
84
- });
85
- const item = {
86
- id: record.id,
87
- image,
88
- source: image.getAttribute('src'),
89
- srcset: image.getAttribute('srcset'),
90
- style: image.getAttribute('style'),
91
- appliedSource: image.getAttribute('src'),
92
- appliedSrcset: image.getAttribute('srcset'),
93
- appliedStyle: image.getAttribute('style'),
94
- nonce: 0,
95
- dispose() {}
96
- };
97
- const layout = () => {
98
- const rect = image.getBoundingClientRect();
99
- const previous = record.layout;
100
- const shifted = record.status === 'loaded' && previous && (previous.width !== rect.width || previous.height !== rect.height);
101
- updateRecord(record.id, {
102
- layout: {
103
- width: rect.width,
104
- height: rect.height
105
- },
106
- layoutShifts: (record.layoutShifts ?? 0) + (shifted ? 1 : 0)
107
- });
108
- };
109
- const loaded = () => {
110
- const timings = performance.getEntriesByName(image.currentSrc || image.src);
111
- const timing = timings[timings.length - 1];
112
- updateRecord(record.id, {
113
- status: 'loaded',
114
- loadedAt: Date.now(),
115
- intrinsic: {
116
- width: image.naturalWidth,
117
- height: image.naturalHeight
118
- },
119
- ...(!getOverride(record.id)?.source && getGlobalModes().network === 'normal' ? {
120
- uri: image.currentSrc || image.src
121
- } : {}),
122
- durationMs: timing?.duration,
123
- bytesTotal: timing && timing.encodedBodySize > 0 ? timing.encodedBodySize : undefined,
124
- cacheVerdict: timing && timing.transferSize > 0 ? 'none' : undefined,
125
- cacheVerdictSource: timing ? 'event' : undefined
126
- });
127
- layout();
128
- };
129
- const failed = () => updateRecord(record.id, {
130
- status: 'error',
131
- erroredAt: Date.now(),
132
- error: 'The browser could not load this image.'
133
- });
134
- image.addEventListener('load', loaded);
135
- image.addEventListener('error', failed);
136
- const observer = typeof ResizeObserver === 'undefined' ? undefined : new ResizeObserver(layout);
137
- observer?.observe(image);
138
- item.dispose = () => {
139
- observer?.disconnect();
140
- image.removeEventListener('load', loaded);
141
- image.removeEventListener('error', failed);
142
- };
143
- tracked.set(image, item);
144
- layout();
145
- updateRecord(record.id, {
146
- status: 'loading',
147
- startedAt: Date.now(),
148
- loadCount: 1
149
- });
150
- if (image.complete) {
151
- if (image.naturalWidth > 0) loaded();else failed();
152
- }
153
- apply(item);
154
- }
155
- export function installImageCapture() {
156
- const state = imagesState();
157
- if (typeof document === 'undefined' || state.captureDisabled || detach) return;
158
- state.captureInstalled = true;
159
- const scan = () => {
160
- for (const [image, item] of tracked) if (!image.isConnected) {
161
- item.dispose();
162
- tracked.delete(image);
163
- updateRecord(item.id, {
164
- mounted: false
165
- });
166
- }
167
- document.querySelectorAll('img').forEach(track);
168
- };
169
- const observer = new MutationObserver(changes => {
170
- if (imagesState().captureDisabled) {
171
- stopBrowserImageCapture();
172
- return;
173
- }
174
- for (const change of changes) {
175
- const image = change.target;
176
- const item = tracked.get(image);
177
- if (!item || change.type !== 'attributes') continue;
178
- if (change.attributeName === 'src' && image.getAttribute('src') !== item.appliedSource || change.attributeName === 'srcset' && image.getAttribute('srcset') !== item.appliedSrcset) {
179
- item.dispose();
180
- tracked.delete(image);
181
- updateRecord(item.id, {
182
- mounted: false
183
- });
184
- } else if (change.attributeName === 'style' && image.getAttribute('style') !== item.appliedStyle) {
185
- item.style = image.getAttribute('style');
186
- apply(item);
187
- }
188
- }
189
- scan();
190
- });
191
- observer.observe(document.documentElement, {
192
- childList: true,
193
- subtree: true,
194
- attributes: true,
195
- attributeFilter: ['src', 'srcset', 'style', 'alt']
196
- });
197
- const actions = () => {
198
- for (const item of tracked.values()) apply(item);
199
- };
200
- state.actionListeners.add(actions);
201
- detach = () => {
202
- observer.disconnect();
203
- state.actionListeners.delete(actions);
204
- for (const item of tracked.values()) {
205
- item.dispose();
206
- for (const [attribute, value, applied] of [['src', item.source, item.appliedSource], ['srcset', item.srcset, item.appliedSrcset], ['style', item.style, item.appliedStyle]]) {
207
- if (item.image.getAttribute(attribute) !== applied) continue;
208
- if (value === null) item.image.removeAttribute(attribute);else item.image.setAttribute(attribute, value);
209
- }
210
- updateRecord(item.id, {
211
- mounted: false
212
- });
213
- }
214
- tracked.clear();
215
- state.captureInstalled = false;
216
- };
217
- scan();
218
- }
219
- export function stopBrowserImageCapture() {
220
- detach?.();
221
- detach = undefined;
222
- }
223
- export function startBrowserImageCapture() {
224
- if (typeof document === 'undefined') return () => {};
225
- if (leases++ === 0) installImageCapture();
226
- let released = false;
227
- return () => {
228
- if (released) return;
229
- released = true;
230
- if (--leases === 0) stopBrowserImageCapture();
231
- };
232
- }
233
- export function getCaptureStatus() {
234
- return imagesState().mirrorCaptureStatus ?? {
235
- installed: !!detach,
236
- rnDecoratorActive: false,
237
- rnDecoratorTooLate: false,
238
- expoPatched: false,
239
- expoAvailable: false,
240
- browserObserverActive: !!detach
241
- };
242
- }
243
- //# sourceMappingURL=install.web.js.map
1
+ "use strict";import{imagesState as b}from"../state";import{createRecord as x,getRecord as L,updateRecord as u}from"../store/imageEventStore";import{getOverride as g,getGlobalModes as S}from"./overrides";const f=new Map;let p;let A=0;const w="data:image/png;base64,";function h(e){const d=L(e.id);if(!d)return;const n=b();const l=g(e.id);const r=S();let t=e.source;if(r.network==="offline"&&d.sourceKind==="network")t=w;if(l?.source){const i=l.source;if(i.type==="url")t=i.uri;else if(i.type==="error")t=w;else t=null;if(i.type==="hang")u(e.id,{status:"loading"})}const s=n.reloadRequests.get(e.id);const o=s&&s.nonce!==e.nonce;if(o){e.nonce=s.nonce;if(s.bust&&t&&/^https?:/.test(new URL(t,document.baseURI).href)){const i=new URL(t,document.baseURI);i.searchParams.set("__buoy_reload",String(Date.now()));t=i.href}e.image.removeAttribute("src");u(e.id,{status:"loading",startedAt:Date.now(),loadCount:d.loadCount+1})}if(r.network==="cold"&&t&&/^https?:/.test(new URL(t,document.baseURI).href)){if(e.coldSource!==t||!e.coldURL||o){e.coldSource=t;const i=new URL(t,document.baseURI);i.searchParams.set("__buoy_reload",`${Date.now()}-${e.nonce}`);e.coldURL=i.href}t=e.coldURL}else{e.coldSource=void 0;e.coldURL=void 0}e.appliedSource=t;e.appliedSrcset=t!==e.source?null:e.srcset;if(e.appliedSrcset===null)e.image.removeAttribute("srcset");else if(e.image.getAttribute("srcset")!==e.appliedSrcset)e.image.setAttribute("srcset",e.appliedSrcset);if(t===null)e.image.removeAttribute("src");else if(e.image.getAttribute("src")!==t)e.image.setAttribute("src",t);const a=document.createElement("span").style;a.cssText=e.style??"";const c=l?.extraProps?.contentFit??l?.extraProps?.resizeMode;if(typeof c==="string")a.objectFit={stretch:"fill",center:"none"}[c]??c;if(r.blank||l?.source?.type==="blank")a.opacity="0";for(const[i,y]of Object.entries(l?.style??{})){const v=i.replace(/[A-Z]/g,R=>`-${R.toLowerCase()}`);a.setProperty(v,typeof y==="number"&&!["opacity","zIndex","flex","flexGrow","flexShrink"].includes(i)?`${y}px`:String(y))}if((n.flashUntil.get(e.id)??0)>Date.now())a.outline="3px solid #ff453a";e.appliedStyle=a.cssText||null;if(e.image.getAttribute("style")!==e.appliedStyle){if(e.appliedStyle===null)e.image.removeAttribute("style");else e.image.setAttribute("style",e.appliedStyle)}}function U(e){if(f.has(e)||e.closest("[data-buoy-root]"))return;const d=e.currentSrc||e.src;if(!d)return;const n=x({lib:"web",uri:d,sourceKind:d.startsWith("data:")?"data":d.startsWith("blob:")?"file":"network",hasAltText:e.hasAttribute("alt")||e.hasAttribute("aria-label")});const l={id:n.id,image:e,source:e.getAttribute("src"),srcset:e.getAttribute("srcset"),style:e.getAttribute("style"),appliedSource:e.getAttribute("src"),appliedSrcset:e.getAttribute("srcset"),appliedStyle:e.getAttribute("style"),nonce:0,dispose(){}};const r=()=>{const a=e.getBoundingClientRect();const c=n.layout;const i=n.status==="loaded"&&c&&(c.width!==a.width||c.height!==a.height);u(n.id,{layout:{width:a.width,height:a.height},layoutShifts:(n.layoutShifts??0)+(i?1:0)})};const t=()=>{const a=performance.getEntriesByName(e.currentSrc||e.src);const c=a[a.length-1];u(n.id,{status:"loaded",loadedAt:Date.now(),intrinsic:{width:e.naturalWidth,height:e.naturalHeight},...!g(n.id)?.source&&S().network==="normal"?{uri:e.currentSrc||e.src}:{},durationMs:c?.duration,bytesTotal:c&&c.encodedBodySize>0?c.encodedBodySize:void 0,cacheVerdict:c&&c.transferSize>0?"none":void 0,cacheVerdictSource:c?"event":void 0});r()};const s=()=>u(n.id,{status:"error",erroredAt:Date.now(),error:"The browser could not load this image."});e.addEventListener("load",t);e.addEventListener("error",s);const o=typeof ResizeObserver==="undefined"?void 0:new ResizeObserver(r);o?.observe(e);l.dispose=()=>{o?.disconnect();e.removeEventListener("load",t);e.removeEventListener("error",s)};f.set(e,l);r();u(n.id,{status:"loading",startedAt:Date.now(),loadCount:1});if(e.complete){if(e.naturalWidth>0)t();else s()}h(l)}export function installImageCapture(){const e=b();if(typeof document==="undefined"||e.captureDisabled||p)return;e.captureInstalled=true;const d=()=>{for(const[r,t]of f)if(!r.isConnected){t.dispose();f.delete(r);u(t.id,{mounted:false})}document.querySelectorAll("img").forEach(U)};const n=new MutationObserver(r=>{if(b().captureDisabled){stopBrowserImageCapture();return}for(const t of r){const s=t.target;const o=f.get(s);if(!o||t.type!=="attributes")continue;if(t.attributeName==="src"&&s.getAttribute("src")!==o.appliedSource||t.attributeName==="srcset"&&s.getAttribute("srcset")!==o.appliedSrcset){o.dispose();f.delete(s);u(o.id,{mounted:false})}else if(t.attributeName==="style"&&s.getAttribute("style")!==o.appliedStyle){o.style=s.getAttribute("style");h(o)}}d()});n.observe(document.documentElement,{childList:true,subtree:true,attributes:true,attributeFilter:["src","srcset","style","alt"]});const l=()=>{for(const r of f.values())h(r)};e.actionListeners.add(l);p=()=>{n.disconnect();e.actionListeners.delete(l);for(const r of f.values()){r.dispose();for(const[t,s,o]of[["src",r.source,r.appliedSource],["srcset",r.srcset,r.appliedSrcset],["style",r.style,r.appliedStyle]]){if(r.image.getAttribute(t)!==o)continue;if(s===null)r.image.removeAttribute(t);else r.image.setAttribute(t,s)}u(r.id,{mounted:false})}f.clear();e.captureInstalled=false};d()}export function stopBrowserImageCapture(){p?.();p=void 0}export function startBrowserImageCapture(){if(typeof document==="undefined")return()=>{};if(A++===0)installImageCapture();let e=false;return()=>{if(e)return;e=true;if(--A===0)stopBrowserImageCapture()}}export function getCaptureStatus(){return b().mirrorCaptureStatus??{installed:!!p,rnDecoratorActive:false,rnDecoratorTooLate:false,expoPatched:false,expoAvailable:false,browserObserverActive:!!p}}
@@ -1,94 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * expo-image interception via class-prototype patch.
5
- *
6
- * expo-image's <Image> is a class component (React.PureComponent) whose
7
- * render() reads `this.props`, so wrapping the prototype's render and swapping
8
- * `this.props` for an instrumented copy for the duration of the original
9
- * render is timing-immune (prototype methods are looked up dynamically — no
10
- * import-order race like the RN core decorator). Props are restored in
11
- * `finally`, so PureComponent's shouldComponentUpdate still compares the
12
- * app's real props.
13
- *
14
- * Double-patch safety: install flags live on the globalThis singleton AND a
15
- * marker is stamped on the prototype itself, so even two module instances of
16
- * this package can't wrap render() twice.
17
- *
18
- * expo-image is an optional peer: if it isn't installed, this is a no-op.
19
- */
20
-
21
- import { imagesState } from "../state";
22
- import { registerExpoInstance } from "./actions";
23
- import { applyOverrides } from "./overrides";
24
- import { ImageInstanceTracker, isInternalImage } from "./shared";
25
- const PATCH_MARKER = "__buoyImagesPatched";
26
- const trackers = new WeakMap();
27
- function trackerFor(instance) {
28
- let tracker = trackers.get(instance);
29
- if (!tracker) {
30
- tracker = new ImageInstanceTracker("expo");
31
- trackers.set(instance, tracker);
32
- }
33
- return tracker;
34
- }
35
- export function installExpoImageInterceptor() {
36
- const s = imagesState();
37
- if (s.expoInstalled) return;
38
- s.expoInstalled = true;
39
- let ImageClass;
40
- try {
41
- ImageClass = require("expo-image").Image;
42
- } catch {
43
- s.expoAvailable = false;
44
- return; // expo-image not installed in this app
45
- }
46
- if (!ImageClass?.prototype?.render) {
47
- s.expoAvailable = false;
48
- return;
49
- }
50
- s.expoAvailable = true;
51
- const proto = ImageClass.prototype;
52
- if (proto[PATCH_MARKER]) {
53
- s.expoPatched = true;
54
- return; // already patched by another module instance of this package
55
- }
56
- proto[PATCH_MARKER] = true;
57
- const originalRender = proto.render;
58
- const originalUnmount = proto.componentWillUnmount;
59
- proto.render = function buoyImagesRender() {
60
- const originalProps = this.props;
61
- if (isInternalImage(originalProps?.testID)) {
62
- return originalRender.call(this);
63
- }
64
- const tracker = trackerFor(this);
65
- tracker.syncSource(originalProps?.source);
66
- tracker.noteA11y(Boolean(originalProps?.alt ?? originalProps?.accessibilityLabel));
67
- // Keep the action layer pointed at the live instance (reloadAsync etc.).
68
- registerExpoInstance(tracker.getRecordId(), this);
69
- const wrapped = tracker.handlers(originalProps);
70
- try {
71
- // Simulation layer: global modes + per-record override + locate-flash.
72
- this.props = applyOverrides({
73
- ...originalProps,
74
- ...wrapped
75
- }, tracker.getRecordId(), "expo");
76
- return originalRender.call(this);
77
- } finally {
78
- this.props = originalProps;
79
- }
80
- };
81
- proto.componentWillUnmount = function buoyImagesUnmount() {
82
- trackers.get(this)?.unmount();
83
- originalUnmount?.call(this);
84
- };
85
- s.expoPatched = true;
86
- }
87
- export function expoCaptureStatus() {
88
- const s = imagesState();
89
- return {
90
- available: s.expoAvailable,
91
- patched: s.expoPatched
92
- };
93
- }
94
- //# sourceMappingURL=installExpoImage.js.map
1
+ "use strict";import{imagesState as i}from"../state";import{registerExpoInstance as m}from"./actions";import{applyOverrides as d}from"./overrides";import{ImageInstanceTracker as g,isInternalImage as f}from"./shared";const l="__buoyImagesPatched";const a=new WeakMap;function x(e){let t=a.get(e);if(!t){t=new g("expo");a.set(e,t)}return t}export function installExpoImageInterceptor(){const e=i();if(e.expoInstalled)return;e.expoInstalled=true;let t;try{t=require("expo-image").Image}catch{e.expoAvailable=false;return}if(!t?.prototype?.render){e.expoAvailable=false;return}e.expoAvailable=true;const o=t.prototype;if(o[l]){e.expoPatched=true;return}o[l]=true;const s=o.render;const p=o.componentWillUnmount;o.render=function c(){const r=this.props;if(f(r?.testID)){return s.call(this)}const n=x(this);n.syncSource(r?.source);n.noteA11y(Boolean(r?.alt??r?.accessibilityLabel));m(n.getRecordId(),this);const u=n.handlers(r);try{this.props=d({...r,...u},n.getRecordId(),"expo");return s.call(this)}finally{this.props=r}};o.componentWillUnmount=function c(){a.get(this)?.unmount();p?.call(this)};e.expoPatched=true}export function expoCaptureStatus(){const e=i();return{available:e.expoAvailable,patched:e.expoPatched}}
@@ -1,125 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * RN core <Image> interception via the official injection hook.
5
- *
6
- * `unstable_setImageComponentDecorator` wraps EVERY RN <Image> app-wide — but
7
- * the decorator is latched ONCE, at Image module evaluation
8
- * (`Image.ios.js` / `Image.android.js` read it at module scope). So install
9
- * order matters: this must run before anything touches `Image` from
10
- * 'react-native' — hence the `@buoy-gg/images/register` first-import.
11
- *
12
- * Detection strategy: the decorator sets `decoratorInvoked` when RN's Image
13
- * module applies it. `unstable_registerImageAttachedCallback` is a live Set
14
- * (never latched), so image mounts are always visible — if mounts happen but
15
- * the decorator never ran, we were too late and CaptureStatus reports it.
16
- *
17
- * All flags live on the globalThis singleton (../state.ts) so a second module
18
- * instance of this package neither re-installs nor reports a stale status.
19
- */
20
-
21
- import * as React from "react";
22
- import { imagesState } from "../state";
23
- import { getReloadNonce, getReloadRequest, subscribeActions } from "./actions";
24
- import { applyOverrides, getRenderVersion, patchSourceCache } from "./overrides";
25
- import { ImageInstanceTracker, isInternalImage } from "./shared";
26
- import { jsx as _jsx } from "react/jsx-runtime";
27
- /** Wraps one RN Image render with capture instrumentation + reload actions. */
28
- export function useImageCapture(props) {
29
- const trackerRef = React.useRef(null);
30
- if (trackerRef.current == null) {
31
- trackerRef.current = new ImageInstanceTracker("rn");
32
- }
33
- const tracker = trackerRef.current;
34
- const internal = isInternalImage(props.testID);
35
- if (!internal) {
36
- tracker.syncSource(props.source);
37
- tracker.noteA11y(Boolean(props.alt ?? props.accessibilityLabel ?? props["aria-label"]));
38
- }
39
-
40
- // Action/override bus: version bumps re-render just this instance (snapshot
41
- // is per-record with a global floor, so unrelated actions don't invalidate
42
- // other images but global-mode toggles reach everyone).
43
- React.useSyncExternalStore(subscribeActions, () => getRenderVersion(internal ? null : tracker.getRecordId()));
44
- React.useEffect(() => {
45
- if (internal) return undefined;
46
- return () => tracker.unmount();
47
- }, [tracker, internal]);
48
- if (internal) return {
49
- props,
50
- reloadKey: 0
51
- };
52
- const recordId = tracker.getRecordId();
53
- const wrapped = tracker.handlers(props);
54
- const out = {
55
- ...props,
56
- ...wrapped
57
- };
58
-
59
- // While a bust request is pending (cleared when the load settles), refetch
60
- // bypassing caches — VERIFIED both platforms honor source.cache: 'reload'.
61
- const request = getReloadRequest(recordId);
62
- if (request?.bust) {
63
- out.source = patchSourceCache(out.source, "reload");
64
- }
65
- // Simulation layer: global modes + per-record override + locate-flash.
66
- applyOverrides(out, recordId, "rn");
67
- return {
68
- props: out,
69
- reloadKey: getReloadNonce(recordId)
70
- };
71
- }
72
- export function installRnImageInterceptor() {
73
- const s = imagesState();
74
- if (s.rnInstalled) return;
75
- s.rnInstalled = true;
76
- try {
77
- // Deep import: evaluates ONLY the injection module, never Image itself.
78
- const injection = require("react-native/Libraries/Image/ImageInjection");
79
- const setDecorator = injection.unstable_setImageComponentDecorator;
80
- const registerAttached = injection.unstable_registerImageAttachedCallback;
81
-
82
- // `register-early` (a pre-InitializeCore entry) may have registered the
83
- // decorator already; registering again would replace it with an identical one.
84
- if (typeof setDecorator === "function" && !s.decoratorRegistered) {
85
- setDecorator(BaseImage => {
86
- imagesState().decoratorInvoked = true;
87
- const CapturedImage = /*#__PURE__*/React.forwardRef(function BuoyCapturedImage(props, ref) {
88
- const {
89
- props: instrumented,
90
- reloadKey
91
- } = useImageCapture(props);
92
- // key bump forces a native remount → fresh load cycle (retry).
93
- return /*#__PURE__*/_jsx(BaseImage, {
94
- ...instrumented,
95
- ref: ref
96
- }, `buoy-r${reloadKey}`);
97
- });
98
- return CapturedImage;
99
- });
100
- s.decoratorRegistered = true;
101
- }
102
-
103
- // Live mount signal — works regardless of decorator timing. Used purely
104
- // to detect the "decorator registered too late" condition.
105
- if (typeof registerAttached === "function") {
106
- registerAttached(() => {
107
- imagesState().attachSeen++;
108
- });
109
- }
110
- } catch {
111
- // Internal RN path moved (version drift) or non-RN platform — expo-image
112
- // capture still works; status will report the decorator as inactive.
113
- s.decoratorRegistered = false;
114
- }
115
- }
116
- export function rnCaptureStatus() {
117
- const s = imagesState();
118
- return {
119
- decoratorRegistered: s.decoratorRegistered,
120
- decoratorActive: s.decoratorInvoked,
121
- // Mounts observed but our wrapper never rendered → Image latched first.
122
- tooLate: s.decoratorRegistered && !s.decoratorInvoked && s.attachSeen > 0
123
- };
124
- }
125
- //# sourceMappingURL=installRnImage.js.map
1
+ "use strict";import*as c from"react";import{imagesState as s}from"../state";import{getReloadNonce as m,getReloadRequest as g,subscribeActions as I}from"./actions";import{applyOverrides as R,getRenderVersion as y,patchSourceCache as p}from"./overrides";import{ImageInstanceTracker as b,isInternalImage as h}from"./shared";import{jsx as S}from"react/jsx-runtime";export function useImageCapture(e){const o=c.useRef(null);if(o.current==null){o.current=new b("rn")}const t=o.current;const r=h(e.testID);if(!r){t.syncSource(e.source);t.noteA11y(Boolean(e.alt??e.accessibilityLabel??e["aria-label"]))}c.useSyncExternalStore(I,()=>y(r?null:t.getRecordId()));c.useEffect(()=>{if(r)return void 0;return()=>t.unmount()},[t,r]);if(r)return{props:e,reloadKey:0};const n=t.getRecordId();const u=t.handlers(e);const a={...e,...u};const i=g(n);if(i?.bust){a.source=p(a.source,"reload")}R(a,n,"rn");return{props:a,reloadKey:m(n)}}export function installRnImageInterceptor(){const e=s();if(e.rnInstalled)return;e.rnInstalled=true;try{const o=require("react-native/Libraries/Image/ImageInjection");const t=o.unstable_setImageComponentDecorator;const r=o.unstable_registerImageAttachedCallback;if(typeof t==="function"&&!e.decoratorRegistered){t(n=>{s().decoratorInvoked=true;const u=c.forwardRef(function a(i,d){const{props:l,reloadKey:f}=useImageCapture(i);return S(n,{...l,ref:d},`buoy-r${f}`)});return u});e.decoratorRegistered=true}if(typeof r==="function"){r(()=>{s().attachSeen++})}}catch{e.decoratorRegistered=false}}export function rnCaptureStatus(){const e=s();return{decoratorRegistered:e.decoratorRegistered,decoratorActive:e.decoratorInvoked,tooLate:e.decoratorRegistered&&!e.decoratorInvoked&&e.attachSeen>0}}
@@ -1,24 +1 @@
1
- "use strict";
2
-
3
- export function loadExpoImage() {
4
- try {
5
- return require('expo-image');
6
- } catch {
7
- return null;
8
- }
9
- }
10
- export function loadLegacyFileSystem() {
11
- try {
12
- return require('expo-file-system/legacy');
13
- } catch {
14
- return null;
15
- }
16
- }
17
- export function loadFileSystemModule() {
18
- try {
19
- return require('expo-file-system');
20
- } catch {
21
- return null;
22
- }
23
- }
24
- //# sourceMappingURL=nativeImageModules.js.map
1
+ "use strict";export function loadExpoImage(){try{return require("expo-image")}catch{return null}}export function loadLegacyFileSystem(){try{return require("expo-file-system/legacy")}catch{return null}}export function loadFileSystemModule(){try{return require("expo-file-system")}catch{return null}}
@@ -1,12 +1 @@
1
- "use strict";
2
-
3
- export function loadExpoImage() {
4
- return null;
5
- }
6
- export function loadLegacyFileSystem() {
7
- return null;
8
- }
9
- export function loadFileSystemModule() {
10
- return null;
11
- }
12
- //# sourceMappingURL=nativeImageModules.web.js.map
1
+ "use strict";export function loadExpoImage(){return null}export function loadLegacyFileSystem(){return null}export function loadFileSystemModule(){return null}