Skip to content

docs(config): finish #933 — kill BACKEND_URL stragglers + document runtime precedence#1042

Merged
senamakel merged 6 commits intotinyhumansai:mainfrom
obchain:feat/933-tauri-bootstrap-rpc-url
Apr 30, 2026
Merged

docs(config): finish #933 — kill BACKEND_URL stragglers + document runtime precedence#1042
senamakel merged 6 commits intotinyhumansai:mainfrom
obchain:feat/933-tauri-bootstrap-rpc-url

Conversation

@obchain
Copy link
Copy Markdown
Contributor

@obchain obchain commented Apr 30, 2026

Summary

  • Add a useBackendUrl React hook + matching unit tests so components resolve the API URL at runtime from openhuman.config_resolve_api_url instead of the build-time BACKEND_URL constant.
  • Migrate the two remaining direct BACKEND_URL consumers (WebhooksDebugPanel, TunnelList) off the build-time short-circuit so the URLs they render reflect whichever core sidecar the user picked on the login screen.
  • Document the runtime URL precedence (login-screen → Tauri core_rpc_urlVITE_* → hardcoded default) and the new "use the hook, not the constant" rule in app/.env.example, docs/src/01-architecture.md, and docs/src/08-hooks-utils.md.

Problem

PR #948 already shipped most of the umbrella (#933): the login-screen RPC URL field, persistence, coreRpcClient cache, and services/backendUrl#getBackendUrl calling openhuman.config_resolve_api_url. The remaining acceptance criteria were:

  1. Two stragglers — app/src/components/settings/panels/WebhooksDebugPanel.tsx:19 and app/src/components/webhooks/TunnelList.tsx:57 — still imported the build-time BACKEND_URL synchronously and short-circuited to https://api.tinyhumans.ai when it was empty. That bypassed the runtime resolver, so a self-hosted user pointing the app at a custom sidecar would still see the canonical hostnames in the webhook panels.
  2. No documentation of the precedence chain, so contributors had no signal that BACKEND_URL was build-time-only and that runtime callers must use getBackendUrl().
  3. No Vitest coverage for the services/backendUrl resolver — easy for a future refactor to silently break the config_resolve_api_url happy path.

Solution

  • New app/src/hooks/useBackendUrl.ts wraps getBackendUrl() in a tiny hook that returns null while the resolution is in flight or if it fails. Components render a Resolving backend URL… placeholder rather than guessing a hardcoded host.
  • WebhooksDebugPanel and TunnelList swap to the hook and gate the rendered ingress URL + Copy button on the resolved value, dropping the BACKEND_URL import + https://api.tinyhumans.ai fallback entirely.
  • New app/src/services/__tests__/backendUrl.test.ts exercises the real services/backendUrl (it's globally mocked in app/src/test/setup.ts, so the suite uses vi.unmock to opt out): Tauri happy-path against openhuman.config_resolve_api_url, trailing-slash trim, in-process cache, the apiUrl camelCase alias, and the empty-response refusal that stops callers silently using a stale fallback.
  • Docs land the precedence chain in three places (env example, architecture doc, hooks/utils doc) so the next contributor finds the rule in whichever file they open first.

Submission Checklist

  • Unit tests — Added app/src/hooks/useBackendUrl.test.ts (3 cases: resolve, failure, unmount-safety) and app/src/services/__tests__/backendUrl.test.ts (4 cases: happy path, cache, empty refusal, apiUrl alias). Full Vitest suite green: 1042 passed / 4 skipped / 1 todo.
  • E2E / integration — N/A. The new code only touches the runtime URL resolver path that PR feat(config): runtime RPC URL configuration bootstrap (Issue #933) #948 already wired end-to-end; the changes are localized to two components plus a hook and don't introduce new RPC surface or cross-process behavior, so existing tests/json_rpc_e2e.rs coverage of openhuman.config_resolve_api_url is sufficient.
  • Doc commentsuseBackendUrl carries a JSDoc that explains why null is the in-flight signal and that the underlying resolver caches.
  • Inline comments — Added a single grep-friendly comment on the vi.unmock('../backendUrl') line in the new test, since the global setup mock is otherwise non-obvious.

Impact

  • Runtime/platform: Desktop only — the two converted components are part of the Tauri webhook UI. Web usage is unaffected (the hook falls through to the same webFallbackBackendUrl that getBackendUrl already uses).
  • Performance: One extra RPC per session (cached after the first call), and one re-render per consuming component when the resolution settles.
  • Security: No secrets touched; the URL is the same one already exposed via openhuman.config_resolve_api_url.
  • Migration: Build-time VITE_BACKEND_URL is now documented as a web-only fallback. Existing local dev keeps working because the hook falls through to the same value when not running in Tauri.

Related

Summary by CodeRabbit

  • New Features

    • Implemented runtime dynamic backend URL resolution, replacing build-time configuration for improved flexibility and environment adaptation.
    • Components display "Resolving backend URL..." placeholders while backend configuration loads.
  • Bug Fixes

    • Eliminated hardcoded API endpoint fallbacks from webhook debug panels and tunnel components.
  • Documentation

    • Enhanced architecture and configuration documentation clarifying runtime URL precedence.
    • Updated environment variable guidance distinguishing build-time fallbacks from runtime resolution.

obchain added 4 commits April 30, 2026 12:49
Wraps services/backendUrl#getBackendUrl in a small React hook so components
can read the core-derived API URL (resolved at runtime via
openhuman.config_resolve_api_url) without importing the build-time
BACKEND_URL constant. Returns null while the resolution is in flight or if
it fails so callers render a placeholder rather than guessing a hardcoded
host.

Refs tinyhumansai#933.
…_url

Adds Vitest coverage for services/backendUrl#getBackendUrl: the Tauri
happy-path that pulls api_url from openhuman.config_resolve_api_url,
trailing-slash trimming, in-process caching, the camelCase apiUrl alias,
and the empty-response refusal that prevents callers from silently using
a stale fallback.

Refs tinyhumansai#933.
WebhooksDebugPanel and TunnelList previously imported the build-time
BACKEND_URL constant from utils/config and short-circuited to
'https://api.tinyhumans.ai' when it was empty, so the rendered tunnel
ingress URLs ignored whatever core sidecar the user pointed the app at on
the login screen. Switch both components to useBackendUrl() so the URL
the core resolves over JSON-RPC is the one shown in the UI, and surface
a 'Resolving backend URL…' placeholder while the lookup is in flight.

Refs tinyhumansai#933.
Spells out the runtime precedence chain for the core RPC URL (login-screen
field > Tauri core_rpc_url command > VITE_OPENHUMAN_CORE_RPC_URL > hardcoded
default) and clarifies that VITE_BACKEND_URL is a web-only fallback once
desktop builds derive api_url from the core via
openhuman.config_resolve_api_url.

Updates app/.env.example, docs/src/01-architecture.md, and
docs/src/08-hooks-utils.md so contributors know to call useBackendUrl()
or getBackendUrl() instead of importing the build-time BACKEND_URL
constant. Logs the migration in CHANGELOG.md under the existing tinyhumansai#933
entry.

Refs tinyhumansai#933.
@obchain obchain requested a review from a team April 30, 2026 07:24
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Warning

Rate limit exceeded

@obchain has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 32 minutes and 14 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e878a1c-e3bd-4a2e-afd4-65df2172bac4

📥 Commits

Reviewing files that changed from the base of the PR and between ba74c71 and b0ea37a.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • app/src/hooks/useBackendUrl.test.ts
📝 Walkthrough

Walkthrough

The changes implement runtime backend URL resolution by introducing a useBackendUrl() React hook and getBackendUrl() service that dynamically resolve the API URL from the Rust core configuration via openhuman.config_resolve_api_url, replacing static build-time BACKEND_URL constants in webhook components. New test suites and documentation updates accompany the changes.

Changes

Cohort / File(s) Summary
Documentation Updates
CHANGELOG.md, docs/src/01-architecture.md, docs/src/08-hooks-utils.md, app/.env.example
Updated changelog with new hook and migration details; refined architecture docs to document runtime URL resolution via core config; clarified BACKEND_URL as build-time fallback only; documented runtime precedence rules for core RPC and backend URLs.
Backend URL Resolution Service
app/src/hooks/useBackendUrl.ts, app/src/services/__tests__/backendUrl.test.ts
Added useBackendUrl hook that resolves backend URL at runtime from core config with unmount safety guard; test suite covering caching, empty URL rejection, apiUrl alias handling, and Tauri-specific resolution behavior.
Hook Tests
app/src/hooks/useBackendUrl.test.ts
Test coverage for useBackendUrl hook verifying null initial state, async resolution with waitFor, rejection handling, and unmount state-update prevention.
Webhook Components Migration
app/src/components/settings/panels/WebhooksDebugPanel.tsx, app/src/components/webhooks/TunnelList.tsx
Removed static BACKEND_URL imports and hardcoded fallbacks; components now use useBackendUrl() to dynamically resolve backend URL with "Resolving backend URL…" placeholder during resolution.

Sequence Diagram

sequenceDiagram
    actor User
    participant Component as WebhooksDebugPanel<br/>TunnelList
    participant Hook as useBackendUrl
    participant Service as getBackendUrl
    participant Tauri as Tauri IPC
    participant Core as Rust Core
    participant Web as Web API

    User->>Component: Load component
    Component->>Hook: Call useBackendUrl()
    Hook->>Service: Call getBackendUrl()
    Service->>Tauri: Invoke config_resolve_api_url
    Tauri->>Core: Request api_url from config
    Core-->>Tauri: Return api_url
    Tauri-->>Service: Return response
    Service->>Service: Cache result
    Service-->>Hook: Return backend URL
    Hook->>Component: Update with resolved URL
    Component->>Web: Render with live backend URL
    Component-->>User: Display webhook ingress URLs
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus
  • senamakel

Poem

🐰 Hark! The backend URL, once locked in stone,
Now dances free at runtime, never alone!
With hooks that hook and services so true,
The core configuration guides the view!
No more hardcoded paths of yesterday—
Dynamic resolution lights the way!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately summarizes the main changes: finishing issue #933 by removing build-time BACKEND_URL imports from stragglers (WebhooksDebugPanel, TunnelList) and documenting the new runtime-based URL resolution with precedence rules.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 32 minutes and 14 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
app/src/services/__tests__/backendUrl.test.ts (1)

21-64: ⚡ Quick win

Add coverage for the non-Tauri fallback path.

This suite exercises the RPC-backed Tauri branch thoroughly, but the new contract also depends on the web-only fallback when isTauri() is false. A test here would keep Storybook/web-preview behavior from regressing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/services/__tests__/backendUrl.test.ts` around lines 21 - 64, Add a
test that covers the non-Tauri fallback path by setting
hoisted.isTauriMock.mockReturnValue(false) and verifying getBackendUrl (loaded
via loadFreshModule) returns the expected fallback value (e.g., process.env or
hardcoded fallback used by the module) and that hoisted.callCoreRpcMock is not
called; place this alongside the existing tests and mirror patterns used in the
suite (use hoisted.callCoreRpcMock.mockReset() in beforeEach) so the web-only
branch of getBackendUrl is exercised and protected from regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/hooks/useBackendUrl.test.ts`:
- Around line 34-51: The test currently uses a fixed sleep (setTimeout) after
resolving the deferred mock promise which is flaky; instead, after calling
resolveFn?.('https://api.example.com'), immediately flush pending microtasks by
awaiting a resolved promise (e.g. await Promise.resolve()) or wrapping that in
testing-library's act (e.g. await act(() => Promise.resolve())) so the hook's
async resolution runs before asserting result.current; update the test that uses
mockGetBackendUrl, resolveFn, renderHook(() => useBackendUrl()), unmount(), and
result.current to replace the setTimeout wait with a microtask flush.

In `@CHANGELOG.md`:
- Around line 27-29: Update the CHANGELOG.md entry so the test-coverage bullet
lists both added tests: services/__tests__/backendUrl.test.ts and
hooks/useBackendUrl.test.ts; locate the existing bullet that mentions
services/__tests__/backendUrl.test.ts and append or replace it with a single
line that names both files (e.g., "Added services/__tests__/backendUrl.test.ts
and hooks/useBackendUrl.test.ts covering...") so the changelog accurately
reflects shipped coverage.

---

Nitpick comments:
In `@app/src/services/__tests__/backendUrl.test.ts`:
- Around line 21-64: Add a test that covers the non-Tauri fallback path by
setting hoisted.isTauriMock.mockReturnValue(false) and verifying getBackendUrl
(loaded via loadFreshModule) returns the expected fallback value (e.g.,
process.env or hardcoded fallback used by the module) and that
hoisted.callCoreRpcMock is not called; place this alongside the existing tests
and mirror patterns used in the suite (use hoisted.callCoreRpcMock.mockReset()
in beforeEach) so the web-only branch of getBackendUrl is exercised and
protected from regressions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6c8f9c92-ea16-4195-9b83-6ce5c94044c0

📥 Commits

Reviewing files that changed from the base of the PR and between 84d7814 and ba74c71.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • app/.env.example
  • app/src/components/settings/panels/WebhooksDebugPanel.tsx
  • app/src/components/webhooks/TunnelList.tsx
  • app/src/hooks/useBackendUrl.test.ts
  • app/src/hooks/useBackendUrl.ts
  • app/src/services/__tests__/backendUrl.test.ts
  • docs/src/01-architecture.md
  • docs/src/08-hooks-utils.md

Comment thread app/src/hooks/useBackendUrl.test.ts
Comment thread CHANGELOG.md Outdated
obchain added 2 commits April 30, 2026 13:18
- Replace `setTimeout(10)` with `await Promise.resolve()`
- Hook's `.then` cancel path runs on the microtask queue, so a flush is
  enough; drops a 10ms wall-clock wait and removes timing flake.
…verage

- Test-coverage bullet now names both files added in this PR
  (`backendUrl.test.ts` + `useBackendUrl.test.ts`) instead of just
  the resolver test.
@senamakel senamakel merged commit f2858f7 into tinyhumansai:main Apr 30, 2026
12 checks passed
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.

2 participants