Multi-file React prototypes loaded via Babel-standalone
(`<script type="text/babel" src="…">`) fetch each `.jsx` / `.tsx` source
over HTTP. The daemon's `EXT_MIME` map in `apps/daemon/src/projects.ts`
served `.jsx` as `application/octet-stream` (no entry → fallback) and
`.tsx` as `text/typescript`, neither of which is a recognized JavaScript
MIME. Strict CSPs and browser module loaders reject both, which is one
of the failure modes flagged in #336 for the Open-button render path.
Map both to `text/javascript; charset=utf-8`, matching the existing
treatment of `.js` / `.mjs` / `.cjs`. `.ts` is intentionally left as
`text/typescript` — it has no browser-execution path here; tooling that
reads `.ts` as TypeScript source is the load-bearing consumer.
Tests in `apps/daemon/tests/project-classifiers.test.ts` were updated
to pin the new mappings and document the rationale.
Refs #336.
Both helpers in `apps/daemon/src/projects.ts` are dispatch points
multiple modules depend on, but had zero test coverage:
- `kindFor` returns the coarse 'image' / 'sketch' / 'code' / 'video' /
'audio' / 'text' / 'html' / 'pdf' / 'document' / 'presentation' /
'spreadsheet' / 'binary' bucket the frontend uses to pick a viewer in
`apps/web/src/components/FileViewer.tsx`. Called from
`projects.ts:66/88/130`, `media.ts:448`, and `document-preview.ts:18`.
- `mimeFor` is the Content-Type the daemon sends when serving the file
directly. Called from the file-serving routes in `server.ts`.
Adding `tests/project-classifiers.test.ts` (15 cases) pins both
contracts so the next bucket addition (e.g. issue #61's recently-merged
`.py` extension, or upcoming `.yaml` / `.toml` / `.sh` requests) can
be made with a clear regression net.
`kindFor` coverage:
- compound `.sketch.json` extension wins over `.json`
- `.html` / `.htm` → `'html'`
- `.svg` → `'sketch'`
- raster image extensions → `'image'`, with `sketch-` prefix → `'sketch'`
- video / audio / markdown / text / code (incl. `.py`) buckets
- office docs → respective `'pdf' / 'document' / 'presentation' /
'spreadsheet'` buckets
- unknown extensions and extensionless names → `'binary'`
- case-insensitive on extension
`mimeFor` coverage:
- every `EXT_MIME` mapping (charset where applicable)
- unmapped extensions → `'application/octet-stream'`
- case-insensitive on extension
No production change — pure test addition.
Verification:
- `pnpm --filter @open-design/daemon test` — 16 files / 240 tests pass
(was 15 files / 225 tests on main; +1 file, +15 tests).