Skip to content

feat(web): per-instance display name (CODEG_INSTANCE_NAME) + server-side client preferences API - #1000

Open
unixcs wants to merge 3 commits into
spacering-net:mainfrom
unixcs:feat/instance-name-client-prefs
Open

unixcs wants to merge 3 commits into
spacering-net:mainfrom
unixcs:feat/instance-name-client-prefs

Conversation

@unixcs

@unixcs unixcs commented Oct 20, 2026

Copy link
Copy Markdown

What

Two server-side additions that make self-hosted multi-instance deployments friendlier. Both are opt-in / additive; default behavior is byte-identical to current main.

1. Per-instance display name — CODEG_INSTANCE_NAME env

Self-hosters running several codeg servers (e.g. one per machine) all get identical tab titles and identical PWA names (codeg) when installed to a phone home screen — indistinguishable icons.

Setting CODEG_INSTANCE_NAME=Tencent-codeg rewrites at the static-serving layer:

  • <title> in served HTML (codeg → Tencent-codeg, and the client-side - codeg suffix → - Tencent-codeg, including the RSC payload)
  • manifest.json name / short_name (JSON-aware, escaped)

Key property: build artifacts stay byte-identical to upstream. The name lives in deployment config, not in the bundle — rebasing a fork or using the built-in self-updater never loses it.

Implementation: a small axum middleware (src-tauri/src/web/instance_name.rs) that buffers HTML/manifest responses (8 MB cap), rewrites, fixes Content-Length. Invalid/empty values are ignored (falls back to stock naming). 8 unit tests included.

2. Server-side client preferences KV — get_client_preferences / update_client_preferences

Floating-ball / appearance settings currently live only in localStorage, so a new browser, cleared site data, or a different machine starts from zero every time.

These two all-POST endpoints (Bearer auth, same as the rest of /api) store one opaque JSON blob ({"prefs": "<json>", "synced_at_ms": N}) in the existing app_metadata KV table:

  • Opaque to the server — schema owned by the frontend, so future keys need no server changes
  • 64 KB cap, malformed prefs rejected
  • Desktop/Tauri builds are unaffected (no-op path)

The web frontend wiring (hydrate-on-load, debounced dual-write, echo guard) lives in our fork and is not part of this PR; cross-server reconciliation is intentionally outside the server, done by a loopback agent + timer that replays the winning blob between nodes. 4 unit tests for the handlers.

Testing

  • cargo test --lib --no-default-features --features server-bin — 12 new tests green
  • Deployed on 3 self-hosted instances (x64 + arm64): verified title/manifest rewrite, prefs round-trip, and a 3-node reconciler converging in-sync every 5 min

fengx added 3 commits October 20, 2026 17:29
Instance name (CODEG_INSTANCE_NAME env):
- Rewrites served HTML <title> and the client-side ' - codeg' suffix,
  plus manifest.json name/short_name, at the static-serving layer. The
  build artifacts stay byte-identical to upstream, so rebasing the fork
  or self-updating never loses the per-deployment name (PWA installs on
  the same phone need distinct labels per server).

Client preferences (get_client_preferences / update_client_preferences):
- Opaque JSON blob (schema owned by frontend) in the app_metadata KV.
- Web frontend seeds localStorage from the server on hydration (new
  browser / cleared site data self-heals), pushes local state up when
  the server is empty (first configured browser becomes the seed), and
  dual-writes changes debounced; cross-window storage events re-enter
  local state without re-pushing (echo guard). Desktop/Tauri skipped.
- Floating-ball settings (enabled/position/bindings/size/favorites)
  are the first synced blocks; cross-server reconciliation is handled
  outside the server by a loopback agent + timer.

# Conflicts:
#	src/components/appearance-provider.tsx
…client-prefs

# Conflicts:
#	src-tauri/src/web/handlers/mod.rs
Handing back the raw app_metadata row made clients parse
{"prefs":"…","synced_at_ms":N} as their own blob, find no keys, conclude
"server has nothing" and push their local copy — the server never seeded
anyone. GET now unwraps the envelope (legacy nested rows included) and PUT
normalises on write, so a single bad import cannot wedge the row.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant