Skip to content

Releases: hazptr/ember

v0.40.8 — don't orphan the browser on a failed portal login

Choose a tag to compare

@hazptr hazptr released this 16 Oct 15:58

Close the headless browser when acquiring a portal session fails (#171).

v0.40.7 — split layoutEngine + registry-only widgets

Choose a tag to compare

@hazptr hazptr released this 22 Jun 20:36

Tech-debt batch 5c — final batch of the June 2026 cleanup sweep (epic #161). Behavior-preserving.

  • #157 — split layoutEngine.ts into lib/layout/{placements,merge,pagination}.ts behind a barrel; lifted Dashboard/WidgetLayout placement transforms into pure tested lib/layout/transforms.ts. Persisted layout shape + merge semantics unchanged (existing layoutEngine.test.ts 70/70 passes unchanged).
  • #155 — WidgetDef.defaultVisible flag; Dashboard derives the interval-widget lists from the registry (renamed availableChartsAll→fullChartUniverse); "add a widget" is now registry-only.
    isPlaced gating byte-identical (the #121/v0.40.2 surface). Verified on staging: saved-layout migration unchanged + force-mount all widgets renders clean (no fit overflow, 0 console errors). Docker test 1005; build green. No schema change.

v0.40.6 — decompose IntervalHistory into hooks

Choose a tag to compare

@hazptr hazptr released this 22 Jun 20:02

Tech-debt batch 5b (epic #161). Behavior-preserving decomposition.

  • #156 — IntervalHistory.tsx 1424→899 LOC; extracted useIntervalFetch/useOverscanLoad/useChartNavigation hooks (pure window math stays in intervalZoom.ts). Explicitly guarded every payload deref against the loading/null state (the v0.40.2 #150 crash class); preserved fresh-curWindowRef, horizontal-wheel pan + stopPropagation, and the justified exhaustive-deps disable.
    Verified: Docker test 983 / build green; staging force-mount probe (cleared layout → all interval widgets mount) renders clean, 0 console errors. No schema change. Gesture interactions (zoom/pan/drag-select) are byte-equivalent code — confirm on the live dashboard.

v0.40.5 — decompose projectSeason + API consistency

Choose a tag to compare

@hazptr hazptr released this 22 Jun 19:35

Tech-debt batch 5a (epic #161). Behavior-preserving; no schema change.

  • #158 — decomposed projectSeason into pure helpers (resolvePricingMode/priceSeasonMonth/combineAnnualBand) + 10 hand-calc tests; existing seasonProjection test unchanged (byte-identical proof).
  • #159 — uniform error envelope via withAccount; export routes use withAccount; bills/[date]/pdf honors ?accountId=. Secrets unaffected.
    Verified: Docker test 983; build green; /api/verify 50/50 on staging; routes smoke-tested; dashboard renders clean.

v0.40.4 — rename currentCharges fields + hot-path query dedupe

Choose a tag to compare

@hazptr hazptr released this 22 Jun 19:15

Tech-debt batch 4 (epic #161). Behavior-preserving; money values byte-identical.

  • #153 — renamed the in-memory fields that carry currentCharges but were misnamed totalDueAmount (series/queries/csv/notifications + readers). The forbidden API totalDueAmount is never used for analysis; the ?? totalDueAmount PDF-not-yet-parsed fallback and the persisted Notification.payload key are deliberately unchanged (append-only).
  • #154 — /api/settings now uses a lightweight getAccountMeta instead of the full overview pipeline; getOverview fetches account+bills once and feeds getMonthlySeries (was double-querying per /api/overview).

Verified: Docker test 973 / build green; /api/verify 50/50 green on staging's real data; settings + dashboard render clean. No schema change.

v0.40.3 — fix IntervalHeatmap null-payload crash (v0.40.2 regression)

Choose a tag to compare

@hazptr hazptr released this 22 Jun 18:38

Hotfix release. Fixes a client-side crash introduced in v0.40.2 (#150) and restores the interval-heatmap widget.

  • #166 — IntervalHeatmap dereferenced payload!.grid in eagerly-evaluated children during the loading tick (payload null), throwing an unguarded render-time TypeError that took down the whole dashboard whenever the heatmap widget was mounted. Now gated on {payload && (…)}. Siblings (LoadShape/History) audited safe.

Verified on staging against the exact crash repro (default layout mounts the heatmap → renders skeleton/data, 0 console errors; previously "Application error"). Docker test 67 files / 973 tests; production build green. No schema change.

Prod was rolled back to v0.40.1 during the incident; this release restores forward to the full batch-1/2/3 cleanup with the fix.

v0.40.2 — tech-debt batches 2 & 3 (shared primitives, lib/stats, scraper dedup, typed ESLint)

Choose a tag to compare

@hazptr hazptr released this 22 Jun 18:08

Tech-debt batches 2 + 3 of the June 2026 cleanup sweep (epic #161). All behavior-preserving; no feature/visual change. (Batch 2 was build/CI-only with no runtime delta, so it gets its first version label here alongside batch 3.)

Batch 3 — shared primitives + tests (#150/#151/#152):

  • #150 — consolidated duplicated UI primitives: one Segmented, lib/chartTheme.ts, useDismissable, useIntervalPayload + IntervalWidgetBody, pure formatPeakReadout (hand-calc tested). Class/output strings byte-identical.
  • #151 — extracted pure lib/stats.ts (median/mad/stdev) replacing ~4 dup median bodies; added missing hand-calc tests (parsePdf fallbacks, ymToLastYmd, interval grain edges). +52 tests (921→973).
  • #152 — scraper dedup: one fillEmailAndPassword, typed the collect.ts GraphQL any cluster (collectRaw.ts, zero any left), shared GQL_URL_RE / lib/ngrid/dates.ts / errMessage.ts.

Batch 2 — tooling hardening (#149/#160):

  • #149 — type-checked @typescript-eslint (no-floating-promises/no-misused-promises errors, no-explicit-any warn) scoped to src/lib/**; enforced by next build. Zero floating-promise errors in existing code.
  • #160 — buildx GHA cache on test/smoke-boot, report-only coverage, Node-24 GitHub Actions bumps.

Verified: Docker test 65 files / 973 tests; production build green (lint+typecheck); /api/verify 50/50 green on staging's prod-seeded data; dashboard renders clean (33 chart surfaces, 0 console errors). No schema change.

⚠ #152's auth.ts login extraction is the live login path — to be confirmed against a real account on the next scheduled scrape.

v0.40.1 — tech-debt batch 1 (dead code + build hygiene)

Choose a tag to compare

@hazptr hazptr released this 22 Jun 16:16

Tech-debt batch 1 of the June 2026 cleanup sweep (epic #161). Low-risk, no runtime behavior change.

  • #146 — removed confirmed-dead code: discoverInterval.ts, layoutEngine computeFitRowHeight/placementRows, intervalParams grain/IntervalGrain/FIFTEEN_MIN_SECONDS, prediction horizonK, redundant ReconcileRow alias, stale prisma:migrate/prisma:dev scripts.
  • #147 — enabled tsconfig noUnusedLocals / noUnusedParameters / noImplicitReturns; fixed fallout at the root.
  • #148 — Dockerfile npm install → npm ci; un-ignored the tracked package-lock.json; documented DATA_DIR.

Verified: Docker test stage 63 files / 921 tests, tsc clean, production build clean, and /api/verify green (50/50) on staging with prod-seeded data. No schema change.

v0.40.0 — Usage history rework + chart navigation

Choose a tag to compare

@hazptr hazptr released this 22 Jun 04:55

Usage history: server-side aggregation, energy splice, and focused navigation

A ground-up rework of the Usage history interval widget (#145).

Performance

  • /api/interval aggregates in Postgres (reconcile + SUM into the zoom-appropriate bucket), returning ≤600 points instead of hydrating ~20k rows. Wide load ~150–200ms → ~42ms on full-history data; all zoom levels 11–42ms. Short Cache-Control; stale-while-revalidate (no cold-blank).

Energy-correct, finest-grain-by-zoom

  • No more 1h/15m toggle — grain is chosen by the zoom span, always by SUMming adjacent intervals (4×15-min == 1h). An "end of 15-min data" marker shows where the 15-min archive begins; a straddle window renders real 15-min plus flat hourly/4 quarter-steps (no cliff). Hourly→15-min extrapolation only in the genuine straddle. Reconcile never double-counts overlapping grains; the line reaches the latest reading at every grain. In-grid grain pill.

Focused mouse navigation

  • Click to focus (amber ring). Wheel = zoom on cursor; shift/horizontal-wheel = pan; ctrl+drag = move the viewport. Overscan preloads data left/right for smooth, live panning. Modifier cursors (grab / ew-resize). Fixes for macOS horizontal-wheel shift+scroll, the cockpit paginator stealing the gesture, and pan stability.

Notes

  • Display-only: never touches billed numbers; /api/verify unaffected. No schema change (additive query). 930 unit tests; verified on a prod-seeded copy.

v0.39.2 — fix: 1h history view clipped at the 15-min-data boundary

Choose a tag to compare

@hazptr hazptr released this 14 Jun 16:16

Fix (#144): the 1h Usage history chart capped its right edge at the date 15-min recording began (e.g. Jun 7), hiding the most recent week of hourly data.

Root cause was order-of-operations: the 1h view consumed the downsampled all-grain feed and reconciled on the client, so downsampling turned recent 15-min rows into lone slots that reconcileToHourly's "partial 15-min + no hourly → skip" rule discarded.

New server-side ?grain=1h path reconciles raw rows → hourly first, then downsamples (symmetric with ?grain=15m). Legacy 'all' feed unchanged. Display-only — no /api/verify / billed-number surface touched. 830 tests pass (+6, incl. a regression on the ordering).