Skip to content

feat: add custom_msg websocket type with QR download links#574

Merged
WcaleNieWolny merged 2 commits intomainfrom
feat/custom-msg-qr-download
Apr 5, 2026
Merged

feat: add custom_msg websocket type with QR download links#574
WcaleNieWolny merged 2 commits intomainfrom
feat/custom-msg-qr-download

Conversation

@WcaleNieWolny
Copy link
Copy Markdown
Contributor

@WcaleNieWolny WcaleNieWolny commented Apr 5, 2026

Summary

  • Adds a generic custom_msg websocket message type with kind and data fields — extensible for future use cases
  • First kind: qr_download_link renders a scannable QR code + URL text in the terminal for APK/IPA downloads
  • Unknown kind values show a warning + raw data dump (forward-compatible with newer server versions)
  • Wired up in both the default BuildLogger (console path) and the Ink onboarding UI

Companion PR: Cap-go/capgo_builder — pushes the custom_msg from the server on build success

Test plan

  • Build with --output-upload and verify QR code renders after success
  • Verify QR code is scannable and resolves to the download URL
  • Verify URL text appears below QR code for copy-paste
  • Verify unknown kind values show warning + raw JSON
  • Verify tsc --noEmit passes

Summary by CodeRabbit

  • New Features
    • QR codes are now rendered in build logs for quick scanning of download links.
    • Build output now shows custom messages from the build process (including link notifications) inline with logs.

Add a generic `custom_msg` websocket message type that the CLI can
handle in a custom way. First use case: `qr_download_link` renders
a scannable QR code + URL text for APK/IPA download links.

- Add `customMsg` callback to BuildLogger interface
- Add `custom_msg` case to websocket message handler
- Create qr.ts helper with QR rendering (qrcode package)
- Unknown message kinds show warning + raw data dump
- Wire up both default logger and Ink onboarding UI
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 085a8042-42ce-4ee9-af00-0b2970a9370c

📥 Commits

Reviewing files that changed from the base of the PR and between 42b6fd4 and e0d4006.

📒 Files selected for processing (3)
  • src/build/onboarding/ui/app.tsx
  • src/build/qr.ts
  • src/build/request.ts
✅ Files skipped from review due to trivial changes (1)
  • src/build/onboarding/ui/app.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/build/qr.ts

📝 Walkthrough

Walkthrough

Adds QR code generation and custom WebSocket message handling to the build log pipeline: a new qrcode dependency, a handleCustomMsg QR handler module, integration into the build logger via a new customMsg callback, and streaming changes to dispatch custom_msg entries through the handler.

Changes

Cohort / File(s) Summary
Dependencies
package.json
Added runtime and type dependencies: qrcode (^1.5.4) and @types/qrcode (^1.5.6).
QR Code Handler
src/build/qr.ts
New exported handleCustomMsg(kind, data, log, warn): Promise<void> that handles qr_download_link (validates data.url, attempts QR generation, logs QR ASCII + URL) and warns/logs raw JSON for unknown kinds.
Build Logging & Streaming
src/build/request.ts, src/build/onboarding/ui/app.tsx
Added customMsg to BuildLogger; createDefaultLogger delegates to handleCustomMsg; streamBuildLogs message handler is now async, parses kind/data, and routes entries with type === 'custom_msg' to logger.customMsg (or fallback) before continuing.

Sequence Diagram

sequenceDiagram
    participant WS as WebSocket Stream
    participant REQ as streamBuildLogs (request.ts)
    participant LOG as BuildLogger (app.tsx)
    participant QR as handleCustomMsg (qr.ts)
    participant OUT as Console / Output

    WS->>REQ: Emit message (batch or single) containing entry with type='custom_msg', kind, data
    REQ->>REQ: Parse message, detect entry.type === 'custom_msg'
    REQ->>LOG: await logger.customMsg(kind, data)  or fallback to QR handler
    LOG->>QR: handleCustomMsg(kind, data, logFn, warnFn)
    alt kind == "qr_download_link"
        QR->>QR: validate data.url is string
        QR->>QR: QRCode.toString(url, {type:'utf8', errorCorrectionLevel:'L'})
        QR->>OUT: log empty line, each QR line, URL, empty line
    else unknown kind
        QR->>OUT: warn about unknown kind
        QR->>OUT: log pretty-printed data JSON
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped into logs where messages play,
Turned links into matrices, black and gray,
A QR nibble, a tiny scanned light,
Now builds beam patterns into the night,
Hooray—tiny squares that guide your byte! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: adding a custom_msg websocket type with QR download links, which is the primary feature being implemented across the modified files.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/custom-msg-qr-download

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

@WcaleNieWolny
Copy link
Copy Markdown
Contributor Author

Companion server-side PR: Cap-go/capgo_builder#67

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

🧹 Nitpick comments (1)
src/build/request.ts (1)

62-63: Consider documenting or fixing the sync/async interface mismatch.

The customMsg callback is typed as synchronous void, but all implementations call async handleCustomMsg without awaiting. While this works for the current single-message use case, the interface doesn't communicate that implementations may be async.

💡 Option: Update interface to support async
   /** Called with custom messages from the builder (QR codes, etc.) */
-  customMsg: (kind: string, data: Record<string, unknown>) => void
+  customMsg: (kind: string, data: Record<string, unknown>) => void | Promise<void>

This makes the async nature explicit and allows callers to await if needed in the future.

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

In `@src/build/request.ts` around lines 62 - 63, The customMsg callback is
currently declared as synchronous (customMsg: (kind: string, data:
Record<string, unknown>) => void) but implementations call async functions like
handleCustomMsg without awaiting; change the callback signature to return a
Promise<void> so the async contract is explicit (customMsg: (kind: string, data:
Record<string, unknown>) => Promise<void>), update all implementations (e.g.,
functions calling handleCustomMsg) to be async and return/await the promise, and
update any callers of customMsg to await its result where appropriate to
preserve correct async flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/build/onboarding/ui/app.tsx`:
- Around line 546-553: The call to async handleCustomMsg is not awaited, causing
possible out-of-order buildOutput updates; update the BuildLogger.customMsg
signature (in the BuildLogger interface) to return Promise<void> (or
void|Promise<void>), change the customMsg implementation in app.tsx to be async
and await handleCustomMsg(...) (i.e., make the customMsg callback async and
await the handleCustomMsg call), and update any other call sites/types that rely
on BuildLogger.customMsg to accept the Promise-returning signature so the async
behavior is properly propagated.

In `@src/build/qr.ts`:
- Line 16: The warn messages in src/build/qr.ts are double-prefixed because the
warn callback already prepends "⚠ "; update the two warn(...) calls (the ones
currently passing strings that start with "⚠ ") to remove the manual "⚠ " prefix
so they only pass the descriptive text (e.g., change warn('⚠ qr_download_link
message missing url field') to warn('qr_download_link message missing url
field') and likewise for the other warn at line 39), leaving the warn function
and its callback unchanged.

In `@src/build/request.ts`:
- Around line 114-124: customMsg currently calls handleCustomMsg without
awaiting and passes a logger that causes duplicate warning prefixes; update
customMsg to await handleCustomMsg (so it isn't fire-and-forget) and pass a
plain warning printer that does not add an extra "⚠" (replace clackLog.warn with
a simple wrapper or use clackLog.info/print depending on clack API) and keep the
console.log printer for standard lines; also ensure you apply the same
single-prefix change you made in qr.ts so the warning symbol isn't duplicated
when clackLog functions already add styling.

---

Nitpick comments:
In `@src/build/request.ts`:
- Around line 62-63: The customMsg callback is currently declared as synchronous
(customMsg: (kind: string, data: Record<string, unknown>) => void) but
implementations call async functions like handleCustomMsg without awaiting;
change the callback signature to return a Promise<void> so the async contract is
explicit (customMsg: (kind: string, data: Record<string, unknown>) =>
Promise<void>), update all implementations (e.g., functions calling
handleCustomMsg) to be async and return/await the promise, and update any
callers of customMsg to await its result where appropriate to preserve correct
async flow.
🪄 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: d67aca46-604c-48d0-babd-760311137f76

📥 Commits

Reviewing files that changed from the base of the PR and between e5bf612 and 42b6fd4.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • package.json
  • src/build/onboarding/ui/app.tsx
  • src/build/qr.ts
  • src/build/request.ts

- Make customMsg callback async and await handleCustomMsg at all
  call sites (default logger, websocket handler, onboarding UI)
- Update BuildLogger.customMsg signature to void | Promise<void>
- Remove manual ⚠ prefix from warn() calls in qr.ts since the
  warn callbacks already add their own warning styling
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 5, 2026

@WcaleNieWolny WcaleNieWolny merged commit 136db48 into main Apr 5, 2026
18 of 19 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