@buoy-gg/images 7.0.13 → 7.0.15
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/lib/commonjs/capture/actions.js +15 -0
- package/lib/commonjs/capture/actions.js.map +1 -1
- package/lib/commonjs/capture/install.js +5 -1
- package/lib/commonjs/capture/install.js.map +1 -1
- package/lib/commonjs/capture/overrides.js +70 -10
- package/lib/commonjs/capture/overrides.js.map +1 -1
- package/lib/commonjs/capture/savings.js +16 -0
- package/lib/commonjs/capture/savings.js.map +1 -1
- package/lib/commonjs/components/ImageDetail.js +11 -1
- package/lib/commonjs/components/ImageDetail.js.map +1 -1
- package/lib/commonjs/components/ImagesModal.js +103 -38
- package/lib/commonjs/components/ImagesModal.js.map +1 -1
- package/lib/commonjs/index.js +26 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/remote.js +42 -0
- package/lib/commonjs/remote.js.map +1 -0
- package/lib/commonjs/state.js +5 -1
- package/lib/commonjs/state.js.map +1 -1
- package/lib/commonjs/store/imageEventStore.js +79 -1
- package/lib/commonjs/store/imageEventStore.js.map +1 -1
- package/lib/commonjs/sync/imagesSyncAdapter.js.map +1 -1
- package/lib/module/capture/actions.js +15 -0
- package/lib/module/capture/actions.js.map +1 -1
- package/lib/module/capture/install.js +5 -1
- package/lib/module/capture/install.js.map +1 -1
- package/lib/module/capture/overrides.js +70 -10
- package/lib/module/capture/overrides.js.map +1 -1
- package/lib/module/capture/savings.js +16 -0
- package/lib/module/capture/savings.js.map +1 -1
- package/lib/module/components/ImageDetail.js +13 -3
- package/lib/module/components/ImageDetail.js.map +1 -1
- package/lib/module/components/ImagesModal.js +104 -40
- package/lib/module/components/ImagesModal.js.map +1 -1
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/remote.js +36 -0
- package/lib/module/remote.js.map +1 -0
- package/lib/module/state.js +5 -1
- package/lib/module/state.js.map +1 -1
- package/lib/module/store/imageEventStore.js +76 -1
- package/lib/module/store/imageEventStore.js.map +1 -1
- package/lib/module/sync/imagesSyncAdapter.js.map +1 -1
- package/lib/typescript/capture/actions.d.ts.map +1 -1
- package/lib/typescript/capture/install.d.ts.map +1 -1
- package/lib/typescript/capture/overrides.d.ts.map +1 -1
- package/lib/typescript/capture/savings.d.ts.map +1 -1
- package/lib/typescript/components/ImageDetail.d.ts.map +1 -1
- package/lib/typescript/components/ImagesModal.d.ts +9 -1
- package/lib/typescript/components/ImagesModal.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +5 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/remote.d.ts +16 -0
- package/lib/typescript/remote.d.ts.map +1 -0
- package/lib/typescript/state.d.ts +9 -1
- package/lib/typescript/state.d.ts.map +1 -1
- package/lib/typescript/store/imageEventStore.d.ts +15 -1
- package/lib/typescript/store/imageEventStore.d.ts.map +1 -1
- package/lib/typescript/sync/imagesSyncAdapter.d.ts +3 -70
- package/lib/typescript/sync/imagesSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +53 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/capture/actions.ts +9 -0
- package/src/capture/install.ts +5 -1
- package/src/capture/overrides.ts +59 -9
- package/src/capture/savings.ts +11 -0
- package/src/components/ImageDetail.tsx +12 -2
- package/src/components/ImagesModal.tsx +107 -39
- package/src/index.tsx +12 -0
- package/src/remote.ts +42 -0
- package/src/state.ts +16 -1
- package/src/store/imageEventStore.ts +76 -2
- package/src/sync/imagesSyncAdapter.ts +2 -2
- package/src/types.ts +43 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote-dispatch seam for dashboard mirrors (Buoy Desktop).
|
|
3
|
+
*
|
|
4
|
+
* On device this stays null and every action in capture/ runs locally. A
|
|
5
|
+
* dashboard sets a handler that forwards the action name + params over the
|
|
6
|
+
* external-sync protocol to the SAME adapter actions the MCP uses
|
|
7
|
+
* (sync/imagesSyncAdapter.ts), so one action vocabulary serves phone UI,
|
|
8
|
+
* desktop UI, and LLM automation.
|
|
9
|
+
*/
|
|
10
|
+
import type { ActionResult } from "./capture/actions";
|
|
11
|
+
export type ImagesRemoteDispatch = (action: string, params?: Record<string, unknown>) => Promise<unknown>;
|
|
12
|
+
export declare function setRemoteImagesHandler(handler: ImagesRemoteDispatch | null): void;
|
|
13
|
+
export declare function remoteImagesDispatch(): ImagesRemoteDispatch | null;
|
|
14
|
+
/** Coerce an adapter action's `{ ok, message }` reply into an ActionResult. */
|
|
15
|
+
export declare function remoteActionResult(call: Promise<unknown>): Promise<ActionResult>;
|
|
16
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,CACjC,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,oBAAoB,GAAG,IAAI,GACnC,IAAI,CAEN;AAED,wBAAgB,oBAAoB,IAAI,oBAAoB,GAAG,IAAI,CAElE;AAED,+EAA+E;AAC/E,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GACrB,OAAO,CAAC,YAAY,CAAC,CAUvB"}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* flag. Keying all mutable state on globalThis under a well-known symbol makes
|
|
10
10
|
* every copy operate on the same data.
|
|
11
11
|
*/
|
|
12
|
-
import type { ImageRecord } from "./types";
|
|
12
|
+
import type { CaptureStatus, ImageRecord } from "./types";
|
|
13
13
|
export interface ImagesGlobalState {
|
|
14
14
|
records: ImageRecord[];
|
|
15
15
|
byId: Map<number, ImageRecord>;
|
|
@@ -49,6 +49,14 @@ export interface ImagesGlobalState {
|
|
|
49
49
|
network: "normal" | "offline" | "cold";
|
|
50
50
|
blank: boolean;
|
|
51
51
|
};
|
|
52
|
+
/** True on dashboards: local capture must never install (mirror only). */
|
|
53
|
+
captureDisabled: boolean;
|
|
54
|
+
/** Forwards actions to the synced device instead of running them locally. */
|
|
55
|
+
remoteDispatch: ((action: string, params?: Record<string, unknown>) => Promise<unknown>) | null;
|
|
56
|
+
/** Device PixelRatio derived from the synced snapshot (layout → neededPx). */
|
|
57
|
+
mirrorPixelRatio: number | null;
|
|
58
|
+
/** Device-reported capture status (overrides the local probe on mirrors). */
|
|
59
|
+
mirrorCaptureStatus: CaptureStatus | null;
|
|
52
60
|
}
|
|
53
61
|
export declare function imagesState(): ImagesGlobalState;
|
|
54
62
|
//# sourceMappingURL=state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1D,MAAM,WAAW,iBAAiB;IAEhC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IAC3B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IAEvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IAEvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IAEnB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IAErB,uEAAuE;IACvE,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9D,gFAAgF;IAChF,eAAe,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IACjC,wEAAwE;IACxE,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEpC,6EAA6E;IAC7E,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,wEAAwE;IACxE,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,6EAA6E;IAC7E,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,WAAW,EAAE;QAAE,OAAO,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAExE,0EAA0E;IAC1E,eAAe,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,cAAc,EACV,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,GACxE,IAAI,CAAC;IACT,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,6EAA6E;IAC7E,mBAAmB,EAAE,aAAa,GAAG,IAAI,CAAC;CAC3C;AAID,wBAAgB,WAAW,IAAI,iBAAiB,CAkC/C"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* globalThis singleton (see ../state.ts) so a dual module instance of this
|
|
9
9
|
* package still reads/writes one shared store.
|
|
10
10
|
*/
|
|
11
|
-
import type { ImageRecord, ImageStats } from "../types";
|
|
11
|
+
import type { ImageRecord, ImageStats, ImagesSnapshotPayload } from "../types";
|
|
12
12
|
export declare function createRecord(partial: Omit<ImageRecord, "id" | "createdAt" | "loadCount" | "mounted" | "status">): ImageRecord;
|
|
13
13
|
/** Mutate a record in place (records are owned by the store) and notify. */
|
|
14
14
|
export declare function updateRecord(id: number, patch: Partial<ImageRecord>): ImageRecord | undefined;
|
|
@@ -16,6 +16,20 @@ export declare function getRecord(id: number): ImageRecord | undefined;
|
|
|
16
16
|
export declare function getSnapshot(): ImageRecord[];
|
|
17
17
|
export declare function subscribe(listener: () => void): () => void;
|
|
18
18
|
export declare function clearRecords(): void;
|
|
19
|
+
/**
|
|
20
|
+
* Dashboards never instrument their own images — the store is purely a mirror
|
|
21
|
+
* of the synced device. Makes installImageCapture() a permanent no-op.
|
|
22
|
+
*/
|
|
23
|
+
export declare function disableImagesCapture(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Replace the whole store from a synced adapter snapshot (wire records are
|
|
26
|
+
* newest-first; the store keeps oldest-first and useImageRecords reverses).
|
|
27
|
+
* Also adopts the device's global modes / capture status and derives the
|
|
28
|
+
* DEVICE's PixelRatio so oversize math doesn't use the dashboard display's.
|
|
29
|
+
*/
|
|
30
|
+
export declare function replaceImagesFromSnapshot(payload: ImagesSnapshotPayload): void;
|
|
31
|
+
/** Device PixelRatio on device; the SYNCED device's ratio on a mirror. */
|
|
32
|
+
export declare function effectivePixelRatio(): number;
|
|
19
33
|
/** Physical pixels actually needed to fill the laid-out view 1:1. */
|
|
20
34
|
export declare function neededPixels(record: ImageRecord): {
|
|
21
35
|
width: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageEventStore.d.ts","sourceRoot":"","sources":["../../../src/store/imageEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"imageEventStore.d.ts","sourceRoot":"","sources":["../../../src/store/imageEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAsB/E,wBAAgB,YAAY,CAC1B,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC,GAClF,WAAW,CAkBb;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,WAAW,GAAG,SAAS,CAOzB;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE7D;AAED,wBAAgB,WAAW,IAAI,WAAW,EAAE,CAE3C;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAI1D;AAED,wBAAgB,YAAY,IAAI,IAAI,CAWnC;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CA6C9E;AAMD,0EAA0E;AAC1E,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAO1F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAOjE;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAG3D;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAQ1D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,UAAU,CAuB5D"}
|
|
@@ -8,44 +8,11 @@
|
|
|
8
8
|
* global modes, and cache clears.
|
|
9
9
|
*/
|
|
10
10
|
import type { NetworkMode } from "../capture/overrides";
|
|
11
|
+
import type { ImageRecordWire } from "../types";
|
|
11
12
|
export declare const imagesSyncAdapter: {
|
|
12
13
|
version: number;
|
|
13
14
|
getSnapshot: () => {
|
|
14
|
-
records:
|
|
15
|
-
id: number;
|
|
16
|
-
lib: import("..").ImageLib;
|
|
17
|
-
uri: string;
|
|
18
|
-
kind: import("..").SourceKind;
|
|
19
|
-
status: import("..").ImageStatus;
|
|
20
|
-
mounted: boolean;
|
|
21
|
-
cache: import("..").CacheVerdict | null;
|
|
22
|
-
cacheSource: "event" | "queryCache" | null;
|
|
23
|
-
ms: number | null;
|
|
24
|
-
intrinsic: {
|
|
25
|
-
width: number;
|
|
26
|
-
height: number;
|
|
27
|
-
} | null;
|
|
28
|
-
layout: {
|
|
29
|
-
width: number;
|
|
30
|
-
height: number;
|
|
31
|
-
} | null;
|
|
32
|
-
neededPx: {
|
|
33
|
-
width: number;
|
|
34
|
-
height: number;
|
|
35
|
-
} | null;
|
|
36
|
-
oversizeFactor: number | null;
|
|
37
|
-
decodedKB: number;
|
|
38
|
-
wastedKB: number;
|
|
39
|
-
progressSeen: boolean;
|
|
40
|
-
bytesTotal: number | null;
|
|
41
|
-
error: string | null;
|
|
42
|
-
errorCode: number | null;
|
|
43
|
-
loadCount: number;
|
|
44
|
-
overrideLabel: string | null;
|
|
45
|
-
hasAltText: boolean | null;
|
|
46
|
-
layoutShifts: number;
|
|
47
|
-
ageMs: number;
|
|
48
|
-
}[];
|
|
15
|
+
records: ImageRecordWire[];
|
|
49
16
|
stats: import("..").ImageStats;
|
|
50
17
|
captureStatus: import("..").CaptureStatus;
|
|
51
18
|
globalModes: {
|
|
@@ -59,41 +26,7 @@ export declare const imagesSyncAdapter: {
|
|
|
59
26
|
/** List records (newest first). Params: { limit?, status? }. */
|
|
60
27
|
list: (params: unknown) => {
|
|
61
28
|
total: number;
|
|
62
|
-
records:
|
|
63
|
-
id: number;
|
|
64
|
-
lib: import("..").ImageLib;
|
|
65
|
-
uri: string;
|
|
66
|
-
kind: import("..").SourceKind;
|
|
67
|
-
status: import("..").ImageStatus;
|
|
68
|
-
mounted: boolean;
|
|
69
|
-
cache: import("..").CacheVerdict | null;
|
|
70
|
-
cacheSource: "event" | "queryCache" | null;
|
|
71
|
-
ms: number | null;
|
|
72
|
-
intrinsic: {
|
|
73
|
-
width: number;
|
|
74
|
-
height: number;
|
|
75
|
-
} | null;
|
|
76
|
-
layout: {
|
|
77
|
-
width: number;
|
|
78
|
-
height: number;
|
|
79
|
-
} | null;
|
|
80
|
-
neededPx: {
|
|
81
|
-
width: number;
|
|
82
|
-
height: number;
|
|
83
|
-
} | null;
|
|
84
|
-
oversizeFactor: number | null;
|
|
85
|
-
decodedKB: number;
|
|
86
|
-
wastedKB: number;
|
|
87
|
-
progressSeen: boolean;
|
|
88
|
-
bytesTotal: number | null;
|
|
89
|
-
error: string | null;
|
|
90
|
-
errorCode: number | null;
|
|
91
|
-
loadCount: number;
|
|
92
|
-
overrideLabel: string | null;
|
|
93
|
-
hasAltText: boolean | null;
|
|
94
|
-
layoutShifts: number;
|
|
95
|
-
ageMs: number;
|
|
96
|
-
}[];
|
|
29
|
+
records: ImageRecordWire[];
|
|
97
30
|
stats: import("..").ImageStats;
|
|
98
31
|
captureStatus: import("..").CaptureStatus;
|
|
99
32
|
globalModes: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imagesSyncAdapter.d.ts","sourceRoot":"","sources":["../../../src/sync/imagesSyncAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"imagesSyncAdapter.d.ts","sourceRoot":"","sources":["../../../src/sync/imagesSyncAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,sBAAsB,CAAC;AAYxE,OAAO,KAAK,EAAe,eAAe,EAAE,MAAM,UAAU,CAAC;AA6D7D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;0BAMN,MAAM,IAAI;;QAE9B,gEAAgE;uBACjD,OAAO;;;;;;;;;;;QAatB,kDAAkD;4BAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAI3B,2CAA2C;6BACtB,OAAO;QAC5B,qFAAqF;+BAC9D,OAAO;QAC9B,gDAAgD;wBAChC,OAAO;QACvB,uEAAuE;4BAC7C,OAAO;;;;QAUjC,iEAAiE;wBACjD,OAAO;;;;QAIvB;;;WAGG;8BACmB,OAAO;;;;QAwB7B,oDAAoD;gCAC5B,OAAO;;;;QAI/B;;;WAGG;6BACwB,OAAO;QA6BlC,8EAA8E;iCACrD,OAAO;;;;;;;QAQhC,iEAAiE;iCACxC,OAAO;;;;;;;QAIhC,2DAA2D;;;;;QAK3D,0EAA0E;kCAC1C,OAAO;;;;;;CAsB1C,CAAC"}
|
|
@@ -106,6 +106,59 @@ export interface ImageStats {
|
|
|
106
106
|
/** Σ estimated wasted decoded bytes from oversized sources (mounted). */
|
|
107
107
|
estWastedBytes: number;
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Slim wire form of a record as pushed by the external-sync adapter (heavy
|
|
111
|
+
* derived math precomputed on device). This is what dashboards receive and
|
|
112
|
+
* what `replaceFromSnapshot` reconstructs ImageRecords from — keep it in
|
|
113
|
+
* lockstep with `toWire` in sync/imagesSyncAdapter.ts (and the Flutter port).
|
|
114
|
+
*/
|
|
115
|
+
export interface ImageRecordWire {
|
|
116
|
+
id: number;
|
|
117
|
+
lib: ImageLib;
|
|
118
|
+
uri: string;
|
|
119
|
+
kind: SourceKind;
|
|
120
|
+
status: ImageStatus;
|
|
121
|
+
mounted: boolean;
|
|
122
|
+
cache: CacheVerdict | null;
|
|
123
|
+
cacheSource: "event" | "queryCache" | null;
|
|
124
|
+
ms: number | null;
|
|
125
|
+
intrinsic: {
|
|
126
|
+
width: number;
|
|
127
|
+
height: number;
|
|
128
|
+
} | null;
|
|
129
|
+
layout: {
|
|
130
|
+
width: number;
|
|
131
|
+
height: number;
|
|
132
|
+
} | null;
|
|
133
|
+
neededPx: {
|
|
134
|
+
width: number;
|
|
135
|
+
height: number;
|
|
136
|
+
} | null;
|
|
137
|
+
oversizeFactor: number | null;
|
|
138
|
+
decodedKB: number;
|
|
139
|
+
wastedKB: number;
|
|
140
|
+
progressSeen: boolean;
|
|
141
|
+
bytesTotal: number | null;
|
|
142
|
+
error: string | null;
|
|
143
|
+
errorCode: number | null;
|
|
144
|
+
loadCount: number;
|
|
145
|
+
overrideLabel: string | null;
|
|
146
|
+
hasAltText: boolean | null;
|
|
147
|
+
layoutShifts: number;
|
|
148
|
+
ageMs: number;
|
|
149
|
+
}
|
|
150
|
+
/** Full snapshot payload the adapter pushes to watching dashboards. */
|
|
151
|
+
export interface ImagesSnapshotPayload {
|
|
152
|
+
stats?: ImageStats;
|
|
153
|
+
captureStatus?: CaptureStatus;
|
|
154
|
+
globalModes?: {
|
|
155
|
+
network: "normal" | "offline" | "cold";
|
|
156
|
+
blank: boolean;
|
|
157
|
+
};
|
|
158
|
+
insights?: ImageInsights;
|
|
159
|
+
/** Newest first, capped at 100. */
|
|
160
|
+
records?: ImageRecordWire[];
|
|
161
|
+
}
|
|
109
162
|
/** Capture capability report — what the interceptors managed to hook. */
|
|
110
163
|
export interface CaptureStatus {
|
|
111
164
|
installed: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/images",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.15",
|
|
4
4
|
"description": "Debug every image in your React Native app — live load registry, cache verdicts (memory/disk/network), timings, oversize + wasted-memory checks, and failure diagnosis for RN <Image> and expo-image. Part of Buoy devtools.",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"**/index.*"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@buoy-gg/shared-ui": "^7.0.
|
|
21
|
+
"@buoy-gg/shared-ui": "^7.0.15"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"expo-image": "*",
|
package/src/capture/actions.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* rewrites both cache tiers.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { remoteActionResult, remoteImagesDispatch } from "../remote";
|
|
19
20
|
import { imagesState } from "../state";
|
|
20
21
|
import { touchRecord } from "./overrides";
|
|
21
22
|
import type { ImageRecord } from "../types";
|
|
@@ -147,6 +148,8 @@ export type ActionResult = { ok: boolean; message: string };
|
|
|
147
148
|
|
|
148
149
|
/** Fresh load attempt for a mounted image (no cache bypass). */
|
|
149
150
|
export async function retryRecord(record: ImageRecord): Promise<ActionResult> {
|
|
151
|
+
const remote = remoteImagesDispatch();
|
|
152
|
+
if (remote) return remoteActionResult(remote("retry", { id: record.id }));
|
|
150
153
|
if (!record.mounted) {
|
|
151
154
|
return { ok: false, message: "Instance unmounted — cannot reload" };
|
|
152
155
|
}
|
|
@@ -166,6 +169,10 @@ export async function retryRecord(record: ImageRecord): Promise<ActionResult> {
|
|
|
166
169
|
|
|
167
170
|
/** Hard-reload every mounted image (mass cache-bust). Returns count started. */
|
|
168
171
|
export async function hardReloadAllMounted(): Promise<ActionResult> {
|
|
172
|
+
const remote = remoteImagesDispatch();
|
|
173
|
+
if (remote) {
|
|
174
|
+
return remoteActionResult(remote("massAction", { kind: "reload" }));
|
|
175
|
+
}
|
|
169
176
|
const { getSnapshot } = require("../store/imageEventStore") as {
|
|
170
177
|
getSnapshot: () => ImageRecord[];
|
|
171
178
|
};
|
|
@@ -180,6 +187,8 @@ export async function hardReloadAllMounted(): Promise<ActionResult> {
|
|
|
180
187
|
|
|
181
188
|
/** Bypass-cache reload: refetches from network and rewrites the caches. */
|
|
182
189
|
export async function hardReloadRecord(record: ImageRecord): Promise<ActionResult> {
|
|
190
|
+
const remote = remoteImagesDispatch();
|
|
191
|
+
if (remote) return remoteActionResult(remote("hardReload", { id: record.id }));
|
|
183
192
|
if (!record.mounted) {
|
|
184
193
|
return { ok: false, message: "Instance unmounted — cannot reload" };
|
|
185
194
|
}
|
package/src/capture/install.ts
CHANGED
|
@@ -17,13 +17,17 @@ import type { CaptureStatus } from "../types";
|
|
|
17
17
|
|
|
18
18
|
export function installImageCapture(): void {
|
|
19
19
|
const s = imagesState();
|
|
20
|
-
|
|
20
|
+
// Mirror mode (desktop dashboard): never instrument the dashboard's own UI.
|
|
21
|
+
if (s.captureDisabled || s.captureInstalled) return;
|
|
21
22
|
s.captureInstalled = true;
|
|
22
23
|
installRnImageInterceptor();
|
|
23
24
|
installExpoImageInterceptor();
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export function getCaptureStatus(): CaptureStatus {
|
|
28
|
+
// Mirror mode: report the synced DEVICE's capture status, not the local probe.
|
|
29
|
+
const mirrored = imagesState().mirrorCaptureStatus;
|
|
30
|
+
if (mirrored) return mirrored;
|
|
27
31
|
const rn = rnCaptureStatus();
|
|
28
32
|
const expo = expoCaptureStatus();
|
|
29
33
|
return {
|
package/src/capture/overrides.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* directly via forceUpdate() from the per-record instance registry.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { remoteImagesDispatch } from "../remote";
|
|
17
18
|
import { imagesState } from "../state";
|
|
18
19
|
import { getRecord, getSnapshot, updateRecord } from "../store/imageEventStore";
|
|
19
20
|
import type { ImageLib } from "../types";
|
|
@@ -106,18 +107,47 @@ export function getRenderVersion(recordId: number | null): number {
|
|
|
106
107
|
// Per-record overrides
|
|
107
108
|
// ---------------------------------------------------------------------------
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
/** Remote param shape for the adapter's `setOverride` action. */
|
|
111
|
+
function overrideParams(
|
|
112
|
+
recordId: number,
|
|
113
|
+
source: OverrideSource
|
|
114
|
+
): Record<string, unknown> {
|
|
115
|
+
return source.type === "url"
|
|
116
|
+
? { id: recordId, kind: "url", uri: source.uri }
|
|
117
|
+
: { id: recordId, kind: source.type };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Local bookkeeping only (no remote forward) — mirrors keep this as an
|
|
122
|
+
* optimistic UI update; the next device snapshot is the source of truth.
|
|
123
|
+
*/
|
|
124
|
+
function setOverrideLocal(recordId: number, override: ImageOverride): void {
|
|
110
125
|
imagesState().overrides.set(recordId, override);
|
|
111
126
|
updateRecord(recordId, { overrideLabel: override.label });
|
|
112
127
|
touchRecord(recordId);
|
|
113
128
|
}
|
|
114
129
|
|
|
115
|
-
export function
|
|
130
|
+
export function setOverride(recordId: number, override: ImageOverride): void {
|
|
131
|
+
if (override.source) {
|
|
132
|
+
void remoteImagesDispatch()?.(
|
|
133
|
+
"setOverride",
|
|
134
|
+
overrideParams(recordId, override.source)
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
setOverrideLocal(recordId, override);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function clearOverrideLocal(recordId: number): void {
|
|
116
141
|
imagesState().overrides.delete(recordId);
|
|
117
142
|
updateRecord(recordId, { overrideLabel: undefined });
|
|
118
143
|
touchRecord(recordId);
|
|
119
144
|
}
|
|
120
145
|
|
|
146
|
+
export function clearOverride(recordId: number): void {
|
|
147
|
+
void remoteImagesDispatch()?.("clearOverride", { id: recordId });
|
|
148
|
+
clearOverrideLocal(recordId);
|
|
149
|
+
}
|
|
150
|
+
|
|
121
151
|
export function getOverride(recordId: number | null): ImageOverride | undefined {
|
|
122
152
|
if (recordId == null) return undefined;
|
|
123
153
|
return imagesState().overrides.get(recordId) as ImageOverride | undefined;
|
|
@@ -127,12 +157,19 @@ export function getOverride(recordId: number | null): ImageOverride | undefined
|
|
|
127
157
|
// Mass actions (every mounted image at once)
|
|
128
158
|
// ---------------------------------------------------------------------------
|
|
129
159
|
|
|
160
|
+
/** Adapter `massAction` kind for a mass override (per-record 'hang' is mass 'loading'). */
|
|
161
|
+
function massKind(source: OverrideSource): string {
|
|
162
|
+
return source.type === "hang" ? "loading" : source.type;
|
|
163
|
+
}
|
|
164
|
+
|
|
130
165
|
/** Apply one override to every mounted record. Returns how many were hit. */
|
|
131
166
|
export function setOverrideForAllMounted(source: OverrideSource, label: string): number {
|
|
167
|
+
// One mass action on the device, not N per-record forwards.
|
|
168
|
+
void remoteImagesDispatch()?.("massAction", { kind: massKind(source) });
|
|
132
169
|
let count = 0;
|
|
133
170
|
for (const record of getSnapshot()) {
|
|
134
171
|
if (!record.mounted) continue;
|
|
135
|
-
|
|
172
|
+
setOverrideLocal(record.id, { source, label });
|
|
136
173
|
count++;
|
|
137
174
|
}
|
|
138
175
|
return count;
|
|
@@ -140,24 +177,29 @@ export function setOverrideForAllMounted(source: OverrideSource, label: string):
|
|
|
140
177
|
|
|
141
178
|
/** Remove every active override. Returns how many were cleared. */
|
|
142
179
|
export function clearAllOverrides(): number {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
180
|
+
void remoteImagesDispatch()?.("massAction", { kind: "restore" });
|
|
181
|
+
// Mirrors track labels on records, not the overrides map — clear both.
|
|
182
|
+
const ids = new Set<number>(imagesState().overrides.keys());
|
|
183
|
+
for (const record of getSnapshot()) {
|
|
184
|
+
if (record.overrideLabel != null) ids.add(record.id);
|
|
185
|
+
}
|
|
186
|
+
for (const id of ids) clearOverrideLocal(id);
|
|
187
|
+
return ids.size;
|
|
146
188
|
}
|
|
147
189
|
|
|
148
190
|
/** Flash every mounted image (locate everything the tool tracks). */
|
|
149
191
|
export function flashAllMounted(durationMs = 2500): number {
|
|
192
|
+
void remoteImagesDispatch()?.("massAction", { kind: "flash" });
|
|
150
193
|
let count = 0;
|
|
151
194
|
for (const record of getSnapshot()) {
|
|
152
195
|
if (!record.mounted) continue;
|
|
153
|
-
|
|
196
|
+
flashRecordLocal(record.id, durationMs);
|
|
154
197
|
count++;
|
|
155
198
|
}
|
|
156
199
|
return count;
|
|
157
200
|
}
|
|
158
201
|
|
|
159
|
-
|
|
160
|
-
export function flashRecord(recordId: number, durationMs = 2500): void {
|
|
202
|
+
function flashRecordLocal(recordId: number, durationMs = 2500): void {
|
|
161
203
|
const s = imagesState();
|
|
162
204
|
s.flashUntil.set(recordId, Date.now() + durationMs);
|
|
163
205
|
touchRecord(recordId);
|
|
@@ -167,6 +209,12 @@ export function flashRecord(recordId: number, durationMs = 2500): void {
|
|
|
167
209
|
}, durationMs + 50);
|
|
168
210
|
}
|
|
169
211
|
|
|
212
|
+
/** Flash a border on the on-screen image so it can be located visually. */
|
|
213
|
+
export function flashRecord(recordId: number, durationMs = 2500): void {
|
|
214
|
+
void remoteImagesDispatch()?.("flash", { id: recordId });
|
|
215
|
+
flashRecordLocal(recordId, durationMs);
|
|
216
|
+
}
|
|
217
|
+
|
|
170
218
|
// ---------------------------------------------------------------------------
|
|
171
219
|
// Global simulation modes
|
|
172
220
|
// ---------------------------------------------------------------------------
|
|
@@ -181,12 +229,14 @@ export function flashRecord(recordId: number, durationMs = 2500): void {
|
|
|
181
229
|
* `cachePolicy:'none'`): first-launch behavior without clearing anything.
|
|
182
230
|
*/
|
|
183
231
|
export function setNetworkMode(mode: NetworkMode): void {
|
|
232
|
+
void remoteImagesDispatch()?.("setNetworkMode", { mode });
|
|
184
233
|
imagesState().globalModes.network = mode;
|
|
185
234
|
touchGlobal();
|
|
186
235
|
}
|
|
187
236
|
|
|
188
237
|
/** Chrome-style "disable images": render every image without a source. */
|
|
189
238
|
export function setBlankImages(enabled: boolean): void {
|
|
239
|
+
void remoteImagesDispatch()?.("setBlankImages", { enabled });
|
|
190
240
|
imagesState().globalModes.blank = enabled;
|
|
191
241
|
touchGlobal();
|
|
192
242
|
}
|
package/src/capture/savings.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* total) → expo disk-cache file size → HEAD Content-Length.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import { remoteImagesDispatch } from "../remote";
|
|
15
16
|
import { neededPixels } from "../store/imageEventStore";
|
|
16
17
|
import type { ImageRecord } from "../types";
|
|
17
18
|
|
|
@@ -104,6 +105,16 @@ async function resolveOriginalBytes(
|
|
|
104
105
|
* Requires expo-image-manipulator (graceful message when absent).
|
|
105
106
|
*/
|
|
106
107
|
export async function proveSavings(record: ImageRecord): Promise<SavingsResult> {
|
|
108
|
+
// Mirror mode: the re-encode must happen ON DEVICE (that's the whole point —
|
|
109
|
+
// real bytes from the real encoder); forward and relay the result.
|
|
110
|
+
const remote = remoteImagesDispatch();
|
|
111
|
+
if (remote) {
|
|
112
|
+
try {
|
|
113
|
+
return (await remote("proveSavings", { id: record.id })) as SavingsResult;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
return { ok: false, message: String((error as Error)?.message ?? error) };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
107
118
|
if (!record.uri || (record.sourceKind !== "network" && record.sourceKind !== "asset" && record.sourceKind !== "file")) {
|
|
108
119
|
return { ok: false, message: "No loadable source URI on this record" };
|
|
109
120
|
}
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
import { useState, type ReactNode } from "react";
|
|
9
9
|
import {
|
|
10
10
|
Image,
|
|
11
|
-
PixelRatio,
|
|
12
11
|
ScrollView,
|
|
13
12
|
StyleSheet,
|
|
14
13
|
Text,
|
|
@@ -20,7 +19,9 @@ import { macOSColors } from "@buoy-gg/shared-ui";
|
|
|
20
19
|
import { clearOverride, setOverride } from "../capture/overrides";
|
|
21
20
|
import { proveSavings } from "../capture/savings";
|
|
22
21
|
import type { SavingsResult } from "../capture/savings";
|
|
22
|
+
import { remoteImagesDispatch } from "../remote";
|
|
23
23
|
import {
|
|
24
|
+
effectivePixelRatio,
|
|
24
25
|
estDecodedBytes,
|
|
25
26
|
estWastedBytes,
|
|
26
27
|
neededPixels,
|
|
@@ -54,6 +55,15 @@ function Row({ label, value, color }: { label: string; value: string; color?: st
|
|
|
54
55
|
|
|
55
56
|
/** expo-image global cache clears (no-ops if expo-image is absent). */
|
|
56
57
|
function clearExpoCache(kind: "memory" | "disk"): void {
|
|
58
|
+
// Mirror mode: the caches live on the synced device.
|
|
59
|
+
const remote = remoteImagesDispatch();
|
|
60
|
+
if (remote) {
|
|
61
|
+
void remote("clearExpoCaches", {
|
|
62
|
+
memory: kind === "memory",
|
|
63
|
+
disk: kind === "disk",
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
57
67
|
try {
|
|
58
68
|
const expo = require("expo-image");
|
|
59
69
|
if (kind === "memory") void expo.Image.clearMemoryCache();
|
|
@@ -289,7 +299,7 @@ export function ImageDetail({ record }: ImageDetailProps) {
|
|
|
289
299
|
label="Displayed"
|
|
290
300
|
value={`${Math.round(record.layout.width)}×${Math.round(record.layout.height)} dp (needs ${
|
|
291
301
|
needed ? `${needed.width}×${needed.height}` : "?"
|
|
292
|
-
} px @${
|
|
302
|
+
} px @${Math.round(effectivePixelRatio() * 100) / 100}x)`}
|
|
293
303
|
/>
|
|
294
304
|
) : (
|
|
295
305
|
<Row label="Displayed" value="no layout yet" />
|