@buoy-gg/images 7.0.40 → 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.
- package/README.md +12 -65
- package/lib/commonjs/autoCapture.js +1 -0
- package/lib/commonjs/autoCapture.web.js +1 -0
- package/lib/commonjs/capture/actions.js +1 -242
- package/lib/commonjs/capture/install.js +1 -45
- package/lib/commonjs/capture/install.web.js +1 -0
- package/lib/commonjs/capture/installExpoImage.js +1 -99
- package/lib/commonjs/capture/installRnImage.js +1 -128
- package/lib/commonjs/capture/nativeImageModules.js +1 -0
- package/lib/commonjs/capture/nativeImageModules.web.js +1 -0
- package/lib/commonjs/capture/overrides.js +1 -346
- package/lib/commonjs/capture/rnDecoratorEarly.js +1 -0
- package/lib/commonjs/capture/savings.js +1 -209
- package/lib/commonjs/capture/savings.web.js +1 -0
- package/lib/commonjs/capture/shared.js +1 -378
- package/lib/commonjs/components/ImageDetail.js +1 -454
- package/lib/commonjs/components/ImageDetailFooter.js +1 -158
- package/lib/commonjs/components/ImageRow.js +1 -156
- package/lib/commonjs/components/ImagesHeader.js +1 -63
- package/lib/commonjs/components/ImagesIcon.js +1 -19
- package/lib/commonjs/components/ImagesListFooter.js +1 -126
- package/lib/commonjs/components/ImagesModal.js +1 -240
- package/lib/commonjs/components/ImagesRoot.js +1 -24
- package/lib/commonjs/components/ImagesRoot.web.js +1 -0
- package/lib/commonjs/components/InsightsBar.js +1 -59
- package/lib/commonjs/export.js +1 -81
- package/lib/commonjs/format.js +1 -117
- package/lib/commonjs/hooks/useImageRecords.js +1 -20
- package/lib/commonjs/index.js +1 -261
- package/lib/commonjs/preset.js +1 -39
- package/lib/commonjs/register.js +1 -19
- package/lib/commonjs/registerEarly.js +1 -0
- package/lib/commonjs/remote.js +1 -42
- package/lib/commonjs/state.js +1 -58
- package/lib/commonjs/store/imageEventStore.js +1 -238
- package/lib/commonjs/store/insights.js +1 -76
- package/lib/commonjs/sync/imagesSyncAdapter.js +1 -360
- package/lib/commonjs/types.js +0 -1
- package/lib/module/autoCapture.js +1 -0
- package/lib/module/autoCapture.web.js +1 -0
- package/lib/module/capture/actions.js +1 -229
- package/lib/module/capture/install.js +1 -40
- package/lib/module/capture/install.web.js +1 -0
- package/lib/module/capture/installExpoImage.js +1 -94
- package/lib/module/capture/installRnImage.js +1 -122
- package/lib/module/capture/nativeImageModules.js +1 -0
- package/lib/module/capture/nativeImageModules.web.js +1 -0
- package/lib/module/capture/overrides.js +1 -329
- package/lib/module/capture/rnDecoratorEarly.js +1 -0
- package/lib/module/capture/savings.js +1 -205
- package/lib/module/capture/savings.web.js +1 -0
- package/lib/module/capture/shared.js +1 -369
- package/lib/module/components/ImageDetail.js +1 -450
- package/lib/module/components/ImageDetailFooter.js +1 -154
- package/lib/module/components/ImageRow.js +1 -152
- package/lib/module/components/ImagesHeader.js +1 -59
- package/lib/module/components/ImagesIcon.js +1 -12
- package/lib/module/components/ImagesListFooter.js +1 -122
- package/lib/module/components/ImagesModal.js +1 -235
- package/lib/module/components/ImagesRoot.js +1 -20
- package/lib/module/components/ImagesRoot.web.js +1 -0
- package/lib/module/components/InsightsBar.js +1 -55
- package/lib/module/export.js +1 -76
- package/lib/module/format.js +1 -108
- package/lib/module/hooks/useImageRecords.js +1 -16
- package/lib/module/index.js +1 -79
- package/lib/module/preset.js +1 -35
- package/lib/module/register.js +1 -19
- package/lib/module/registerEarly.js +1 -0
- package/lib/module/remote.js +1 -36
- package/lib/module/state.js +1 -54
- package/lib/module/store/imageEventStore.js +1 -221
- package/lib/module/store/insights.js +1 -71
- package/lib/module/sync/imagesSyncAdapter.js +1 -355
- package/lib/module/types.js +0 -1
- package/lib/typescript/autoCapture.d.ts +2 -0
- package/lib/typescript/autoCapture.web.d.ts +2 -0
- package/lib/typescript/capture/actions.d.ts +0 -17
- package/lib/typescript/capture/install.web.d.ts +6 -0
- package/lib/typescript/capture/installRnImage.d.ts +5 -0
- package/lib/typescript/capture/nativeImageModules.d.ts +4 -0
- package/lib/typescript/capture/nativeImageModules.web.d.ts +4 -0
- package/lib/typescript/capture/rnDecoratorEarly.d.ts +18 -0
- package/lib/typescript/capture/savings.web.d.ts +5 -0
- package/lib/typescript/components/ImageDetail.d.ts +0 -6
- package/lib/typescript/components/ImagesRoot.web.d.ts +2 -0
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/registerEarly.d.ts +10 -0
- package/lib/typescript/sync/imagesSyncAdapter.d.ts +0 -9
- package/lib/typescript/types.d.ts +2 -1
- package/lib/web/chunks/chunk-TTS5EH4R.mjs +1 -0
- package/lib/web/index.mjs +3 -0
- package/lib/web/register.mjs +1 -0
- package/package.json +52 -6
- package/register.js +1 -15
- package/lib/commonjs/capture/actions.js.map +0 -1
- package/lib/commonjs/capture/install.js.map +0 -1
- package/lib/commonjs/capture/installExpoImage.js.map +0 -1
- package/lib/commonjs/capture/installRnImage.js.map +0 -1
- package/lib/commonjs/capture/overrides.js.map +0 -1
- package/lib/commonjs/capture/savings.js.map +0 -1
- package/lib/commonjs/capture/shared.js.map +0 -1
- package/lib/commonjs/components/ImageDetail.js.map +0 -1
- package/lib/commonjs/components/ImageDetailFooter.js.map +0 -1
- package/lib/commonjs/components/ImageRow.js.map +0 -1
- package/lib/commonjs/components/ImagesHeader.js.map +0 -1
- package/lib/commonjs/components/ImagesIcon.js.map +0 -1
- package/lib/commonjs/components/ImagesListFooter.js.map +0 -1
- package/lib/commonjs/components/ImagesModal.js.map +0 -1
- package/lib/commonjs/components/ImagesRoot.js.map +0 -1
- package/lib/commonjs/components/InsightsBar.js.map +0 -1
- package/lib/commonjs/export.js.map +0 -1
- package/lib/commonjs/format.js.map +0 -1
- package/lib/commonjs/hooks/useImageRecords.js.map +0 -1
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/preset.js.map +0 -1
- package/lib/commonjs/register.js.map +0 -1
- package/lib/commonjs/remote.js.map +0 -1
- package/lib/commonjs/state.js.map +0 -1
- package/lib/commonjs/store/imageEventStore.js.map +0 -1
- package/lib/commonjs/store/insights.js.map +0 -1
- package/lib/commonjs/sync/imagesSyncAdapter.js.map +0 -1
- package/lib/commonjs/types.js.map +0 -1
- package/lib/module/capture/actions.js.map +0 -1
- package/lib/module/capture/install.js.map +0 -1
- package/lib/module/capture/installExpoImage.js.map +0 -1
- package/lib/module/capture/installRnImage.js.map +0 -1
- package/lib/module/capture/overrides.js.map +0 -1
- package/lib/module/capture/savings.js.map +0 -1
- package/lib/module/capture/shared.js.map +0 -1
- package/lib/module/components/ImageDetail.js.map +0 -1
- package/lib/module/components/ImageDetailFooter.js.map +0 -1
- package/lib/module/components/ImageRow.js.map +0 -1
- package/lib/module/components/ImagesHeader.js.map +0 -1
- package/lib/module/components/ImagesIcon.js.map +0 -1
- package/lib/module/components/ImagesListFooter.js.map +0 -1
- package/lib/module/components/ImagesModal.js.map +0 -1
- package/lib/module/components/ImagesRoot.js.map +0 -1
- package/lib/module/components/InsightsBar.js.map +0 -1
- package/lib/module/export.js.map +0 -1
- package/lib/module/format.js.map +0 -1
- package/lib/module/hooks/useImageRecords.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/preset.js.map +0 -1
- package/lib/module/register.js.map +0 -1
- package/lib/module/remote.js.map +0 -1
- package/lib/module/state.js.map +0 -1
- package/lib/module/store/imageEventStore.js.map +0 -1
- package/lib/module/store/insights.js.map +0 -1
- package/lib/module/sync/imagesSyncAdapter.js.map +0 -1
- package/lib/module/types.js.map +0 -1
- package/lib/typescript/capture/actions.d.ts.map +0 -1
- package/lib/typescript/capture/install.d.ts.map +0 -1
- package/lib/typescript/capture/installExpoImage.d.ts.map +0 -1
- package/lib/typescript/capture/installRnImage.d.ts.map +0 -1
- package/lib/typescript/capture/overrides.d.ts.map +0 -1
- package/lib/typescript/capture/savings.d.ts.map +0 -1
- package/lib/typescript/capture/shared.d.ts.map +0 -1
- package/lib/typescript/components/ImageDetail.d.ts.map +0 -1
- package/lib/typescript/components/ImageDetailFooter.d.ts.map +0 -1
- package/lib/typescript/components/ImageRow.d.ts.map +0 -1
- package/lib/typescript/components/ImagesHeader.d.ts.map +0 -1
- package/lib/typescript/components/ImagesIcon.d.ts.map +0 -1
- package/lib/typescript/components/ImagesListFooter.d.ts.map +0 -1
- package/lib/typescript/components/ImagesModal.d.ts.map +0 -1
- package/lib/typescript/components/ImagesRoot.d.ts.map +0 -1
- package/lib/typescript/components/InsightsBar.d.ts.map +0 -1
- package/lib/typescript/export.d.ts.map +0 -1
- package/lib/typescript/format.d.ts.map +0 -1
- package/lib/typescript/hooks/useImageRecords.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/register.d.ts.map +0 -1
- package/lib/typescript/remote.d.ts.map +0 -1
- package/lib/typescript/state.d.ts.map +0 -1
- package/lib/typescript/store/imageEventStore.d.ts.map +0 -1
- package/lib/typescript/store/insights.d.ts.map +0 -1
- package/lib/typescript/sync/imagesSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/types.d.ts.map +0 -1
|
@@ -1,360 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.imagesSyncAdapter = exports.SNAPSHOT_URI_INLINE_LIMIT = void 0;
|
|
7
|
-
exports.toWireUri = toWireUri;
|
|
8
|
-
var _actions = require("../capture/actions");
|
|
9
|
-
var _install = require("../capture/install");
|
|
10
|
-
var _overrides = require("../capture/overrides");
|
|
11
|
-
var _savings = require("../capture/savings");
|
|
12
|
-
var _insights = require("../store/insights");
|
|
13
|
-
var _imageEventStore = require("../store/imageEventStore");
|
|
14
|
-
/**
|
|
15
|
-
* Sync adapter for the Images tool, consumed by @buoy-gg/external-sync's
|
|
16
|
-
* `useExternalSync` (structurally matches its ToolSyncAdapter interface so
|
|
17
|
-
* this package doesn't need a dependency on it — same pattern as js-top's
|
|
18
|
-
* adapter). Exposes the live image registry to the desktop dashboard and the
|
|
19
|
-
* MCP server, plus every action the on-device UI has: reload/retry,
|
|
20
|
-
* simulation overrides (force error/loading/blank/URL swap), locate-flash,
|
|
21
|
-
* global modes, and cache clears.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* `data:` URIs (and any URI over this) are NOT copied onto the snapshot.
|
|
26
|
-
* A single inline PNG is routinely hundreds of KB to several MB of base64;
|
|
27
|
-
* 100 of those on every ~200ms tick exceed the 2MB emit budget and drop
|
|
28
|
-
* the whole images panel. The list already uses a "?" thumb for `data`
|
|
29
|
-
* sources (see ImageRow), so the payload is unused on the wire. Dashboards
|
|
30
|
-
* still get `kind: "data"` and a short unique stub for the row label.
|
|
31
|
-
*/
|
|
32
|
-
const SNAPSHOT_URI_INLINE_LIMIT = exports.SNAPSHOT_URI_INLINE_LIMIT = 2 * 1024;
|
|
33
|
-
function toWireUri(uri) {
|
|
34
|
-
if (!uri) return uri;
|
|
35
|
-
if (uri.startsWith("data:")) {
|
|
36
|
-
const comma = uri.indexOf(",");
|
|
37
|
-
const header = comma >= 0 ? uri.slice(0, Math.min(comma + 1, 64)) : "data:";
|
|
38
|
-
const payload = comma >= 0 ? uri.slice(comma + 1) : uri;
|
|
39
|
-
const hint = payload.length > 16 ? `${payload.slice(0, 8)}…${payload.slice(-8)}` : payload;
|
|
40
|
-
return `${header}[${uri.length} chars ${hint}]`;
|
|
41
|
-
}
|
|
42
|
-
if (uri.length <= SNAPSHOT_URI_INLINE_LIMIT) return uri;
|
|
43
|
-
return `${uri.slice(0, SNAPSHOT_URI_INLINE_LIMIT)}… [${uri.length - SNAPSHOT_URI_INLINE_LIMIT} more]`;
|
|
44
|
-
}
|
|
45
|
-
function capText(value, limit = SNAPSHOT_URI_INLINE_LIMIT) {
|
|
46
|
-
if (!value) return null;
|
|
47
|
-
if (value.length <= limit) return value;
|
|
48
|
-
return `${value.slice(0, limit)}… [${value.length - limit} more]`;
|
|
49
|
-
}
|
|
50
|
-
function toWireInsights(insights) {
|
|
51
|
-
return {
|
|
52
|
-
...insights,
|
|
53
|
-
duplicates: insights.duplicates.map(d => ({
|
|
54
|
-
...d,
|
|
55
|
-
uri: toWireUri(d.uri)
|
|
56
|
-
})),
|
|
57
|
-
retryStorms: insights.retryStorms.map(s => ({
|
|
58
|
-
...s,
|
|
59
|
-
uri: toWireUri(s.uri)
|
|
60
|
-
})),
|
|
61
|
-
layoutShifters: insights.layoutShifters.map(s => ({
|
|
62
|
-
...s,
|
|
63
|
-
uri: toWireUri(s.uri)
|
|
64
|
-
}))
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Slim wire form of a record (heavy/derived fields precomputed + rounded). */
|
|
69
|
-
function toWire(record) {
|
|
70
|
-
const factor = (0, _imageEventStore.oversizeFactor)(record);
|
|
71
|
-
return {
|
|
72
|
-
id: record.id,
|
|
73
|
-
lib: record.lib,
|
|
74
|
-
uri: toWireUri(record.uri),
|
|
75
|
-
kind: record.sourceKind,
|
|
76
|
-
status: record.status,
|
|
77
|
-
mounted: record.mounted,
|
|
78
|
-
cache: record.cacheVerdict ?? null,
|
|
79
|
-
cacheSource: record.cacheVerdictSource ?? null,
|
|
80
|
-
ms: record.durationMs != null ? Math.round(record.durationMs) : null,
|
|
81
|
-
intrinsic: record.intrinsic ?? null,
|
|
82
|
-
layout: record.layout ? {
|
|
83
|
-
width: Math.round(record.layout.width),
|
|
84
|
-
height: Math.round(record.layout.height)
|
|
85
|
-
} : null,
|
|
86
|
-
neededPx: (0, _imageEventStore.neededPixels)(record),
|
|
87
|
-
oversizeFactor: factor != null ? Math.round(factor * 100) / 100 : null,
|
|
88
|
-
decodedKB: Math.round((0, _imageEventStore.estDecodedBytes)(record) / 1024),
|
|
89
|
-
wastedKB: Math.round((0, _imageEventStore.estWastedBytes)(record) / 1024),
|
|
90
|
-
progressSeen: record.progressSeen === true,
|
|
91
|
-
bytesTotal: record.bytesTotal ?? null,
|
|
92
|
-
error: capText(record.error),
|
|
93
|
-
errorCode: record.errorCode ?? null,
|
|
94
|
-
loadCount: record.loadCount,
|
|
95
|
-
overrideLabel: record.overrideLabel ?? null,
|
|
96
|
-
hasAltText: record.hasAltText ?? null,
|
|
97
|
-
layoutShifts: record.layoutShifts ?? 0,
|
|
98
|
-
ageMs: Date.now() - record.createdAt
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function requireRecord(params) {
|
|
102
|
-
const id = params?.id;
|
|
103
|
-
if (typeof id !== "number") throw new Error("Missing numeric `id` param");
|
|
104
|
-
const record = (0, _imageEventStore.getRecord)(id);
|
|
105
|
-
if (!record) {
|
|
106
|
-
throw new Error(`Image record ${id} not found (cleared or evicted) — re-run the list action for current ids.`);
|
|
107
|
-
}
|
|
108
|
-
return record;
|
|
109
|
-
}
|
|
110
|
-
function overview() {
|
|
111
|
-
const snapshot = (0, _imageEventStore.getSnapshot)();
|
|
112
|
-
return {
|
|
113
|
-
stats: (0, _imageEventStore.computeStats)(snapshot),
|
|
114
|
-
captureStatus: (0, _install.getCaptureStatus)(),
|
|
115
|
-
globalModes: (0, _overrides.getGlobalModes)(),
|
|
116
|
-
insights: toWireInsights((0, _insights.computeInsights)(snapshot)),
|
|
117
|
-
records: [...snapshot].reverse() // newest first
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
const imagesSyncAdapter = exports.imagesSyncAdapter = {
|
|
121
|
-
version: 1,
|
|
122
|
-
getSnapshot: () => {
|
|
123
|
-
const {
|
|
124
|
-
records,
|
|
125
|
-
...rest
|
|
126
|
-
} = overview();
|
|
127
|
-
return {
|
|
128
|
-
...rest,
|
|
129
|
-
records: records.slice(0, 100).map(toWire)
|
|
130
|
-
};
|
|
131
|
-
},
|
|
132
|
-
subscribe: onChange => (0, _imageEventStore.subscribe)(onChange),
|
|
133
|
-
actions: {
|
|
134
|
-
/** List records (newest first). Params: { limit?, status? }. */
|
|
135
|
-
list: params => {
|
|
136
|
-
const p = params ?? {};
|
|
137
|
-
const limit = Math.min(Math.max(p.limit ?? 50, 1), 200);
|
|
138
|
-
const {
|
|
139
|
-
records,
|
|
140
|
-
...rest
|
|
141
|
-
} = overview();
|
|
142
|
-
const filtered = p.status ? records.filter(r => r.status === p.status) : records;
|
|
143
|
-
return {
|
|
144
|
-
...rest,
|
|
145
|
-
total: filtered.length,
|
|
146
|
-
records: filtered.slice(0, limit).map(toWire)
|
|
147
|
-
};
|
|
148
|
-
},
|
|
149
|
-
/** Full detail for one record. Params: { id }. */
|
|
150
|
-
getDetail: params => {
|
|
151
|
-
const record = requireRecord(params);
|
|
152
|
-
return {
|
|
153
|
-
...toWire(record),
|
|
154
|
-
errorHeaders: record.errorHeaders ?? null
|
|
155
|
-
};
|
|
156
|
-
},
|
|
157
|
-
/** Bypass-cache reload. Params: { id }. */
|
|
158
|
-
hardReload: params => (0, _actions.hardReloadRecord)(requireRecord(params)),
|
|
159
|
-
/** Re-encode at displayed size as WebP, return real byte savings. Params: { id }. */
|
|
160
|
-
proveSavings: params => (0, _savings.proveSavings)(requireRecord(params)),
|
|
161
|
-
/** Plain fresh load attempt. Params: { id }. */
|
|
162
|
-
retry: params => (0, _actions.retryRecord)(requireRecord(params)),
|
|
163
|
-
/** Evict the expo-image disk entry for this record. Params: { id }. */
|
|
164
|
-
evictDisk: async params => {
|
|
165
|
-
const record = requireRecord(params);
|
|
166
|
-
const evicted = await (0, _actions.evictExpoDiskEntry)(record);
|
|
167
|
-
return {
|
|
168
|
-
ok: evicted,
|
|
169
|
-
message: evicted ? "Disk cache entry deleted" : "No disk entry found (expo-image + expo-file-system required)"
|
|
170
|
-
};
|
|
171
|
-
},
|
|
172
|
-
/** Flash a red border on the on-screen image. Params: { id }. */
|
|
173
|
-
flash: params => {
|
|
174
|
-
(0, _overrides.flashRecord)(requireRecord(params).id);
|
|
175
|
-
return {
|
|
176
|
-
ok: true,
|
|
177
|
-
message: "Flashing for 2.5s"
|
|
178
|
-
};
|
|
179
|
-
},
|
|
180
|
-
/**
|
|
181
|
-
* Apply a simulation override. Params: { id, kind, uri? } where kind is
|
|
182
|
-
* 'error' | 'hang' | 'blank' | 'url' ('url' requires uri).
|
|
183
|
-
*/
|
|
184
|
-
setOverride: params => {
|
|
185
|
-
const record = requireRecord(params);
|
|
186
|
-
const p = params;
|
|
187
|
-
const kinds = {
|
|
188
|
-
error: {
|
|
189
|
-
source: {
|
|
190
|
-
type: "error"
|
|
191
|
-
},
|
|
192
|
-
label: "Forced error"
|
|
193
|
-
},
|
|
194
|
-
hang: {
|
|
195
|
-
source: {
|
|
196
|
-
type: "hang"
|
|
197
|
-
},
|
|
198
|
-
label: "Forced loading"
|
|
199
|
-
},
|
|
200
|
-
blank: {
|
|
201
|
-
source: {
|
|
202
|
-
type: "blank"
|
|
203
|
-
},
|
|
204
|
-
label: "Blanked"
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
if (p.kind === "url") {
|
|
208
|
-
if (!p.uri) throw new Error("kind 'url' requires a `uri` param");
|
|
209
|
-
(0, _overrides.setOverride)(record.id, {
|
|
210
|
-
source: {
|
|
211
|
-
type: "url",
|
|
212
|
-
uri: p.uri
|
|
213
|
-
},
|
|
214
|
-
label: "URL swapped"
|
|
215
|
-
});
|
|
216
|
-
return {
|
|
217
|
-
ok: true,
|
|
218
|
-
message: `Source overridden to ${p.uri}`
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
const entry = p.kind ? kinds[p.kind] : undefined;
|
|
222
|
-
if (!entry) throw new Error(`Unknown override kind: ${String(p.kind)}`);
|
|
223
|
-
if (!record.mounted) {
|
|
224
|
-
return {
|
|
225
|
-
ok: false,
|
|
226
|
-
message: "Instance unmounted — overrides need the image on screen"
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
(0, _overrides.setOverride)(record.id, entry);
|
|
230
|
-
return {
|
|
231
|
-
ok: true,
|
|
232
|
-
message: `${entry.label} applied`
|
|
233
|
-
};
|
|
234
|
-
},
|
|
235
|
-
/** Remove a simulation override. Params: { id }. */
|
|
236
|
-
clearOverride: params => {
|
|
237
|
-
(0, _overrides.clearOverride)(requireRecord(params).id);
|
|
238
|
-
return {
|
|
239
|
-
ok: true,
|
|
240
|
-
message: "Override removed — original source restored"
|
|
241
|
-
};
|
|
242
|
-
},
|
|
243
|
-
/**
|
|
244
|
-
* Mass action on every mounted image. Params: { kind } where kind is
|
|
245
|
-
* 'error' | 'loading' | 'blank' | 'reload' | 'flash' | 'restore'.
|
|
246
|
-
*/
|
|
247
|
-
massAction: async params => {
|
|
248
|
-
const kind = params?.kind;
|
|
249
|
-
switch (kind) {
|
|
250
|
-
case "error":
|
|
251
|
-
{
|
|
252
|
-
const n = (0, _overrides.setOverrideForAllMounted)({
|
|
253
|
-
type: "error"
|
|
254
|
-
}, "Forced error");
|
|
255
|
-
return {
|
|
256
|
-
ok: n > 0,
|
|
257
|
-
message: `Forced error on ${n} images`
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
case "loading":
|
|
261
|
-
{
|
|
262
|
-
const n = (0, _overrides.setOverrideForAllMounted)({
|
|
263
|
-
type: "hang"
|
|
264
|
-
}, "Forced loading");
|
|
265
|
-
return {
|
|
266
|
-
ok: n > 0,
|
|
267
|
-
message: `Forced loading on ${n} images`
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
case "blank":
|
|
271
|
-
{
|
|
272
|
-
const n = (0, _overrides.setOverrideForAllMounted)({
|
|
273
|
-
type: "blank"
|
|
274
|
-
}, "Blanked");
|
|
275
|
-
return {
|
|
276
|
-
ok: n > 0,
|
|
277
|
-
message: `Blanked ${n} images`
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
case "reload":
|
|
281
|
-
return (0, _actions.hardReloadAllMounted)();
|
|
282
|
-
case "flash":
|
|
283
|
-
{
|
|
284
|
-
const n = (0, _overrides.flashAllMounted)();
|
|
285
|
-
return {
|
|
286
|
-
ok: n > 0,
|
|
287
|
-
message: `Flashing ${n} images`
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
case "restore":
|
|
291
|
-
{
|
|
292
|
-
const n = (0, _overrides.clearAllOverrides)();
|
|
293
|
-
return {
|
|
294
|
-
ok: true,
|
|
295
|
-
message: `Restored ${n} images`
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
default:
|
|
299
|
-
throw new Error(`Unknown mass kind: ${String(kind)}`);
|
|
300
|
-
}
|
|
301
|
-
},
|
|
302
|
-
/** Global network simulation. Params: { mode: 'normal'|'offline'|'cold' }. */
|
|
303
|
-
setNetworkMode: params => {
|
|
304
|
-
const mode = params?.mode;
|
|
305
|
-
if (mode !== "normal" && mode !== "offline" && mode !== "cold") {
|
|
306
|
-
throw new Error("mode must be 'normal' | 'offline' | 'cold'");
|
|
307
|
-
}
|
|
308
|
-
(0, _overrides.setNetworkMode)(mode);
|
|
309
|
-
return {
|
|
310
|
-
ok: true,
|
|
311
|
-
modes: (0, _overrides.getGlobalModes)()
|
|
312
|
-
};
|
|
313
|
-
},
|
|
314
|
-
/** Chrome-style disable-images. Params: { enabled: boolean }. */
|
|
315
|
-
setBlankImages: params => {
|
|
316
|
-
(0, _overrides.setBlankImages)(params?.enabled === true);
|
|
317
|
-
return {
|
|
318
|
-
ok: true,
|
|
319
|
-
modes: (0, _overrides.getGlobalModes)()
|
|
320
|
-
};
|
|
321
|
-
},
|
|
322
|
-
/** Clear the captured registry (keeps in-flight loads). */
|
|
323
|
-
clearRecords: () => {
|
|
324
|
-
(0, _imageEventStore.clearRecords)();
|
|
325
|
-
return {
|
|
326
|
-
ok: true,
|
|
327
|
-
message: "Registry cleared"
|
|
328
|
-
};
|
|
329
|
-
},
|
|
330
|
-
/** Clear expo-image caches. Params: { memory?, disk? } (default both). */
|
|
331
|
-
clearExpoCaches: async params => {
|
|
332
|
-
const p = params ?? {};
|
|
333
|
-
const doMemory = p.memory !== false;
|
|
334
|
-
const doDisk = p.disk !== false;
|
|
335
|
-
try {
|
|
336
|
-
const expo = require("expo-image");
|
|
337
|
-
const results = [];
|
|
338
|
-
if (doMemory) {
|
|
339
|
-
await expo.Image.clearMemoryCache();
|
|
340
|
-
results.push("memory");
|
|
341
|
-
}
|
|
342
|
-
if (doDisk) {
|
|
343
|
-
await expo.Image.clearDiskCache();
|
|
344
|
-
results.push("disk");
|
|
345
|
-
}
|
|
346
|
-
return {
|
|
347
|
-
ok: true,
|
|
348
|
-
message: `Cleared expo-image ${results.join(" + ")} cache`
|
|
349
|
-
};
|
|
350
|
-
} catch {
|
|
351
|
-
return {
|
|
352
|
-
ok: false,
|
|
353
|
-
message: "expo-image not installed"
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
},
|
|
357
|
-
getCaptureStatus: () => (0, _install.getCaptureStatus)()
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
//# sourceMappingURL=imagesSyncAdapter.js.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.imagesSyncAdapter=exports.SNAPSHOT_URI_INLINE_LIMIT=void 0;exports.toWireUri=toWireUri;var _nativeImageModules=require("../capture/nativeImageModules");var _actions=require("../capture/actions");var _install=require("../capture/install");var _overrides=require("../capture/overrides");var _savings=require("../capture/savings");var _insights=require("../store/insights");var _imageEventStore=require("../store/imageEventStore");const SNAPSHOT_URI_INLINE_LIMIT=exports.SNAPSHOT_URI_INLINE_LIMIT=2*1024;function toWireUri(e){if(!e)return e;if(e.startsWith("data:")){const r=e.indexOf(",");const t=r>=0?e.slice(0,Math.min(r+1,64)):"data:";const s=r>=0?e.slice(r+1):e;const o=s.length>16?`${s.slice(0,8)}\u2026${s.slice(-8)}`:s;return`${t}[${e.length} chars ${o}]`}if(e.length<=SNAPSHOT_URI_INLINE_LIMIT)return e;return`${e.slice(0,SNAPSHOT_URI_INLINE_LIMIT)}\u2026 [${e.length-SNAPSHOT_URI_INLINE_LIMIT} more]`}function capText(e,r=SNAPSHOT_URI_INLINE_LIMIT){if(!e)return null;if(e.length<=r)return e;return`${e.slice(0,r)}\u2026 [${e.length-r} more]`}function toWireInsights(e){return{...e,duplicates:e.duplicates.map(r=>({...r,uri:toWireUri(r.uri)})),retryStorms:e.retryStorms.map(r=>({...r,uri:toWireUri(r.uri)})),layoutShifters:e.layoutShifters.map(r=>({...r,uri:toWireUri(r.uri)}))}}function toWire(e){const r=(0,_imageEventStore.oversizeFactor)(e);return{id:e.id,lib:e.lib,uri:toWireUri(e.uri),kind:e.sourceKind,status:e.status,mounted:e.mounted,cache:e.cacheVerdict??null,cacheSource:e.cacheVerdictSource??null,ms:e.durationMs!=null?Math.round(e.durationMs):null,intrinsic:e.intrinsic??null,layout:e.layout?{width:Math.round(e.layout.width),height:Math.round(e.layout.height)}:null,neededPx:(0,_imageEventStore.neededPixels)(e),oversizeFactor:r!=null?Math.round(r*100)/100:null,decodedKB:Math.round((0,_imageEventStore.estDecodedBytes)(e)/1024),wastedKB:Math.round((0,_imageEventStore.estWastedBytes)(e)/1024),progressSeen:e.progressSeen===true,bytesTotal:e.bytesTotal??null,error:capText(e.error),errorCode:e.errorCode??null,loadCount:e.loadCount,overrideLabel:e.overrideLabel??null,hasAltText:e.hasAltText??null,layoutShifts:e.layoutShifts??0,ageMs:Date.now()-e.createdAt}}function requireRecord(e){const r=e?.id;if(typeof r!=="number")throw new Error("Missing numeric `id` param");const t=(0,_imageEventStore.getRecord)(r);if(!t){throw new Error(`Image record ${r} not found (cleared or evicted) \u2014 re-run the list action for current ids.`)}return t}function overview(){const e=(0,_imageEventStore.getSnapshot)();return{stats:(0,_imageEventStore.computeStats)(e),captureStatus:(0,_install.getCaptureStatus)(),globalModes:(0,_overrides.getGlobalModes)(),insights:toWireInsights((0,_insights.computeInsights)(e)),records:[...e].reverse()}}const imagesSyncAdapter=exports.imagesSyncAdapter={version:1,getSnapshot:()=>{const{records:e,...r}=overview();return{...r,records:e.slice(0,100).map(toWire)}},subscribe:e=>(0,_imageEventStore.subscribe)(e),actions:{list:e=>{const r=e??{};const t=Math.min(Math.max(r.limit??50,1),200);const{records:s,...o}=overview();const n=r.status?s.filter(a=>a.status===r.status):s;return{...o,total:n.length,records:n.slice(0,t).map(toWire)}},getDetail:e=>{const r=requireRecord(e);return{...toWire(r),errorHeaders:r.errorHeaders??null}},hardReload:e=>(0,_actions.hardReloadRecord)(requireRecord(e)),proveSavings:e=>(0,_savings.proveSavings)(requireRecord(e)),retry:e=>(0,_actions.retryRecord)(requireRecord(e)),evictDisk:async e=>{const r=requireRecord(e);const t=await(0,_actions.evictExpoDiskEntry)(r);return{ok:t,message:t?"Disk cache entry deleted":"No disk entry found (expo-image + expo-file-system required)"}},flash:e=>{(0,_overrides.flashRecord)(requireRecord(e).id);return{ok:true,message:"Flashing for 2.5s"}},setOverride:e=>{const r=requireRecord(e);const t=e;const s={error:{source:{type:"error"},label:"Forced error"},hang:{source:{type:"hang"},label:"Forced loading"},blank:{source:{type:"blank"},label:"Blanked"}};if(t.kind==="url"){if(!t.uri)throw new Error("kind 'url' requires a `uri` param");(0,_overrides.setOverride)(r.id,{source:{type:"url",uri:t.uri},label:"URL swapped"});return{ok:true,message:`Source overridden to ${t.uri}`}}const o=t.kind?s[t.kind]:void 0;if(!o)throw new Error(`Unknown override kind: ${String(t.kind)}`);if(!r.mounted){return{ok:false,message:"Instance unmounted \u2014 overrides need the image on screen"}}(0,_overrides.setOverride)(r.id,o);return{ok:true,message:`${o.label} applied`}},clearOverride:e=>{(0,_overrides.clearOverride)(requireRecord(e).id);return{ok:true,message:"Override removed \u2014 original source restored"}},massAction:async e=>{const r=e?.kind;switch(r){case"error":{const t=(0,_overrides.setOverrideForAllMounted)({type:"error"},"Forced error");return{ok:t>0,message:`Forced error on ${t} images`}}case"loading":{const t=(0,_overrides.setOverrideForAllMounted)({type:"hang"},"Forced loading");return{ok:t>0,message:`Forced loading on ${t} images`}}case"blank":{const t=(0,_overrides.setOverrideForAllMounted)({type:"blank"},"Blanked");return{ok:t>0,message:`Blanked ${t} images`}}case"reload":return(0,_actions.hardReloadAllMounted)();case"flash":{const t=(0,_overrides.flashAllMounted)();return{ok:t>0,message:`Flashing ${t} images`}}case"restore":{const t=(0,_overrides.clearAllOverrides)();return{ok:true,message:`Restored ${t} images`}}default:throw new Error(`Unknown mass kind: ${String(r)}`)}},setNetworkMode:e=>{const r=e?.mode;if(r!=="normal"&&r!=="offline"&&r!=="cold"){throw new Error("mode must be 'normal' | 'offline' | 'cold'")}(0,_overrides.setNetworkMode)(r);return{ok:true,modes:(0,_overrides.getGlobalModes)()}},setBlankImages:e=>{(0,_overrides.setBlankImages)(e?.enabled===true);return{ok:true,modes:(0,_overrides.getGlobalModes)()}},clearRecords:()=>{(0,_imageEventStore.clearRecords)();return{ok:true,message:"Registry cleared"}},clearExpoCaches:async e=>{const r=e??{};const t=r.memory!==false;const s=r.disk!==false;try{const o=(0,_nativeImageModules.loadExpoImage)();const n=[];if(t){await o.Image.clearMemoryCache();n.push("memory")}if(s){await o.Image.clearDiskCache();n.push("disk")}return{ok:true,message:`Cleared expo-image ${n.join(" + ")} cache`}}catch{return{ok:false,message:"expo-image not installed"}}},getCaptureStatus:()=>(0,_install.getCaptureStatus)()}};
|
package/lib/commonjs/types.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import"./register";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export{};
|
|
@@ -1,229 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Per-image actions: hard reload (bypass cache) and retry.
|
|
5
|
-
*
|
|
6
|
-
* RN core path: the decorator wrapper owns every mounted <Image>'s props, so a
|
|
7
|
-
* reload request re-renders the wrapper with a bumped `key` (native remount →
|
|
8
|
-
* fresh load cycle) and, for cache-busting, `source.cache: 'reload'` injected
|
|
9
|
-
* — VERIFIED supported on BOTH platforms (iOS NSURLRequest policy;
|
|
10
|
-
* Android ReactImageView.kt reads source."cache" → Fresco full-fetch). The
|
|
11
|
-
* override stays applied until the load settles, then reverts lazily on the
|
|
12
|
-
* app's next natural re-render (avoids an extra cache round-trip).
|
|
13
|
-
*
|
|
14
|
-
* expo-image path: the patched class instance exposes the public
|
|
15
|
-
* `reloadAsync()`. Cache-busting first evicts the disk entry (cache path +
|
|
16
|
-
* expo-file-system delete) and clears expo's memory cache (global — no
|
|
17
|
-
* per-entry memory eviction exists), so the reload is a true refetch that
|
|
18
|
-
* rewrites both cache tiers.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { remoteActionResult, remoteImagesDispatch } from "../remote";
|
|
22
|
-
import { imagesState } from "../state";
|
|
23
|
-
import { touchRecord } from "./overrides";
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
// RN reload-request bus (consumed by the decorator wrapper)
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
|
|
28
|
-
export function subscribeActions(listener) {
|
|
29
|
-
const s = imagesState();
|
|
30
|
-
s.actionListeners.add(listener);
|
|
31
|
-
return () => imagesState().actionListeners.delete(listener);
|
|
32
|
-
}
|
|
33
|
-
export function getReloadRequest(recordId) {
|
|
34
|
-
if (recordId == null) return undefined;
|
|
35
|
-
return imagesState().reloadRequests.get(recordId);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Reload nonce for a record (0 = never requested). Snapshot for the wrapper. */
|
|
39
|
-
export function getReloadNonce(recordId) {
|
|
40
|
-
return getReloadRequest(recordId)?.nonce ?? 0;
|
|
41
|
-
}
|
|
42
|
-
function requestRnReload(recordId, bust) {
|
|
43
|
-
const s = imagesState();
|
|
44
|
-
const prev = s.reloadRequests.get(recordId);
|
|
45
|
-
s.reloadRequests.set(recordId, {
|
|
46
|
-
nonce: (prev?.nonce ?? 0) + 1,
|
|
47
|
-
bust
|
|
48
|
-
});
|
|
49
|
-
// touchRecord bumps the render version (the wrapper's snapshot) and emits.
|
|
50
|
-
touchRecord(recordId);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Mark a request consumed once its load settles (called from the tracker on
|
|
55
|
-
* load/error). Silent — the wrapper reverts the prop override on the app's
|
|
56
|
-
* next natural re-render instead of forcing an immediate one.
|
|
57
|
-
*/
|
|
58
|
-
export function settleReloadRequest(recordId) {
|
|
59
|
-
const s = imagesState();
|
|
60
|
-
const req = s.reloadRequests.get(recordId);
|
|
61
|
-
if (req?.bust) {
|
|
62
|
-
s.reloadRequests.set(recordId, {
|
|
63
|
-
nonce: req.nonce,
|
|
64
|
-
bust: false
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
export function dropActionState(recordId) {
|
|
69
|
-
const s = imagesState();
|
|
70
|
-
s.reloadRequests.delete(recordId);
|
|
71
|
-
s.expoInstances.delete(recordId);
|
|
72
|
-
s.overrides.delete(recordId);
|
|
73
|
-
s.flashUntil.delete(recordId);
|
|
74
|
-
s.recordVersions.delete(recordId);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
|
-
// expo instance registry (populated by the render patch)
|
|
79
|
-
// ---------------------------------------------------------------------------
|
|
80
|
-
|
|
81
|
-
export function registerExpoInstance(recordId, instance) {
|
|
82
|
-
if (recordId == null) return;
|
|
83
|
-
imagesState().expoInstances.set(recordId, instance);
|
|
84
|
-
}
|
|
85
|
-
function expoImageStatics() {
|
|
86
|
-
try {
|
|
87
|
-
return require("expo-image").Image ?? null;
|
|
88
|
-
} catch {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* expo-file-system, legacy path first (v19+/SDK 54+ moved the function API
|
|
94
|
-
* there) then the main import — same pattern as shared-ui's persistentStorage.
|
|
95
|
-
*/
|
|
96
|
-
function loadFileSystem() {
|
|
97
|
-
try {
|
|
98
|
-
const mod = require("expo-file-system/legacy");
|
|
99
|
-
const fs = mod?.default || mod;
|
|
100
|
-
if (fs?.deleteAsync) return fs;
|
|
101
|
-
} catch {
|
|
102
|
-
// try main import
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
const mod = require("expo-file-system");
|
|
106
|
-
const fs = mod?.default || mod;
|
|
107
|
-
if (fs?.deleteAsync) return fs;
|
|
108
|
-
} catch {
|
|
109
|
-
// not installed
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Delete an expo-image disk-cache entry (JS-only: cache path + file delete).
|
|
116
|
-
* Returns true if an entry existed and was deleted.
|
|
117
|
-
*/
|
|
118
|
-
export async function evictExpoDiskEntry(record) {
|
|
119
|
-
const statics = expoImageStatics();
|
|
120
|
-
const fileSystem = loadFileSystem();
|
|
121
|
-
if (!statics?.getCachePathAsync || !fileSystem?.deleteAsync || !record.uri) return false;
|
|
122
|
-
try {
|
|
123
|
-
const path = await statics.getCachePathAsync(record.uri);
|
|
124
|
-
if (!path) return false;
|
|
125
|
-
const uri = path.startsWith("file://") ? path : `file://${path}`;
|
|
126
|
-
await fileSystem.deleteAsync(uri, {
|
|
127
|
-
idempotent: true
|
|
128
|
-
});
|
|
129
|
-
return true;
|
|
130
|
-
} catch {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
136
|
-
// High-level dispatchers (used by the detail view)
|
|
137
|
-
// ---------------------------------------------------------------------------
|
|
138
|
-
|
|
139
|
-
/** Fresh load attempt for a mounted image (no cache bypass). */
|
|
140
|
-
export async function retryRecord(record) {
|
|
141
|
-
const remote = remoteImagesDispatch();
|
|
142
|
-
if (remote) return remoteActionResult(remote("retry", {
|
|
143
|
-
id: record.id
|
|
144
|
-
}));
|
|
145
|
-
if (!record.mounted) {
|
|
146
|
-
return {
|
|
147
|
-
ok: false,
|
|
148
|
-
message: "Instance unmounted — cannot reload"
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
if (record.lib === "expo") {
|
|
152
|
-
const instance = imagesState().expoInstances.get(record.id);
|
|
153
|
-
if (!instance?.reloadAsync) {
|
|
154
|
-
return {
|
|
155
|
-
ok: false,
|
|
156
|
-
message: "Live instance not reachable"
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
await instance.reloadAsync();
|
|
160
|
-
return {
|
|
161
|
-
ok: true,
|
|
162
|
-
message: "Reload requested"
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
requestRnReload(record.id, false);
|
|
166
|
-
return {
|
|
167
|
-
ok: true,
|
|
168
|
-
message: "Remounting image"
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** Hard-reload every mounted image (mass cache-bust). Returns count started. */
|
|
173
|
-
export async function hardReloadAllMounted() {
|
|
174
|
-
const remote = remoteImagesDispatch();
|
|
175
|
-
if (remote) {
|
|
176
|
-
return remoteActionResult(remote("massAction", {
|
|
177
|
-
kind: "reload"
|
|
178
|
-
}));
|
|
179
|
-
}
|
|
180
|
-
const {
|
|
181
|
-
getSnapshot
|
|
182
|
-
} = require("../store/imageEventStore");
|
|
183
|
-
let count = 0;
|
|
184
|
-
for (const record of getSnapshot()) {
|
|
185
|
-
if (!record.mounted) continue;
|
|
186
|
-
const result = await hardReloadRecord(record);
|
|
187
|
-
if (result.ok) count++;
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
ok: count > 0,
|
|
191
|
-
message: `Hard-reloading ${count} mounted image${count === 1 ? "" : "s"}`
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** Bypass-cache reload: refetches from network and rewrites the caches. */
|
|
196
|
-
export async function hardReloadRecord(record) {
|
|
197
|
-
const remote = remoteImagesDispatch();
|
|
198
|
-
if (remote) return remoteActionResult(remote("hardReload", {
|
|
199
|
-
id: record.id
|
|
200
|
-
}));
|
|
201
|
-
if (!record.mounted) {
|
|
202
|
-
return {
|
|
203
|
-
ok: false,
|
|
204
|
-
message: "Instance unmounted — cannot reload"
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
if (record.sourceKind !== "network") {
|
|
208
|
-
// Local/asset sources have no HTTP cache to bust — plain remount instead.
|
|
209
|
-
return retryRecord(record);
|
|
210
|
-
}
|
|
211
|
-
if (record.lib === "expo") {
|
|
212
|
-
const evicted = await evictExpoDiskEntry(record);
|
|
213
|
-
const statics = expoImageStatics();
|
|
214
|
-
// No per-entry memory eviction exists — global clear is the honest option.
|
|
215
|
-
await statics?.clearMemoryCache?.().catch?.(() => false);
|
|
216
|
-
const result = await retryRecord(record);
|
|
217
|
-
if (!result.ok) return result;
|
|
218
|
-
return {
|
|
219
|
-
ok: true,
|
|
220
|
-
message: evicted ? "Disk entry evicted, memory cache cleared, refetching" : "Memory cache cleared, refetching (no disk entry found)"
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
requestRnReload(record.id, true);
|
|
224
|
-
return {
|
|
225
|
-
ok: true,
|
|
226
|
-
message: "Refetching with cache bypassed"
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
//# sourceMappingURL=actions.js.map
|
|
1
|
+
"use strict";import{loadExpoImage as l,loadLegacyFileSystem as f,loadFileSystemModule as d}from"./nativeImageModules";import{remoteActionResult as r,remoteImagesDispatch as i}from"../remote";import{imagesState as o}from"../state";import{touchRecord as m}from"./overrides";export function subscribeActions(e){const t=o();t.actionListeners.add(e);return()=>o().actionListeners.delete(e)}export function getReloadRequest(e){if(e==null)return void 0;return o().reloadRequests.get(e)}export function getReloadNonce(e){return getReloadRequest(e)?.nonce??0}function c(e,t){const n=o();const s=n.reloadRequests.get(e);n.reloadRequests.set(e,{nonce:(s?.nonce??0)+1,bust:t});m(e)}export function settleReloadRequest(e){const t=o();const n=t.reloadRequests.get(e);if(n?.bust){t.reloadRequests.set(e,{nonce:n.nonce,bust:false})}}export function dropActionState(e){const t=o();t.reloadRequests.delete(e);t.expoInstances.delete(e);t.overrides.delete(e);t.flashUntil.delete(e);t.recordVersions.delete(e)}export function registerExpoInstance(e,t){if(e==null)return;o().expoInstances.set(e,t)}function u(){try{return l().Image??null}catch{return null}}function g(){try{const e=f();const t=e?.default||e;if(t?.deleteAsync)return t}catch{}try{const e=d();const t=e?.default||e;if(t?.deleteAsync)return t}catch{}return null}export async function evictExpoDiskEntry(e){const t=u();const n=g();if(!t?.getCachePathAsync||!n?.deleteAsync||!e.uri)return false;try{const s=await t.getCachePathAsync(e.uri);if(!s)return false;const a=s.startsWith("file://")?s:`file://${s}`;await n.deleteAsync(a,{idempotent:true});return true}catch{return false}}export async function retryRecord(e){const t=i();if(t)return r(t("retry",{id:e.id}));if(!e.mounted){return{ok:false,message:"Instance unmounted \u2014 cannot reload"}}if(e.lib==="expo"){const n=o().expoInstances.get(e.id);if(!n?.reloadAsync){return{ok:false,message:"Live instance not reachable"}}await n.reloadAsync();return{ok:true,message:"Reload requested"}}c(e.id,false);return{ok:true,message:"Remounting image"}}export async function hardReloadAllMounted(){const e=i();if(e){return r(e("massAction",{kind:"reload"}))}const{getSnapshot:t}=require("../store/imageEventStore");let n=0;for(const s of t()){if(!s.mounted)continue;const a=await hardReloadRecord(s);if(a.ok)n++}return{ok:n>0,message:`Hard-reloading ${n} mounted image${n===1?"":"s"}`}}export async function hardReloadRecord(e){const t=i();if(t)return r(t("hardReload",{id:e.id}));if(!e.mounted){return{ok:false,message:"Instance unmounted \u2014 cannot reload"}}if(e.sourceKind!=="network"){return retryRecord(e)}if(e.lib==="expo"){const n=await evictExpoDiskEntry(e);const s=u();await s?.clearMemoryCache?.().catch?.(()=>false);const a=await retryRecord(e);if(!a.ok)return a;return{ok:true,message:n?"Disk entry evicted, memory cache cleared, refetching":"Memory cache cleared, refetching (no disk entry found)"}}c(e.id,true);return{ok:true,message:"Refetching with cache bypassed"}}
|
|
@@ -1,40 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* installImageCapture — idempotent entry point for the capture layer.
|
|
5
|
-
*
|
|
6
|
-
* IMPORTANT (timing): the RN-core decorator only takes effect if this runs
|
|
7
|
-
* before anything evaluates the `Image` module from 'react-native'. The
|
|
8
|
-
* recommended integration is `import "@buoy-gg/images/register"` as the FIRST
|
|
9
|
-
* import of the app entry file. The expo-image patch has no such constraint.
|
|
10
|
-
*
|
|
11
|
-
* Idempotency is keyed on the globalThis singleton, so even if this package
|
|
12
|
-
* gets evaluated as two module instances, capture installs exactly once.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { imagesState } from "../state";
|
|
16
|
-
import { installExpoImageInterceptor, expoCaptureStatus } from "./installExpoImage";
|
|
17
|
-
import { installRnImageInterceptor, rnCaptureStatus } from "./installRnImage";
|
|
18
|
-
export function installImageCapture() {
|
|
19
|
-
const s = imagesState();
|
|
20
|
-
// Mirror mode (desktop dashboard): never instrument the dashboard's own UI.
|
|
21
|
-
if (s.captureDisabled || s.captureInstalled) return;
|
|
22
|
-
s.captureInstalled = true;
|
|
23
|
-
installRnImageInterceptor();
|
|
24
|
-
installExpoImageInterceptor();
|
|
25
|
-
}
|
|
26
|
-
export function getCaptureStatus() {
|
|
27
|
-
// Mirror mode: report the synced DEVICE's capture status, not the local probe.
|
|
28
|
-
const mirrored = imagesState().mirrorCaptureStatus;
|
|
29
|
-
if (mirrored) return mirrored;
|
|
30
|
-
const rn = rnCaptureStatus();
|
|
31
|
-
const expo = expoCaptureStatus();
|
|
32
|
-
return {
|
|
33
|
-
installed: imagesState().captureInstalled,
|
|
34
|
-
rnDecoratorActive: rn.decoratorActive,
|
|
35
|
-
rnDecoratorTooLate: rn.tooLate,
|
|
36
|
-
expoPatched: expo.patched,
|
|
37
|
-
expoAvailable: expo.available
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=install.js.map
|
|
1
|
+
"use strict";import{imagesState as e}from"../state";import{installExpoImageInterceptor as o,expoCaptureStatus as n}from"./installExpoImage";import{installRnImageInterceptor as p,rnCaptureStatus as c}from"./installRnImage";export function installImageCapture(){const t=e();if(t.captureDisabled||t.captureInstalled)return;t.captureInstalled=true;p();o()}export function getCaptureStatus(){const t=e().mirrorCaptureStatus;if(t)return t;const r=c();const a=n();return{installed:e().captureInstalled,rnDecoratorActive:r.decoratorActive,rnDecoratorTooLate:r.tooLate,expoPatched:a.patched,expoAvailable:a.available}}
|
|
@@ -0,0 +1 @@
|
|
|
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}}
|