@flemo/devtools 0.1.0
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/LICENSE +21 -0
- package/README.md +310 -0
- package/dist/__tests__/anomalies.test.d.ts +1 -0
- package/dist/__tests__/environment.test.d.ts +1 -0
- package/dist/__tests__/overrides.test.d.ts +1 -0
- package/dist/__tests__/panel.test.d.ts +1 -0
- package/dist/__tests__/recorder.branches.test.d.ts +1 -0
- package/dist/__tests__/recorder.guards.test.d.ts +1 -0
- package/dist/__tests__/recorder.regressions.test.d.ts +1 -0
- package/dist/__tests__/recorder.test.d.ts +1 -0
- package/dist/__tests__/sampling.test.d.ts +1 -0
- package/dist/anomalies.d.ts +45 -0
- package/dist/blindSpots.d.ts +1 -0
- package/dist/environment.d.ts +31 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.mjs +1056 -0
- package/dist/judging.d.ts +1 -0
- package/dist/overrides.d.ts +22 -0
- package/dist/panel/dom.d.ts +7 -0
- package/dist/panel/format.d.ts +29 -0
- package/dist/panel/index.d.ts +25 -0
- package/dist/panel/styles.d.ts +1 -0
- package/dist/panel/view.d.ts +12 -0
- package/dist/recorder.d.ts +17 -0
- package/dist/sampling.d.ts +26 -0
- package/dist/types.d.ts +280 -0
- package/package.json +62 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1056 @@
|
|
|
1
|
+
//#region src/anomalies.ts
|
|
2
|
+
var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = (e) => {
|
|
3
|
+
let n = [], { t0Ms: r, driver: i, frameSamples: a, playerGaps: o, longTasks: s, holdLongTasks: c, landing: l } = e, u = r + (e.releasedAtMs ?? 0);
|
|
4
|
+
if (o && o.over30Count > 0 && n.push(`player frame gap up to ${o.maxMs}ms ×${o.over30Count} during flight (the rAF player missed frames — convergence jank on this navigation)`), a.released.over30Count > 0) {
|
|
5
|
+
let e = i === "compiled" ? " (compiled/compositor flights can still present cleanly through main-thread gaps)" : "";
|
|
6
|
+
n.push(`main-thread rAF gap up to ${a.released.maxGapMs}ms ×${a.released.over30Count} during visible motion${e}`);
|
|
7
|
+
}
|
|
8
|
+
for (let e of s) e.startMs <= u + 120 && e.startMs + e.durationMs >= u - 50 ? n.push(`long task ${Math.round(e.durationMs)}ms overlapped the visible-motion start (opening-swallow risk: the first presented frames of the transition may have been lost)`) : e.durationMs >= 100 && n.push(`long task ${Math.round(e.durationMs)}ms mid-flight`);
|
|
9
|
+
for (let e of c) e.durationMs >= 100 && n.push(`long task ${Math.round(e.durationMs)}ms absorbed by the hold (screen posed, not yet moving — the hold doing its job, not user-visible jank)`);
|
|
10
|
+
let { motion: d, images: f } = e;
|
|
11
|
+
return d.holdReassertedAtMs !== null && n.push(`hold re-asserted ${d.holdReassertedAtMs}ms into the flight, after it had already released (an interleaved commit wrote the stale paused hold attribute over a running flight — the flemo 2026-08-18 release-race signature; the motion pauses while every timing metric stays clean)`), d.pausedAfterRelease && n.push("compiled animation reported playState=paused after its release (the flight was posed and then stopped mid-motion, not merely starved of frames)"), d.longestStallMs >= 48 && n.push(`motion stalled ${d.longestStallMs}ms mid-flight (${d.stalledFrames}/${d.sampledFrames} released frames advanced neither the animation clock nor the pose — freeze, or freeze-then-leap if the flight still landed on time)`), d.sampledFrames === 0 && e.releasedAtMs !== null && n.push("no released frames were sampled (the flight ended at or before its own hold release — the visible motion, if any, was never observed)"), f.completedUnheld > 0 && n.push(`${f.completedUnheld} image(s) finished loading mid-flight without a hold (${f.completedDuringFlight} completed, ${f.heldDuringFlight} held; ${f.loadingAtStart} were loading at t0, ${f.addedDuringFlight} arrived mid-flight) — each decode rasters on the moving layer and costs a present; this is the warm-side image-hold regression`), l.orphanedHolds.length > 0 && n.push(`hold markers left on the page at rest: ${l.orphanedHolds.join("; ")} (whatever they hide has no owner left to reveal it — the permanently-blank-avatar class)`), l.residualInlineTransforms.length > 0 && n.push(`residual inline style after COMPLETED: ${l.residualInlineTransforms.join("; ")} (landing cleanup failure — the landed scope belongs to the compiled rest rules)`), l.offViewportAtRest && n.push("screen resting at from-pose while COMPLETED+active (blank-viewport signature — the flemo PR #259 class: a residual pose left the landed screen parked off-viewport)"), l.stuckStatuses.length > 0 && n.push(`transitional status stuck >${t / 1e3}s: ${l.stuckStatuses.join(", ")} (navigation queue lock or missed animationend — later navigations will be swallowed)`), i === "unknown" && n.push("driver could not be classified (no running flemo-* CSSAnimation and no player inline-style signature observed — zero-duration flight, or the sampler attached after motion ended)"), n;
|
|
12
|
+
}, o = (e) => {
|
|
13
|
+
let n = [];
|
|
14
|
+
if (e.forcePin !== null && n.push(`active force pin flemo:motion-driver-force=${e.forcePin} — every transition this session is pinned to one driver (A/B residue? pins expire after 24h; clear the key before judging behavior)`), e.clearedForcePin !== null && e.forcePin === null && n.push(`force pin flemo:motion-driver-force=${e.clearedForcePin} was present at attach and has since been cleared (the library strips malformed/expired pins on sight) — early driver decisions in this session may still have been shaped by it`), e.legacyLocalForcePin !== null && n.push(`legacy localStorage driver pin present (flemo:motion-driver-force=${e.legacyLocalForcePin}) — never honored, but it marks A/B residue on this profile`), e.emulationSuspected) {
|
|
15
|
+
let t = /Win/i.test(e.platform) ? " (Windows touch hardware makes this signal ambiguous — confirm the DevTools device toolbar state)" : "";
|
|
16
|
+
n.push("DevTools device emulation suspected — the page composites to a rescaled surface, so visual reports from this session are untrustworthy; judge motion in a plain window or on a real device" + t);
|
|
17
|
+
}
|
|
18
|
+
return e.stuckFlightOpen && n.push(`a flight is still transitional after ${t / 1e3}s — the navigation queue is likely locked; subsequent navigations will be ignored`), e.flightAnomalies.some((e) => e.some((e) => e.includes("blank-viewport"))) && n.push("at least one flight landed with the blank-viewport signature (see that flight's anomalies)"), n;
|
|
19
|
+
}, s = [
|
|
20
|
+
"macOS Chrome present-pipeline pacing: on 120Hz ProMotion displays Chrome can present frames unevenly even when rAF cadence and this report read perfectly clean (Chromium issues 40062488 / 345275139; proven with a no-script pure-CSS control page that still juddered). Not diagnosable or fixable from page code.",
|
|
21
|
+
"Display-hardware effects: local dimming, backlight modulation, and panel overdrive alter perceived motion and are invisible to every web API.",
|
|
22
|
+
"Compositor-internal present skips: a frame can be produced on time (clean rAF, clean player gaps) yet dropped or delayed inside the compositor's present queue; only platform tools (about:tracing, Instruments) see that layer.",
|
|
23
|
+
"DevTools device emulation composites the page to a rescaled surface: every in-page instrument reads the pre-scale surface and reports clean while the eye watches the post-scale one, so emulated sessions grow shimmer/flash artifacts that do not exist in a plain window or on a real device."
|
|
24
|
+
], c = () => {
|
|
25
|
+
if (typeof navigator > "u") return null;
|
|
26
|
+
let e = navigator.userAgentData;
|
|
27
|
+
return !e || !Array.isArray(e.brands) ? null : e.brands.map((e) => ({
|
|
28
|
+
brand: String(e.brand ?? ""),
|
|
29
|
+
version: String(e.version ?? "")
|
|
30
|
+
}));
|
|
31
|
+
}, l = () => {
|
|
32
|
+
if (typeof navigator > "u") return "unknown";
|
|
33
|
+
let e = c();
|
|
34
|
+
if (e?.some((e) => /Chromium/i.test(e.brand))) return "blink";
|
|
35
|
+
let t = navigator.userAgent ?? "";
|
|
36
|
+
return /Firefox|FxiOS/i.test(t) ? "gecko" : e || /AppleWebKit/i.test(t) && !/Chrome|Chromium|Android/i.test(t) ? "webkit" : /Android/i.test(t) ? "blink" : "unknown";
|
|
37
|
+
}, u = () => {
|
|
38
|
+
if (typeof navigator > "u" || l() !== "blink") return !1;
|
|
39
|
+
let e = navigator.platform ?? "";
|
|
40
|
+
return /Mac|Win|Linux/i.test(e) ? /Android/i.test(navigator.userAgent ?? "") && !/Mac|Win/i.test(e) ? /Linux (x86_64|i686)/i.test(e) : (navigator.maxTouchPoints ?? 0) > 0 : !1;
|
|
41
|
+
}, d = (e = 20) => new Promise((t) => {
|
|
42
|
+
let n = Number.isFinite(e) ? Math.max(1, Math.floor(e)) : 20;
|
|
43
|
+
if (typeof requestAnimationFrame != "function" || typeof performance > "u") {
|
|
44
|
+
t({
|
|
45
|
+
medianGapMs: null,
|
|
46
|
+
sampleCount: 0
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let r = [], i = null, a = () => {
|
|
51
|
+
let e = performance.now();
|
|
52
|
+
if (i !== null && r.push(e - i), i = e, r.length >= n) {
|
|
53
|
+
let e = [...r].sort((e, t) => e - t), n = e[Math.floor(e.length / 2)];
|
|
54
|
+
t({
|
|
55
|
+
medianGapMs: Math.round(n * 100) / 100,
|
|
56
|
+
sampleCount: r.length
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
requestAnimationFrame(a);
|
|
61
|
+
};
|
|
62
|
+
requestAnimationFrame(a);
|
|
63
|
+
}), f = () => {
|
|
64
|
+
try {
|
|
65
|
+
return typeof PerformanceObserver < "u" && Array.isArray(PerformanceObserver.supportedEntryTypes) && PerformanceObserver.supportedEntryTypes.includes("longtask");
|
|
66
|
+
} catch {
|
|
67
|
+
return !1;
|
|
68
|
+
}
|
|
69
|
+
}, p = (e) => {
|
|
70
|
+
let t = typeof navigator < "u" ? navigator : null, n = typeof window < "u" ? window : null, r = !1;
|
|
71
|
+
try {
|
|
72
|
+
r = n?.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? !1;
|
|
73
|
+
} catch {
|
|
74
|
+
r = !1;
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
userAgent: t?.userAgent ?? "",
|
|
78
|
+
uaBrands: c(),
|
|
79
|
+
engine: l(),
|
|
80
|
+
platform: t?.platform ?? "",
|
|
81
|
+
maxTouchPoints: t?.maxTouchPoints ?? 0,
|
|
82
|
+
devicePixelRatio: n?.devicePixelRatio ?? 1,
|
|
83
|
+
screen: {
|
|
84
|
+
width: n?.screen?.width ?? 0,
|
|
85
|
+
height: n?.screen?.height ?? 0
|
|
86
|
+
},
|
|
87
|
+
viewport: {
|
|
88
|
+
width: n?.innerWidth ?? 0,
|
|
89
|
+
height: n?.innerHeight ?? 0
|
|
90
|
+
},
|
|
91
|
+
visualViewportScale: n?.visualViewport?.scale ?? null,
|
|
92
|
+
rafCadence: e,
|
|
93
|
+
reducedMotion: r,
|
|
94
|
+
emulationSuspected: u(),
|
|
95
|
+
observation: {
|
|
96
|
+
longTasks: f(),
|
|
97
|
+
elementAnimations: typeof Element < "u" && typeof Element.prototype.getAnimations == "function",
|
|
98
|
+
playerGapMirror: Array.isArray(n?.__flemoPlayerGaps)
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}, m = [
|
|
102
|
+
"DevTools must be CLOSED while judging motion. An open inspector serializes requests and repaints its own panels on the same machine; the 2026-08 campaign's entire residual 'stutter' was this, and it is invisible to every in-page metric.",
|
|
103
|
+
"No screen recording or display capture while judging. A capture client forces WindowServer to composite every vsync, which SUPPRESSES the symptom — a capture that looks smooth proves nothing about the uncaptured session.",
|
|
104
|
+
"Judge with real input (a finger, a mouse). Synthetic dispatch — evaluate().click() and friends — never fires pointerdown, so it bypasses the swipe/gesture machinery that a real navigation goes through.",
|
|
105
|
+
"Establish the viewing configuration before believing any verdict: device emulation off, which physical display, its refresh rate and HiDPI scaling, Low Power Mode. Ask for a photo of the setup if it is not certain."
|
|
106
|
+
], h = [
|
|
107
|
+
{
|
|
108
|
+
key: "flemo:motion-driver",
|
|
109
|
+
storage: "local",
|
|
110
|
+
kind: "production-state",
|
|
111
|
+
description: "learned driver ledger ('css' = player demoted on this device, 'raf' = clean probe)"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
key: "flemo:motion-driver-force",
|
|
115
|
+
storage: "session",
|
|
116
|
+
kind: "opt-in-diagnostic",
|
|
117
|
+
description: "hard driver pin ('css@<epoch-ms>' / 'raf@<epoch-ms>', 24h TTL) — pins EVERY transition"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
key: "flemo:lpm",
|
|
121
|
+
storage: "session",
|
|
122
|
+
kind: "production-state",
|
|
123
|
+
description: "low-power-mode cadence seed (learned)"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: "flemo:sixty",
|
|
127
|
+
storage: "session",
|
|
128
|
+
kind: "production-state",
|
|
129
|
+
description: "steady-60 display verdict seed ('high' latches, a count seeds the streak)"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
key: "flemo:lat",
|
|
133
|
+
storage: "session",
|
|
134
|
+
kind: "production-state",
|
|
135
|
+
description: "LPM release-latency seed (learned)"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
key: "flemo:landing-snap",
|
|
139
|
+
storage: "session",
|
|
140
|
+
kind: "opt-in-diagnostic",
|
|
141
|
+
description: "Blink landing pixel-snap easing A/B"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
key: "flemo:imghold",
|
|
145
|
+
storage: "session",
|
|
146
|
+
kind: "opt-in-diagnostic",
|
|
147
|
+
description: "flight-scoped <img> reveal hold"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
key: "flemo:settle-gate",
|
|
151
|
+
storage: "session",
|
|
152
|
+
kind: "production-default-with-override",
|
|
153
|
+
description: "render-settle entry gate override"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
key: "flemo:handoff",
|
|
157
|
+
storage: "session",
|
|
158
|
+
kind: "opt-in-diagnostic",
|
|
159
|
+
description: "anchored-opening handoff (POP-scoped)"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
key: "flemo:handoffms",
|
|
163
|
+
storage: "session",
|
|
164
|
+
kind: "opt-in-diagnostic",
|
|
165
|
+
description: "handoff point override (ms)"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
key: "flemo:apply",
|
|
169
|
+
storage: "session",
|
|
170
|
+
kind: "opt-in-diagnostic",
|
|
171
|
+
description: "force the scrub-WAAPI value-application tier"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
key: "flemo:snap",
|
|
175
|
+
storage: "session",
|
|
176
|
+
kind: "production-default-with-override",
|
|
177
|
+
description: "player device-pixel snap policy override"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
key: "flemo:snapband",
|
|
181
|
+
storage: "session",
|
|
182
|
+
kind: "opt-in-diagnostic",
|
|
183
|
+
description: "'hybrid' snap jitter-band width (device px)"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
key: "flemo:layers",
|
|
187
|
+
storage: "session",
|
|
188
|
+
kind: "opt-in-diagnostic",
|
|
189
|
+
description: "resident screen layers at rest (armed by ?flemo-layers=)"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
key: "flemo:freeze",
|
|
193
|
+
storage: "session",
|
|
194
|
+
kind: "opt-in-diagnostic",
|
|
195
|
+
description: "keep the direct prev screen live (armed by ?flemo-freeze=)"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
key: "flemo:preraster",
|
|
199
|
+
storage: "session",
|
|
200
|
+
kind: "opt-in-diagnostic",
|
|
201
|
+
description: "promote the entering content layer through the hold"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
key: "flemo:imgoffload",
|
|
205
|
+
storage: "session",
|
|
206
|
+
kind: "production-default-with-override",
|
|
207
|
+
description: "image decode offloader override"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: "flemo:devtools",
|
|
211
|
+
storage: "session",
|
|
212
|
+
kind: "opt-in-diagnostic",
|
|
213
|
+
description: "arms this flight recorder in the playground (?devtools=on)"
|
|
214
|
+
}
|
|
215
|
+
], g = "flemo:motion-driver-force", _ = `${g} (localStorage — legacy location)`, v = (e) => {
|
|
216
|
+
try {
|
|
217
|
+
let t = e === "session" ? sessionStorage : localStorage;
|
|
218
|
+
return t.length, t;
|
|
219
|
+
} catch {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}, y = (e, t) => {
|
|
223
|
+
try {
|
|
224
|
+
return e ? e.getItem(t) : null;
|
|
225
|
+
} catch {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
}, b = new Set(h.map((e) => e.key)), x = () => {
|
|
229
|
+
let e = {}, t = v("session"), n = v("local");
|
|
230
|
+
for (let r of h) {
|
|
231
|
+
let i = y(r.storage === "session" ? t : n, r.key);
|
|
232
|
+
i !== null && (e[r.key] = i);
|
|
233
|
+
}
|
|
234
|
+
let r = y(n, g);
|
|
235
|
+
r !== null && (e[_] = r);
|
|
236
|
+
for (let [r, i] of [[t, "sessionStorage"], [n, "localStorage"]]) if (r) try {
|
|
237
|
+
for (let t = 0; t < r.length; t += 1) {
|
|
238
|
+
let n = r.key(t);
|
|
239
|
+
!n || !n.startsWith("flemo:") || b.has(n) || (e[`${n} (${i}, unknown key)`] = r.getItem(n) ?? "");
|
|
240
|
+
}
|
|
241
|
+
} catch {}
|
|
242
|
+
return e;
|
|
243
|
+
}, S = (e) => {
|
|
244
|
+
let t = [];
|
|
245
|
+
for (let [n, r] of Object.entries(e)) {
|
|
246
|
+
if (n === g) {
|
|
247
|
+
t.push(`${n}=${r} — A DRIVER PIN IS ACTIVE: every transition this session is forced onto one driver, bypassing measurement and demotion. If you did not set it deliberately just now, it is A/B residue (mobile tab restoration resurrects sessionStorage across days; pins expire after 24h). This exact residue once burned a multi-day investigation — clear the key before judging any behavior.`);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (n === _) {
|
|
251
|
+
t.push(`${n}=${r} — legacy localStorage driver pin present. The library removes it on sight and never honors it, but its existence means an old A/B session left residue on this profile.`);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (n.startsWith(`${g} `)) {
|
|
255
|
+
t.push(`${n}=${r} — a driver force pin was observed this session (see marker in the key). Even a since-cleared pin may have shaped early driver decisions; treat this session's routing as suspect.`);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
let e = h.find((e) => n === e.key || n.startsWith(`${e.key} `));
|
|
259
|
+
!e || e.key === "flemo:devtools" || (e.kind === "opt-in-diagnostic" ? t.push(`${n}=${r} — opt-in diagnostic active (${e.description}); behavior differs from stock. Possible left-over A/B toggle from an earlier debugging session.`) : e.kind === "production-default-with-override" && t.push(`${n}=${r} — production default overridden for this session (${e.description}).`));
|
|
260
|
+
}
|
|
261
|
+
return t;
|
|
262
|
+
}, C = (e) => Math.round(e * 10) / 10, w = (e) => {
|
|
263
|
+
if (e.length === 0) return {
|
|
264
|
+
count: 0,
|
|
265
|
+
medianGapMs: 0,
|
|
266
|
+
maxGapMs: 0,
|
|
267
|
+
over30Count: 0
|
|
268
|
+
};
|
|
269
|
+
let t = [...e].sort((e, t) => e - t);
|
|
270
|
+
return {
|
|
271
|
+
count: e.length,
|
|
272
|
+
medianGapMs: C(t[Math.floor(t.length / 2)]),
|
|
273
|
+
maxGapMs: C(t[t.length - 1]),
|
|
274
|
+
over30Count: e.filter((e) => e >= 30).length
|
|
275
|
+
};
|
|
276
|
+
}, T = (e, t = []) => {
|
|
277
|
+
let n = [...e, ...t];
|
|
278
|
+
return {
|
|
279
|
+
...n.length === 0 ? {
|
|
280
|
+
count: 0,
|
|
281
|
+
medianGapMs: 0,
|
|
282
|
+
maxGapMs: 0
|
|
283
|
+
} : (() => {
|
|
284
|
+
let e = [...n].sort((e, t) => e - t);
|
|
285
|
+
return {
|
|
286
|
+
count: n.length,
|
|
287
|
+
medianGapMs: C(e[Math.floor(e.length / 2)]),
|
|
288
|
+
maxGapMs: C(e[e.length - 1])
|
|
289
|
+
};
|
|
290
|
+
})(),
|
|
291
|
+
longGaps: n.filter((e) => e >= 30).map(C),
|
|
292
|
+
held: w(e),
|
|
293
|
+
released: w(t)
|
|
294
|
+
};
|
|
295
|
+
}, E = (e) => e.length === 0 ? null : {
|
|
296
|
+
maxMs: C(Math.max(...e)),
|
|
297
|
+
over30Count: e.filter((e) => e >= 30).length
|
|
298
|
+
}, D = (e) => {
|
|
299
|
+
let t = e.playerSuppression || e.playerAdvance;
|
|
300
|
+
return t && e.compiledAnimation ? "mixed" : t ? "player" : e.compiledAnimation ? "compiled" : "unknown";
|
|
301
|
+
}, O = (e) => e === "PUSHING" ? "PUSH" : e === "POPPING" ? "POP" : e === "REPLACING" ? "REPLACE" : null, ee = (e) => {
|
|
302
|
+
let t = /^matrix3d\(([^)]+)\)$/.exec(e.trim());
|
|
303
|
+
if (t) {
|
|
304
|
+
let e = t[1].split(",").map((e) => Number(e.trim()));
|
|
305
|
+
return e.length === 16 && Number.isFinite(e[12]) ? e[12] : null;
|
|
306
|
+
}
|
|
307
|
+
let n = /^matrix\(([^)]+)\)$/.exec(e.trim());
|
|
308
|
+
if (n) {
|
|
309
|
+
let e = n[1].split(",").map((e) => Number(e.trim()));
|
|
310
|
+
return e.length === 6 && Number.isFinite(e[4]) ? e[4] : null;
|
|
311
|
+
}
|
|
312
|
+
return null;
|
|
313
|
+
}, k = "2", A = /* @__PURE__ */ new Set([
|
|
314
|
+
"PUSHING",
|
|
315
|
+
"POPPING",
|
|
316
|
+
"REPLACING"
|
|
317
|
+
]), j = /* @__PURE__ */ new Set([
|
|
318
|
+
"true",
|
|
319
|
+
"park",
|
|
320
|
+
"park-under",
|
|
321
|
+
"park-over"
|
|
322
|
+
]), M = "[data-flemo-screen]", N = "data-flemo-status", te = "data-flemo-active", P = "data-flemo-anim-hold", F = 2, I = 2e3, L = "data-flemo-img-hold", ne = "data-flemo-held-arrival", re = 2, R = 200, ie = 1e3, z = (e) => Math.round(e * 10) / 10, B = null, V = () => window, ae = (e = {}) => {
|
|
323
|
+
if (B) return B;
|
|
324
|
+
if (typeof window > "u" || typeof document > "u") return {
|
|
325
|
+
detach: () => {},
|
|
326
|
+
report: () => ({
|
|
327
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
328
|
+
version: "2",
|
|
329
|
+
environment: p({
|
|
330
|
+
medianGapMs: null,
|
|
331
|
+
sampleCount: 0
|
|
332
|
+
}),
|
|
333
|
+
overrides: {
|
|
334
|
+
active: {},
|
|
335
|
+
warnings: ["no DOM available — recorder ran inert"]
|
|
336
|
+
},
|
|
337
|
+
driverPolicy: {
|
|
338
|
+
demotion: null,
|
|
339
|
+
forcePin: null
|
|
340
|
+
},
|
|
341
|
+
flights: [],
|
|
342
|
+
anomalies: [],
|
|
343
|
+
blindSpots: [...s],
|
|
344
|
+
judgingProtocol: [...m]
|
|
345
|
+
})
|
|
346
|
+
};
|
|
347
|
+
let n = e.maxFlights ?? 50, r = e.log ?? !1, i = e.installGlobal ?? !0, c = x(), l = {
|
|
348
|
+
medianGapMs: null,
|
|
349
|
+
sampleCount: 0
|
|
350
|
+
};
|
|
351
|
+
d().then((e) => {
|
|
352
|
+
l = e;
|
|
353
|
+
});
|
|
354
|
+
let u = [], f = null;
|
|
355
|
+
try {
|
|
356
|
+
typeof PerformanceObserver < "u" && PerformanceObserver.supportedEntryTypes?.includes("longtask") && (f = new PerformanceObserver((e) => {
|
|
357
|
+
for (let t of e.getEntries()) u.push({
|
|
358
|
+
startMs: z(t.startTime),
|
|
359
|
+
durationMs: z(t.duration)
|
|
360
|
+
});
|
|
361
|
+
u.length > ie && u.splice(0, u.length - ie);
|
|
362
|
+
}), f.observe({
|
|
363
|
+
type: "longtask",
|
|
364
|
+
buffered: !0
|
|
365
|
+
}));
|
|
366
|
+
} catch {
|
|
367
|
+
f = null;
|
|
368
|
+
}
|
|
369
|
+
let h = [], g = 0, v = null, y = [], b = !1, C = !1, w = () => Array.from(document.querySelectorAll(M)).filter((e) => A.has(e.getAttribute(N) ?? "")), k = (e) => {
|
|
370
|
+
let t = Array.from(document.querySelectorAll("[data-flemo-bar]")).filter((e) => A.has(e.getAttribute("data-flemo-bar-status") ?? "") || e.getAttribute("data-flemo-bar-riding") === "true").length, n = Array.from(document.querySelectorAll("[data-flemo-decorator]")).filter((e) => A.has(e.getAttribute(N) ?? "")).length, r = Array.from(document.querySelectorAll("[data-flemo-part-name]")).filter((e) => A.has(e.getAttribute(N) ?? "")).length;
|
|
371
|
+
return {
|
|
372
|
+
screens: e.length,
|
|
373
|
+
bars: t,
|
|
374
|
+
decorators: n,
|
|
375
|
+
parts: r
|
|
376
|
+
};
|
|
377
|
+
}, ae = (e) => {
|
|
378
|
+
let t = [];
|
|
379
|
+
for (let n of e) for (let e of Array.from(n.querySelectorAll("img"))) t.push(e);
|
|
380
|
+
return t;
|
|
381
|
+
}, H = (e) => {
|
|
382
|
+
let t = 0, n = 0;
|
|
383
|
+
for (let r of e.imagesTracked) r.complete && (t += 1, e.imagesHeld.has(r) || (n += 1));
|
|
384
|
+
return {
|
|
385
|
+
loadingAtStart: e.imagesLoadingAtStart,
|
|
386
|
+
addedDuringFlight: e.imagesAddedDuringFlight,
|
|
387
|
+
completedDuringFlight: t,
|
|
388
|
+
heldDuringFlight: e.imagesHeld.size,
|
|
389
|
+
completedUnheld: n
|
|
390
|
+
};
|
|
391
|
+
}, U = (e) => {
|
|
392
|
+
let t = v;
|
|
393
|
+
if (!(!t || t.imagesTracked.size >= R)) for (let n of Array.from(e)) {
|
|
394
|
+
if (!(n instanceof Element) || !t.elements.some((e) => e === n || e.contains(n))) continue;
|
|
395
|
+
let e = n instanceof HTMLImageElement ? [n] : Array.from(n.querySelectorAll("img"));
|
|
396
|
+
for (let n of e) if (!(n.complete || t.imagesTracked.has(n))) {
|
|
397
|
+
if (t.imagesTracked.size >= R) return;
|
|
398
|
+
t.imagesTracked.add(n), t.imagesAddedDuringFlight += 1;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}, W = (e) => {
|
|
402
|
+
for (let t of e.elements) for (let n of Array.from(t.querySelectorAll(`img[${L}]`))) e.imagesHeld.add(n);
|
|
403
|
+
for (let t of e.imagesTracked) t.hasAttribute(L) && e.imagesHeld.add(t);
|
|
404
|
+
}, G = (e, t) => {
|
|
405
|
+
e.releasedFrames += 1;
|
|
406
|
+
let n = !1;
|
|
407
|
+
for (let t of e.elements) {
|
|
408
|
+
let r = e.clocks.get(t);
|
|
409
|
+
if (r) {
|
|
410
|
+
r.playState === "paused" && (e.pausedAfterRelease = !0);
|
|
411
|
+
let i = typeof r.currentTime == "number" ? r.currentTime : null;
|
|
412
|
+
if (i !== null) {
|
|
413
|
+
let r = e.lastClock.get(t);
|
|
414
|
+
r !== void 0 && i !== r && (n = !0), e.lastClock.set(t, i);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
let i = t.style;
|
|
418
|
+
if (i && i.animation !== "") {
|
|
419
|
+
let r = `${i.transform}/${i.opacity}`;
|
|
420
|
+
e.lastPose.get(t) !== r && (n = !0);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (!(e.releasedFrames < re)) {
|
|
424
|
+
if (n) {
|
|
425
|
+
e.stallRunMs = 0;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
e.stalledFrames += 1, e.stallRunMs += t, e.stallRunMs > e.longestStallMs && (e.longestStallMs = e.stallRunMs);
|
|
429
|
+
}
|
|
430
|
+
}, K = (e) => {
|
|
431
|
+
for (let t of e.elements) {
|
|
432
|
+
let n = t.style, r = t.getAnimations, i = e.clocks.get(t);
|
|
433
|
+
if (i !== void 0 && i.playState !== "finished") {
|
|
434
|
+
if (i.playState === "running" && (e.evidence.compiledAnimation = !0), n && n.animation !== "") {
|
|
435
|
+
e.evidence.playerSuppression = !0;
|
|
436
|
+
let r = `${n.transform}/${n.opacity}`, i = e.lastPose.get(t);
|
|
437
|
+
i !== void 0 && i !== r && (e.evidence.playerAdvance = !0), e.lastPose.set(t, r);
|
|
438
|
+
}
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
if (typeof r == "function") try {
|
|
442
|
+
for (let n of r.call(t)) {
|
|
443
|
+
let r = n.animationName;
|
|
444
|
+
typeof r == "string" && r.startsWith("flemo-") && (e.clocks.set(t, n), n.playState === "running" && (e.evidence.compiledAnimation = !0));
|
|
445
|
+
}
|
|
446
|
+
} catch {}
|
|
447
|
+
if (n && n.animation !== "") {
|
|
448
|
+
e.evidence.playerSuppression = !0;
|
|
449
|
+
let r = `${n.transform}/${n.opacity}`, i = e.lastPose.get(t);
|
|
450
|
+
i !== void 0 && i !== r && (e.evidence.playerAdvance = !0), e.lastPose.set(t, r);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}, q = (e) => e.elements.some((e) => {
|
|
454
|
+
let t = e.getAttribute(P);
|
|
455
|
+
return t !== null && j.has(t);
|
|
456
|
+
}), J = () => {
|
|
457
|
+
let e = v;
|
|
458
|
+
if (!e || b) return;
|
|
459
|
+
let t = performance.now();
|
|
460
|
+
if (e.lastFrameAt !== null && e.heldGaps.length + e.releasedGaps.length < I) {
|
|
461
|
+
let n = t - e.lastFrameAt, r = q(e);
|
|
462
|
+
(r ? e.heldGaps : e.releasedGaps).push(n), r || (G(e, n), e.releasedFrames === 1 && W(e));
|
|
463
|
+
}
|
|
464
|
+
if (e.lastFrameAt = t, K(e), t - e.t0Ms > 1e4) {
|
|
465
|
+
y = [...e.elements], le(t, Y(e));
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
e.rafId = requestAnimationFrame(J);
|
|
469
|
+
}, Y = (e) => {
|
|
470
|
+
let t = /* @__PURE__ */ new Set();
|
|
471
|
+
for (let n of e.elements) {
|
|
472
|
+
let e = n.getAttribute(N) ?? "";
|
|
473
|
+
A.has(e) && t.add(e);
|
|
474
|
+
}
|
|
475
|
+
return [...t];
|
|
476
|
+
}, X = (e) => {
|
|
477
|
+
let t = performance.now();
|
|
478
|
+
g += 1;
|
|
479
|
+
let n = e.find((e) => e.getAttribute(te) === "true") ?? e[0], r = O(n.getAttribute(N) ?? "") ?? "PUSH", i = null;
|
|
480
|
+
for (let t of e) {
|
|
481
|
+
let e = t.getAttribute(P);
|
|
482
|
+
if (e !== null && j.has(e)) {
|
|
483
|
+
i = e;
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
v = {
|
|
488
|
+
id: `flight-${g}`,
|
|
489
|
+
kind: r,
|
|
490
|
+
routerId: n.getAttribute("data-flemo-router") ?? void 0,
|
|
491
|
+
t0Ms: t,
|
|
492
|
+
t0Iso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
493
|
+
elements: [...e],
|
|
494
|
+
participants: k(e),
|
|
495
|
+
holdKind: i,
|
|
496
|
+
holdReleasedAtMs: null,
|
|
497
|
+
playerGapStartIndex: V().__flemoPlayerGaps?.length ?? 0,
|
|
498
|
+
heldGaps: [],
|
|
499
|
+
releasedGaps: [],
|
|
500
|
+
lastFrameAt: null,
|
|
501
|
+
evidence: {
|
|
502
|
+
compiledAnimation: !1,
|
|
503
|
+
playerSuppression: !1,
|
|
504
|
+
playerAdvance: !1
|
|
505
|
+
},
|
|
506
|
+
lastPose: /* @__PURE__ */ new Map(),
|
|
507
|
+
clocks: /* @__PURE__ */ new Map(),
|
|
508
|
+
lastClock: /* @__PURE__ */ new Map(),
|
|
509
|
+
releasedFrames: 0,
|
|
510
|
+
stalledFrames: 0,
|
|
511
|
+
stallRunMs: 0,
|
|
512
|
+
longestStallMs: 0,
|
|
513
|
+
pausedAfterRelease: !1,
|
|
514
|
+
holdReassertedAtMs: null,
|
|
515
|
+
imagesTracked: new Set(ae(e).filter((e) => !e.complete)),
|
|
516
|
+
imagesLoadingAtStart: 0,
|
|
517
|
+
imagesAddedDuringFlight: 0,
|
|
518
|
+
imagesHeld: /* @__PURE__ */ new Set(),
|
|
519
|
+
rafId: null
|
|
520
|
+
}, v.imagesLoadingAtStart = v.imagesTracked.size, K(v), v.rafId = requestAnimationFrame(J);
|
|
521
|
+
}, oe = (e, t) => {
|
|
522
|
+
let n = F, r = () => {
|
|
523
|
+
if (!b) {
|
|
524
|
+
if (--n, n > 0) {
|
|
525
|
+
requestAnimationFrame(r);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
ce(e, t);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
requestAnimationFrame(r);
|
|
532
|
+
}, se = () => {
|
|
533
|
+
if (v !== null || w().length > 0) return [];
|
|
534
|
+
let e = [];
|
|
535
|
+
for (let [t, n] of [[L, "image reveal hold"], [ne, "arrival hold"]]) {
|
|
536
|
+
let r = document.querySelectorAll(`[${t}]`).length;
|
|
537
|
+
r > 0 && e.push(`${r} × ${n} (${t}) still marked at rest`);
|
|
538
|
+
}
|
|
539
|
+
return e;
|
|
540
|
+
}, ce = (e, t) => {
|
|
541
|
+
let n = [], r = !1, i = window.visualViewport?.width ?? window.innerWidth ?? 0;
|
|
542
|
+
t.forEach((e, t) => {
|
|
543
|
+
if (!(e instanceof HTMLElement) || !e.isConnected) return;
|
|
544
|
+
let a = "", o = "";
|
|
545
|
+
try {
|
|
546
|
+
let t = getComputedStyle(e);
|
|
547
|
+
a = t.transform ?? "", o = t.display ?? "";
|
|
548
|
+
} catch {}
|
|
549
|
+
if (o === "none") return;
|
|
550
|
+
let s = e.getAttribute(te) === "true", c = `screen[${t}]${s ? " (active)" : ""}`;
|
|
551
|
+
if (e.style.transform !== "" && e.style.transform !== "none" && n.push(`${c} transform=${e.style.transform}`), e.style.opacity !== "" && e.style.opacity !== "1" && n.push(`${c} opacity=${e.style.opacity}`), s && e.getAttribute(N) === "COMPLETED" && i > 0) {
|
|
552
|
+
let e = ee(a);
|
|
553
|
+
e !== null && Math.abs(e) >= i * .5 && (r = !0);
|
|
554
|
+
}
|
|
555
|
+
}), e.landing.residualInlineTransforms = n, e.landing.offViewportAtRest = r, e.landing.orphanedHolds = se();
|
|
556
|
+
}, le = (e, t) => {
|
|
557
|
+
let i = v;
|
|
558
|
+
if (!i) return;
|
|
559
|
+
W(i), v = null, i.rafId !== null && cancelAnimationFrame(i.rafId);
|
|
560
|
+
let a = E((V().__flemoPlayerGaps ?? []).slice(i.playerGapStartIndex)), o = {
|
|
561
|
+
id: i.id,
|
|
562
|
+
...i.routerId === void 0 ? {} : { routerId: i.routerId },
|
|
563
|
+
kind: i.kind,
|
|
564
|
+
t0: {
|
|
565
|
+
ms: z(i.t0Ms),
|
|
566
|
+
iso: i.t0Iso
|
|
567
|
+
},
|
|
568
|
+
t1: {
|
|
569
|
+
ms: z(e),
|
|
570
|
+
iso: (/* @__PURE__ */ new Date()).toISOString()
|
|
571
|
+
},
|
|
572
|
+
durationMs: z(e - i.t0Ms),
|
|
573
|
+
driver: D(i.evidence),
|
|
574
|
+
participants: i.participants,
|
|
575
|
+
holds: {
|
|
576
|
+
kind: i.holdKind,
|
|
577
|
+
releasedAtMs: i.holdReleasedAtMs
|
|
578
|
+
},
|
|
579
|
+
frameSamples: T(i.heldGaps, i.releasedGaps),
|
|
580
|
+
motion: {
|
|
581
|
+
sampledFrames: i.releasedFrames,
|
|
582
|
+
stalledFrames: i.stalledFrames,
|
|
583
|
+
longestStallMs: z(i.longestStallMs),
|
|
584
|
+
pausedAfterRelease: i.pausedAfterRelease,
|
|
585
|
+
holdReassertedAtMs: i.holdReassertedAtMs
|
|
586
|
+
},
|
|
587
|
+
images: H(i),
|
|
588
|
+
...a ? { playerGaps: a } : {},
|
|
589
|
+
longTasks: [],
|
|
590
|
+
holdLongTasks: [],
|
|
591
|
+
landing: {
|
|
592
|
+
residualInlineTransforms: [],
|
|
593
|
+
offViewportAtRest: !1,
|
|
594
|
+
stuckStatuses: t,
|
|
595
|
+
orphanedHolds: []
|
|
596
|
+
},
|
|
597
|
+
anomalies: []
|
|
598
|
+
};
|
|
599
|
+
h.push(o), h.length > n && h.splice(0, h.length - n), t.length === 0 && oe(o, i.elements), r && console.info(`[flemo devtools] ${o.id} ${o.kind} driver=${o.driver} ${o.durationMs}ms screens=${o.participants.screens}`);
|
|
600
|
+
}, ue = (e) => {
|
|
601
|
+
let t = v;
|
|
602
|
+
if (!t || !(e.target instanceof Element)) return;
|
|
603
|
+
let n = e.target.getAttribute(P);
|
|
604
|
+
n !== null && j.has(n) && t.holdKind === null && (t.holdKind = n), n !== null && j.has(n) && t.holdReleasedAtMs !== null && t.holdReassertedAtMs === null && (t.holdReassertedAtMs = z(performance.now() - t.t0Ms)), (n === "false" || n === null) && e.oldValue !== null && j.has(e.oldValue) && t.holdReleasedAtMs === null && !q(t) && (t.holdReleasedAtMs = z(performance.now() - t.t0Ms));
|
|
605
|
+
}, de = () => {
|
|
606
|
+
let e = w();
|
|
607
|
+
if (y.length > 0) {
|
|
608
|
+
if (e.some((e) => y.includes(e))) return;
|
|
609
|
+
y = [];
|
|
610
|
+
}
|
|
611
|
+
if (!v && e.length > 0) {
|
|
612
|
+
X(e);
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
if (v && e.length === 0) {
|
|
616
|
+
le(performance.now(), []);
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
if (v) for (let t of e) v.elements.includes(t) || (v.elements.push(t), U(t.querySelectorAll("img")), v.participants = k(v.elements));
|
|
620
|
+
}, Z = null, Q = null, $ = () => {
|
|
621
|
+
let e = document.documentElement;
|
|
622
|
+
if (!e) return !1;
|
|
623
|
+
let t = new MutationObserver((e) => {
|
|
624
|
+
if (!b) {
|
|
625
|
+
for (let t of e) t.type === "attributes" && t.attributeName === P ? ue(t) : t.type === "childList" && t.addedNodes.length > 0 && U(t.addedNodes);
|
|
626
|
+
de();
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
try {
|
|
630
|
+
t.observe(e, {
|
|
631
|
+
subtree: !0,
|
|
632
|
+
childList: !0,
|
|
633
|
+
attributes: !0,
|
|
634
|
+
attributeOldValue: !0,
|
|
635
|
+
attributeFilter: [
|
|
636
|
+
N,
|
|
637
|
+
te,
|
|
638
|
+
P
|
|
639
|
+
]
|
|
640
|
+
});
|
|
641
|
+
} catch {
|
|
642
|
+
return !1;
|
|
643
|
+
}
|
|
644
|
+
return Z = t, de(), !0;
|
|
645
|
+
};
|
|
646
|
+
if (!$()) {
|
|
647
|
+
let e = () => {
|
|
648
|
+
Q = null, b || $();
|
|
649
|
+
};
|
|
650
|
+
Q = e, document.addEventListener("DOMContentLoaded", e, { once: !0 });
|
|
651
|
+
}
|
|
652
|
+
let fe = (e) => {
|
|
653
|
+
let t = u.filter((t) => t.startMs + t.durationMs >= e.t0.ms - 120 && t.startMs <= e.t1.ms), n = e.holds.kind === null ? e.t0.ms : e.holds.releasedAtMs === null ? e.t1.ms : e.t0.ms + e.holds.releasedAtMs;
|
|
654
|
+
return {
|
|
655
|
+
released: t.filter((e) => e.startMs + e.durationMs > n),
|
|
656
|
+
held: t.filter((e) => e.startMs + e.durationMs <= n)
|
|
657
|
+
};
|
|
658
|
+
}, pe = () => {
|
|
659
|
+
let e = performance.now(), n = h.map((e) => {
|
|
660
|
+
let t = fe(e), n = {
|
|
661
|
+
...e,
|
|
662
|
+
longTasks: t.released,
|
|
663
|
+
holdLongTasks: t.held,
|
|
664
|
+
landing: {
|
|
665
|
+
residualInlineTransforms: [...e.landing.residualInlineTransforms],
|
|
666
|
+
offViewportAtRest: e.landing.offViewportAtRest,
|
|
667
|
+
stuckStatuses: [...e.landing.stuckStatuses],
|
|
668
|
+
orphanedHolds: [...e.landing.orphanedHolds]
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
return n.anomalies = a({
|
|
672
|
+
t0Ms: n.t0.ms,
|
|
673
|
+
t1Ms: n.t1.ms,
|
|
674
|
+
driver: n.driver,
|
|
675
|
+
frameSamples: n.frameSamples,
|
|
676
|
+
playerGaps: n.playerGaps ?? null,
|
|
677
|
+
longTasks: n.longTasks,
|
|
678
|
+
holdLongTasks: n.holdLongTasks,
|
|
679
|
+
releasedAtMs: n.holds.releasedAtMs,
|
|
680
|
+
landing: n.landing,
|
|
681
|
+
motion: n.motion,
|
|
682
|
+
images: n.images
|
|
683
|
+
}), n;
|
|
684
|
+
}), r = v;
|
|
685
|
+
if (!r) return n;
|
|
686
|
+
let i = e - r.t0Ms > t, o = {
|
|
687
|
+
id: `${r.id} (in flight)`,
|
|
688
|
+
...r.routerId === void 0 ? {} : { routerId: r.routerId },
|
|
689
|
+
kind: r.kind,
|
|
690
|
+
t0: {
|
|
691
|
+
ms: z(r.t0Ms),
|
|
692
|
+
iso: r.t0Iso
|
|
693
|
+
},
|
|
694
|
+
t1: {
|
|
695
|
+
ms: z(e),
|
|
696
|
+
iso: (/* @__PURE__ */ new Date()).toISOString()
|
|
697
|
+
},
|
|
698
|
+
durationMs: z(e - r.t0Ms),
|
|
699
|
+
driver: D(r.evidence),
|
|
700
|
+
participants: r.participants,
|
|
701
|
+
holds: {
|
|
702
|
+
kind: r.holdKind,
|
|
703
|
+
releasedAtMs: r.holdReleasedAtMs
|
|
704
|
+
},
|
|
705
|
+
frameSamples: T(r.heldGaps, r.releasedGaps),
|
|
706
|
+
motion: {
|
|
707
|
+
sampledFrames: r.releasedFrames,
|
|
708
|
+
stalledFrames: r.stalledFrames,
|
|
709
|
+
longestStallMs: z(r.longestStallMs),
|
|
710
|
+
pausedAfterRelease: r.pausedAfterRelease,
|
|
711
|
+
holdReassertedAtMs: r.holdReassertedAtMs
|
|
712
|
+
},
|
|
713
|
+
images: H(r),
|
|
714
|
+
longTasks: [],
|
|
715
|
+
holdLongTasks: [],
|
|
716
|
+
landing: {
|
|
717
|
+
residualInlineTransforms: [],
|
|
718
|
+
offViewportAtRest: !1,
|
|
719
|
+
stuckStatuses: i ? Y(r) : [],
|
|
720
|
+
orphanedHolds: []
|
|
721
|
+
},
|
|
722
|
+
anomalies: []
|
|
723
|
+
}, s = fe(o);
|
|
724
|
+
return o.longTasks = s.released, o.holdLongTasks = s.held, o.anomalies = a({
|
|
725
|
+
t0Ms: o.t0.ms,
|
|
726
|
+
t1Ms: o.t1.ms,
|
|
727
|
+
driver: o.driver,
|
|
728
|
+
frameSamples: o.frameSamples,
|
|
729
|
+
playerGaps: o.playerGaps ?? null,
|
|
730
|
+
longTasks: o.longTasks,
|
|
731
|
+
holdLongTasks: o.holdLongTasks,
|
|
732
|
+
releasedAtMs: o.holds.releasedAtMs,
|
|
733
|
+
landing: o.landing,
|
|
734
|
+
motion: o.motion,
|
|
735
|
+
images: o.images
|
|
736
|
+
}), [...n, o];
|
|
737
|
+
}, me = (e, t) => {
|
|
738
|
+
try {
|
|
739
|
+
return (e === "session" ? sessionStorage : localStorage).getItem(t);
|
|
740
|
+
} catch {
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
}, he = () => {
|
|
744
|
+
let e = x(), t = { ...e };
|
|
745
|
+
for (let [n, r] of Object.entries(c)) n in e || (t[`${n} (at attach, since cleared)`] = r);
|
|
746
|
+
let n = S(t), r = p(l), i = me("session", "flemo:motion-driver-force"), a = i === null ? c["flemo:motion-driver-force"] ?? null : null, u = pe(), d = v;
|
|
747
|
+
return {
|
|
748
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
749
|
+
version: "2",
|
|
750
|
+
environment: r,
|
|
751
|
+
overrides: {
|
|
752
|
+
active: t,
|
|
753
|
+
warnings: n
|
|
754
|
+
},
|
|
755
|
+
driverPolicy: {
|
|
756
|
+
demotion: me("local", "flemo:motion-driver"),
|
|
757
|
+
forcePin: i
|
|
758
|
+
},
|
|
759
|
+
flights: u,
|
|
760
|
+
anomalies: o({
|
|
761
|
+
forcePin: i,
|
|
762
|
+
legacyLocalForcePin: t[_] ?? null,
|
|
763
|
+
clearedForcePin: a,
|
|
764
|
+
emulationSuspected: r.emulationSuspected,
|
|
765
|
+
platform: r.platform,
|
|
766
|
+
stuckFlightOpen: d !== null && performance.now() - d.t0Ms > 1e4,
|
|
767
|
+
flightAnomalies: u.map((e) => e.anomalies)
|
|
768
|
+
}),
|
|
769
|
+
blindSpots: [...s],
|
|
770
|
+
judgingProtocol: [...m]
|
|
771
|
+
};
|
|
772
|
+
}, ge = () => {
|
|
773
|
+
if (!b) {
|
|
774
|
+
if (b = !0, Z?.disconnect(), Q !== null && (document.removeEventListener("DOMContentLoaded", Q), Q = null), f?.disconnect(), v?.rafId != null && cancelAnimationFrame(v.rafId), v = null, C) {
|
|
775
|
+
let e = V();
|
|
776
|
+
e.flemo?.__flemoDevtools === !0 && delete e.flemo;
|
|
777
|
+
}
|
|
778
|
+
B = null;
|
|
779
|
+
}
|
|
780
|
+
}, _e = {
|
|
781
|
+
detach: ge,
|
|
782
|
+
report: he
|
|
783
|
+
};
|
|
784
|
+
if (i) {
|
|
785
|
+
let e = V(), t = e.flemo;
|
|
786
|
+
(t === void 0 || t?.__flemoDevtools === !0) && (e.flemo = {
|
|
787
|
+
__flemoDevtools: !0,
|
|
788
|
+
report: he,
|
|
789
|
+
flights: pe,
|
|
790
|
+
detach: ge
|
|
791
|
+
}, C = !0);
|
|
792
|
+
}
|
|
793
|
+
return B = _e, _e;
|
|
794
|
+
}, H = "http://www.w3.org/2000/svg", U = (e, t, n) => {
|
|
795
|
+
let r = document.createElement(e);
|
|
796
|
+
return t !== void 0 && (r.className = t), n !== void 0 && (r.textContent = n), r;
|
|
797
|
+
}, W = (e, t) => {
|
|
798
|
+
let n = document.createElementNS(H, e);
|
|
799
|
+
for (let [e, r] of Object.entries(t)) n.setAttribute(e, r);
|
|
800
|
+
return n;
|
|
801
|
+
}, G = (e) => {
|
|
802
|
+
for (; e.firstChild !== null;) e.removeChild(e.firstChild);
|
|
803
|
+
}, K = (e, t) => {
|
|
804
|
+
e.textContent !== t && (e.textContent = t);
|
|
805
|
+
}, q = (e) => e == null || e === "" ? "—" : String(e), J = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e)}ms` : "—", Y = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e * 10) / 10}ms` : "—", X = (e) => typeof e == "number" && Number.isFinite(e) ? String(e) : "—", oe = (e) => e === !0 ? "yes" : e === !1 ? "no" : "—", se = (e) => {
|
|
806
|
+
let t = e?.environment;
|
|
807
|
+
if (!t) return "—";
|
|
808
|
+
let n = t.viewport, r = n && typeof n.width == "number" && typeof n.height == "number" ? `${Math.round(n.width)}×${Math.round(n.height)}` : "—";
|
|
809
|
+
return [
|
|
810
|
+
q(t.engine),
|
|
811
|
+
`dpr ${q(t.devicePixelRatio)}`,
|
|
812
|
+
r,
|
|
813
|
+
`rAF ${Y(t.rafCadence?.medianGapMs)}`
|
|
814
|
+
].join(" · ");
|
|
815
|
+
}, ce = (e, t) => `${t ?? ""}#${e.map((e) => `${e?.id ?? ""}|${e?.kind ?? ""}|${e?.driver ?? ""}|${Math.round(e?.durationMs ?? 0)}|${e?.participants?.screens ?? 0}|${e?.anomalies?.length ?? 0}`).join(",")}`, le = (e) => {
|
|
816
|
+
let t = e?.released?.gaps;
|
|
817
|
+
if (!Array.isArray(t)) return null;
|
|
818
|
+
let n = t.filter((e) => typeof e == "number" && Number.isFinite(e));
|
|
819
|
+
return n.length >= 2 ? n : null;
|
|
820
|
+
}, ue = "\n:host {\n all: initial;\n color-scheme: dark;\n}\n* { box-sizing: border-box; }\n.root {\n --bg: #14161a;\n --bg-soft: #1b1e24;\n --line: #2b3038;\n --fg: #e6e9ef;\n --fg-dim: #99a1b0;\n --accent: #7cc4ff;\n --warn: #ffb454;\n --bad: #ff6b6b;\n font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n color: var(--fg);\n}\n@media (prefers-color-scheme: light) {\n .root {\n --bg: #ffffff;\n --bg-soft: #f4f6f9;\n --line: #dde1e8;\n --fg: #1a1d22;\n --fg-dim: #5c6472;\n --accent: #0b6bcb;\n --warn: #a35a00;\n --bad: #c2261f;\n }\n}\n.toggle {\n position: fixed;\n bottom: 12px;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n padding: 6px 10px;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--bg);\n color: var(--fg);\n font: inherit;\n cursor: pointer;\n}\n.toggle:hover { background: var(--bg-soft); }\n.toggle[data-corner=\"bottom-right\"] { right: 12px; }\n.toggle[data-corner=\"bottom-left\"] { left: 12px; }\n.mark { font-weight: 700; letter-spacing: 0.04em; }\n.count {\n padding: 0 6px;\n border-radius: 999px;\n background: var(--bg-soft);\n color: var(--fg-dim);\n}\n.dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--bad);\n}\n.dot[hidden] { display: none; }\n.panel {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2147482999;\n display: flex;\n flex-direction: column;\n max-width: 100%;\n border-top: 1px solid var(--line);\n background: var(--bg);\n overflow: hidden;\n}\n.panel[hidden] { display: none; }\n.grip {\n flex: 0 0 6px;\n height: 6px;\n background: var(--line);\n cursor: ns-resize;\n touch-action: none;\n}\n.head {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n border-bottom: 1px solid var(--line);\n}\n.env { color: var(--fg-dim); }\n.spacer { flex: 1 1 auto; }\n.act {\n padding: 4px 8px;\n border: 1px solid var(--line);\n border-radius: 4px;\n background: var(--bg-soft);\n color: var(--fg);\n font: inherit;\n cursor: pointer;\n}\n.chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n flex: 1 1 100%;\n}\n.chips:empty { display: none; }\n.chip {\n padding: 2px 8px;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--bg-soft);\n color: var(--fg-dim);\n max-width: 100%;\n overflow-wrap: anywhere;\n}\n.chip.warn { border-color: var(--warn); color: var(--warn); }\n.chip.bad { border-color: var(--bad); color: var(--bad); }\n.body {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n}\n.list {\n flex: 0 0 40%;\n max-width: 340px;\n min-width: 180px;\n overflow: auto;\n border-right: 1px solid var(--line);\n}\n.row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 6px 10px;\n border: 0;\n border-bottom: 1px solid var(--line);\n background: none;\n color: var(--fg);\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.row[aria-selected=\"true\"] { background: var(--bg-soft); }\n.row .kind { font-weight: 700; }\n.row .driver { color: var(--accent); }\n.row .dur, .row .screens { color: var(--fg-dim); }\n.row .n {\n margin-left: auto;\n padding: 0 6px;\n border-radius: 999px;\n background: var(--bg-soft);\n color: var(--fg-dim);\n}\n.row .n.bad { background: var(--bad); color: #fff; }\n.detail { flex: 1 1 auto; overflow: auto; padding: 8px 10px; }\n.section { margin: 0 0 10px; }\n.section > h2 {\n margin: 0 0 4px;\n font: inherit;\n font-weight: 700;\n color: var(--fg-dim);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.kv { display: flex; gap: 8px; }\n.kv > .k { flex: 0 0 34%; max-width: 180px; color: var(--fg-dim); }\n.kv > .v { flex: 1 1 auto; overflow-wrap: anywhere; }\n/* A value that IS the finding — a stall, a re-asserted hold, an orphan. */\n.kv > .v.bad { color: var(--bad); }\n.li { overflow-wrap: anywhere; }\n.li.bad { color: var(--bad); }\n.dim { color: var(--fg-dim); }\n.spark { display: block; width: 100%; height: 28px; }\n.foot { border-top: 1px solid var(--line); padding: 6px 10px; color: var(--fg-dim); }\n.foot summary { cursor: pointer; }\n.foot .li { margin-top: 4px; }\n", de = 48, Z = (e, t, n, r) => {
|
|
821
|
+
let i = U("div", "kv");
|
|
822
|
+
i.appendChild(U("span", "k", t)), i.appendChild(U("span", r ? `v ${r}` : "v", n)), e.appendChild(i);
|
|
823
|
+
}, Q = (e, t) => {
|
|
824
|
+
let n = U("section", "section");
|
|
825
|
+
return n.appendChild(U("h2", void 0, t)), e.appendChild(n), n;
|
|
826
|
+
}, $ = (e, t, n = "li") => {
|
|
827
|
+
e.appendChild(U("div", n, t));
|
|
828
|
+
}, fe = (e, t) => {
|
|
829
|
+
G(e);
|
|
830
|
+
for (let n of t?.overrides?.warnings ?? []) e.appendChild(U("span", "chip warn", q(n)));
|
|
831
|
+
for (let n of t?.anomalies ?? []) e.appendChild(U("span", "chip bad", q(n)));
|
|
832
|
+
for (let [n, r] of Object.entries(t?.overrides?.active ?? {})) e.appendChild(U("span", "chip", `${n}=${String(r)}`));
|
|
833
|
+
}, pe = (e, t, n, r) => {
|
|
834
|
+
if (G(e), t.length === 0) {
|
|
835
|
+
$(e, "no flights recorded yet — navigate once", "li dim");
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
for (let i = t.length - 1; i >= 0; --i) {
|
|
839
|
+
let a = t[i], o = q(a?.id), s = U("button", "row");
|
|
840
|
+
s.type = "button", s.setAttribute("data-flight-id", o), s.setAttribute("aria-selected", String(o === n)), s.appendChild(U("span", "kind", q(a?.kind))), s.appendChild(U("span", "driver", q(a?.driver))), s.appendChild(U("span", "dur", J(a?.durationMs))), s.appendChild(U("span", "screens", `${X(a?.participants?.screens)} scr`));
|
|
841
|
+
let c = a?.anomalies?.length ?? 0;
|
|
842
|
+
s.appendChild(U("span", c > 0 ? "n bad" : "n", String(c))), s.addEventListener("click", () => r(o)), e.appendChild(s);
|
|
843
|
+
}
|
|
844
|
+
}, me = (e, t, n) => {
|
|
845
|
+
if (!n) {
|
|
846
|
+
Z(e, t, "—");
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
let r = [
|
|
850
|
+
`${X(n.count)} frames`,
|
|
851
|
+
`median ${Y(n.medianGapMs)}`,
|
|
852
|
+
`max ${Y(n.maxGapMs)}`
|
|
853
|
+
];
|
|
854
|
+
typeof n.over30Count == "number" && r.push(`>30ms ×${n.over30Count}`), Z(e, t, r.join(" · "));
|
|
855
|
+
}, he = (e) => {
|
|
856
|
+
let t = Math.max(...e), n = t > 0 ? t : 1, r = 100 / (e.length - 1), i = e.map((e, t) => `${Math.round(t * r * 10) / 10},${Math.round((27 - e / n * 26) * 10) / 10}`).join(" "), a = W("svg", {
|
|
857
|
+
class: "spark",
|
|
858
|
+
viewBox: "0 0 100 28",
|
|
859
|
+
preserveAspectRatio: "none",
|
|
860
|
+
"aria-hidden": "true"
|
|
861
|
+
});
|
|
862
|
+
return a.appendChild(W("polyline", {
|
|
863
|
+
points: i,
|
|
864
|
+
fill: "none",
|
|
865
|
+
stroke: "currentColor",
|
|
866
|
+
"stroke-width": "1",
|
|
867
|
+
"vector-effect": "non-scaling-stroke"
|
|
868
|
+
})), a;
|
|
869
|
+
}, ge = (e, t) => {
|
|
870
|
+
let n = t.longTasks ?? [], r = t.holdLongTasks ?? [];
|
|
871
|
+
if (n.length === 0 && r.length === 0) {
|
|
872
|
+
$(e, "none", "li dim");
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
let i = (e) => `${J(e?.startMs)} + ${J(e?.durationMs)}`;
|
|
876
|
+
for (let t of n) $(e, i(t), "li bad");
|
|
877
|
+
for (let t of r) $(e, `${i(t)} (absorbed by hold)`, "li dim");
|
|
878
|
+
}, _e = (e, t) => {
|
|
879
|
+
if (G(e), !t) {
|
|
880
|
+
$(e, "select a flight", "li dim");
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
let n = Q(e, "timing");
|
|
884
|
+
Z(n, "id", q(t.id)), Z(n, "kind / driver", `${q(t.kind)} · ${q(t.driver)}`), Z(n, "router", q(t.routerId)), Z(n, "t0", q(t.t0?.iso)), Z(n, "duration", J(t.durationMs)), Z(n, "participants", `${X(t.participants?.screens)} screens · ${X(t.participants?.bars)} bars · ${X(t.participants?.decorators)} decorators · ${X(t.participants?.parts)} parts`), Z(n, "hold", `${q(t.holds?.kind)} · released ${J(t.holds?.releasedAtMs)}`);
|
|
885
|
+
let r = Q(e, "frames");
|
|
886
|
+
me(r, "held (absorbed)", t.frameSamples?.held), me(r, "released (visible)", t.frameSamples?.released), t.playerGaps && Z(r, "player mirror", `max ${Y(t.playerGaps.maxMs)} · >30ms ×${X(t.playerGaps.over30Count)}`);
|
|
887
|
+
let i = le(t.frameSamples);
|
|
888
|
+
i && r.appendChild(he(i));
|
|
889
|
+
let a = Q(e, "motion (did it move)"), o = t.motion?.longestStallMs, s = t.motion?.holdReassertedAtMs;
|
|
890
|
+
Z(a, "released frames", X(t.motion?.sampledFrames)), Z(a, "stalled frames", X(t.motion?.stalledFrames), (t.motion?.stalledFrames ?? 0) > 0 ? "bad" : void 0), Z(a, "longest stall", J(o), (o ?? 0) >= de ? "bad" : void 0), Z(a, "paused after release", oe(t.motion?.pausedAfterRelease), t.motion?.pausedAfterRelease === !0 ? "bad" : void 0), Z(a, "hold re-asserted", s == null ? "no" : J(s), typeof s == "number" ? "bad" : void 0);
|
|
891
|
+
let c = Q(e, "images"), l = t.images?.completedDuringFlight ?? 0, u = t.images?.heldDuringFlight ?? 0, d = t.images?.completedUnheld, f = typeof d == "number" ? d > 0 : l > u;
|
|
892
|
+
Z(c, "loading at t0", X(t.images?.loadingAtStart)), Z(c, "added mid-flight", X(t.images?.addedDuringFlight)), Z(c, "completed mid-flight", X(t.images?.completedDuringFlight), f ? "bad" : void 0), Z(c, "held by the engine", X(t.images?.heldDuringFlight)), Z(c, "completed without hold", X(d), f ? "bad" : void 0), ge(Q(e, "long tasks"), t);
|
|
893
|
+
let p = Q(e, "landing"), m = t.landing?.residualInlineTransforms ?? [];
|
|
894
|
+
if (m.length === 0) Z(p, "inline residue", "clean");
|
|
895
|
+
else for (let e of m) Z(p, "inline residue", q(e));
|
|
896
|
+
Z(p, "off-viewport at rest", oe(t.landing?.offViewportAtRest));
|
|
897
|
+
let h = t.landing?.stuckStatuses ?? [];
|
|
898
|
+
Z(p, "stuck statuses", h.length === 0 ? "none" : h.join(", "));
|
|
899
|
+
let g = t.landing?.orphanedHolds ?? [];
|
|
900
|
+
if (g.length === 0) Z(p, "orphaned holds", "none");
|
|
901
|
+
else for (let e of g) Z(p, "orphaned holds", q(e), "bad");
|
|
902
|
+
let _ = Q(e, "anomalies"), v = t.anomalies ?? [];
|
|
903
|
+
if (v.length === 0) {
|
|
904
|
+
$(_, "none", "li dim");
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
for (let e of v) $(_, q(e), "li bad");
|
|
908
|
+
}, ve = (e, t) => {
|
|
909
|
+
G(e);
|
|
910
|
+
for (let n of t ?? []) $(e, q(n));
|
|
911
|
+
}, ye = "[data-flemo-screen][data-flemo-status=\"PUSHING\"],[data-flemo-screen][data-flemo-status=\"POPPING\"],[data-flemo-screen][data-flemo-status=\"REPLACING\"]", be = "flemo:devtools-panel-height", xe = 320, Se = 2e3, Ce = 120, we = "Copy report JSON", Te = () => {}, Ee = null, De = (e = {}) => {
|
|
912
|
+
if (Ee) return Ee;
|
|
913
|
+
if (typeof document > "u") return { detach: Te };
|
|
914
|
+
let t = !1, n, r = window.flemo;
|
|
915
|
+
e.recorder ? n = e.recorder : r?.__flemoDevtools === !0 && typeof r.report == "function" ? n = {
|
|
916
|
+
report: r.report,
|
|
917
|
+
detach: Te
|
|
918
|
+
} : (n = ae(), t = !0);
|
|
919
|
+
let i = U("div");
|
|
920
|
+
i.setAttribute("data-flemo-devtools-panel", ""), i.style.position = "fixed", i.style.top = "0", i.style.left = "0", i.style.width = "0", i.style.height = "0", i.style.zIndex = "2147483000";
|
|
921
|
+
let a = i.attachShadow({ mode: "open" }), o = U("style");
|
|
922
|
+
o.textContent = ue, a.appendChild(o);
|
|
923
|
+
let s = U("div", "root");
|
|
924
|
+
a.appendChild(s);
|
|
925
|
+
let c = U("button", "toggle");
|
|
926
|
+
c.type = "button", c.setAttribute("data-corner", e.position ?? "bottom-right"), c.setAttribute("aria-label", "flemo devtools");
|
|
927
|
+
let l = U("span", "count", "0"), u = U("span", "dot");
|
|
928
|
+
u.hidden = !0, c.appendChild(U("span", "mark", "flemo")), c.appendChild(l), c.appendChild(u);
|
|
929
|
+
let d = U("section", "panel");
|
|
930
|
+
d.hidden = !0;
|
|
931
|
+
let f = U("div", "grip");
|
|
932
|
+
f.setAttribute("role", "separator"), f.setAttribute("aria-label", "Resize flemo devtools panel");
|
|
933
|
+
let p = U("header", "head"), m = U("div", "env", "—"), h = U("button", "act", we);
|
|
934
|
+
h.type = "button";
|
|
935
|
+
let g = U("button", "act", "Close");
|
|
936
|
+
g.type = "button";
|
|
937
|
+
let _ = U("button", "act", "Detach");
|
|
938
|
+
_.type = "button";
|
|
939
|
+
let v = U("div", "chips");
|
|
940
|
+
p.appendChild(m), p.appendChild(U("div", "spacer")), p.appendChild(h), p.appendChild(g), p.appendChild(_), p.appendChild(v);
|
|
941
|
+
let y = U("div", "body"), b = U("div", "list"), x = U("div", "detail");
|
|
942
|
+
y.appendChild(b), y.appendChild(x);
|
|
943
|
+
let S = U("div", "foot"), C = U("details");
|
|
944
|
+
C.appendChild(U("summary", void 0, "What this cannot see"));
|
|
945
|
+
let w = U("div");
|
|
946
|
+
C.appendChild(w), S.appendChild(C), d.appendChild(f), d.appendChild(p), d.appendChild(y), d.appendChild(S), s.appendChild(c), s.appendChild(d);
|
|
947
|
+
let T = !1, E = e.initialOpen === !0, D = null, O = "", ee = "", k = "", A = !1, j = 0, M = 0, N = (e) => Math.min(Math.max(e, Ce), Math.max(Ce, window.innerHeight * .9)), te = () => {
|
|
948
|
+
try {
|
|
949
|
+
let e = sessionStorage.getItem(be);
|
|
950
|
+
if (e === null) return null;
|
|
951
|
+
let t = Number.parseFloat(e);
|
|
952
|
+
return Number.isFinite(t) ? t : null;
|
|
953
|
+
} catch {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
}, P = (e) => {
|
|
957
|
+
try {
|
|
958
|
+
sessionStorage.setItem(be, String(Math.round(e)));
|
|
959
|
+
} catch {}
|
|
960
|
+
}, F = N(te() ?? window.innerHeight * .4);
|
|
961
|
+
d.style.height = `${Math.round(F)}px`;
|
|
962
|
+
let I = () => document.querySelector(ye) !== null, L = () => {
|
|
963
|
+
try {
|
|
964
|
+
return n.report();
|
|
965
|
+
} catch {
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
}, ne = (e) => {
|
|
969
|
+
e !== D && (D = e, R());
|
|
970
|
+
}, re = () => {
|
|
971
|
+
let e = L(), t = e?.flights ?? [];
|
|
972
|
+
K(l, String(t.length));
|
|
973
|
+
let n = t.some((e) => (e?.anomalies?.length ?? 0) > 0);
|
|
974
|
+
if (u.hidden = !n, d.hidden = !E, !E) return;
|
|
975
|
+
K(m, se(e));
|
|
976
|
+
let r = JSON.stringify([
|
|
977
|
+
e?.overrides?.warnings ?? [],
|
|
978
|
+
e?.anomalies ?? [],
|
|
979
|
+
e?.overrides?.active ?? {}
|
|
980
|
+
]);
|
|
981
|
+
r !== k && (k = r, fe(v, e)), D === null && t.length > 0 && (D = t[t.length - 1]?.id ?? null);
|
|
982
|
+
let i = ce(t, D);
|
|
983
|
+
i !== O && (O = i, pe(b, t, D, ne));
|
|
984
|
+
let a = t.find((e) => e?.id === D) ?? null, o = JSON.stringify(a);
|
|
985
|
+
o !== ee && (ee = o, _e(x, a)), A || (A = !0, ve(w, e?.blindSpots));
|
|
986
|
+
};
|
|
987
|
+
function R() {
|
|
988
|
+
T || I() || re();
|
|
989
|
+
}
|
|
990
|
+
function ie() {
|
|
991
|
+
j = 0, R(), z();
|
|
992
|
+
}
|
|
993
|
+
function z() {
|
|
994
|
+
j = window.setTimeout(ie, E ? xe : Se);
|
|
995
|
+
}
|
|
996
|
+
let B = () => {
|
|
997
|
+
window.clearTimeout(j), z();
|
|
998
|
+
}, V = (e) => {
|
|
999
|
+
E = e, B(), R();
|
|
1000
|
+
};
|
|
1001
|
+
c.addEventListener("click", () => V(!E)), g.addEventListener("click", () => V(!1)), _.addEventListener("click", () => Y());
|
|
1002
|
+
let H = () => {
|
|
1003
|
+
if (!T) {
|
|
1004
|
+
if (I()) {
|
|
1005
|
+
window.clearTimeout(M), M = window.setTimeout(H, xe);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
K(h, "Copied ✓"), window.clearTimeout(M), M = window.setTimeout(W, 1200);
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
function W() {
|
|
1012
|
+
if (I()) {
|
|
1013
|
+
M = window.setTimeout(W, xe);
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
M = 0, K(h, we);
|
|
1017
|
+
}
|
|
1018
|
+
let G = (e) => {
|
|
1019
|
+
if (T) return;
|
|
1020
|
+
if (I()) {
|
|
1021
|
+
window.clearTimeout(M), M = window.setTimeout(() => G(e), xe);
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
let t = U("textarea");
|
|
1025
|
+
t.value = e, t.setAttribute("aria-hidden", "true"), t.style.position = "fixed", t.style.opacity = "0", t.style.pointerEvents = "none", document.body.appendChild(t), t.select();
|
|
1026
|
+
let n = document;
|
|
1027
|
+
try {
|
|
1028
|
+
n.execCommand?.("copy");
|
|
1029
|
+
} catch {}
|
|
1030
|
+
t.remove(), H();
|
|
1031
|
+
};
|
|
1032
|
+
h.addEventListener("click", () => {
|
|
1033
|
+
let e = JSON.stringify(L(), null, 2), t = navigator.clipboard;
|
|
1034
|
+
if (t && typeof t.writeText == "function") {
|
|
1035
|
+
t.writeText(e).then(H, () => G(e));
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
G(e);
|
|
1039
|
+
});
|
|
1040
|
+
let q = (e) => {
|
|
1041
|
+
F = N(window.innerHeight - e.clientY), d.style.height = `${Math.round(F)}px`;
|
|
1042
|
+
}, J = () => {
|
|
1043
|
+
window.removeEventListener("pointermove", q), window.removeEventListener("pointerup", J), P(F);
|
|
1044
|
+
};
|
|
1045
|
+
f.addEventListener("pointerdown", (e) => {
|
|
1046
|
+
e.preventDefault(), window.addEventListener("pointermove", q), window.addEventListener("pointerup", J);
|
|
1047
|
+
});
|
|
1048
|
+
function Y() {
|
|
1049
|
+
T || (T = !0, window.clearTimeout(j), j = 0, window.clearTimeout(M), M = 0, window.removeEventListener("pointermove", q), window.removeEventListener("pointerup", J), i.remove(), t && n.detach(), Ee = null);
|
|
1050
|
+
}
|
|
1051
|
+
document.body.appendChild(i), R(), z();
|
|
1052
|
+
let X = { detach: Y };
|
|
1053
|
+
return Ee = X, X;
|
|
1054
|
+
};
|
|
1055
|
+
//#endregion
|
|
1056
|
+
export { s as BLIND_SPOTS, h as FLAG_REGISTRY, _ as LEGACY_LOCAL_PIN_KEY, e as LONG_GAP_MS, i as MID_FLIGHT_TASK_MS, n as OPENING_WINDOW_LEAD_MS, r as OPENING_WINDOW_TAIL_MS, k as REPORT_SCHEMA_VERSION, t as STUCK_STATUS_MS, De as attachDevtoolsPanel, ae as attachFlightRecorder, p as captureEnvironment, D as classifyDriver, T as computeFrameStats, w as computePhaseStats, E as computePlayerGapStats, a as deriveFlightAnomalies, S as deriveOverrideWarnings, o as deriveReportAnomalies, l as detectEngine, u as isEmulationSuspected, O as kindFromStatus, ee as parseTranslateX, d as sampleRafCadence, x as snapshotOverrides };
|