Files
nosterm-client/README.md
T
Robert Goodall cd2b900639
ci / build (push) Successful in 1m3s
ci / image (push) Successful in 41s
Initial commit: Nosterm client (terminal-style Nostr chat SPA)
2026-07-24 13:47:53 -04:00

111 lines
4.7 KiB
Markdown

# Nosterm
<p align="center">
<img src="assets/nosterm-banner.svg" alt="Nosterm — a terminal-style Nostr chat application" width="640" />
</p>
**A terminal-style Nostr chat client.**
The Nosterm web client: a terminal-style Nostr chat SPA built with
[SvelteKit](https://kit.svelte.dev/) and served as static files by
[Caddy](https://caddyserver.com/). Nostr is a client-side protocol, so there is
no application backend here — the browser talks directly to relays over
WebSocket. Run a relay from the companion
[nosterm-relay](https://git.nerdworks.io/nerdworks/nosterm-relay) repository if
you want your own home relay.
This is the **public, contribution-focused** repository for the Nosterm client.
Open a pull request against `main` — see [CONTRIBUTING.md](CONTRIBUTING.md). Each
merge to `main` builds the container image and publishes it to ECR Public for
anonymous pulls (see [Deploy](#deploy)).
## Layout
```
nosterm-client/
src/ # SvelteKit source (components, stores, nostr, commands…)
static/ # static assets
Dockerfile # build the SPA → serve with Caddy
Caddyfile # static file server + security headers + optional /relay proxy
docker-compose.yml # one-command deploy on port 8080
.env.example # copy to .env and configure
package.json # dev/build/test scripts
```
## Develop
```bash
npm install
npm run dev # vite dev server
npm run check # svelte-check (type-check)
npm run lint # prettier --check + eslint
npm test # vitest
npm run test:e2e # playwright
npm run build # static build → ./build
```
## Deploy
```bash
cp .env.example .env # then set NOSTERM_DEFAULT_RELAYS at minimum
docker compose up -d --build
```
The client is then served at <http://localhost:8080>.
To run the prebuilt public image with your own relays — no rebuild, no AWS
account (anonymous pull from ECR Public):
```bash
docker run -p 8080:80 \
-e NOSTERM_DEFAULT_RELAYS=wss://relay.example.com \
public.ecr.aws/k3k1z1x5/nosterm:latest
```
`NOSTERM_DEFAULT_RELAYS` accepts a comma-separated list. On startup the
container's entrypoint writes it to `/config.json`, which the SPA fetches on
load — so one shared image serves every deployment with different relays.
## Configuration
Relays are configured at **runtime** (`NOSTERM_DEFAULT_RELAYS`), so a single
prebuilt image works for any deployment. The remaining `PUBLIC_*` tunables are
**build-time** args baked into the browser bundle (client-visible, never
secrets) — change one → rebuild the image.
**Runtime** (set on the running container, no rebuild):
| Variable | Default | Purpose |
| ------------------------ | ------------ | ------------------------------------------------------------ |
| `NOSTERM_DEFAULT_RELAYS` | _empty_ | Comma-separated relay WebSocket URLs to preload |
| `RELAY_UPSTREAM` | `relay:3334` | Upstream for Caddy's optional `/relay` reverse-proxy (below) |
**Build-time** (baked into the bundle; rebuild to change):
| Variable | Default | Purpose |
| ------------------------------------- | ------- | --------------------------------------------- |
| `PUBLIC_DEFAULT_RELAYS` | _empty_ | Fallback relays when no runtime config is set |
| `PUBLIC_DEFAULT_THEME` | `nord` | Theme applied before the user picks one |
| `PUBLIC_MAX_TERMINAL_ENTRIES` | `1000` | Terminal entries kept in memory / rendered |
| `PUBLIC_MAX_MESSAGE_LENGTH` | `2000` | Max outbound message length (characters) |
| `PUBLIC_MAX_CACHED_MESSAGES_PER_ROOM` | `500` | Messages retained per room in IndexedDB |
## Talking to a relay
The client connects directly to whatever relays are configured in
`NOSTERM_DEFAULT_RELAYS` (and any the user adds at runtime). Two common setups:
- **External relay** — set `NOSTERM_DEFAULT_RELAYS=wss://relay.example.com`.
You can delete the `handle /relay*` block from the `Caddyfile`.
- **Same-origin home relay** — run
[nosterm-relay](https://git.nerdworks.io/nerdworks/nosterm-relay), set
`NOSTERM_DEFAULT_RELAYS=ws://localhost:8080/relay` (or `wss://…` behind TLS),
and set `RELAY_UPSTREAM` to the relay's address so Caddy proxies `/relay` to
it. Put both services on a shared Docker network for name resolution.
## Production TLS
For a real domain, edit the `Caddyfile`: replace `:80` with your hostname (e.g.
`nosterm.example.com { … }`) and Caddy will obtain and renew a certificate
automatically. Expose ports 80 and 443 in `docker-compose.yml`.