<!--
SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>

SPDX-License-Identifier: GPL-2.0-or-later
-->

# Frontend source

This directory contains the strict TypeScript source for the browser assets
embedded by `trx-frontend-http`. `bootstrap.ts` is the production entry point;
esbuild follows its imports and emits `/app.js`. Feature plugins are ESM entry
points loaded on demand by `plugin-loader.ts`, and the decode-history worker is
built with its own Web Worker TypeScript configuration.

Run all frontend commands from the parent `frontend` directory:

```sh
npm ci
npm run typecheck
npm run lint
npm test
npm run test:browser
npm run build
npm run verify-generated
```

`npm run verify-generated` regenerates Rust wire contracts and browser bundles,
then rejects drift from the committed files. The browser smoke test needs a
local Chromium-family executable; set `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH`
when it is not installed at `/usr/bin/chromium`.

Cargo consumes committed output under `../assets/web/generated`. It never
invokes Node.js, installs packages, or accesses the network. After changing a
source file, commit the deterministic generated asset changes together with the
source change.

## Boundaries

- `api/generated.ts` is generated from Rust and must not be edited manually.
- `api/client.ts` owns runtime validation at version-sensitive HTTP and SSE
  boundaries.
- `core/` contains dependency-light shared helpers.
- `features/` contains application behavior grouped by responsibility.
- `plugins/` contains lazy decoder and high-coupling feature entries.
- `plugins/host.ts` declares the typed `window.trx` state and services that
  feature bundles read; feature entries import it rather than reaching for bare
  `window` properties, which the module graph does not publish.
- Files under `assets/web/vendor/` are vendored JavaScript and are not part of
  the TypeScript migration.

First-party features communicate through imports, the typed plugin runtime, or
the documented `window.trx` host interface. New standalone `window` callbacks
are not permitted.
