Skip to content

v1.5.0

Choose a tag to compare

@github-actions github-actions released this 11 Nov 04:12
· 317 commits to main since this release
Immutable release. Only release title and notes can be modified.

1.5.0 (2026-11-11)

Upgrade notes

  • API paths: every API route now lives under /api/v1/; the old paths are not aliased. QR links, health, readiness and the API docs stay unversioned. Update API clients and webhook targets (Grocy, Spoolman, scripts).
  • PROXY_IP is required in the Traefik, Caddy and Pangolin compose examples. The hub trusts X-Forwarded-For only from that one fixed address (no subnet, no wildcard); set it to your proxy's address before you redeploy, or docker compose refuses to start the stack.
  • Printer-restricted keys: a print key restricted to printers other than the default tape printer can no longer use POST /api/v1/print or POST /api/v1/printer/resume (403 printer_not_allowed).
  • Pending jobs: jobs that were queued before the upgrade are rendered again when they print.
  • Device swaps: after the first status probe each printer remembers its hardware identity. If a different device answers at the same address, sheet and calibration pages wait until an admin resolves the swap in the printer view.

Security audits run 17 to 19 covered this release; deferred low and informational findings are tracked in #263.

Changes

  • Merge pull request #278 from strausmann/milestone/1.5.0 (db5b4de), closes #278
  • Merge remote-tracking branch 'origin/main' into feat/api-v1-status-manifest (67603d0)
  • fix(api): bracket IPv6 hosts once in the test print URL and log a dropped QR (#228) (0373a44), closes #228
  • fix(auth): bound and validate the sign-in limiter; no wildcard forwarded IPs in examples (9409198), closes #153
  • fix(auth): enforce per-printer access on the legacy print routes (b179950), closes #153
  • fix(batches): keep earlier confirmations when a run is reprinted again (#277) (b2bf30f), closes #277
  • fix(examples): trust only the proxy fixed address for X-Forwarded-For (55bb30a), closes #153
  • fix(print): free run pictures, flag every pre-send refusal, keep cards in step with the run (#277) (c5b079e), closes #277 #277
  • fix(print): keep refused groups out of the unknown, hold the printer during a reprint, bound held ru (809e922), closes #277 #277
  • fix(printers): apply printer create, update, enable and disable without a restart (#224) (eb15b1d), closes #224
  • fix(printers): bind the swap resolution to the reviewed device and release the hold from the databas (0772477), closes #231
  • fix(printers): keep the identity hold across a re-wire and settle review findings (#231) (4a7c39e), closes #231
  • fix(printers): make the identity hold fail closed (#231) (0987b8d), closes #231
  • fix(printers): never release the identity hold on an unverified clear (#231) (9670724), closes #231
  • fix(printers): publish the status before the identity query and harden identity capture (#231) (c0f1e19), closes #231
  • fix(ql): bound QL layout cost, mark cut text and refuse conflicting batches (#258) (358bc4b), closes #258 #258
  • fix(ql): bound text layout work and label length (#258) (e3cfd7e), closes #258 #258
  • fix(ql): lay QL labels across the tape width with a fixed QR size per tape (#258) (4512080), closes #258 #258
  • fix(ql): pick the QR version per payload inside a fixed QR box (#258) (7ff1273), closes #258 #258
  • fix(ql): store the QL layout default per printer and tape width (#258) (d22d098), closes #258 #258
  • fix(queue): announce a run that waits for confirmation (#277) (6c6e0ad), closes #277
  • fix(queue): serialize add and remove of the same printer (#224) (2af0888), closes #224
  • fix(sheets): send the source URL to the issue only while it is the shipped one (#230) (49d82ee), closes #230
  • fix(status): cover the IPP failure backoff in the bound and stop serving a stale tape (#227) (d046ecc), closes #227
  • fix(status): make the roll write a compare-and-swap so a colour PUT cannot be lost (#229) (97d0c15), closes #229
  • fix(status): one tape status schema; the tape endpoint works for SNMP-polled printers (#229) (e753718), closes #229
  • fix(status): show a stale or unpolled printer status as unknown with its age (#227) (7ba92b6), closes #227
  • fix(ui): a click starts a new sheet type search, the list stays above the tab bar (#237) (1d04d72), closes #237 #237
  • fix(ui): announce a calibration print once and share one retry per job (#239) (fbff230), closes #239
  • fix(ui): drop obsolete catalogue entries, give the colour Clear a context, finish the roll prompt (# (f46809d), closes #229
  • fix(ui): drop the restart note from the printer settings (#224) (57cd990), closes #224
  • fix(ui): harden the print status stack after review (#245) (e7a0685), closes #245
  • fix(ui): import the mutation type as a type (#228) (d2513c4), closes #228
  • fix(ui): keep held tape runs reachable and show a refused group as not printed (#277) (04f2d81), closes #277 #277
  • fix(ui): keep identities from non-admins, announce only the swap sentence, say 'settled' outside the (1a52d99), closes #231
  • fix(ui): keep the chosen sheet type when the calibration tray changes (#238) (e81b48d), closes #238
  • fix(ui): keep the read outcome code on reconnect (#277) (f2d12f0), closes #277
  • fix(ui): load the web app manifest with credentials so the hub installs behind SSO (#225) (0fc0830), closes #225
  • fix(ui): never leave a calibration print card unannounced after the page left (#239) (647d711), closes #239
  • fix(ui): no status request without a printer (8466e48)
  • fix(ui): read a status again when an event lands during its first fetch (#277) (83d8e68), closes #277
  • fix(ui): reset the print status store between tests (#245) (cb0c061), closes #245
  • fix(ui): route every event invalidation through the first-load follow-up (#277) (67dad11), closes #277
  • fix(ui): scope the started-by-invalidation mark to one event (#277) (ebe26ad), closes #277
  • fix(ui): searchable sheet type picker (#237) (94887ba), closes #237 #237
  • fix(ui): show a stale or unpolled printer as Status unknown or Not monitored (#227) (29c8ca9), closes #227
  • fix(ui): show the live job status below the calibration print buttons (#239) (6463e06), closes #239
  • fix(ui): show the test print answer in its own row and add e2e specs (#228) (c9f88ad), closes #228
  • fix(ui): show the unknown status and its age in the overview material block (#227) (8ee5c58), closes #227
  • fix(ui): tray labels, localized refusals and a neutral cancel text for test prints (#228) (4987f61), closes #228
  • test(api): give the batch response test its sub-job size, which the contract requires (#277) (e0cec89), closes #277 #277
  • test(api): share the route walk and the SPA fixtures (#226) (ce870a5), closes #226
  • test(e2e): stop the e2e app from leaking settings at import (77f6f3e)
  • test(printer-backends): the fake page printer reports a default paper size (#228) (b6d0c4d), closes #228
  • test(printers): pick the identity events off the shared state channel in the resolve tests (#231) (b935c45), closes #231 #231
  • test(printers): release the detach gate when the lock test fails (#224) (61f82f4), closes #224 #224
  • test(printers): restore the model and backend registries after each integration test (#224) (839adcd), closes #224
  • test(printers): wait for probes instead of a fixed budget in the producer loop test (#224) (50e0dd3), closes #224
  • test(queue): make the add ordering observable in the membership tests (#224) (46f4a00), closes #224
  • test(sheets): leave the previous cart page before waiting for the preview answer (#277) (544a801), closes #277 #277
  • test(sheets): name the sheet field exactly in the print-sheet e2e spec (#277) (1e04f55), closes #277 #277
  • test(sheets): prove the roomy-sheet button acts and widen the per-test limit of the sheet section fi (c534672), closes #277 #277
  • test(sheets): use a documentation address in the feedback link test (135d0e9)
  • test(status): mark the printer of the snapshot test as polled (#227) (42d30e9), closes #227
  • test(status): prove the cached status endpoint never contacts the printer (#277) (a11cf7a), closes #277
  • test(ui): bring the sheet type field into view before tapping it on a phone (7ea5e30)
  • test(ui): expect no restart note after adding a page printer in the browser test (#224) (dda206c), closes #224
  • test(ui): give the first label preview in the layout choice tests a 5 s window (#277) (2a5b0c1), closes #277
  • test(ui): page test print reaches done, own test print describe, more shots (#228) (16c9814), closes #228
  • test(ui): start the tape-run e2e tests without held runs of other specs (#277) (451ae5e), closes #277 #277
  • test(ui): wait for the hub's fresh reading before the missing paper size test print (62607d2)
  • docs: bring ADRs and the decision register up to date and anchor their upkeep (#252) (6e46039), closes #252
  • docs: document the /api/v1 paths in docs, examples and dev setup (#226) (390b7ac), closes #226
  • docs: fix the print example and error table in README and api-keys (#226) (10e8bb3), closes #226
  • docs: PRINTER_HUB_PUBLIC_URL may be a local address (055520c), closes #153
  • docs: README features shipped, ADR 0005 restart note (3d0e4c4)
  • docs(adr): record runtime printer wiring and hardware identity (0024) (f677cbe), closes #252 #224 #231
  • docs(plan): add Task 19 for #237 #238 #239 #245 (04e1571), closes #237 #238 #239 #245
  • docs(plan): API v1, live printer wiring and installable PWA (#224 #225 #226) (56f0683), closes #224 #225 #226
  • docs(plan): apply second plan review (rev 4) (230e08f)
  • docs(plan): record spike results, add #230 and #231 tasks (3a6f41f), closes #230 #231
  • docs(plan): revise after plan review, add #227 #228 #229 (d9f021f), closes #227 #228 #229
  • feat(api): remove the legacy job routes and guard the /api/v1 layout (#226) (f0132b7), closes #226
  • feat(api): test print endpoint for tape and page printers (#228) (b1488d6), closes #228
  • feat(print): send tape jobs of at most 50 labels in checked groups of 10 (#277) (de8366e), closes #277 #277
  • feat(printers): capture a hardware identity from SNMP and IPP probes (#231) (3766e67), closes #231
  • feat(printers): detect a swapped device and hold sheet and calibration jobs (#231) (442fe2c), closes #231
  • feat(printers): let an admin resolve a device swap, keeping or resetting calibration (#231) (05abb64), closes #231
  • feat(printers): wire printers through one runtime used at startup and on change (#224) (d40a996), closes #224 #224
  • feat(queue): add and remove printers on a running queue without losing jobs (#224) (cb40f63), closes #224
  • feat(sheets): print at most one sheet per run and keep the rest in the cart (#277) (769b902), closes #277 #277
  • feat(sheets): report or confirm sheet type dimensions through a pre-filled issue (#230) (819a42a), closes #230
  • feat(status): remember the roll colour per printer and detect roll changes (#229) (9bce9c9), closes #229
  • feat(ui): ask for the roll colour on a roll change and show the tape colour truthfully (#229) (8de7978), closes #229
  • feat(ui): call the API under /api/v1 (#226) (6fd5468), closes #226
  • feat(ui): choose the QL label layout with a live preview (#258) (88e13ba), closes #258
  • feat(ui): live print status notification for every print action (#245) (71547d9), closes #245
  • feat(ui): show the printer's hardware identity and a device swap (#231) (6636e77), closes #231
  • feat(ui): test print button on every printer page (#228) (30d4efa), closes #228
  • chore(ci): allow the print commit scope (98741d9), closes #277
  • chore(ci): allow the printers commit scope (e26741a)
  • chore(ci): allow the ql commit scope (e88026a), closes #258 #258
  • chore(ci): allow the sheets commit scope (1506e09)
  • refactor(api): drop the response model and live-status helper of the removed job route (#226) (270016a), closes #226
  • refactor(api): serve every API route under /api/v1 (#226) (6e198cf), closes #226