Skip to content

feat: Bluetooth printer setup overhaul — scan feedback, OS-paired Classic printers, typed discovery errors#590

Merged
kilbot merged 23 commits into
mainfrom
feat/bluetooth-scan-ux
Jun 13, 2026
Merged

feat: Bluetooth printer setup overhaul — scan feedback, OS-paired Classic printers, typed discovery errors#590
kilbot merged 23 commits into
mainfrom
feat/bluetooth-scan-ux

Conversation

@kilbot

@kilbot kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Why

Windows 1.9.3 users report the Bluetooth "Scan for printers" button "does nothing". Diagnosis (instrumented Electron main + standalone CoreBluetooth scan): the Web Bluetooth chooser opened invisibly, found no filter-matching BLE device, and waited forever with zero UI feedback; a re-click cancelled the orphaned session with an error the connector library swallows. Deeper: Web Bluetooth is BLE-only — Bluetooth Classic printers (most receipt printers, e.g. Epson TM-m30 family) can never appear in that scan, on any platform.

Companion PR: wcpos/electron#268 (chooser listener-leak fix + serial printing path). Merge order: electron PR first, then bump the submodule pointer here to electron main's merge commit (currently pinned to the PR branch head 8ab4894 so CI builds the right code).

What

Make Classic printers work via OS pairing (the printers users actually have)

  • Windows: the Bluetooth tab now leads with an Installed printers section (spooler queues incl. paired BT printers, auto-scanned on mount) — printing routes through the existing winspool RAW path.
  • macOS/Linux: a Paired Bluetooth printers section lists OS-paired serial devices (serial-discovery IPC → /dev/cu.*, noise-filtered); printing routes via a new SerialElectronAdapterprint-raw-serial (serialport, open→write→drain→close, timeout + ghost-print guard).
  • Transport routing is by address prefix (winspool: / serial: → native adapters, before connectionType), so profiles created from the Bluetooth tab always print natively.

Make the BLE scan honest and stateful

  • New pure session state machine (bluetooth-scan-session.ts): 20s discovery timeout, 30s connect timeout (GATT setup on slow printers; deliberate deviation from the spec's 10s), cancel, per-session generation guards against stale timers/closures from uncancellable in-flight connects.
  • Scan button shows loading/"Scanning…" + Cancel; live candidate list; timeout yields translated guidance ("Bluetooth Classic printers cannot be discovered by this scan — if your printer is paired with this computer, it appears under Paired or Installed printers."); a persistent hint explains the scan's BLE scope (TM-P/Star L class printers). Double-click-cancels-scan is impossible (button disabled while active).
  • Chooser candidate state moved out of the picker component into the discovery hook (single owner; ElectronBtPicker is now a dumb list).

Typed discovery errors

  • Hooks emit DiscoveryError codes (bt-none-found, bt-connect-failed, usb-none-found, network-none-found, ipc-unavailable, discovery-failed+detail) instead of hardcoded English strings; dialogs map codes → translated strings via formatDiscoveryError. Note: this migrates the error shape across web/native hook variants too (compatibility migration forced by shared types; all consumers updated in this PR).
  • USB tab now auto-loads on entry (usb-discovery is an instant enumeration); the button became Refresh for hot-plug re-checks. It also gained a busy state (getPrintersAsync can stall on Windows with offline queues — the button looked dead).

Validation

  • Root lint 9/9 · pnpm typecheck --force 6/6 · new CI gates pass locally (check-dep-duplicates, check-expo-alignment)
  • packages/printer vitest: 388 passed (incl. 15 session-machine, 13 hook, 7 adapter/routing tests)
  • packages/core jest (printer settings): 75 passed
  • Electron suite (in feat(cart): add optional product image column #268): all 8 scripts incl. new test:bluetooth-select, test:serial-printer, and the packaging test that now genuinely loads serialport from the packaged tree
  • Manual verification on macOS dev: scan lifecycle (scanning → none-found guidance), cancel, paired-printers section rendering

Needs live verification on Windows: the Installed-printers section + winspool print from the BT tab (no Windows machine locally).

Known limitations / follow-ups

  • Bluetooth Classic inquiry (unpaired discovery) intentionally out of scope — OS pairing is the supported flow.
  • Linux serial listing is permissive (/dev/ttyS*/ttyUSB* appear alongside rfcomm) — deliberate, USB-serial printers are legitimate POS hardware.
  • A lingering bt-none-found message can remain visible after switching tabs (only usb-none-found is suppressed cross-tab) — cosmetic.

Spec + plan: local planning docs (not committed per repo policy).

Summary by CodeRabbit

  • New Features

    • Bluetooth device chooser and explicit scan/cancel controls for printer pairing.
    • Serial printer support and improved Windows-native printer discovery routing.
  • Improvements

    • Separate USB/Bluetooth/Serial scanning states with clearer scanning statuses and progress text.
    • Structured, more specific discovery error messages and centralized formatting.
    • Additional localization strings for printer discovery and helper texts.
  • Tests

    • Added unit/integration tests covering discovery flows and adapters.

kilbot added 18 commits June 13, 2026 00:35
- Add generation counter; increment in start() and finish() to invalidate
  stale timers and closures from ended sessions.
- Guard discovery timer body, connect timer body, and startChooser
  onConnected closure with gen !== generation checks.
- Bail after startChooser call (Fix 2) if a synchronous onConnected already
  ended the session, preventing a dangling discovery timer.
- Send sendSelection('') in onConnected when phase === 'discovering' (Fix 3)
  to dismiss the still-pending main-process chooser on auto-reconnect.
- Add 7 new vitest tests: timeout overrides, cancel-during-connecting,
  restart interval hygiene (×2), discovering auto-connect, stale-closure
  ignore, and reentrancy/onError-restart.
…ed discovery errors

- Rewrites use-printer-discovery.electron.ts: wires createBluetoothScanSession (per-session
  generation guards, discovery/connect timeouts), adds isUsbScanning busy state, migrates
  error type from string to DiscoveryError, exposes bluetoothCandidates/selectBluetoothCandidate/
  cancelBluetoothScan, expands ElectronIpc to include send/on for session IPC
- Migrates use-printer-discovery.web.ts: DiscoveryError error type, optional session members
  for interface congruence, structured error codes (network-none-found, discovery-failed)
- Migrates use-printer-discovery.ts (base/native): same DiscoveryError migration, optional
  session members, maps SDK failure strings to structured codes
- Adds JSDoc to DiscoveryError in types.ts (review feedback)
- Adds 6 hook-level integration tests in vitest; adds webbluetooth ESM alias to vitest config
  so the browser-only package resolves in the node test environment

# Conflicts:
#	pnpm-lock.yaml
…connect-timeout, ipc-unavailable, cancel paths
…s on BT tab, typed error mapping

- add-printer.electron: wire isUsbScanning/isBluetoothScanning/bluetoothCandidates/selectBluetoothCandidate/cancelBluetoothScan from hook; USB scan button shows loading/disabled state; Bluetooth section replaced with scan+cancel button row, searching text, ElectronBtPicker (props-driven), and InstalledPrintersSection on Windows; error render uses formatDiscoveryError
- add-printer.tsx + add-printer.web.tsx: replace .replace('%s', error) with formatDiscoveryError(error, t)
- installed-printers-section: add useWatch selected-state highlight matching DeviceList idiom; test adds scanning branch and useWatch mock
…or electron

Adds SerialElectronAdapter (mirrors UsbElectronAdapter, channel print-raw-serial),
routes serial: addresses in device-adapter.electron.ts, and adds connectSerialDevice
/ isSerialScanning to the electron discovery hook (no error on empty — UI owns that
state). Interface members added to web and native hook variants for congruence.
…paired serial devices

Generalise InstalledPrintersSection → OsPrintersSection with configurable
addressPrefix/heading/hint/emptyText/loadingText/testIdPrefix props, covering
both the Windows winspool: path and the new macOS/Linux serial: path.  Wire
the Bluetooth tab of add-printer.electron.tsx to show the winspool variant on
Windows and the serial variant elsewhere (guarded by connectSerialDevice
existence).  Exclude serial: entries from DeviceList to avoid duplication.
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 85ae9815-5593-48fa-abb7-5ec38c920d04

📥 Commits

Reviewing files that changed from the base of the PR and between dd628cb and f5d5d21.

📒 Files selected for processing (2)
  • packages/printer/src/transport/__tests__/serial-adapter.electron.test.ts
  • packages/printer/src/transport/serial-adapter.electron.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/printer/src/transport/tests/serial-adapter.electron.test.ts

📝 Walkthrough

Walkthrough

This PR implements structured Bluetooth printer discovery and error handling across the POS system. It introduces a state-machine-based Bluetooth session controller with timeout management, refactors printer discovery hooks to report typed errors, adds composable UI components for device selection, and extends the transport layer to support serial device printing via Electron.

Changes

Printer Discovery and Error Handling Refactoring

Layer / File(s) Summary
Discovery error types and formatting
packages/printer/src/types.ts, packages/core/src/screens/main/settings/printer/dialog/discovery-error-message.ts, packages/printer/src/index.ts
Introduces DiscoveryError (with code and optional detail) and DiscoveryErrorCode union type for standardized error reporting; adds BluetoothCandidate shape; provides formatDiscoveryError helper to map error codes to translated user messages, centralizing error formatting logic across web/Electron dialogs.
Bluetooth scan session state machine
packages/printer/src/discovery/bluetooth-scan-session.ts, packages/printer/src/discovery/bluetooth-scan-session.test.ts
Implements createBluetoothScanSession state machine managing idle/discovering/connecting phases with per-session generation counters to prevent stale timer and callback issues; enforces discovery (20s) and connect (30s) timeouts; sends empty selection on timeout/cancel to dismiss Bluetooth chooser; includes comprehensive test coverage for lifecycle, timeout overrides, reentrancy, and stale closure handling.
Printer discovery hooks (web/Electron/shared)
packages/printer/src/hooks/use-printer-discovery.ts, packages/printer/src/hooks/use-printer-discovery.web.ts, packages/printer/src/hooks/use-printer-discovery.electron.ts, packages/printer/src/hooks/use-printer-discovery.electron.test.tsx
Updates usePrinterDiscovery to return structured `DiscoveryError
Discovery UI components
packages/core/src/screens/main/settings/printer/dialog/connection/usb-printers-section.tsx, packages/core/src/screens/main/settings/printer/dialog/connection/os-printers-section.tsx, packages/core/src/screens/main/settings/printer/dialog/connection/electron-bt-picker.tsx, packages/core/src/screens/main/settings/printer/dialog/connection/is-windows.ts, packages/core/src/screens/main/settings/printer/dialog/connection/*.test.tsx
Adds UsbPrintersSection with optional refresh button and mount auto-scan; implements OsPrintersSection filtering printers by address prefix with form integration for winspool/serial address selection; refactors ElectronBtPicker from IPC-driven to prop-driven component accepting candidates array and selection callback; adds isWindowsPlatform helper for branch logic; full unit test coverage validates component behavior, form updates, and scanning state transitions.
Add-printer dialog integration
packages/core/src/screens/main/settings/printer/add-printer.electron.tsx, packages/core/src/screens/main/settings/printer/add-printer.tsx, packages/core/src/screens/main/settings/printer/add-printer.web.tsx
Electron dialog integrates new UsbPrintersSection and OsPrintersSection, branches UI by platform (Windows vs non-Windows) for installed/paired printer discovery, adds Bluetooth scan/cancel buttons with candidate picker, filters device list to exclude serial addresses; suppresses USB "none found" error during Bluetooth mode; web/shared dialogs use formatDiscoveryError for consistent error display; removes inline translation templates in favor of centralized error formatter.
Serial transport adapter
packages/printer/src/transport/serial-adapter.electron.ts, packages/printer/src/transport/device-adapter.electron.ts, packages/printer/src/transport/__tests__/*
Introduces SerialElectronAdapter implementing PrinterTransport for sending raw bytes to Electron main process via IPC with 30s timeout; updates createDeviceTransport to route winspool: and serial: address prefixes to appropriate adapters before falling back to connection-type logic; includes tests verifying IPC invocation, timeout behavior, and error handling when IPC is unavailable.
Translations and configuration
packages/core/src/contexts/translations/locales/en/core.json, packages/printer/package.json, packages/printer/vitest.config.ts, pnpm-workspace.yaml, apps/electron
Adds English translation strings for Bluetooth/USB/serial discovery UI (scan prompts, pairing hints, "no devices found" messages, IPC error notices); updates dev dependencies to support React Testing Library; configures Vitest module alias for Bluetooth receipt printer ESM bundle; adds pnpm workspace overrides for native module versions; bumps Electron submodule commit.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant Dialog as Add-Printer Dialog
  participant Hook as usePrinterDiscovery
  participant Session as BluetoothScanSession
  participant IPC as Electron IPC
  participant Chooser as Web Bluetooth Chooser
  User->>Dialog: Click "Scan for Bluetooth"
  Dialog->>Hook: connectBluetoothDevice()
  Hook->>Session: start()
  Session->>IPC: invoke startChooser
  IPC->>Chooser: show device picker
  Chooser-->>IPC: onConnected(device)
  IPC->>Hook: emit bluetooth-devices update with candidates
  Dialog->>Dialog: render ElectronBtPicker with candidates
  User->>Dialog: select device
  Dialog->>Hook: selectBluetoothCandidate(id)
  Hook->>Session: select(deviceId)
  Session->>IPC: sendSelection(deviceId)
  Session->>Session: schedule 30s connect timeout
  Chooser-->>IPC: onConnected(selectedDevice)
  Hook->>Hook: merge device into printers list
  Dialog->>Dialog: show selected printer
  User->>Dialog: confirm and save
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • wcpos/monorepo#522: Both PRs modify Electron printer discovery/connection UI and add Bluetooth/USB device selection flows.
  • wcpos/monorepo#553: Both PRs update the apps/electron submodule commit pointer.
  • wcpos/monorepo#505: Both PRs update printer discovery hooks and error handling in use-printer-discovery.web.ts to support structured discovery errors and state management.

"🐰 Hop, hop — scanners sing, timeouts keep,
Bluetooth picks, and errors speak,
Sessions guard the chooser's way,
Printers found to save the day! "

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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 accurately describes the main change: Bluetooth printer setup improvements including scan feedback, OS-paired Classic printers support, and typed discovery errors.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/bluetooth-scan-ux

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

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

The following issues were found:

  • ❌ 1 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ✅ 0 package(s) with unknown licenses.
  • ⚠️ 130 packages with OpenSSF Scorecard issues.

View full job summary

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a28be5196b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/printer/src/hooks/use-printer-discovery.electron.ts
@wcpos-bot

wcpos-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

PR fix round 3 triage (pre-fix):

# Source File Class Category Decision Outcome
1 chatgpt-codex-connector use-printer-discovery.electron.ts Logic Inline review Fix Catch synchronous Web Bluetooth chooser/connect failures and finish the scan session with a typed error.
2 CI: Lint locale files Mechanical Translation check Fix Add the 16 missing English settings.* translation source strings.
3 CI: dependency-review pnpm-lock.yaml Mechanical Vulnerable dependency Fix Remove vulnerable shell-quote@1.8.3 from the lockfile resolution path.
4 CI: Merge Gate workflow Mechanical Required check aggregation Skip This is downstream of the lint failure and should clear once lint passes.

Skipped threads: none at pre-fix inventory time; the fresh GraphQL query shows one unresolved inline thread and it is row #1.

…mes Refresh

usb-discovery is an instant enumeration (libusb on macOS/Linux, spooler
queues on Windows), so trigger it on mount via UsbPrintersSection — consistent
with OsPrintersSection's auto-load pattern. The button's remaining purpose is
re-checking after hot-plug; relabelled to Refresh (settings.refresh_devices).
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

🚀 Deployment Summary

Item Status
Preview URL https://wcpos--p2bd4der8o.expo.app
E2E Tests ✅ Passed
Commit 35f228d

🔗 Quick Links


🤖 Updated by GitHub Actions

kilbot added 2 commits June 13, 2026 01:01
concurrently@9.2.1 (apps/electron devDep) pins the vulnerable 1.8.3 exactly,
so the resolver cannot pick the patched release without an override.
…issing translation source strings

Codex review: a sync throw from the connector constructor (no
navigator.bluetooth / policy-disabled) escaped start() after scanning state
was set, wedging the scan button. The session machine now catches it and
finishes with discovery-failed. Adds the 16 new settings.* keys to the
English locale file (translations:check gate).
@kilbot

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Fix round triage (complete — extends wcpos-bot's pre-fix inventory):

# Source File Class Category Decision Outcome
1 chatgpt-codex-connector bluetooth-scan-session.ts Logic P2 inline Fix Fixed in f2119d735 — sync startChooser throw now ends the session with discovery-failed; session + hook tests added. Fixed at the session machine (not the hook) so every chooser-throw path is covered. Thread resolved.
2 CI: Lint (translations:check) en/core.json Mechanical Missing source strings Fix Fixed in f2119d735 — all 16 new settings.* keys added to the English locale file (alphabetical, exact fallback strings from source).
3 CI: dependency-review pnpm-workspace.yaml Mechanical Critical vuln (GHSA-w7jw-789q-3m8p) Fix Fixed in 3320719ccconcurrently@9.2.1 pins shell-quote@1.8.3 exactly, so a pnpm override (shell-quote: >=1.8.4) forces the patched release; lockfile now resolves 1.8.4 only.
4 CI: Merge Gate workflow Mechanical Downstream Skip Clears once Lint passes (same root cause as #2).

Validation on f2119d735: printer vitest 390/390, translations:check clean, check-dep-duplicates + check-expo-alignment clean, package tsc clean. Companion wcpos/electron#268 is CI-green and unchanged this round.

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix round triage (post-fix):

Thread File Issue Decision Commit
PRRT_kwDOGW7Gic6JRDny use-printer-discovery.electron.ts Synchronous Web Bluetooth chooser/connect throw could leave the Bluetooth scan session stuck in discovering state. Fixed and resolved. createBluetoothScanSession.start() now catches synchronous chooser failures, finishes the session, and surfaces a typed discovery-failed error with detail; session and hook tests cover the retry/non-wedged state. f2119d7

Excluded threads:

Thread Reason for skipping
None Fresh GraphQL review-thread inventory shows 0 unresolved threads.

CI blockers observed during this round:

Check Status
🧹 Lint translation source check Fixed by f2119d7; restarted check currently pending.
dependency-review vulnerable shell-quote@1.8.3 Fixed by 3320719; restarted check currently pending.

Remaining unresolved inline review threads: 0.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

📊 Test Coverage Report

Package Statements Branches Functions Lines
@wcpos/core 🔴 23.1% 🔴 26.8% 🔴 22.4% 🔴 22.6%
@wcpos/components 🔴 24.6% 🔴 27.3% 🔴 16.8% 🔴 24.3%
@wcpos/database 🟡 60.2% 🔴 55.0% 🟡 62.7% 🔴 59.7%
@wcpos/hooks 🔴 52.4% 🔴 50.1% 🔴 45.0% 🔴 52.4%
@wcpos/utils 🔴 55.9% 🟡 61.5% 🟡 71.4% 🔴 53.8%
@wcpos/query 🟢 83.7% 🟡 76.7% 🟡 77.7% 🟢 83.9%
Average 🔴 50.0% 🔴 49.6% 🔴 49.3% 🔴 49.4%
Coverage Legend
  • 🟢 Good (≥80%)
  • 🟡 Moderate (60-79%)
  • 🔴 Needs improvement (<60%)
  • ⚪ No coverage data
--- 🤖 Updated by GitHub Actions • [View full report](https://github.com/wcpos/monorepo/actions/runs/27448919585)

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix round 1 triage (pre-fix inventory on 2026-06-12):

# Source File Class Category Decision Outcome
1 CI: dependency-review pnpm-lock.yaml Mechanical Vulnerable dependency Fix tmp@0.0.33 is introduced via external-editor@3.1.0 and triggers GHSA-ph9p-34f9-6g65 (high severity path traversal). Add a focused pnpm override to force patched tmp@0.2.7 and regenerate the lockfile.

Skipped threads: none. Fresh GraphQL review-thread inventory shows 0 unresolved inline threads.

@wcpos-bot

wcpos-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

PR fix round triage (post-push):

Fresh unresolved inline review-thread inventory: 0 remaining.

Thread File Issue Decision Commit
CI: dependency-review pnpm-lock.yaml tmp@0.0.33 flagged by GHSA-ph9p-34f9-6g65 (high). external-editor@3.1.0 was the remaining resolver path. Fixed — added a targeted pnpm override for external-editor@3.1.0>tmp and regenerated the lockfile so only tmp@0.2.7 remains. dd628cb

Skipped threads:

Thread Reason for skipping
None Fresh GraphQL inventory after push returned 0 unresolved inline review threads.

Verification:

  • npm view tmp version versions --json confirmed tmp@0.2.7 is the current npm release.
  • pnpm install --lockfile-only completed against the initialized full workspace.
  • pnpm install --frozen-lockfile --lockfile-only passed.
  • node scripts/check-dep-duplicates.mjs passed.
  • node scripts/check-expo-alignment.mjs passed.
  • rg "tmp@0\\.0\\.33|tmp: 0\\.0\\.33|version: 0\\.0\\.33" pnpm-lock.yaml pnpm-workspace.yaml returned no matches.

Note: full pnpm install --frozen-lockfile --ignore-scripts hit local node_modules import filesystem errors (ENOTEMPTY/ENOENT) after confirming the lockfile was up to date; the lockfile-only frozen validation passed.

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix status update:

Thread File Issue Decision Commit
PRRT_kwDOGW7Gic6JRDny use-printer-discovery.electron.ts Synchronous Web Bluetooth chooser/connect throw could leave the Bluetooth scan session stuck in discovering state. Fixed and resolved. f2119d7

Excluded threads:

Thread Reason for skipping
None Fresh GraphQL review-thread inventory shows 0 unresolved threads.

Current non-thread blockers:

Check Status
dependency-review Latest failure was tmp@0.0.33; fixed by dd628cb. Restarted check is pending.
🧹 Lint translation source check Fixed by f2119d7. Restarted check is pending.

Remaining unresolved inline review threads: 0.

@wcpos-bot

wcpos-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Post-fix triage for PR #590:

Thread File Issue Decision Commit
discussion_r3406609355 use-printer-discovery.electron.ts Synchronous WebBluetoothReceiptPrinter.connect() / chooser failures could leave the Bluetooth scan session stuck in discovering state because the timeout was never armed. Fixed and thread resolved; startChooser throws now finish the session with typed discovery-failed. f2119d7

Excluded threads:

Thread Reason for skipping
None Fresh GraphQL inventory found 0 unresolved inline review threads.

CI handled separately:

Check Issue Decision Commit / Evidence
Lint Missing English settings.* translation source strings. Fixed. f2119d7; local pnpm translations:check passes.
dependency-review tmp@0.0.33 high advisory GHSA-ph9p-34f9-6g65. Fixed. dd628cb; current dependency-review check passes.
Merge Gate Aggregate required-check status. Pending/downstream. No failing merge-gate result on current head at comment time; lint/deploy/CodeRabbit are still running.

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix round 2 triage (post-check, no-op on current head):

Thread File Issue Decision Commit

Excluded threads:

Thread Reason for skipping
None Fresh GraphQL review-thread inventory shows 0 unresolved inline threads.

CI blockers checked this round:

Check Status
dependency-review vulnerable tmp@0.0.33 / GHSA-ph9p-34f9-6g65 Cleared on current head dd628cb. external-editor@3.1.0>tmp is overridden to 0.2.7; tmp@0.0.33 is absent from pnpm-lock.yaml; GitHub dependency-review is passing.
Review threads Fresh GraphQL inventory: 0 unresolved.
Lint / typecheck / script tests / translation source check Passing on current head.
Unit Tests Pending at time of this comment.
Deploy Pending at time of this comment.
CodeRabbit Pending at time of this comment.

No new commit was pushed in this round because the current PR head already contains the remaining dependency-review fix and the rerun has passed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@packages/printer/src/transport/serial-adapter.electron.ts`:
- Around line 26-37: The printRaw function leaves the timeout active because
Promise.race can't cancel losing branches; modify printRaw (in
serial-adapter.electron.ts) to create a cancelable timeout and clear it when
ipc.invoke('print-raw-serial', { device: this.deviceKey, data: Array.from(data)
}) resolves or rejects: e.g., store the setTimeout id and call
clearTimeout(timeoutId) after the IPC promise settles, or use an AbortController
to signal cancellation to the timeout branch, ensuring the timeout created with
PRINT_TIMEOUT_MS is cleaned up to avoid timer leaks.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d91f6e02-dd4b-4b58-a8e4-b5b4b76e325c

📥 Commits

Reviewing files that changed from the base of the PR and between f273d97 and dd628cb.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (29)
  • apps/electron
  • packages/core/src/contexts/translations/locales/en/core.json
  • packages/core/src/screens/main/settings/printer/add-printer.electron.tsx
  • packages/core/src/screens/main/settings/printer/add-printer.tsx
  • packages/core/src/screens/main/settings/printer/add-printer.web.tsx
  • packages/core/src/screens/main/settings/printer/dialog/connection/electron-bt-picker.test.tsx
  • packages/core/src/screens/main/settings/printer/dialog/connection/electron-bt-picker.tsx
  • packages/core/src/screens/main/settings/printer/dialog/connection/is-windows.ts
  • packages/core/src/screens/main/settings/printer/dialog/connection/os-printers-section.test.tsx
  • packages/core/src/screens/main/settings/printer/dialog/connection/os-printers-section.tsx
  • packages/core/src/screens/main/settings/printer/dialog/connection/usb-printers-section.test.tsx
  • packages/core/src/screens/main/settings/printer/dialog/connection/usb-printers-section.tsx
  • packages/core/src/screens/main/settings/printer/dialog/discovery-error-message.test.ts
  • packages/core/src/screens/main/settings/printer/dialog/discovery-error-message.ts
  • packages/printer/package.json
  • packages/printer/src/discovery/bluetooth-scan-session.test.ts
  • packages/printer/src/discovery/bluetooth-scan-session.ts
  • packages/printer/src/hooks/use-printer-discovery.electron.test.tsx
  • packages/printer/src/hooks/use-printer-discovery.electron.ts
  • packages/printer/src/hooks/use-printer-discovery.ts
  • packages/printer/src/hooks/use-printer-discovery.web.ts
  • packages/printer/src/index.ts
  • packages/printer/src/transport/__tests__/device-adapter.electron.test.ts
  • packages/printer/src/transport/__tests__/serial-adapter.electron.test.ts
  • packages/printer/src/transport/device-adapter.electron.ts
  • packages/printer/src/transport/serial-adapter.electron.ts
  • packages/printer/src/types.ts
  • packages/printer/vitest.config.ts
  • pnpm-workspace.yaml

Comment thread packages/printer/src/transport/serial-adapter.electron.ts

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix round 1 triage update (fresh pre-commit inventory on 2026-06-12):

# Source File Class Category Decision Outcome
1 CI: dependency-review pnpm-lock.yaml Mechanical Vulnerable dependency Fix tmp@0.0.33 is introduced via external-editor@3.1.0 and triggers GHSA-ph9p-34f9-6g65 (high severity path traversal). Add a focused pnpm override to force patched tmp@0.2.7 and regenerate the lockfile.
2 CodeRabbit serial-adapter.electron.ts Logic Timer leak Fix New unresolved thread reports that the timeout branch in Promise.race remains active after IPC resolves. Add a focused regression test and clear the timeout when the IPC promise settles.

Skipped threads: none. Fresh GraphQL review-thread inventory shows 1 unresolved inline thread, row #2, and it will be fixed in this round.

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix round 2 triage (post-fix):

Thread File Issue Decision Commit
PRRT_kwDOGW7Gic6JRYPy serial-adapter.electron.ts printRaw() left the losing timeout branch alive after ipc.invoke('print-raw-serial', ...) resolved, leaking a 30s timer per successful print. Fixed and resolved. Timeout id is now cleared in finally when the IPC race settles; regression test asserts no pending timers remain after IPC resolves. f5d5d21

Excluded threads:

Thread Reason for skipping
None Fresh post-push GraphQL review-thread inventory shows 0 unresolved threads.

CI blockers checked this round:

Check Status
dependency-review vulnerable tmp@0.0.33 / GHSA-ph9p-34f9-6g65 Passing on f5d5d21; the transitive tmp override from dd628cb remains in place.
Review threads Fresh GraphQL inventory after push/thread resolution: 0 unresolved.
Local focused regression pnpm --filter @wcpos/printer exec vitest run src/transport/__tests__/serial-adapter.electron.test.ts passed, 5/5.
Local printer package tests pnpm --filter @wcpos/printer exec vitest run passed, 391/391.
Local typecheck/lint check pnpm turbo typecheck --filter=@wcpos/printer passed for applicable task; pnpm turbo lint --filter=@wcpos/printer had no package lint task to run.
GitHub checks Passing on f5d5d21: dependency-review, lint/typecheck/script tests/translations, unit tests, deploy, E2E shards, CodeQL, CodeRabbit, and merge gate.

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix round 1 post-fix triage:

Thread File Issue Decision Commit
PRRT_kwDOGW7Gic6JRYPy serial-adapter.electron.ts Serial printRaw left the 30s timeout active when IPC settled first. Fixed and resolved. The timeout id is now cleared in finally, and the regression test asserts no timer remains after successful IPC. f5d5d21

Excluded threads:

Thread Reason for skipping
None Fresh GraphQL review-thread inventory shows 0 unresolved inline threads.

CI blockers handled this round:

Check File Issue Decision Commit
dependency-review pnpm-lock.yaml tmp@0.0.33 via external-editor@3.1.0 triggered GHSA-ph9p-34f9-6g65. Fixed. pnpm-workspace.yaml now overrides external-editor@3.1.0>tmp to 0.2.7; lockfile no longer contains tmp@0.0.33. GitHub dependency-review is passing on head f5d5d21. dd628cb

Validation:

Command Result
pnpm install --frozen-lockfile --ignore-scripts Pass
pnpm lint Pass (warnings only)
pnpm typecheck Pass
pnpm --filter @wcpos/printer exec vitest run src/transport/__tests__/serial-adapter.electron.test.ts Pass (5/5)
pnpm --filter @wcpos/printer exec vitest run Pass (40 files, 391 tests)
pnpm test:ci Pass (151 Jest suites / 1957 tests, then query CI 21 suites / 366 passed / 2 skipped)
pnpm test Fails outside this diff: root script runs Playwright e2e specs under Jest in apps/main, and @wcpos/query has an isolated-passing collection-swap timeout under concurrent root test load.

Remaining unresolved inline review threads: 0.

Current GitHub checks on head f5d5d21: dependency-review and 🧹 Lint are passing; 🧪 Unit Tests and 🚀 Deploy are still pending.

@wcpos-bot

wcpos-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Final post-fix triage for PR #590:

Thread File Issue Decision Commit
discussion_r3406609355 use-printer-discovery.electron.ts Synchronous Web Bluetooth chooser/connect failures could leave the scan session stuck in discovering state. Fixed and resolved; startChooser throws now finish the session with typed discovery-failed. f2119d7
discussion_r3406730322 serial-adapter.electron.ts Serial print timeout stayed active when IPC settled first. Fixed and resolved; timeout handle is cleared in finally, with focused timer cleanup coverage. f5d5d21

Excluded threads:

Thread Reason for skipping
None Fresh GraphQL inventory found 0 unresolved inline review threads.

CI handled separately:

Check Issue Decision Commit / Evidence
Lint Missing English settings.* translation source strings. Fixed. f2119d7; current Lint passes.
dependency-review tmp@0.0.33 high advisory GHSA-ph9p-34f9-6g65. Fixed. dd628cb; current dependency-review passes.
Merge Gate Required-check aggregation. Passed. Current Merge Gate passes on f5d5d21.
E2E / Deploy Deploy workflow and six E2E shards. Passed. Current deploy, E2E shards, merged E2E report, and PR comment jobs pass.

kilbot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR fix round 2 no-op verification on current head f5d5d21.

Thread File Issue Decision Commit
PRRT_kwDOGW7Gic6JRYPy serial-adapter.electron.ts printRaw() timeout branch could stay alive after ipc.invoke('print-raw-serial', ...) settled. Already fixed and resolved on current head; no new commit needed this round. f5d5d21

Excluded threads:

Thread Reason for skipping
None Fresh GraphQL review-thread inventory shows 0 unresolved inline review threads.

CI status checked after the rerun:

Check Status
Review threads 0 unresolved.
Merge state CLEAN / mergeable.
GitHub checks Passing, including Lint, Unit Tests, Deploy, CodeRabbit, dependency-review, CodeQL, Merge Gate, and all six E2E shards.
Local validation pnpm lint, pnpm typecheck, and pnpm test:ci passed. pnpm test is not a reliable local gate as configured because apps/main runs jest --watchAll and Jest discovers Playwright specs under apps/main/e2e; GitHub Unit Tests use the CI test path and pass.

No code changes were pushed in this round because the live PR head already contains the requested timer cleanup and all current blockers are clear.

@wcpos-bot

wcpos-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Post-fix triage for PR #590 at f5d5d21.

Thread File Issue Decision Commit
PRRT_kwDOGW7Gic6JRDny use-printer-discovery.electron.ts Synchronous Bluetooth chooser failures could leave discovery stuck scanning. Fixed and thread is now resolved; latest unresolved-thread inventory count is 0. f2119d7

Skipped threads: none. Fresh GraphQL unresolved inline review-thread inventory returned 0 unresolved threads.

CI status checked on latest head f5d5d21:

Check Status Notes
dependency-review Pass shell-quote override is present via 3320719; tmp override is present via dd628cb.
Lint Pass Missing translation source strings fixed via f2119d7.
Unit Tests Pass Latest run passed.
Deploy Pass Latest run passed.
E2E Tests Pass All 6 shards and report merge passed.
Merge Gate Pass Latest run passed.
CodeQL / CodeRabbit Pass Latest checks completed successfully.

No additional push was made from this session because the remote branch advanced while I was working and now contains the required fixes; my push attempt was rejected as non-fast-forward before the current green head.

@kilbot kilbot merged commit dd0f46e into main Jun 13, 2026
20 checks passed
@kilbot kilbot deleted the feat/bluetooth-scan-ux branch June 13, 2026 08:27
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