# Publishing buuh on project.uhhm.no Two different distribution problems, two different mechanisms. Gitea handles one of them natively; the other needs a static host. ## 1. `npm install` — Gitea Packages (yes, it does what you hope) Gitea ships a real npm registry per user/org. For the `uhhm` org the endpoint is: ``` https://project.uhhm.no/api/packages/uhhm/npm/ ``` **Publishing** happens from the release workflow (`.gitea/workflows/release.yml`): tag `v8.0.0`, push the tag, and every workspace package is published with a `package:write` token stored as the `PACKAGES_TOKEN` repo secret. Bump the workspace versions before tagging. **Consuming** needs one line of `.npmrc` in a project (or `~/.npmrc`): ```ini @uhhm:registry=https://project.uhhm.no/api/packages/uhhm/npm/ ``` Then plain npm works, and this is why the packages are scoped: npm routes *by scope*, so `@uhhm/*` resolves against your Gitea while everything else still comes from npmjs.org. No token is needed to install if the packages are public (they inherit visibility from the owner). Starting a project is: ```console $ echo "@uhhm:registry=https://project.uhhm.no/api/packages/uhhm/npm/" >> .npmrc $ npm i @uhhm/buuh @uhhm/buuh-html $ npm i -D @uhhm/bankai $ npx bankai start app.js ``` ## 2. "CDN require" — the part Gitea does NOT do This is the misunderstanding worth clearing up: **Gitea's npm registry serves tarballs to package managers, not individual JavaScript files to browsers.** There is no unpkg-style `https://…/@uhhm/buuh/index.js` endpoint, and the generic-package download URLs serve `application/octet-stream` — browsers refuse that for ES modules (strict MIME checking). So an import map cannot point at Gitea directly. What works instead, in order of effort: **a. cdn.uhhm.no — live, and it's just a pages site (recommended).** `https://cdn.uhhm.no/buuh@.js` is real: the CDN is a git-pages site (see uhhm/infrastructure PAGES.md) — an A record, an allowlist TXT pointing at this repo, and the release workflow PATCHing each version's bundle in (PATCH is incremental, so old versions persist forever). A `_headers` file provides `Access-Control-Allow-Origin: *` everywhere, year-long immutable caching on versioned files, and short caching on `buuh.js` (the latest alias) and the index. No separate web server, no Caddy site config. ```html ``` **b. Self-hosted esm.sh.** esm.sh is open source and can be pointed at a custom npm registry — run it against the Gitea endpoint and you get real CDN semantics (per-package URLs, versioning, bundling) for everything you publish. More moving parts; worth it only if you want per-package URLs rather than the one-file bundle. **c. Raw Gitea file URLs — don't.** Gitea serves raw `.js` as `text/plain` for safety, which module loading rejects. Fronting raw URLs with a MIME-rewriting proxy works but is a hack with none of the caching benefits of (a). ## Version hygiene - Workspace versions are currently `8.0.0-dev`; set real versions before the first tag (`npm version 8.0.0 --workspaces --no-git-tag-version`). - The tag drives the generic-package version in the workflow, so keep tags and package.json versions in step. - `bankai` the bin name survives; the package is `@uhhm/bankai` so scope routing works.