Skip to content

Releases: elfensky/helldivers.bot

v0.65.0

Choose a tag to compare

@github-actions github-actions released this 29 Jun 11:26
b17e1f3

Features

  • War Narrative enrichment on /archives. The Ministry chronicle now varies
    its phrasing per season (deterministic, SSR-stable), and gains player
    surge/collapse beats, offensive conquest milestones (a faction driven to its
    homeworld's gates / the first homeworld to fall), and a "war by the numbers"
    telemetry beat. Computed server-side, so getCampaign and the rest of the app
    are untouched; telemetry-backed beats appear only for seasons with telemetry.

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.65.0
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.65.0

v0.60.0

Choose a tag to compare

@github-actions github-actions released this 26 Jun 11:36
1923cd5

Features

  • Combat Telemetry on /stats (#178). Three telemetry vizzes fed by the
    sums already carried through getCrossSeasonStats: a reusable RatioTrendChart
    drives Friendly Fire Index (accidentals/kills) and Accuracy Trend
    (hits/shots) as cross-season % line charts, plus a Shots per Planet "big
    number" StatCard. computeTelemetryStats filters to telemetry-bearing seasons
    (live-polled wars; historical seasons predate collection) and narrows BigInt
    sums to Number so the result is safe across the server→client boundary. The
    section and each viz hide when no telemetry exists, so it grows as the worker
    records more wars.
  • Player Engagement chart on /archives (#275). A new lazy-loaded
    per-faction scatter of players_at_start vs. day-into-war, showing whether the
    community rallied, declined, or surged for the final battles. Hidden when a
    season has no event player data.
  • Closest Calls on /archives (#273). The global archives stats now surface
    the top-3 defend events that came nearest to holding (points/points_max
    closest to 1.0 but short), each a danger-accented StatCard with region ·
    faction · % held. Restricted to defend fails — the only events with a clean
    margin signal — and hidden when a war had no genuine nail-biters.

Fixed

  • Lockfile synced to 0.60.0package-lock.json still carried 0.59.1.
  • /stats Combat Telemetry charts deferred via next/dynamic — added
    RatioTrendChartLoader so the Recharts bundle stays out of the initial page
    JS, matching the /archives chart loaders.
  • metrics.yml pinned back to lowlighter/metrics@v3.34 — a CI group bump
    had silently moved it to the unreleased @v4 dev branch (not a release tag).
  • buildEngagementSeries hardened and unit-tested — extracted to its own
    module; the anchor fallback uses reduce instead of Math.min(...spread) (no
    RangeError on large event arrays), and the telemetry ratios guard missing
    BigInt fields with ?? 0n.

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.60.0
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.60.0

v0.59.0

Choose a tag to compare

@github-actions github-actions released this 23 Jun 17:15
942a84f

Features

  • OpenAPI coverage for the /v1 endpoints (#438). GET /api/v1/h1/{status, stats,season,map} are now registered in the OpenAPI spec with query params,
    typed response schemas, the {time,code,message,data} envelope, and the
    401/404/429 + 304 responses — so /docs/api documents the real public API.
  • Rebroadcast action reconciliation (#438). The spec now declares all five
    HD1-API actions; get_available_entitlements, get_leaderboards, and
    get_usernames return an explicit 501 Not Implemented (Demand-Driven
    Compatibility) instead of a silent 404. Adds 501 to the error envelope.

Changed

  • Public/internal API boundary. /docs/api (and the OpenAPI spec) now
    document the public surface only — the versioned /api/v1/h1/* reads,
    /api/h1/rebroadcast, and the now-deprecated /api/h1/campaign. Internal
    plumbing (/api/h1/live, /api/h1/update, /api/notifications/subscribe) is
    excluded from the spec and noted as internal in prose. Deprecated endpoints
    render a badge.
  • Cascade Failures leaderboard requires length ≥4. findAllCascades now
    defaults minLength to 4 (was 3) — length-3 runs are too common to be
    noteworthy and made the board noisy. getCascadeLeaderboard drops its explicit
    override and uses the new default.

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.59.0
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.59.0

v0.52.6

Choose a tag to compare

@github-actions github-actions released this 20 Jun 20:29
d018831

Security

  • Resolve five transitive-dependency advisories via npm audit fix (semver-compatible,
    lockfile-only — package.json unchanged): undici (high, multiple CVEs), form-data
    (high, CRLF injection), dompurify (moderate, XSS bypasses), js-yaml (moderate, DoS),
    and @babel/core (low, arbitrary file read). npm audit now reports 0 vulnerabilities.

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.52.6
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.52.6

v0.52.2

Choose a tag to compare

@github-actions github-actions released this 11 Jun 08:27
6afe734

Fixes

  • Fix image-optimizer 500s (broken avatars/icons; 502s at the edge) caused by Sharp's native binary not loading on the Chainguard runtime. A latent bug unmasked by the 0.52.1 .next/cache permission fix: with the cache now writable, the Next.js image optimizer finally runs far enough to load Sharp — and fails. Dockerfile.app built on node:24-alpine (musl) and stripped Sharp's glibc binaries, but the runtime image cgr.dev/chainguard/node is glibc (Wolfi), so only @img/sharp-linuxmusl-x64 shipped into a glibc runtime → Could not load the "sharp" module using the linux-x64 runtime → every /_next/image request 500s. Fixed by building on a glibc base (node:24 Debian) and removing the musl-only strip, so Sharp's glibc binary (@img/sharp-linux-x64) is installed, traced into the standalone output, and loads at runtime. Verified by building the production linux/amd64 image and confirming Sharp both loads and encodes a WebP. (Prisma was unaffected because it uses the @prisma/adapter-pg JS driver, not a native query engine.)

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.52.2
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.52.2

v0.52.1

Choose a tag to compare

@github-actions github-actions released this 10 Jun 19:11
d34f3c8

Fixes

  • Fix the EACCES: permission denied, mkdir '/app/.next/cache' flood in the production container by chowning the runtime image by numeric uid instead of the unresolvable name nonroot. Root cause: the Chainguard runtime (cgr.dev/chainguard/node:latest) has no nonroot entry in /etc/passwd — uid 65532 is named node — so the runner-stage COPY --from=builder --chown=nonroot:nonroot … lines silently fell back to root (0:0). That left /app/.next root-owned (mode 755), and since the container runs as uid 65532, the Next.js image optimizer's first remote-avatar optimization (mkdir('.next/cache/images', { recursive: true }) in next/dist/server/lib/disk-lru-cache.external.js, triggered by Discord/GitHub/Google/Gravatar avatars) failed with EACCES and rejected on every subsequent cacheable image request. Dockerfile.app now uses --chown=65532:65532 (numeric IDs need no passwd lookup) on all three runner COPY lines, so the runtime user owns the standalone tree as intended and creates .next/cache on demand. Verified by reproducing the exact production state (/app/.next uid=0, mkdir FAILED:EACCES) and confirming the numeric-chown image yields uid=65532 and a successful write. No application code or schema change; the image cache is ephemeral (Postgres holds all persistence). Requires a rebuilt image to deploy — production was on v0.47.7, which carries the same defect.

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.52.1
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.52.1

v0.47.9

Choose a tag to compare

@github-actions github-actions released this 21 May 09:25
a7aa9e5

Documentation

  • timeago.js adoption rationale documented in code (#360). Added a comment to formatTimeAgo.mjs explaining that timeago.js is a deliberate dependency — it replaced a hand-rolled Intl.RelativeTimeFormat helper that lacked edge-case handling — and why a prior "save ~4.2KB by reverting to native Intl.RelativeTimeFormat" suggestion was rejected, so a future desloppify pass does not re-flag it. The optional dynamic-import sub-task was not pursued: formatTimeAgo is a synchronous helper used by two components, and making it async to defer a ~4.2KB import would ripple through callers for a marginal gain.

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.47.9
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.47.9

v0.47.4

Choose a tag to compare

@github-actions github-actions released this 19 May 10:37
dd3e490

Chores

  • postcss pinned to ^8.5.10 via package.json#overrides to remediate the GHSA-qx2v-qp2m-jg93 / CVE-2026-41305 advisory (PostCSS XSS via unescaped </style> in stringified CSS output, < 8.5.10). The vulnerable copy came in transitively via next@16.2.6 → postcss@8.4.31; Tailwind 4's own @tailwindcss/postcss dependency already pulled postcss@8.5.14, proving the 8.5.x line works in our build pipeline. Real-world exploit risk for this app is essentially zero (the vuln requires processing user-submitted CSS through PostCSS's stringifier and embedding the output in an HTML <style> tag — we author all our own CSS via Tailwind utilities and design tokens), but the override is a one-line hygiene fix that drops us from 1 moderate dependabot alert to 0. After install all three postcss consumers (Tailwind, Next, Vite) dedupe onto 8.5.15. Verified end-to-end with the local docker compose -f docker-compose.ci.yml up --build stack.

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.47.4
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.47.4

v0.47.3

Choose a tag to compare

@github-actions github-actions released this 19 May 07:17
6fddabd

Bug fixes

  • Second migrate-container crash from the v0.46.4 validator-protocol cleanup. The v0.46.4 "Validator protocol unified to raw-schema exports" change turned isValidSeason from (data) => rootSchema.safeParse(data) (callable wrapper) into a raw Zod schema (export const isValidSeason = rootSchema). The CHANGELOG noted that callers in src/update/season.mjs and src/update/status.mjs plus tests were updated — but the prisma/seed/seed.mjs:51 caller was missed. With v0.47.0 in production, the migrate container ran the seed and crashed with TypeError: isValidSeason is not a function. v0.47.1 fixed the prior @/shared import error in the same file but only verified the file LOADED under raw Node, not that downstream callers EXECUTED — so this latent bug surfaced only on the next docker-compose-up. Fix: changed the single seed call to isValidSeason.safeParse(seasonData) to match every other caller in the codebase. Verified end-to-end with a full local docker compose -f docker-compose.ci.yml up --build run that brought the stack to healthy (the exact verification step the v0.47.1 hotfix should have done).

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.47.3
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.47.3

v0.47.1

Choose a tag to compare

@github-actions github-actions released this 18 May 18:42
fb15a7c

Bug fixes

  • Migrate container crashed at seed step on @/shared import. The v0.46.x "enum migration" replaced inline string enums in src/validators/isValidSeason.mjs and isValidStatus.mjs with import { CAMPAIGN_STATUS, EVENT_STATUS } from '@/shared/enums/events.mjs'. The @/* alias is a jsconfig.json construct honored by Next.js and Vitest but not by raw Node — so npm run build and npm run test:unit passed locally while the production migrate container (which runs node --experimental-strip-types prisma/seed/seed.mjs after prisma migrate deploy) crashed with ERR_MODULE_NOT_FOUND: Cannot find package '@/shared' imported from /app/src/validators/isValidSeason.mjs. Fix: switched both validator imports to relative paths (../shared/enums/events.mjs), added a clarifying comment on the seed-loaded file documenting the constraint, and updated Dockerfile.migrate to also COPY src/shared/enums/events.mjs alongside the validator (the enums module has no further imports, so the copy chain terminates there).

Docker Images

docker pull ghcr.io/elfensky/helldiversbot:v0.47.1
docker pull ghcr.io/elfensky/helldiversbot-migrate:v0.47.1