OSCAR Viewer is the web operator and administration interface for ORNL/oscar, enabling real-time monitoring, alarm adjudication, operational views, and visualization of OpenSensorHub instances.
Use Node.js 22.12 or newer on an even-numbered release line (22, 24, or 26+). The release and test toolchain does not support odd-numbered Node.js releases.
npm ci
npm run audit:dependencies
npm run lint
npm run test:component
npm run buildThe production static export continues to use Next.js Webpack mode because the pinned osh-js source package still loads web workers through worker-loader. Cypress component tests use Vite and Chrome. The osh-js dependency is pinned directly to the immutable upstream commit and lockfile integrity hash from ORNL/osh-js, so clean installs reproduce the reviewed MQTT MessagePort implementation directly from the ORNL organization. OSCAR imports only osh-js/source/core/...; the larger upstream source archive affects install size, not the static production output.
Event Details uses the occupancy observation UUID as the public media identity. Before requesting a legacy MP4, the Viewer makes an authenticated request to:
{sensorhub bucket endpoint}/videos/media/{event UUID}
A 200 response must use retained-media schema version 1 and contain exactly five independently decodable JPEGs per camera: first, 25%, middle, 75%, and last. The Viewer validates the event identity, schema, frame positions, distinct source-frame ordinals, sizes, dimensions, content types, and event-scoped asset paths before displaying anything. It accepts at most a 1 MiB catalog, eight camera sets, 12 MiB and 20 megapixels per frame, and 64 MiB and 120 megapixels of declared media per event; either frame dimension is limited to 6,000 pixels. Catalog and image response bodies are read through hard streaming byte limits, so a missing or dishonest Content-Length cannot make the browser buffer an unbounded response before validation.
Camera UIDs, source-frame ordinals, and source video timestamps remain visible in the gallery. The Viewer initially downloads only the selected frame for each camera, schedules at most three frame requests across the event, and downloads another frame when the operator selects it. Successfully loaded frame object URLs are reused until the event or page changes. Individual missing or undecodable images fail independently, so the other evidence stays usable.
A 404 means that the event predates retained media, so the existing videoPaths MP4 player is used. Authentication, server, timeout, and malformed-response failures display a warning before offering that same fallback; they are not silently treated as legacy data. Catalog and image requests have a 10-second deadline. During the backend rollback-grace period, the retained gallery is shown first and the still-available source MP4 remains available beneath it. The catalog request bypasses browser caching, while private JPEG responses may use the backend's short cache lifetime. Authenticated JPEGs are held only in memory and their object URLs are revoked when the event or page changes.
Run the focused contract and rendering tests with:
npm run test:retained-mediaUse Share occupancy in an occupancy preview or on Event Details to copy a link.
Links use /event-details/?id=<observation_id>&node=<encoded_api_endpoint> and load
the stored observation directly, including when opened in a new browser or refreshed.
Both alarm and non-alarm occupancies can be shared. For live occupancies, Share
resolves the stored observation ID; if storage is still pending, retry shortly.
Recipients must sign in and have access to the source node. Remote nodes must be configured on their Servers page. Links contain no credentials and do not grant additional access. The node parameter identifies the configured API endpoint, independently of user-chosen node names. An ID-only link is also accepted when it unambiguously identifies an occupancy among configured nodes. Links stop working if the observation is removed by retention or deletion.
The query-string route supports the Viewer's static export without new server rewrite rules. Existing navigation without parameters remains supported.