This note tracks the frontend ES module graph. main.js is the single HTML
entry point; imports determine evaluation order and cache-busted asset URLs.
i18n.jsutils.jsconnections-panel.jsdisplay-scope.jsauth-socket.jsgraph.jssettings.js
settings-backup.jssettings-sessions.jssettings-beacons.jssettings-legacy-routers.jssettings-slack.jssettings-manual-threat.jssettings-ai.jssettings-agents.jsrouter-settings.jsmap-common.jsstats.jstime-filter.jsview-tabs.jslog.jsbeacon.jsthreat-popup.jsdevices.jsnotif-log.jsai-insights.jsmain.jssocket.io, D3, and topojson are loaded before the app scripts.
display-scope.js owns the browser-persisted collection-source selection and
safe router/Agent labels. It does not own collection or storage behavior;
read APIs consume the selected stable source ID as the filtering work is added.
Client and server translations have a single source of truth in
src/data/i18n.json. The server reads the JSON directly. For the browser,
http-app.js safely serializes the same catalog as the virtual ES module
/js/i18n-data.js; i18n.js imports that module with the application asset
version. This keeps the no-build deployment model while preventing client and
server translation dictionaries from drifting apart.
graph.js and stats.js delegate to focused submodules; each is imported by
its parent (and re-exported there for legacy importers), so load order is
resolved by the ES module graph rather than script tags:
graph-helpers.js — pure graph data transforms (no DOM/D3)graph-panels.js — tooltip and side-panel rendering; owns filter-tab stategraph-render.js — D3 force simulation and node/link drawing; owns the
simulation and SVG groupsstats-helpers.js — pure stats aggregation/layout helpers (no DOM/i18n)stats-charts.js — pie / timeline / bar chart rendering; owns the
stack/line chart-mode togglestats-map.js — globe and flat-map rendering; owns all map state
(projection, rotation, spin, particles, zoom/pan, resize bookkeeping)settings.js coordinates the modal, data sources, and general settings.
Backup/restore, authentication sessions, Agent enrollment, beacon detection, manual threat lookup,
and the legacy Yamaha/Cisco/ASUS controls each own their listeners and API calls in a focused section module.
The parent passes only the shared status renderer, avoiding circular imports.
npm run lint:innerhtml audits every innerHTML assignment under
public/js/. P2-27 reduced the inventory to zero, and the empty allowlist in
scripts/frontend-innerhtml-allowlist.json makes any reintroduction fail CI.
New rendering code should use textContent, createElement, and explicit DOM
attributes. Translation strings must also remain plain text; line breaks and
emphasis belong in fixed HTML structure and CSS classes. If an HTML insertion
API ever becomes unavoidable, it requires an explicit security review and a
documented exception rather than silently widening the empty allowlist.
The connection log, notification log, device inventory, and threat detail
markup must not use inline style attributes. Their modules use CSS state
classes for visibility, sorting, and filtering; only runtime top and left
popup coordinates may use the style API. test/unit/frontend-lint.test.js
enforces this boundary.
The following APIs are intentionally mirrored under window.EgressView.api
while the frontend is still migrating toward modules:
apiFetchsocketlookupNoteshowStatusbuildGraphbuildGraphFromConnectionsresizeGraphscheduleGraphAutoFitstopGraphupdateStatsinitStatsMapsupdateStatsMapsapplyTimeFilterrefreshCurrentTimeFilterViewswitchViewupdateLogViewloadDevicesViewrenderDevicesTableloadNotifLogInitializers are registered under window.EgressView.init:
graphstatstimeFilterviewTabslogdevicesnotifLogmainmain.js last until socket handlers can import explicit dependencies.window.EgressView mirrors only after all call sites use imports.