Skip to content

Fix usage credit polling in desktop app#4

Merged
Derpedyea merged 2 commits into
mainfrom
fix/usage-credit-polling
May 5, 2026
Merged

Fix usage credit polling in desktop app#4
Derpedyea merged 2 commits into
mainfrom
fix/usage-credit-polling

Conversation

@Derpedyea
Copy link
Copy Markdown
Member

@Derpedyea Derpedyea commented May 5, 2026

Summary

  • return live Polar billing data from the desktop auth health check
  • refresh desktop account status periodically and after transcription so usage credits catch up after meter ingestion
  • keep the local Electron build copy in sync for desktop runs

Verification

  • pnpm --filter @laryn/worker test
  • pnpm --filter @laryn/worker typecheck
  • pnpm --filter @laryn/worker lint
  • pnpm --filter @laryn/desktop typecheck
  • pnpm --filter @laryn/desktop lint
  • node --check apps/desktop/main.cjs

Summary by CodeRabbit

Release Notes

  • Improvements
    • Automatic periodic authentication refresh now maintains active sessions
    • Usage credits sync in real-time after transcription completion
    • Billing information updates more frequently for improved account accuracy

- Poll worker auth in the desktop app after transcriptions and on a timer
- Fetch live billing on `/health/auth` while keeping cached billing for normal auth
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Warning

Rate limit exceeded

@Derpedyea has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 45 minutes and 3 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: d7f910ed-20c1-4d83-a79a-b1b701019ad3

📥 Commits

Reviewing files that changed from the base of the PR and between 8624bd0 and 0a95cf2.

📒 Files selected for processing (2)
  • apps/desktop/main.cjs
  • apps/worker/src/index.ts
📝 Walkthrough

Walkthrough

The desktop app now implements periodic worker authentication polling with post-transcription refresh scheduling. The worker's /health/auth endpoint was updated to provide live billing data instead of cached billing. These changes enable the desktop app to keep authorization and usage credits current without explicit user action.

Changes

Worker Auth & Live Billing Integration

Layer / File(s) Summary
Worker Authorization Enhancement
apps/worker/src/index.ts
authorizeDesktop now accepts an optional options parameter with liveBilling flag; when enabled, it fetches live billing via getBilling() instead of using getCachedBilling(). The /health/auth endpoint passes { liveBilling: true } when authorizing the desktop.
Desktop Polling State & Configuration
apps/desktop/main.cjs (lines 42–59)
Module-level state added for polling timer, in-flight guard flag, and usage-credit refresh timer tracking. Constants defined for poll interval (5 minutes) and post-transcription refresh delays.
Desktop Polling Core Logic
apps/desktop/main.cjs (lines 594–643)
Implemented configureWorkerAuthPolling() to establish the recurring poll interval, refreshWorkerAuthFromPoll() to execute polls with guards (skips when logged out, already polling, or app is busy recording/transcribing), and scheduleUsageCreditRefresh() / clearUsageCreditRefreshTimers() to manage delayed refresh attempts.
Integration & Lifecycle Management
apps/desktop/main.cjs (lines 139, 170–174, 583–589, 915, 985)
Polling wired into app startup (app.whenReady()); timers cleared on app shutdown (will-quit), device login, and logout. Usage-credit refresh scheduling triggered after transcription completes or when transcript is empty.

Sequence Diagram

sequenceDiagram
    participant Desktop App
    participant Poll Timer
    participant Worker Service
    participant Billing System

    Poll Timer->>Desktop App: Poll interval fires
    Desktop App->>Desktop App: Check if should proceed<br/>(not busy, not already in-flight, signed in)
    
    alt Should proceed
        Desktop App->>Worker Service: GET /health/auth<br/>+ poll attempt
        Worker Service->>Worker Service: authorizeDesktop({<br/>liveBilling: true })
        Worker Service->>Billing System: getBilling(userId)
        Billing System-->>Worker Service: Current usage/credits
        Worker Service-->>Desktop App: DesktopAuthorization<br/>(with live billing)
        Desktop App->>Desktop App: Update auth state
    else Skip (logged out, busy, etc.)
        Desktop App->>Desktop App: Skip poll
    end
    
    Note over Desktop App: Next poll in 5 minutes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop, poll, and refresh so fine,
Five-minute beats in perfect time,
Live billing flows from worker's grace,
Credits tracked at rapid pace!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 'Fix usage credit polling in desktop app' directly aligns with the main changes—adding worker auth polling, post-transcription refresh scheduling, and live billing data refresh in the desktop app.
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
  • Commit unit tests in branch fix/usage-credit-polling

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.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 5, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
laryn-transcribe 0a95cf2 May 05 2026, 02:45 AM

@Derpedyea
Copy link
Copy Markdown
Member Author

cursor review

@Derpedyea
Copy link
Copy Markdown
Member Author

cursor review verbose=true

@cursor
Copy link
Copy Markdown

cursor Bot commented May 5, 2026

Bugbot request id: serverGenReqId_123afca4-ca3d-44ab-bf22-04c0d49067fe

Copy link
Copy Markdown

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

🧹 Nitpick comments (1)
apps/desktop/main.cjs (1)

625-635: ⚡ Quick win

Avoid always firing all three post-transcription retries.

With this PR, each of these timers ends up calling /health/auth, and /health/auth now does a live Polar billing read. Scheduling all three retries unconditionally means every dictation adds three extra live auth/billing checks even when the first refresh already caught up. Please short-circuit the remaining timers once billing changes, or collapse this to a single delayed retry plus the 5-minute poll.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/main.cjs` around lines 625 - 635, The current
scheduleUsageCreditRefresh schedules all
POST_TRANSCRIPTION_USAGE_REFRESH_DELAYS_MS timers unconditionally, causing
multiple /health/auth billing reads; change the flow so retries short-circuit
once a refresh detects billing changes: update refreshWorkerAuthFromPoll to
return a boolean (e.g., true if billing/auth state changed) and in
scheduleUsageCreditRefresh replace the fire-and-forget call with an async
callback that awaits const changed = await refreshWorkerAuthFromPoll(reason); if
changed then call clearUsageCreditRefreshTimers() and exit so remaining timers
are cancelled; keep usageCreditRefreshTimers and timer.unref as before so
outstanding timers can be cleared safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/worker/src/index.ts`:
- Around line 974-976: Replace the unbounded live billing call by wrapping
getBilling(env, device.user_id) in a short timeout (1–2s) and falling back to
getCachedBilling on timeout or error: create a timeout promise (e.g.,
Promise.race with a timer that rejects or resolves after ~1500ms), attempt await
getBilling(...) inside that race, and if the race rejects or throws, catch the
error and call await getCachedBilling(env, device.user_id) instead; log the
timeout/error for observability. Ensure the change targets the billing
resolution logic where options.liveBilling is checked so callers of
getBilling/getCachedBilling (and related flows like
ensurePolarCustomer/withPolarUsageCredits) receive cached billing when live
lookup fails or times out.

---

Nitpick comments:
In `@apps/desktop/main.cjs`:
- Around line 625-635: The current scheduleUsageCreditRefresh schedules all
POST_TRANSCRIPTION_USAGE_REFRESH_DELAYS_MS timers unconditionally, causing
multiple /health/auth billing reads; change the flow so retries short-circuit
once a refresh detects billing changes: update refreshWorkerAuthFromPoll to
return a boolean (e.g., true if billing/auth state changed) and in
scheduleUsageCreditRefresh replace the fire-and-forget call with an async
callback that awaits const changed = await refreshWorkerAuthFromPoll(reason); if
changed then call clearUsageCreditRefreshTimers() and exit so remaining timers
are cancelled; keep usageCreditRefreshTimers and timer.unref as before so
outstanding timers can be cleared safely.
🪄 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: 278a0c0a-9e3f-42b1-845b-d8ccc78a7cab

📥 Commits

Reviewing files that changed from the base of the PR and between 8c04529 and 8624bd0.

📒 Files selected for processing (2)
  • apps/desktop/main.cjs
  • apps/worker/src/index.ts

Comment thread apps/worker/src/index.ts
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 2 files

Confidence score: 3/5

  • There is moderate merge risk: two medium-severity findings (6/10) with solid confidence indicate concrete reliability impact rather than just housekeeping.
  • In apps/desktop/main.cjs, busy-state polling can drop scheduled usage-credit refreshes without retry, which risks missing post-transcription billing updates for users.
  • In apps/worker/src/index.ts, /health/auth performs a live getBilling() call without timeout/fallback, so Polar slowness can stall the endpoint and create false health instability.
  • Pay close attention to apps/desktop/main.cjs and apps/worker/src/index.ts - retry behavior for deferred billing refreshes and timeout/fallback handling around external billing calls.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/main.cjs">

<violation number="1" location="apps/desktop/main.cjs:610">
P2: Busy-state polling returns drop scheduled usage-credit refreshes without retry. Defer and retry instead of returning immediately so post-transcription billing updates are not lost.</violation>
</file>

<file name="apps/worker/src/index.ts">

<violation number="1" location="apps/worker/src/index.ts:975">
P2: The live `getBilling()` call in this health-check endpoint has no timeout or fallback. Since `getBilling` reaches an external service (Polar), a slow or degraded response will stall the entire `/health/auth` response, causing the desktop poller to treat the worker as unreachable. Wrap the call with `withTimeout` (already available in this file) and fall back to `getCachedBilling()` on timeout/error.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Desktop as Desktop App (main.cjs)
    participant Timer as Auth Poll Timer
    participant Worker as Worker (Cloudflare/API)
    participant DB as Database

    Note over Desktop,DB: Desktop Auth & Billing Refresh Flow

    Desktop->>Desktop: configureWorkerAuthPolling()
    Desktop->>Timer: setInterval(5 min)

    loop Every 5 Minutes
        Timer->>Desktop: trigger refreshWorkerAuthFromPoll("interval")
        alt Token exists & no poll in flight
            alt App is idle (not recording/transcribing/pasting)
                Desktop->>Worker: GET /health/auth (Bearer token)
                Worker->>Worker: authorizeDesktop(liveBilling=true)
                Worker->>DB: getBilling(device.user_id) [live, not cached]
                DB-->>Worker: billing data
                Worker-->>Desktop: { deviceId, billing, ... }
                Desktop->>Desktop: patchStatus with new billing
            else App busy
                Desktop->>Desktop: skip poll
            end
        else No token or in flight
            Desktop->>Desktop: skip poll
        end
    end

    Note over Desktop,DB: Post-Transcription Credit Refresh

    Desktop->>Desktop: transcription:submit result
    alt Non-empty transcript
        Desktop->>Desktop: scheduleUsageCreditRefresh("transcription-complete")
    else Empty transcript
        Desktop->>Desktop: scheduleUsageCreditRefresh("transcription-empty")
    end

    Desktop->>Desktop: clearUsageCreditRefreshTimers()
    loop For each delay [5s, 20s, 60s]
        Desktop->>Desktop: setTimeout(refreshWorkerAuthFromPoll, delay)
    end

    Note over Desktop: Each timer fires independently
    Desktop->>Worker: GET /health/auth (Bearer token)
    Worker->>Worker: authorizeDesktop(liveBilling=true)
    Worker->>DB: getBilling(device.user_id) [live]
    DB-->>Worker: updated billing (credits synced)
    Worker-->>Desktop: fresh billing data
    Desktop->>Desktop: patchStatus with new credits

    Note over Desktop,DB: Logout / Device Login

    Desktop->>Desktop: logoutDevice()
    Desktop->>Desktop: clearUsageCreditRefreshTimers()
    Desktop->>Desktop: startDeviceLogin()
    Desktop->>Desktop: clearUsageCreditRefreshTimers()

    Note over Desktop: App quit
    Desktop->>Desktop: clearUsageCreditRefreshTimers()
    Desktop->>Timer: clearInterval(workerAuthPollTimer)
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/desktop/main.cjs Outdated
Comment thread apps/worker/src/index.ts Outdated
- Skip desktop usage refresh while dictation or auth polling is busy
- Add a live billing timeout with cached fallback for desktop auth
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 2 files (changes from recent commits).

@Derpedyea Derpedyea merged commit b2484e3 into main May 5, 2026
5 checks passed
@Derpedyea Derpedyea deleted the fix/usage-credit-polling branch May 5, 2026 02:47
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