screentinker/server/routes
ScreenTinker 08b3d7d404 BrightSign: report IPv6, the attached display and the active video mode
Follow-on from the Node-stdlib work, guided by BrightSign's own dev-cookbook
rather than by guessing at module names.

IPv6 costs nothing extra — it comes from the same os.networkInterfaces() call
the v4 address does. The column, the API field and the dashboard card have all
existed since 1.9.29 and no player has ever filled them; the card is written to
appear ONLY when set, precisely so the overwhelmingly v4 fleet does not pay
screen space for an empty row. fe80:: is skipped for the same reason 169.254 is
— a link-local address is scoped to one interface and cannot be dialled from a
laptop across the office. A ULA is kept, because that one is reachable.

The attached display and video mode are new columns, and they answer the first
question anyone asks about a dark sign: which panel is that, and is the player
outputting at all. screen_width/height could not answer it — they are what the
PAGE believes it has, i.e. the widget's own geometry. Our XT245 drives a CX101
at 1920x1200@60 while the page reports its own canvas.

Per telemetry row rather than on `devices`, because a display can be swapped,
unplugged or renegotiated without the player re-registering.

MULTI-OUTPUT: the output is chosen by screen number, not hard-coded. A
dual-output player registers ONE DEVICE ROW PER OUTPUT (?screen=N →
output_index), so each row must report its own panel — otherwise a box driving
a lobby TV and a menu board shows the lobby TV twice. Both naming forms are
tried: probed on hardware, "hdmi" and "HDMI-1" both resolve to output 1, while
a second output that does not exist fails cleanly ("hdmi2" throws from the
constructor, "HDMI-2" rejects), so a single-output player reports nothing
rather than inventing a screen. That case has its own test.

Dashboard: two cards, shown only when the player reports them, like every other
card in that block.

Verified end to end on the real XT245 (FW 9.1.93.2) — attached_display=CX101,
video_mode=1920x1200@60, alongside local_ip 192.168.1.46, 119616 MB disk,
3656 MB RAM and live CPU.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bvjey4FNam49MN7ybjcq6A
2026-08-10 15:30:40 -05:00
..
activity.js Phase 2.1: tenancy middleware, permission helpers, JWT workspace context, frontend + backend role-rename compat 2026-05-11 20:02:00 -05:00
admin.js Show every plan on the admin tab, with who is on each 2026-07-29 19:36:10 -05:00
agency.js Default a video playlist item to the clip's own length (#237) 2026-08-06 09:36:53 -05:00
ai.js feat(ai): separate optional image API key (#41) 2026-06-09 13:47:47 -05:00
assignments.js Default a video playlist item to the clip's own length (#237) 2026-08-06 09:36:53 -05:00
auth.js feat(auth): self-service password reset 2026-07-27 11:19:39 -05:00
billing.js feat(#146): billing:read scoped token — dual-path auth for the Usage Report (Option C) 2026-07-01 21:16:21 -05:00
contact.js fix(landing): replace broken Custom pricing card with enterprise contact form 2026-05-14 13:52:24 -05:00
content.js QA: close four ways a control or an asset lied about itself 2026-08-06 16:12:29 -05:00
device-groups.js Default a video playlist item to the clip's own length (#237) 2026-08-06 09:36:53 -05:00
devices.js BrightSign: report IPv6, the attached display and the active video mode 2026-08-10 15:30:40 -05:00
folders.js Phase 2.2c: content_folders gets workspace_id (schema + backfill); folders.js scoped; content.js folder-move strict same-workspace 2026-05-11 21:04:03 -05:00
kiosk.js Validate kiosk style values as CSS rather than as HTML 2026-07-27 22:28:47 -05:00
layouts.js Save a layout by diffing its zones, not by deleting and re-inserting them 2026-07-30 20:51:28 -05:00
media.js feat: transition engine — GL wipes across web, Tizen & Android (+ image↔video) (#204) 2026-07-20 16:45:32 -05:00
pip.js Hold overlay pushes to the same write check as every other fleet action 2026-07-30 20:46:03 -05:00
player-debug.js Add player debug overlay and server-side error telemetry sink 2026-05-15 15:20:42 -05:00
playlists.js Default a video playlist item to the clip's own length (#237) 2026-08-06 09:36:53 -05:00
provisioning.js fix(api): consolidate device pairing to /pair, remove vestigial bare endpoint (#90) 2026-06-12 20:13:16 -05:00
reports.js Phase 2.2g: reports.js scoped to workspace_id; fixes pre-existing /export and /uptime cross-tenant leaks 2026-05-11 21:36:54 -05:00
schedules.js Default a video playlist item to the clip's own length (#237) 2026-08-06 09:36:53 -05:00
status.js #240: stop the morning wave buying itself a blocking checkpoint 2026-08-06 20:22:21 -05:00
stripe.js feat(stripe): enable promotion codes on checkout sessions (#227) 2026-07-23 23:44:18 -05:00
subscription.js Initial open source release 2026-04-08 12:14:53 -05:00
teams.js feat(teams): temporarily disable Teams API while feature is redesigned 2026-05-12 13:30:55 -05:00
tokens.js feat(agency): per-token upload folder — auto-created, subtree-confined (#158) (#171) 2026-07-12 21:23:25 -05:00
video-walls.js Describe a portrait video wall as portrait, and stop a wall hiding its screens 2026-08-06 09:46:31 -05:00
white-label.js fix(security): patch quick-win findings from the codebase review 2026-06-08 19:02:19 -05:00
widgets.js Stop shrinking hand-written text widgets into illegibility 2026-07-30 20:28:28 -05:00
workspaces.js fix(workspaces): use APP_URL env var for invite-accept URL generation 2026-05-17 15:26:07 -05:00