Slicer protocol handlers (bambustudio://, orcaslicer://) launch the
slicer app which fetches files via HTTP but cannot send auth headers.
The global auth middleware returned 401, causing "importing failed."
Add short-lived, single-use download tokens: the frontend fetches a
token via authenticated POST, then builds a /dl/{token}/{filename} URL
the slicer can access without auth headers. Tokens are validated
server-side (5-min expiry, single-use). Applies to archive files,
source 3MFs, and library files.
Also fix platform-specific URL formats to match slicer source code:
- macOS: bambustudioopen:// with encodeURIComponent
- Windows/Linux: bambustudio://open?file= (was wrongly using macOS scheme on Linux)
- OrcaSlicer: orcaslicer://open?file=
The spool add/edit modal allowed saving without brand or subtype,
causing incomplete tray_sub_brands when assigned to AMS slots.
BambuStudio then failed to recognize the filament profile.
Brand and Subtype are now mandatory with validation errors on submit.
- Summary cards: 2-col mobile grid with responsive padding, icons, and text sizing; 5th card spans full width on 2-col layout
- Filters: flex-wrap with scaled text/padding; selects share width on mobile; clear history button goes full-width
- Section headers (Pending/History): flex-wrap so sort controls wrap below title; drag hint hidden on mobile; responsive icon and text sizes
- Bulk action toolbar: flex-wrap with tighter gaps/padding; vertical divider hidden on mobile; scaled button text and icons
- SortableQueueItem: top-aligned on mobile; smaller thumbnail (10→14 at sm); metadata row wraps with truncated printer name; username hidden on mobile; badges scale down; status badge and actions stack vertically on mobile; tighter button padding
The /filaments/ endpoint manages material type definitions (cost, temps,
density) but shares its name with the UI's "Filament" page which shows
the spool inventory (/inventory/spools/). This caused users to expect
the API to return their spool inventory.
Rename to /filament-catalog/ to make the distinction clear. No frontend
behavior change — these API methods are defined but unused in the UI.
On dual-nozzle printers (H2C, H2D Pro) with multiple AMS units, usage
tracking attributed filament consumption to the wrong spools. The MQTT
mapping field — a snow-encoded array mapping slicer slots to physical
AMS trays — was preserved in state but never parsed.
Add _decode_mqtt_mapping() to convert snow encoding (ams_hw_id * 256 +
slot) to bambuddy global tray IDs. Insert as priority 2 in the mapping
resolution chain, after print_cmd ams_mapping but before queue/tray_now
fallbacks. Works for all printer models and print sources.
AMS-HT trays (IDs 128-135) are single-slot units, but the snow_slot
computation used `snow_tray % 4 if snow_tray < 128 else -1`, yielding
-1 for AMS HT. This caused a misleading "slot mismatch" debug log on
every MQTT update despite producing the correct tray_now value. Now
returns slot 0 for AMS-HT IDs (128-135), matching the firmware's
tray_now=0 for these single-slot units.
P2S (and X1C) with multiple AMS units incorrectly entered the H2D
dual-nozzle tray_now disambiguation code path, causing warning log
spam. The check `tray_now <= 3` matched any printer loading from
AMS 0. Now uses a persistent `_is_dual_nozzle` flag detected from
device.extruder.info (>= 2 entries), which only dual-nozzle printers
(H2D, H2D Pro) report. Flag is set early in message processing so
it's available before AMS data is parsed.
After clicking "Clear Plate & Start Next", refreshing the page showed
the button again because the frontend determined the state purely from
the printer's FINISH/FAILED status. The backend already tracked a
plate_cleared flag in memory but never exposed it to the frontend.
- Add plate_cleared field to PrinterStatus schema and API response
- Pass plateCleared prop to PrinterQueueWidget
- Skip clear plate UI when plate is already acknowledged
- Add 2 tests for plateCleared=true behavior
Recent BambuStudio/OrcaSlicer updates require a bind/detect handshake on
port 3000 before connecting via MQTT/FTP. Without this, slicers cannot
discover or connect to the virtual printer in any mode.
- Add BindServer for server modes (immediate/review/print_queue)
- Add TCPProxy for raw TCP forwarding (proxy mode)
- Update Dockerfile (EXPOSE 3000) and docker-compose.yml (bridge port)
- Add 10 new tests for BindServer protocol and integration
Some printer MQTT brokers (e.g. P1S) reject subscriptions to the request
topic by killing the TCP connection, causing a disconnect loop. The request
topic subscription for ams_mapping capture is now fail-safe with two
detection paths:
- SUBACK rejection: on_subscribe callback detects failure code 0x80
- Broker kills connection: on_disconnect detects disconnect within 10s of
unconfirmed subscription attempt
After detection, the request topic is disabled for that printer and
reconnection succeeds with only the report topic. Printers that support
the request topic (e.g. X1E, H2D) get ams_mapping capture; printers that
don't (e.g. P1S) gracefully degrade to tray_now-based tracking.