Files
buuh/docs/publishing.md
T
Bendik Aagaard LynghaugandClaude Fable 5 a828c38ae7
ci / test (24) (push) Successful in 42s
ci / test (26) (push) Successful in 34s
ci / e2e (push) Successful in 1m9s
cdn.uhhm.no is real: releases publish to the git-pages CDN
The advertised import URL now exists. The CDN is just a pages site
(PAGES.md pattern): DNS + allowlist TXT in terraform, _headers for CORS
and immutable caching, and the release workflow PATCHes each version's
bundle in — incremental, so old versions persist. Verified in real
Chromium importing buuh@8.0.0 from the live CDN via an import map.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014NgfSjHE11oFpoSnLVKLXd
2026-09-12 11:55:57 +02:00

3.4 KiB

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):

@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:

$ 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@<version>.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.

<script type="importmap">
  { "imports": { "buuh": "https://cdn.uhhm.no/buuh@8.0.0.js" } }
</script>
<script type="module">
  import { choo, html } from 'buuh'
</script>

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.