Skip to content

feat: Hosting UI cleanup, free/paid toggle, and launcher improvements#763

Merged
lucksus merged 11 commits intodevfrom
feat/free-paid-hosting-and-setup-instructions
Mar 22, 2026
Merged

feat: Hosting UI cleanup, free/paid toggle, and launcher improvements#763
lucksus merged 11 commits intodevfrom
feat/free-paid-hosting-and-setup-instructions

Conversation

@lucksus
Copy link
Copy Markdown
Member

@lucksus lucksus commented Mar 21, 2026

Summary

  • Add global free/paid hosting toggle (defaults to free) — when free, all credit checks are bypassed and payment UI is hidden
  • Rename "Multi-user mode" → "Enable multi-user hosting" with collapsible setup instructions (SMTP, TLS, port forwarding)
  • Add hosting profile improvements: info tooltip, prominent endpoint URL with auto-populate from TLS config, auto-dismissing status messages
  • Rename all user-facing HOT/mHOT references to wHOT (wrapped HOT) across UI, Connect, and backend
  • Add trust disclaimer in AD4M Connect host browser for remote connections
  • Add agent picker on login screen, agent switching/deletion from settings, and persist agent state

Summary by CodeRabbit

  • New Features

    • Added global "Paid hosting via wHOT" toggle and admin API to read/set free hosting.
    • Hosting UI updates: auto-expanding setup instructions, auto-clearing status messages, trust/consent notice, and TLS port included in host WebSocket URL.
    • Context/API exposes freeHostingEnabled state and setter for UI use.
  • Behavior Changes

    • Global free-hosting now bypasses credit/payment flows and hides wallet/credit UI when enabled.
    • Currency/unit labels changed from HOT/mHOT to wHOT across the UI.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 21, 2026

Warning

Rate limit exceeded

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

⌛ 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: fcda02c1-c576-48fa-837b-55c027d3c6f8

📥 Commits

Reviewing files that changed from the base of the PR and between 7adf828 and c5f41ef.

📒 Files selected for processing (2)
  • connect/src/components/views/LoggedInDashboard.ts
  • rust-executor/src/graphql/mutation_resolvers.rs
📝 Walkthrough

Walkthrough

Added a global "free hosting enabled" flag and plumbing across DB, GraphQL API (query + admin mutation), Rust credit/hosting enforcement, runtime client, and UI context/components so the system can toggle and honor a global free-hosting mode.

Changes

Cohort / File(s) Summary
Runtime client & schema
core/src/runtime/RuntimeClient.ts, core/src/runtime/RuntimeResolver.ts
Added freeHostingEnabled() query and setFreeHostingEnabled(enabled: boolean) mutation to the runtime client and resolver.
Database settings helpers
rust-executor/src/db.rs
Added get_free_hosting_enabled() and set_free_hosting_enabled(enabled: bool) to read/write the flag in the settings table (string "true"/"false").
GraphQL resolvers — mutations
rust-executor/src/graphql/mutation_resolvers.rs
Respect global flag in compute-credit/payment flows: skip per-user checks when enabled; added admin mutation runtime_set_free_hosting_enabled(enabled: bool) -> bool; updated wallet/payment messaging from mHOT→wHOT.
GraphQL resolvers — queries
rust-executor/src/graphql/query_resolvers.rs
Added runtime_free_hosting_enabled query; propagated global flag into runtime_list_users and runtime_hosting_user_info free_access computation; minor wallet label text changes (mHOT→wHOT).
Credit flush / runtime loop
rust-executor/src/lib.rs
Credit-flush loop now queries global flag first and uses it to decide free_access before falling back to per-user lookup; logs on DB failure and defaults to free access on error.
UI — Hosting component
ui/src/components/Hosting.tsx
Added toggle UI for paid/free hosting, conditional rendering (wallet, credits, settings) based on freeHostingEnabled, auto-expand/collapse behaviors, and TLS port in host URL composition; updated text from mHOT→wHOT.
UI — Wallet component
ui/src/components/Wallet.tsx
Exported HotLogo; switched balance fallback naming and UI labels from HOT/mHOT→wHOT.
UI — Context
ui/src/context/Ad4minContext.tsx
Added freeHostingEnabled state and setFreeHostingEnabled method; initialization now concurrently fetches multi-user and free-hosting values and exposes setter to consumers.
Connect UI views & types
connect/src/components/views/HostBrowser.ts, connect/src/components/views/HostDetail.ts, connect/src/components/views/LoggedInDashboard.ts, connect/src/types.ts, connect/src/web.ts
Added trust-notice UI, adjusted token-rate filtering logic, and updated displayed currency/labels from HOT/mHOT→wHOT; minor comment/type doc updates for remaining credits.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as Hosting UI
    participant Context as Ad4minContext
    participant Client as RuntimeClient
    participant API as GraphQL API
    participant DB as Database
    participant Enforcer as Credit Enforcer

    User->>UI: Toggle "Paid hosting via wHOT"
    UI->>Context: setFreeHostingEnabled(enabled)
    Context->>Client: runtime.setFreeHostingEnabled(enabled)
    Client->>API: Mutation: runtimeSetFreeHostingEnabled(enabled)
    API->>DB: set_free_hosting_enabled(enabled)
    DB-->>API: OK
    API-->>Client: boolean result
    Client-->>Context: result
    Context->>UI: emit freeHostingEnabled change

    Enforcer->>DB: get_free_hosting_enabled()
    DB-->>Enforcer: true/false
    alt Global free hosting enabled
        Enforcer->>Enforcer: Skip per-user credit checks
    else Global flag disabled
        Enforcer->>DB: get_user_free_access(email)
        DB-->>Enforcer: per-user status
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested Reviewers

  • jhweir

Poem

🐰 I hopped into code with a curious grin,
A switch for free hosting I tucked right in,
Databases store it, UI flips the key,
Credits step aside, users roam free,
A tiny rabbit cheers — wHOT for all to win! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 80.95% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title addresses the main UI improvements and feature additions, including the free/paid hosting toggle and setup instructions, which are prominent across multiple files in the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/free-paid-hosting-and-setup-instructions

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
rust-executor/src/lib.rs (1)

508-523: ⚠️ Potential issue | 🟠 Major

Avoid failing into paid mode when global setting read errors.

Using unwrap_or(false) at Line 508-509 silently forces paid behavior on transient DB failures. That can publish wrong hosting state. Also, the global flag should be read once per flush, not once per user.

Proposed fix
-            for email in &dirty_emails {
-                let global_free = Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled())
-                    .unwrap_or(false);
+            let global_free = match Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()) {
+                Ok(v) => v,
+                Err(e) => {
+                    warn!("Credit flush: get_free_hosting_enabled failed: {}. Falling back to free hosting.", e);
+                    true
+                }
+            };
+            for email in &dirty_emails {
                 let free_access = if global_free {
                     true
                 } else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust-executor/src/lib.rs` around lines 508 - 523, The code currently calls
Ad4mDb::with_global_instance(|db|
db.get_free_hosting_enabled()).unwrap_or(false) per user which silently treats
DB read errors as paid (false) and does the lookup repeatedly; instead, call
Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()) once at the
start of the flush and handle errors explicitly: if the call returns Ok(value)
use that value, but if it returns Err(e) log the error (using error!) and set
global_free = true to avoid forcing paid mode on transient failures; keep the
existing per-user call to Ad4mDb::with_global_instance(|db|
db.get_user_free_access(email)) and its error handling for get_user_free_access,
and remove the unwrap_or(false) usage.
ui/src/components/Hosting.tsx (2)

1304-1439: ⚠️ Potential issue | 🟡 Minor

Show a consistent badge when global free hosting is on.

In free-hosting mode every user has effective free access, but this card still badges only users whose stored per-user flag is true. The list becomes misleading right when the credit/free-access controls are hidden.

🔧 Suggested fix
-                              {(user as any).freeAccess && (
-                                <j-badge variant="success">Free Access</j-badge>
-                              )}
+                              {freeHostingEnabled ? (
+                                <j-badge variant="success">Free Hosting</j-badge>
+                              ) : (user as any).freeAccess ? (
+                                <j-badge variant="success">Free Access</j-badge>
+                              ) : null}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/src/components/Hosting.tsx` around lines 1304 - 1439, The user cards only
show the "Free Access" j-badge when (user as any).freeAccess is true, which is
misleading when global freeHostingEnabled is on; update the badge rendering
inside the users.map card (where j-badge is rendered) to display when
freeHostingEnabled || (user as any).freeAccess so every card shows a consistent
"Free Access" badge in global free-hosting mode while leaving per-user logic
unchanged elsewhere (e.g., toggles and credit controls).

843-894: ⚠️ Potential issue | 🟠 Major

Skip paid-hosting bootstrap while free hosting is enabled.

This toggle only hides the paid-hosting UI. The mount effects still load any persisted hosting-index session and auto-fetch membrane proofs, so free mode continues calling paid-hosting services and can clear the saved session on a 401 before the admin re-enables paid hosting.

🔧 Suggested fix
-  useEffect(() => {
+  useEffect(() => {
+    if (freeHostingEnabled) return;
     const loadHostSession = async () => {
       try {
         const reg = await invoke<{
@@
     };
     loadHostSession();
-  }, []);
+  }, [freeHostingEnabled]);
@@
   useEffect(() => {
-    if (!client || !hostSession || membraneProofStatus === "done" || membraneProofStatus === "fetching" || membraneProofAttempted.current) return;
+    if (
+      freeHostingEnabled ||
+      !client ||
+      !hostSession ||
+      membraneProofStatus === "done" ||
+      membraneProofStatus === "fetching" ||
+      membraneProofAttempted.current
+    ) return;
     fetchMembraneProof(hostSession);
-  }, [client, hostSession]);
+  }, [client, hostSession, freeHostingEnabled]);

Also applies to: 1152-1178

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

In `@ui/src/components/Hosting.tsx` around lines 843 - 894, The effects that load
persisted paid-hosting state and auto-fetch membrane proofs should be skipped
when the paid-hosting toggle is off; update the outer useEffect that defines
loadHostSession and the subsequent useEffect that calls fetchMembraneProof to
early-return when the paid-hosting flag is disabled (e.g. check your paid/free
toggle like isPaidHostingEnabled or isFreeHostingEnabled at the top of both
hooks), so loadHostSession does not call invoke/get_host_registration or call
setHostSession/saveHostSession on 401 and the second effect does not call
fetchMembraneProof(hostSession); keep the existing logic untouched otherwise and
only add the guard around the existing code paths referencing loadHostSession,
fetchMembraneProof, hostSession, membraneProofStatus, membraneProofAttempted,
setHostSession, and saveHostSession.
🧹 Nitpick comments (1)
rust-executor/src/graphql/query_resolvers.rs (1)

1018-1021: Hoist the global flag out of the user loop.

This value is constant for the whole response, but it is re-read for every user. Reading it once avoids extra DB lock churn and keeps a single snapshot if the toggle changes mid-iteration.

♻️ Suggested simplification
-        for user in users {
+        let global_free =
+            Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()).unwrap_or(false);
+
+        for user in users {
             // Count perspectives owned by this user
             let mut perspective_count = 0;
             for perspective in &all_perspectives {
                 let handle = perspective.persisted.lock().await.clone();
                 if let Some(owners) = &handle.owners {
@@
-            let global_free =
-                Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()).unwrap_or(false);
             let free_access: bool = global_free
                 || Ad4mDb::with_global_instance(|db| db.get_user_free_access(&user.username))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust-executor/src/graphql/query_resolvers.rs` around lines 1018 - 1021, Hoist
the global free-hosting flag out of the per-user loop: call
Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()) once (assign to
a local variable, e.g. global_free) before iterating users, then in the loop
compute free_access as global_free || Ad4mDb::with_global_instance(|db|
db.get_user_free_access(&user.username)); this avoids re-reading
get_free_hosting_enabled per user and prevents extra DB locking and inconsistent
snapshots.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/src/runtime/RuntimeResolver.ts`:
- Around line 516-519: The mock resolver's runtimeFreeHostingEnabled() currently
returns false which inverts the actual default; change the return value in the
RuntimeResolver.runtimeFreeHostingEnabled method from false to true so the mock
matches the new runtime default of "free hosting enabled" (and run/update any
affected tests that assume the old value).

In `@rust-executor/src/graphql/mutation_resolvers.rs`:
- Around line 65-69: The resolver currently checks global_free via
Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()) and returns
early for credits, but later still calls runtime_request_payment which can
create HOT payment proposals; add the same global toggle guard before any call
to runtime_request_payment (or pass the global_free flag into/through the code
path) so that when get_free_hosting_enabled() is true no payment endpoint or
proposal is created or invoked; locate uses of runtime_request_payment in this
resolver and short-circuit them when global_free is true (or thread the flag to
downstream functions).
- Around line 2596-2607: The runtime_set_free_hosting_enabled mutation currently
uses check_capability(&context.capabilities, &AGENT_UPDATE_CAPABILITY) but must
be admin-only; replace that capability check with a guard that requires
context.is_admin_credential (e.g., if !context.is_admin_credential { return
Err(FieldError::new("admin credentials required", Value::null())); }), then
proceed to call Ad4mDb::with_global_instance and
db.set_free_hosting_enabled(enabled) as before; keep existing error mapping to
FieldError for the DB call (related symbols: runtime_set_free_hosting_enabled,
check_capability, AGENT_UPDATE_CAPABILITY, context.is_admin_credential,
Ad4mDb::with_global_instance, set_free_hosting_enabled).

In `@ui/src/components/Hosting.tsx`:
- Around line 1054-1148: The setup disclosure is currently a click-only j-flex
opener (the element that toggles setupInfoExpanded via setSetupInfoExpanded) and
leaves focusable content (the Let's Encrypt anchor) tabbable when collapsed;
replace that j-flex opener with a semantic button element that uses
aria-expanded={setupInfoExpanded} and aria-controls pointing to the panel, move
the onClick logic to the button and add onKeyDown handlers as needed (or rely on
native button behavior) to support keyboard activation, and update the hidden
panel styles (when setupInfoExpanded is false) to include visibility: hidden and
pointer-events: none so inner focusable elements (e.g., the Let's Encrypt <a>)
cannot receive focus while collapsed.

In `@ui/src/context/Ad4minContext.tsx`:
- Around line 351-367: The current loadHostingState inside the useEffect couples
both runtime calls so a single failure prevents updating either flag; change
loadHostingState to fetch each flag independently (e.g., call
state.client.runtime.multiUserEnabled() and
state.client.runtime.freeHostingEnabled() separately or use Promise.allSettled)
and update setState for each result individually so a failure of
freeHostingEnabled() does not suppress updating multiUserEnabled (refer to
loadHostingState, state.client, runtime.multiUserEnabled(),
runtime.freeHostingEnabled(), and setState).

---

Outside diff comments:
In `@rust-executor/src/lib.rs`:
- Around line 508-523: The code currently calls
Ad4mDb::with_global_instance(|db|
db.get_free_hosting_enabled()).unwrap_or(false) per user which silently treats
DB read errors as paid (false) and does the lookup repeatedly; instead, call
Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()) once at the
start of the flush and handle errors explicitly: if the call returns Ok(value)
use that value, but if it returns Err(e) log the error (using error!) and set
global_free = true to avoid forcing paid mode on transient failures; keep the
existing per-user call to Ad4mDb::with_global_instance(|db|
db.get_user_free_access(email)) and its error handling for get_user_free_access,
and remove the unwrap_or(false) usage.

In `@ui/src/components/Hosting.tsx`:
- Around line 1304-1439: The user cards only show the "Free Access" j-badge when
(user as any).freeAccess is true, which is misleading when global
freeHostingEnabled is on; update the badge rendering inside the users.map card
(where j-badge is rendered) to display when freeHostingEnabled || (user as
any).freeAccess so every card shows a consistent "Free Access" badge in global
free-hosting mode while leaving per-user logic unchanged elsewhere (e.g.,
toggles and credit controls).
- Around line 843-894: The effects that load persisted paid-hosting state and
auto-fetch membrane proofs should be skipped when the paid-hosting toggle is
off; update the outer useEffect that defines loadHostSession and the subsequent
useEffect that calls fetchMembraneProof to early-return when the paid-hosting
flag is disabled (e.g. check your paid/free toggle like isPaidHostingEnabled or
isFreeHostingEnabled at the top of both hooks), so loadHostSession does not call
invoke/get_host_registration or call setHostSession/saveHostSession on 401 and
the second effect does not call fetchMembraneProof(hostSession); keep the
existing logic untouched otherwise and only add the guard around the existing
code paths referencing loadHostSession, fetchMembraneProof, hostSession,
membraneProofStatus, membraneProofAttempted, setHostSession, and
saveHostSession.

---

Nitpick comments:
In `@rust-executor/src/graphql/query_resolvers.rs`:
- Around line 1018-1021: Hoist the global free-hosting flag out of the per-user
loop: call Ad4mDb::with_global_instance(|db| db.get_free_hosting_enabled()) once
(assign to a local variable, e.g. global_free) before iterating users, then in
the loop compute free_access as global_free || Ad4mDb::with_global_instance(|db|
db.get_user_free_access(&user.username)); this avoids re-reading
get_free_hosting_enabled per user and prevents extra DB locking and inconsistent
snapshots.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e7f9fd9b-34c6-4e9d-a73c-0cd56cdff42c

📥 Commits

Reviewing files that changed from the base of the PR and between b09ac07 and 0b93952.

📒 Files selected for processing (9)
  • core/src/runtime/RuntimeClient.ts
  • core/src/runtime/RuntimeResolver.ts
  • rust-executor/src/db.rs
  • rust-executor/src/graphql/mutation_resolvers.rs
  • rust-executor/src/graphql/query_resolvers.rs
  • rust-executor/src/lib.rs
  • ui/src/components/Hosting.tsx
  • ui/src/components/Wallet.tsx
  • ui/src/context/Ad4minContext.tsx

lucksus added 7 commits March 21, 2026 21:50
  1. RuntimeResolver mock — runtimeFreeHostingEnabled() now returns true to match the default
  2. Payment guard — runtime_request_payment short-circuits with an error when free hosting is on
  3. Admin-only mutation — runtime_set_free_hosting_enabled now checks is_admin_credential instead of capability
  4. Accessibility — setup disclosure uses a semantic <button> with aria-expanded/aria-controls, collapsed panel has visibility: hidden + pointer-events: none
  5. Independent loading — Promise.allSettled so one failure doesn't block the other
  6. Hoisted global_free in lib.rs — read once before the loop, errors default to true (free) to avoid blocking users
  7. Free Access badge — shows on all user cards when freeHostingEnabled is on
  8. Skip paid-hosting effects — loadHostSession and membrane proof fetch early-return when free hosting is enabled
  9. Hoisted global_free in query_resolvers — read once before the user loop
@lucksus lucksus changed the title feat: free / paid hosting and setup instructions feat: Hosting UI cleanup, free/paid toggle, and launcher improvements Mar 21, 2026
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
connect/src/components/views/LoggedInDashboard.ts (1)

376-438: ⚠️ Potential issue | 🟡 Minor

Finish the unit rename on the balance chip.

The wallet/top-up copy now says wHOT, but the same screen still renders HOT for the remaining-balance label on Line 361. Mixing both labels in one dashboard reads like two different currencies.

✏️ Small follow-up
-            <span class="credit-label">HOT</span>
+            <span class="credit-label">wHOT</span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@connect/src/components/views/LoggedInDashboard.ts` around lines 376 - 438,
The balance unit label still shows "HOT" on the remaining-balance chip in
LoggedInDashboard's render template; update that literal to "wHOT" so the UI
consistently uses the same unit. Locate the remaining balance display in the
LoggedInDashboard component (the render/template that shows the balance
chip/remaining-balance label) and replace the "HOT" text with "wHOT" (and update
any nearby unit strings or helper constants used for that label). Ensure any
related tests or snapshots that assert the label are updated to expect "wHOT".
🧹 Nitpick comments (1)
connect/src/components/views/HostBrowser.ts (1)

279-281: Share the operation-rate predicate with HostDetail.

This normalizes "link write" locally, but connect/src/components/views/HostDetail.ts still uses an exact Set(["link write"]) lookup. A host that publishes "Link Write" or extra whitespace will be excluded from the preview average here but still show up as token pricing in the detail view. Extract one helper and use it in both places so the two screens classify rates identically.

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

In `@connect/src/components/views/HostBrowser.ts` around lines 279 - 281, Extract
a shared helper (e.g., normalizeRateDescription or isLinkWriteRate) that
lowercases and trims rate.description and use it in both HostBrowser (where
tokenRates is computed) and HostDetail (where Set(["link write"]) is currently
used) so both components classify "link write" consistently; replace the inline
filter r => r.description.trim().toLowerCase() !== "link write" and the exact
Set lookup with calls to the new helper (export it from a common module or a
nearby shared utils file) so variants like "Link Write" or extra whitespace are
handled identically.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rust-executor/src/graphql/mutation_resolvers.rs`:
- Around line 65-69: The current reads of get_free_hosting_enabled() use
unwrap_or(false) so DB errors incorrectly fall back to "paid" mode; change those
call sites to fail-open (default to free) by replacing unwrap_or(false) with
unwrap_or(true) or otherwise treating Err as free. Update the global_free
assignment and the other occurrences inside check_compute_credits() and
runtime_request_payment() so that DB read failures result in free hosting (true)
rather than enabling payment logic, ensuring behavior matches
rust-executor/src/lib.rs.
- Around line 2604-2608: After toggling the global flag in
Ad4mDb::with_global_instance (the call to set_free_hosting_enabled), invalidate
connected user state so clients receive updated HostingUserInfo: add all
currently connected user emails (or their identifiers used by the credit flush
loop) to DIRTY_CREDIT_USERS or explicitly publish updated HostingUserInfo for
those users so the credit flush loop in rust-executor/src/lib.rs will push fresh
free_access/remaining_credits to clients; update the mutation_resolvers flow to
perform this after set_free_hosting_enabled (preserving existing error mapping)
and ensure any helper used to enumerate connected users matches the identifier
type expected by DIRTY_CREDIT_USERS.

---

Outside diff comments:
In `@connect/src/components/views/LoggedInDashboard.ts`:
- Around line 376-438: The balance unit label still shows "HOT" on the
remaining-balance chip in LoggedInDashboard's render template; update that
literal to "wHOT" so the UI consistently uses the same unit. Locate the
remaining balance display in the LoggedInDashboard component (the
render/template that shows the balance chip/remaining-balance label) and replace
the "HOT" text with "wHOT" (and update any nearby unit strings or helper
constants used for that label). Ensure any related tests or snapshots that
assert the label are updated to expect "wHOT".

---

Nitpick comments:
In `@connect/src/components/views/HostBrowser.ts`:
- Around line 279-281: Extract a shared helper (e.g., normalizeRateDescription
or isLinkWriteRate) that lowercases and trims rate.description and use it in
both HostBrowser (where tokenRates is computed) and HostDetail (where Set(["link
write"]) is currently used) so both components classify "link write"
consistently; replace the inline filter r => r.description.trim().toLowerCase()
!== "link write" and the exact Set lookup with calls to the new helper (export
it from a common module or a nearby shared utils file) so variants like "Link
Write" or extra whitespace are handled identically.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 358e91c2-e721-415c-a884-1a94ec45edfd

📥 Commits

Reviewing files that changed from the base of the PR and between 0b93952 and 7adf828.

📒 Files selected for processing (12)
  • connect/src/components/views/HostBrowser.ts
  • connect/src/components/views/HostDetail.ts
  • connect/src/components/views/LoggedInDashboard.ts
  • connect/src/types.ts
  • connect/src/web.ts
  • core/src/runtime/RuntimeResolver.ts
  • rust-executor/src/graphql/mutation_resolvers.rs
  • rust-executor/src/graphql/query_resolvers.rs
  • rust-executor/src/lib.rs
  • ui/src/components/Hosting.tsx
  • ui/src/components/Wallet.tsx
  • ui/src/context/Ad4minContext.tsx
✅ Files skipped from review due to trivial changes (2)
  • connect/src/web.ts
  • connect/src/types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • core/src/runtime/RuntimeResolver.ts
  • ui/src/components/Wallet.tsx
  • ui/src/components/Hosting.tsx

@lucksus lucksus merged commit 86dde42 into dev Mar 22, 2026
7 of 8 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.

1 participant