Tests, tooling and the served scripts are TypeScript (#392)
The page and the service worker were strict TypeScript; the tests, the build, the home page's generator, the load tests, boot.js and the directory's site.js were plain JavaScript that nothing checked. All of it is TypeScript now, in five programs, each with its own globals, all checked by npm run typecheck: the page (tsconfig.json, with boot.ts and the directory's site.ts), the worker, Node's (tsconfig.tools.json: the Node tests, the browser suite, the build, the site generator, the load harness), and k6's (tsconfig.k6.json, with @types/k6). Node 24 runs the .ts files by stripping their types, so they hold only TypeScript that erases (erasableSyntaxOnly) and import each other by .ts name; package.json says "type": "module" for it, and Dockerfile.web moves to Node 24 to run build.mts. k6 2.3 strips its scripts' types itself. The browser suite's page.evaluate calls reach the page's globals; the page's tsc run now also writes its declarations to target/page-types, which the suite's program includes, so those calls are typed by the page's own code rather than by hand-written copies. boot.ts is compiled by build.mts with swc, as the worker is, and named by the hash of what is served. The directory's build has no Node, so site.js is compiled from site.ts and committed (node web/build.mts --directory-script), and tests/directory-script.ts fails if they drift. Checked: the site generator's 139 pages are byte for byte what the JavaScript made; the page build's app.js is identical and only boot.js (now minified) and its hash differ; contrast, page-smoke, page-unit, native-bridge, the browser suite (96 passed, 2 skipped) and the directory's and ipx's Rust tests pass; k6 parses each load script. The load tests themselves did not run: they build a release binary outside the capped builder. .agents/skills/security-audit is an installed skill's, not ours, and is left as it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
41
CLAUDE.md
41
CLAUDE.md
@@ -128,8 +128,8 @@ running the command and kills the session (exit 144), which has happened more th
|
||||
|
||||
There are three pages: the app (`web/index.html`), the admin page (`web/admin.html`, sent to
|
||||
admins only) and sign-in (`web/login.html`). The app and admin pages share one stylesheet,
|
||||
`web/app.css`, and their script is TypeScript in `web/src/`; `web/build.mjs` lists which files
|
||||
make up each page's script. The page is its own image, **`ipx-web`** (#203): `web/build.mjs` uses
|
||||
`web/app.css`, and their script is TypeScript in `web/src/`; `web/build.mts` lists which files
|
||||
make up each page's script. The page is its own image, **`ipx-web`** (#203): `web/build.mts` uses
|
||||
swc to strip the types and minify each script (`app.js`, `admin.js`, `login.js`), minifies the
|
||||
pages, and puts them with the icons and typeface in `web/dist`, which Caddy serves
|
||||
(`web/Caddyfile`, `Dockerfile.web`), passing `/api` and `/media` to ipx on the same origin. ipx
|
||||
@@ -143,23 +143,35 @@ not signed in to `/login` and anyone but an admin away from `/admin` (and refuse
|
||||
`/admin.js`); `/api/login-check` sends someone Cloudflare Access vouches for past the form; a page
|
||||
asked for with `?token=` goes to `/api/signin`, which sets the cookie. The page is the same file
|
||||
for everyone, so what ipx used to write into it per person is the page's own job now:
|
||||
`web/boot.js`, in `<head>`, puts the theme from its cookie and an admin's link from the last visit
|
||||
`web/boot.ts`, in `<head>`, puts the theme from its cookie and an admin's link from the last visit
|
||||
on the page before the first frame, and `/api/me` brings the rest (version, the account's old
|
||||
theme).
|
||||
|
||||
The files in `web/src` are not modules. They are one script split up, concatenated in the order
|
||||
`web/build.mjs` lists them, sharing one top-level scope as the single inline script did; a new
|
||||
`web/build.mts` lists them, sharing one top-level scope as the single inline script did; a new
|
||||
file goes into that list. Top-level names are kept as they are, because markup calls some by
|
||||
name (`onclick="closeModal()"`) and the browser tests reach others through `page.evaluate`.
|
||||
|
||||
After any edit to it:
|
||||
|
||||
```sh
|
||||
npx tsc -p . && npx tsc -p tsconfig.sw.json
|
||||
node tests/page-smoke.js
|
||||
node --test tests/page-unit.js
|
||||
npm run -s typecheck
|
||||
node tests/page-smoke.ts
|
||||
node --test tests/page-unit.ts
|
||||
```
|
||||
|
||||
**All the code here is TypeScript** (#392): the page, the service worker, the tests, the build, the
|
||||
home page's generator and the load tests. Node runs a `.ts` file as it is, by stripping the types,
|
||||
so it takes only TypeScript that erases (`erasableSyntaxOnly`: no enums, namespaces or constructor
|
||||
parameter properties) and imports name their `.ts` files; k6 strips its own. What a browser loads
|
||||
on its own is compiled by `web/build.mts` with swc (`boot.ts`, the worker). The directory's
|
||||
`site.js` is compiled from `crates/directory/src/site.ts` and committed, since its build has no
|
||||
Node: after editing `site.ts`, `node web/build.mts --directory-script`, which
|
||||
`node tests/directory-script.ts` checks. `npm run -s typecheck` checks five programs, each with its
|
||||
own globals: the page (`tsconfig.json`, which also writes the page's declarations to
|
||||
`target/page-types` for the browser tests' `page.evaluate` calls), the worker, Node's
|
||||
(`tsconfig.tools.json`), and k6's (`tsconfig.k6.json`).
|
||||
|
||||
The service worker that keeps iPX readable offline (#389) is TypeScript too, `web/sw/sw.ts`,
|
||||
a script of its own built to `/sw.js`, and checked by `tsconfig.sw.json` against a worker's
|
||||
globals, which cannot share a program with the page's. It goes to the network first for
|
||||
@@ -188,13 +200,14 @@ cargo clippy --workspace --all-targets -- -D warnings # no warnings, ever
|
||||
cargo deny check # known vulnerabilities, licences, sources (deny.toml); reads Cargo.lock, builds nothing
|
||||
cargo machete # dependencies a crate lists and does not use; now and then, it can be wrong
|
||||
cargo test # parsing, filters, retention, schedules, SQL, per-user state
|
||||
npm run -s typecheck # web/src, the service worker, and the tests' and build's TypeScript
|
||||
node tests/page-smoke.js
|
||||
node --test tests/page-unit.js # the page's own functions, called directly, in a second
|
||||
node tests/native-bridge.js # the page hands playback to a native shell
|
||||
node tests/contrast.js # every theme's palette against WCAG AA
|
||||
npm run -s typecheck # the page, the service worker, the tests', build's and load tests' TypeScript
|
||||
node tests/page-smoke.ts
|
||||
node tests/directory-script.ts # the directory's site.js is its site.ts as it stands
|
||||
node --test tests/page-unit.ts # the page's own functions, called directly, in a second
|
||||
node tests/native-bridge.ts # the page hands playback to a native shell
|
||||
node tests/contrast.ts # every theme's palette against WCAG AA
|
||||
npx playwright test # the browser tests, against a real daemon on fixture feeds
|
||||
node tests/load/run.js # k6: many people at once against a scratch daemon with 1,500 feeds
|
||||
node tests/load/run.ts # k6: many people at once against a scratch daemon with 1,500 feeds
|
||||
sh scripts/coverage.sh # which Rust lines the cargo tests reach, capped like a build (#390)
|
||||
npm run coverage:page # which lines of web/src the browser tests reach (#390)
|
||||
```
|
||||
@@ -264,7 +277,7 @@ seeking through files, a flood of wrong passwords. Things about them:
|
||||
* Each threshold is a budget well above what the request takes now: it is there to catch a query
|
||||
that has started asking once per feed, or writers queueing on a lock, not a slow minute.
|
||||
* `ipx status` runs every second throughout, and a run fails if one takes 5s.
|
||||
* One at a time: `node tests/load/run.js signin`. All four take about six minutes.
|
||||
* One at a time: `node tests/load/run.ts signin`. All four take about six minutes.
|
||||
* The daemon is on **SQLite** unless `--postgres`, which puts it in `IPX_TEST_DATABASE_URL`, in
|
||||
a schema of its own (`ipx_load`) dropped and made again each run. That URL, in `/src/.envrc`, is
|
||||
`ipodderx_test` on the `databases` project's server, production's, as `ipodderx`, taken from
|
||||
|
||||
Reference in New Issue
Block a user