• v3.18.0 305227ba54

    v3.18.0 - Published artifacts move to the query API
    All checks were successful
    CI / build-and-test (push) Successful in 2m1s
    Stable

    joeyr released this 2026-08-08 10:08:49 -05:00 | 9 commits to main since this release

    Upgrading: this release needs a Published data key (Settings -> Published data key).
    Without one the app still runs, but every published-artifact fetch is refused and each
    feature serves whatever is already cached on disk.

    Changed

    • Published data now comes from the query API, not raw Forgejo URLs. All
      seven consumed artifacts are fetched from https://api.jrendar.org/v1/artifacts/{name}
      over TLS. Nothing about what they contain changed — same schemas, same caches,
      same patch policy. This is the transport and nothing else.

      It is not a cosmetic move. The producer's next phase deletes the raw-URL path,
      and an app still reading one would not have failed loudly: the fetch would
      404, the provider would fall back to its cache, and the board would keep
      working while serving data that got a night older every night. That
      silent-staleness failure is the reason this shipped ahead of the deletion
      rather than after it.

      The seven URL literals that used to be copied provider-to-provider are gone,
      collapsed into src/main/stats/artifact-source.ts — one base plus a name per
      artifact. The count had grown by one in each of the last two releases.

    • Artifacts are validated envelope-in-full, rows-once. Provenance and every
      small top-level dictionary (items, perks, styles, and the counters
      tierList the board's badges read) are strict-parsed on every fetch; one row
      of the big champion-keyed record goes through the real row schema; the rest
      are parsed and trusted.

      Strict whole-file parsing was the right posture while the app fetched a public
      URL it did not control. It is now reading bytes this household's own crawler
      generated, checksummed, and round-trip verified at publish time. But a
      checksum proves integrity, not shape agreement — a producer-side schema change
      publishes with a perfectly valid digest — so the sample stays, and it is what
      catches that. Measured against today's published files, validation cost drops
      from 184 ms to 19 ms across the five largest.

    • ChampionDamageProvider converged onto the shared artifact path. It had
      reimplemented fetch/validate/persist/fall-back by hand since before that path
      existed, which was harmless duplication right up until it meant being the one
      provider still pointed at a raw URL. It is now a thin indexing wrapper. Its
      on-disk cache format is unchanged, so nothing re-downloads.

    Added

    • A Published data key field in Settings. The API authenticates every route
      but health, so the app carries a per-install key — never one baked into the
      build, since an Electron asar unpacks in minutes and a shared key cannot be
      rotated without breaking every install that has not updated. Stored in
      settings.json encrypted at rest via safeStorage, alongside the Riot key
      and now through the same code path.

      Unlike the Riot key it applies immediately rather than on the next launch —
      the providers read it per fetch — because the state it fixes is a fresh
      install looking at an empty board.

      Without a key the app still runs. A 401 is treated as fatal-but-quiet: it
      takes the same branch an unreachable server already takes, so every provider
      serves its cached copy and champ select never sees an error. That makes an
      unconfigured install a supported but invisible state, so the panel shows the
      key status and startup logs artifact.no_api_key.

    Downloads