Commit graph

7 commits

Author SHA1 Message Date
Mitchell R
5d23079086
feat: add anyvali input validation to all external API endpoints
Create shared/api-schemas.ts with av.object schemas for:
- pair/initiate, pair/claim (pairing flow)
- kiosk/heartbeat (telemetry with displays, partitions, hwmon)
- kiosk/event (ONVIF/system events)
- kiosk/logs (batched log entries)
- firmware/applied, os/applied (update reports)
- auth/login, auth/totp, setup (admin auth)

Each endpoint now calls validateBody(Schema, body) which returns 400
on schema violation. All string fields have maxLength, numeric fields
have min/max ranges, arrays strip unknown keys. Rejects malformed
input before it reaches DB or business logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-26 14:03:58 +02:00
Mitchell R
ed2050cfd8
feat(db): full async Repository conversion for PostgreSQL support
Mechanical conversion of the entire data access layer from synchronous
node:sqlite API to async DbAdapter interface. Enables PostgreSQL
(PgAdapter) as a drop-in backend alongside SQLite (SqliteAdapter).

Repository (2208 lines):
  - Constructor accepts DbAdapter instead of DatabaseSync
  - Internal _run/_get/_all/_exec helpers wrap adapter calls
  - All 155 methods converted to async, return Promise<T>
  - transact() uses adapter.transaction() (supports PG savepoints)

14 caller files updated (327 call sites):
  - routes-admin.ts: 202 repo calls + 6 async helper functions
  - service-api-http: 40 repo calls + async getClusterKey
  - routes-firmware.ts, routes-os-updates.ts, routes-auth.ts,
    routes-setup.ts, middleware.ts: all handlers made async
  - shared/auth.ts: resolveSession + revokeSession now async
  - shared/bundle.ts: generateBundle now async, .map→for..of loops
  - shared/pairing.ts: all 3 functions async
  - shared/audit.ts: audit() now async
  - shared/camera-health.ts: checkAll repo calls awaited
  - service-coordinator-ws: session + kiosk lookups awaited
  - service-store/index.ts: creates SqliteAdapter.fromExisting()

SqliteAdapter gains static fromExisting(db) factory for wrapping an
already-opened DatabaseSync (migrations run on raw db, then adapter
wraps for Repository queries).

tsc --noEmit: zero errors.
2026-05-23 02:07:44 +02:00
Mitchell R
7fbda3c2b3 refactor: merge templates into layouts, displays from kiosks
- Eliminated layout_templates as separate entity — regions/grid now
  live directly on layouts
- Displays created from kiosk pairing (not standalone), each display
  has kiosk_id FK
- Removed Templates from sidebar nav and all template routes/pages
- Layout creation uses preset buttons (fullscreen, 2x2, 1+3, 3x3)
  that set regions directly on the layout
- Setup no longer creates default display/layout (deferred to pairing)
- Pairing creates HDMI-0 display for new kiosk
- Bundle reads regions from layout directly, no template lookup
- Rust kiosk updated to match new bundle format
- DB migration adds regions/grid_cols/grid_rows to layouts, kiosk_id
  to displays, copies existing template data
2026-05-10 21:39:09 +02:00
Mitchell R
cc306cec57
feat: layout/template/display CRUD + display-chain bundle routing
Major changes:
- Bundle now follows kiosk → display → layouts → cells → cameras
  (no label filtering for v0.1)
- Setup creates default Fullscreen template + Default layout with
  BetterFrame logo on the primary display
- Pairing auto-assigns kiosk to primary display
- Admin UI: full template CRUD with presets (fullscreen, 2x2, 1+3, 3x3)
- Admin UI: layout CRUD with cell management (assign cameras/web/html
  to template regions)
- Admin UI: display editing (default layout, idle/sleep timeouts)
- Repository: added createLayoutTemplate, createLayout, createLayoutCell,
  updateLayout, deleteLayout, layoutsForDisplayId, camerasForLayoutIds,
  updateDisplay, and more
2026-05-10 03:45:53 +02:00
Mitchell R
a64363258d
fix: use Response wrapper instead of h3 tagged template html()
h3 v2's html() is a tagged template literal, not a function that
accepts a string. JSX-rendered markup passed directly causes
"first.reduce is not a function". Created htmlPage() helper that
wraps markup in a proper Response with text/html content type.
2026-05-10 02:50:16 +02:00
Mitchell R
a8b0fbb2bc
refactor: collapse 6 non-service plugins into shared modules
BSB plugins should be actual services (own port, lifecycle, resource
ownership). Moved secrets, auth, pairing, bundle, nodered-bridge, and
cec-relay from plugin folders to shared modules under server/src/shared/.

4 BSB plugins remain: service-store, service-admin-http,
service-api-http, service-coordinator-ws.

service-admin-http now initializes secrets + auth as plain modules in
init() using the store repo from the plugin-registry singleton. No
more setSiblings() hack or inter-plugin wiring.

sec-config.yaml updated: secrets/auth config moved into
service-admin-http, pairing config into service-api-http, nodered
config into service-coordinator-ws.
2026-05-10 02:29:25 +02:00
Mitchell R
2fd2502b85
adding initial project 2026-05-10 01:09:13 +02:00