Skip to content

v1.4.0 #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ To assess Web Application implementation correctness and expedite issues discove
- Count `requestAnimationFrame` calls per second (CPS).
- If requested recursively - it reflects animation FPS.

- Detect `eval` function usage in runtime, as well as `setTimeout` and `setInterval` when called with a `string` callback instead of a `function`. By default - `off`, cause the fact of wrapping it, excludes the access to local scope variables from the `eval` script, and as a result, may brake the application if it does need it.
- Detect `eval` function usage in runtime, as well as `setTimeout` and `setInterval` when called with a `string` callback instead of a `function`.
- By default - `off`, cause the fact of wrapping it, excludes the access to local scope variables from the `eval` script, and as a result, may break the application if it does depend on it.

- Monitor Worker's instance behaviour, its methods and event handlers.

- Monitor mounted `video` and `audio` media elements in DOM.
- Present control panel with basic media functions.
Expand All @@ -56,6 +59,7 @@ To assess Web Application implementation correctness and expedite issues discove
- `cancelAnimationFrame`
- `requestIdleCallback`
- `cancelIdleCallback`
- `Worker`

</details>
<details>
Expand Down
13 changes: 5 additions & 8 deletions doc/issues.log.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@
### Issues, that could have been spotted during the development

- Timers with short delays unjustified for the use case, wasting CPU time.

- A ~10ms delay interval, from an old third-party library, constantly consuming approximately 10% of CPU solely to check if the window was resized.

- A 150ms delay interval, displaying time in `H:MM:SS` format (1 second precision); and displaying it via `innerHTML`.

- A bundled dependency library that utilizes the `eval` function, thereby preventing the removal of `unsafe-eval` from the `Content-Security-Policy` header.

- A bundled dependency library that utilizes the `eval` function, thereby preventing the removal of `unsafe-eval` from the `Content-Security-Policy` header.
- Code that uses `eval` with modern syntax to check if it's supported by browser (not throws exception).

- Dependency package that was bundled with webpack's config option [`devtool: 'eval'`](https://webpack.js.org/configuration/devtool/) or [`mode: 'development'`](https://webpack.js.org/configuration/mode/).

- A substantial number of hidden video elements in DOM stopped working, after Chrome unexpectedly limited them to 100 per domain (later the limit was lifted to 1000).
Expand All @@ -21,10 +17,11 @@

- `setTimeout`, `setInterval` are used to animate instead of `requestAnimationFrame`.

- `setTimeout` with dynamically computed delay value ends to be called with `NaN`.
- Observed on multiple sites `setTimeout` with dynamically computed delay value, ends to be called with `NaN`, `-Infinity`, `-31`...

- Hidden UI feature runs its logic in the background.

- Indirectly, discovered from the bursts of short timeouts, fired from `ResizeObserver` handler of invisible feature that appears to be: or for a power user only, or just partially deprecated.

- Animation still runs (plus network requests) in the background after a "paywall" fullscreen popup. Despite claiming "it's to conserve data bandwidth". CPU usage doesn't drop to 0%.

- Workers on loose.
- A Government Geo Science related site crashes under 2.25 hours, topping 4GB of RAM with 271 instances of the same Worker code.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.3.0",
"version": "1.4.0",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxQCaHgX3DkPnGmHr+rhWyPvYemxMhBbvulmj4RvEpAnGVprdPCUiHSY0jOcDn3vnU6zm8mR1mT3sdlYoUGikBIT19/Jf1iGlc2dySt2bmDQXlTrqllT/XB8HW/wruFej9waMw9yqtW1wOJtElxWnT11pzXkKeflH1Sh+//Jnplr577vOmWh9TU8JLJHS9WklPHJyXCCMGrg/0Sxqte5qWryE2yIm9375KGkKN4ZKjSIxaCg0qodhf5Ug9s2QD7/s5xt548gbEUm9LqQHkNoIH3KXuYOnLksJFxi7FDwhg+oXalsONr5eEvPjkwxYpMKJXfRSg8sB8N6cXLUfgLAKUwIDAQAB",
"name": "API Monitor",
"manifest_version": 3,
Expand Down
19 changes: 18 additions & 1 deletion public/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
color-scheme: light dark;
--bg: light-dark(rgb(100% 100% 100%), rgb(10% 10% 10%));
--bg-popover: light-dark(rgb(90%, 90%, 90%), rgb(20%, 20%, 20%));
--bg-invert: light-dark(rgb(10% 10% 10%), rgb(100% 100% 100%));
--bg-invert: light-dark(rgb(38% 38% 38%), rgb(62% 62% 62%));
--bg-table-even: light-dark(rgb(30% 30% 30% / 10%), rgb(100% 100% 100% / 8%));
--border: light-dark(rgb(0 0 0 / 35%), rgb(100% 100% 100% / 35%));
--text: light-dark(rgb(10% 10% 10%), rgb(100% 100% 100%));
Expand Down Expand Up @@ -95,6 +95,9 @@ th,
.w-full {
width: 100%;
}
.d-none {
display: none;
}
.divider {
width: 1px;
height: 100%;
Expand Down Expand Up @@ -204,3 +207,17 @@ th .icon {
.icon.-facts {
mask-image: url(img/facts.svg);
}
.scrolled-to {
animation: scrolledTo 0.256s alternate infinite;
}

@keyframes scrolledTo {
0% {
outline: 1px solid var(--attention);
outline-offset: -1px;
}
100% {
outline: 5px solid var(--attention);
outline-offset: -5px;
}
}
8 changes: 7 additions & 1 deletion src/api-monitor-cs-isolated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ Promise.all([loadLocalStorage(), loadSessionStorage()]).then(
windowPost({ msg: EMsg.START_OBSERVE });
}

portListen(windowPost);
portListen((o) => {
if (o.msg === EMsg.CONFIRM_INJECTION) {
runtimePost({ msg: EMsg.INJECTION_CONFIRMED });
} else {
windowPost(o);
}
});
windowListen(runtimePost);

onLocalStorageChange((config) => {
Expand Down
5 changes: 0 additions & 5 deletions src/api-monitor-cs-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { adjustTelemetryDelay, Timer } from './api/time.ts';
import {
applyConfig,
applySession,
cleanHistory,
collectMetrics,
onEachSecond,
runMediaCommand,
Expand Down Expand Up @@ -61,10 +60,6 @@ windowListen((o) => {
tick.stop();
eachSecond.stop();
originalMetrics = currentMetrics = null;
} else if (EMsg.RESET_WRAPPER_HISTORY === o.msg) {
originalMetrics = currentMetrics = null;
cleanHistory();
!tick.isPending() && tick.trigger();
} else if (EMsg.TIMER_COMMAND === o.msg) {
runTimerCommand(o.type, o.handler);
} else if (EMsg.MEDIA_COMMAND === o.msg) {
Expand Down
52 changes: 52 additions & 0 deletions src/api/Mean.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export class Mean {
samples = 0;
mean = 0;
min = Infinity;
max = -Infinity;
sosd = 0; // sum of squared deltas

reset() {
this.samples = 0;
this.mean = 0;
this.min = Infinity;
this.max = -Infinity;
this.sosd = 0;

return this;
}

add(value: number) {
++this.samples;

this.min = Math.min(this.min, value);
this.max = Math.max(this.max, value);

const delta = value - this.mean;
this.mean += delta / this.samples;
this.sosd += delta * (value - this.mean);

return this;
}

sampleVariance() {
return (this.samples > 1) ? this.sosd / (this.samples - 1) : 0;
}

sampleStdDev() {
return (this.samples > 1) ? Math.sqrt(this.sampleVariance()) : 0;
}

populationVariance() {
return (this.samples > 0) ? this.sosd / this.samples : 0;
}

populationStdDev() {
return (this.samples > 0) ? Math.sqrt(this.populationVariance()) : 0;
}

stdError() {
return (this.samples > 1)
? this.sampleStdDev() / Math.sqrt(this.samples)
: 0;
}
}
17 changes: 11 additions & 6 deletions src/api/communication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ export enum EMsg {
TELEMETRY_DELTA,
TELEMETRY_ACKNOWLEDGED,
MEDIA_COMMAND,
RESET_WRAPPER_HISTORY,
TIMER_COMMAND,
SESSION,
CONFIRM_INJECTION,
INJECTION_CONFIRMED,
}

export interface IMsgStartObserve {
Expand All @@ -120,9 +121,6 @@ export interface IMsgStartObserve {
export interface IMsgStopObserve {
msg: EMsg.STOP_OBSERVE;
}
export interface IMsgResetHistory {
msg: EMsg.RESET_WRAPPER_HISTORY;
}
export interface IMsgTimerCommand {
msg: EMsg.TIMER_COMMAND;
type: ETimerType;
Expand Down Expand Up @@ -159,15 +157,22 @@ export interface IMsgSession {
msg: EMsg.SESSION;
session: TSession;
}
export interface IMsgConfirmInjection {
msg: EMsg.CONFIRM_INJECTION;
}
export interface IMsgInjectionConfirmed {
msg: EMsg.INJECTION_CONFIRMED;
}
export type TMsgOptions =
| IMsgTelemetry
| IMsgTelemetryDelta
| IMsgTelemetryAcknowledged
| IMsgStartObserve
| IMsgStopObserve
| IMsgLoaded
| IMsgResetHistory
| IMsgTimerCommand
| IMsgConfig
| IMsgMediaCommand
| IMsgSession;
| IMsgSession
| IMsgConfirmInjection
| IMsgInjectionConfirmed;
2 changes: 0 additions & 2 deletions src/api/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ export const TELEMETRY_FREQUENCY_30PS = 33.3333333333; // ms
export const TELEMETRY_FREQUENCY_1PS = 1000; // ms
export const TIME_60FPS_SEC = 0.0166666666667; // s
export const TIME_60FPS_MS = 16.666666666666668;
export const VARIABLE_ANIMATION_THROTTLE = 3500; // eye blinking average frequency
export const SELF_TIME_MAX_GOOD = 13.333333333333332; // ms

// state native functions
export const setTimeout = /*@__PURE__*/ globalThis.setTimeout.bind(globalThis);
Expand Down
4 changes: 3 additions & 1 deletion src/api/storage/storage.local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import { CONFIG_VERSION, local } from './storage.ts';

type TPanelKey =
| 'callsSummary'
| 'eval'
| 'media'
| 'worker'
| 'eval'
| 'activeTimers'
| 'setTimeout'
| 'clearTimeout'
Expand Down Expand Up @@ -43,6 +44,7 @@ export const DEFAULT_PANELS: TPanel[] = [
{ key: 'callsSummary', label: 'Calls Summary', visible: false, wrap: null },
{ key: 'media', label: 'Media', visible: true, wrap: null },
{ key: 'activeTimers', label: 'Active Timers', visible: true, wrap: null },
{ key: 'worker', label: 'Worker', visible: true, wrap: true },
{ key: 'eval', label: 'eval', visible: true, wrap: false },
{ key: 'setTimeout', label: 'setTimeout History', visible: true, wrap: true },
{
Expand Down
2 changes: 1 addition & 1 deletion src/api/storage/storage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const CONFIG_VERSION = '2025-04-25';
export const CONFIG_VERSION = '2025-06-28';
export const SESSION_VERSION = '2025-04-25';

export const local = /*@__PURE__*/ (() => {
Expand Down
6 changes: 5 additions & 1 deletion src/view/App.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
<script lang="ts">
import Panels from './panels/Panels.svelte';
import Menu from './menu/Menu.svelte';
import { SCROLLABLE_CLASSNAME } from './shared/const.ts';
import ConnectionAlert from './ConnectionAlert.svelte';
</script>

<section>
<header>
<Menu />
</header>
<main>
<main class={SCROLLABLE_CLASSNAME}>
<Panels />
</main>

<ConnectionAlert />
</section>

<style lang="scss">
Expand Down
32 changes: 32 additions & 0 deletions src/view/ConnectionAlert.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { EMsg, portPost, runtimeListen } from '../api/communication.ts';
import { Timer } from '../api/time.ts';
import Alert from './shared/Alert.svelte';
import { INJECTION_ALERT_TIMEOUT } from './shared/const.ts';

let alertEl: Alert | null = null;
const delayedAlert = new Timer(
{ delay: INJECTION_ALERT_TIMEOUT },
() => void alertEl?.show(),
);

runtimeListen((o) => {
if (o.msg === EMsg.INJECTION_CONFIRMED) {
delayedAlert.stop();
alertEl?.hide();
} else if (o.msg === EMsg.CONTENT_SCRIPT_LOADED) {
alertEl?.hide();
}
});

portPost({ msg: EMsg.CONFIRM_INJECTION });
delayedAlert.start();
</script>

<Alert
bind:this={alertEl}
dismissable={false}
title="Attention"
>
<div>Tab reload required to continue live inspection</div>
</Alert>
17 changes: 17 additions & 0 deletions src/view/menu/DevDumpTelemetry.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
import { useTelemetryState } from '../../state/telemetry.state.svelte.ts';

const tm = useTelemetryState();

function dump() {
console.log(tm.telemetry);
}
</script>

<button
onclick={dump}
title={`Dump telemetry\n(look in devtools of the devtools)`}
aria-label="Dump telemetry"
>
<span class="icon -console"></span>
</button>
6 changes: 5 additions & 1 deletion src/view/menu/DevReload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
}
</script>

<button onclick={onDevReload} title="Reload" aria-label="Reload">
<button
onclick={onDevReload}
title="Reload & Clear Storages"
aria-label="Reload & Clear Storages"
>
<span class="icon -refresh"></span>
</button>
10 changes: 5 additions & 5 deletions src/view/menu/Menu.svelte
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<script lang="ts">
import ResetHistory from './ResetHistory.svelte';
import SummaryBar from './SummaryBar.svelte';
import Version from './Version.svelte';
import TogglePanels from './TogglePanels.svelte';
import DevReload from './DevReload.svelte';
import TogglePause from './TogglePause.svelte';
import UpdatePace from './UpdatePace.svelte';
import DevDumpTelemetry from './DevDumpTelemetry.svelte';
</script>

<TogglePanels />
<div class="divider -thin"></div>
<TogglePause />
<div class="divider -thin"></div>
{#if __development__}
<DevReload />
<div class="divider -thin"></div>
<DevDumpTelemetry />
<div class="divider -thin"></div>
{/if}
<TogglePause />
<div class="divider -thin"></div>
<ResetHistory />
<div class="divider -thin"></div>
<SummaryBar />
<div class="divider"></div>
<UpdatePace />
Expand Down
15 changes: 0 additions & 15 deletions src/view/menu/ResetHistory.svelte

This file was deleted.

Loading