Fix SRD monster and spell filters broken by Express 5 query parser change - #352
Open
HarmlessHarm wants to merge 3 commits into
Open
Fix SRD monster and spell filters broken by Express 5 query parser change#352HarmlessHarm wants to merge 3 commits into
HarmlessHarm wants to merge 3 commits into
Conversation
The CR range was expanded with lodash range(min, max + 1), which steps by 1
from min. That only yields valid CRs when min is a whole number. Since the CR
slider started storing real CR values (0, 1/8, 1/4, 1/2, 1-30) instead of
slider positions, a range starting at 1/8, 1/4 or 1/2 produced 0.125, 1.125,
2.125, ... which matches no monster, so the query came back empty.
Because the filter object is spread into every request and persists until
"Clear filter" is pressed, one poisoned challenge_ratings entry also made
type, size, alignment and environment appear broken, while a plain name
search done before opening the dialog still worked.
Pick the CRs out of the canonical CR list instead. This also drops the
min === 0 special case, which force-added 1/8, 1/4 and 1/2 to any range
starting at 0, so a 0-0 range returned those as well.
Also:
- Move the CR list and fraction labels to generalConstants so hk-filter and
the monster service share one definition.
- Drop challenge_ratings from the filter when the slider covers the full
range, so it stops counting towards the active filter badge.
- URL-encode query values in the monster and spell services. Multi-word
options ("Swarm of tiny beasts", "Lawful good") and searches containing
& or + were corrupting the query string.
The API no longer accepts the bracket form for multi-value filters: type=Beast works, type[]=Beast is ignored. Every multi-value monster filter used brackets - type[], size[], environment[], alignment[] and challenge_rating[] - so all of them were silently dropped and results came back unfiltered. name and source are single plain keys, which is why filtering by name kept working. Multiple selections are now sent as the key repeated (type=Beast&type=Dragon). /spells still sends school[], classes[] and level[]. If the API change was global rather than limited to /monsters those need the same treatment, but that is unverified, so they are left alone rather than guessed at.
Express 5 changed the API's default query parser from extended (qs) to simple (Node querystring), which does not interpret the [] suffix. That setting is application-wide, so /spells broke the same way /monsters did: school[], classes[] and level[] were all ignored. /items and /conditions only send name=, so they are unaffected.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Refs #351
Fixes the SRD monster filter, where only filtering by name had any effect and type, size, alignment, environment and CR were silently ignored.
Root cause
The API was upgraded to Express 5, which changed the default
query parserfromextended(qs) tosimple(Node'squerystring). The simple parser does not interpret the[]suffix, sotype[]=Beastbecomes the literal key"type[]"and the filter is dropped. Confirmed against the live API:type=Beastworks,type[]=Beastis ignored.nameandsourceare single plain keys, which is why filtering by name kept working.query parseris application-wide, so/spellsbroke identically (school[],classes[],level[])./itemsand/conditionsonly sendname=and are unaffected.Repeated plain keys parse to an array under both the
simpleandextendedparsers, so this change is correct whether or not the API also restoresapp.set("query parser", "extended"). See #351 for the API-side follow-up.Changes
1. Send multi-value filters as repeated plain keys —
src/services/api/monsters.js,src/services/api/spells.jsMultiple selections repeat the key:
type=Beast&type=Dragon.2. Fix the challenge rating range expansion —
src/services/api/monsters.js,src/utils/generalConstants.js,src/components/hk-components/hk-filter.vueA separate, real bug that was masked by the above. CRs were expanded with
lodash.range(min, max + 1), which steps by 1 frommin— only correct whenminis a whole number. Since 2.41.0 the slider stores real CR values (0, 1/8, 1/4, 1/2, 1-30) rather than slider positions, so a range starting at a fraction produced0.125, 1.125, 2.125, …, matching nothing. The params were being dropped anyway, but this would have surfaced the moment the param names were fixed.CRs are now sliced out of the canonical CR list, which also removes the
min === 0special case that force-added 1/8, 1/4 and 1/2 to any range starting at 0 (so a0 – 0range returned those too).The CR list and its fraction labels moved to
generalConstants.jssohk-filterand the monster service share one definition — that drift is what caused this in the first place.3. URL-encode query values — both services
Values were interpolated raw, so multi-word options (
"Swarm of tiny beasts", and nearly every alignment such as"Lawful good") and searches containing&or+corrupted the query string.4. Minor —
hk-filterdropschallenge_ratingsfrom the filter when the slider covers the full range, so it stops sending every CR as a parameter and stops showing a phantom count on the active-filter badge.Verification
The API host is not reachable from the dev environment (egress policy), so query-string generation was verified in isolation rather than against live responses:
type=Beasttype=Beast&type=Dragonsize=Large&environment=forest&environment=hilltype=Swarm%20of%20tiny%20beastschallenge_rating=0.5&challenge_rating=1&challenge_rating=2challenge_rating=0(previously also returned 1/8, 1/4, 1/2)hk-filter.vuewas compiled with the project'svue-template-compilerto confirm the template still builds. Worth a manual pass over the encounter builder, the public compendium and the spell filter before merging.Spec:
.planning/fix-srd-monster-filter.md🤖 Generated with Claude Code
https://claude.ai/code/session_01JsnXZN9Gbx5a6aCieuW6cR
Generated by Claude Code