You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Treat malformed work-list route payloads as an empty query instead of allowing atob or JSON parsing to fail during rendering.
Root cause
A public URL such as /#/l/not-base64 was decoded directly from the template and computed state. Invalid Base64/JSON threw a browser exception and surfaced an error dialog.
Validation
npm run build
TypeScript build completed successfully
This PR intentionally only handles malformed payloads; query-change pagination is a separate fix.
Wraps the base64/JSON decoding logic in a try/catch and adds a type guard on the parsed result. The change correctly handles throwable operations (atob, JSON.parse) and prevents non-object results from propagating.
🔴 [blocking] Empty catch {} silently swallows all errors
The bare catch {} discards every error (invalid base64, malformed JSON, TextDecoder failures) with zero observability. If this function ever receives unexpected input in production, there is no way to diagnose it — no log, no counter, no trace.
Why this matters: The function is a data-decoding utility. Silent corruption here could cause subtle downstream bugs (empty query objects where real data was expected) that are extremely hard to root-cause.
Fix suggestion: At minimum, log a warning:
}catch(e){console.warn('decodeHrefToQueryObj: failed to decode input',e)return{}}
Or better, let callers decide by not catching at all and propagating the error — or using a Result type.
🟡 [important]for...in should be Object.keys() / Object.entries()
for (const k in result) with hasOwnProperty is correct but unnecessarily verbose and risks confusion. JSON.parse returns a plain object with no prototype enumerable properties, so for...in is safe here — but the guard is still defensive. Cleaner alternatives:
// Option Afor(const[k,v]ofObject.entries(result)){if(Array.isArray(v)&&v.join('').includes(',')){result[kaskeyoftypeofresult]=v[0].split(',')}}// Option B (immutable)returnObject.fromEntries(Object.entries(result).map(([k,v])=>[k,Array.isArray(v)&&v.join('').includes(',') ? v[0].split(',') : v,]))
🟡 [important] No return type annotation
The function signature has no explicit return type. With JSON.parse, TypeScript infers any, which defeats type safety for callers. Consider:
typeof base64Input !== 'string' is unnecessary next to !base64Input — the truthiness check already covers '', null, undefined. If the parameter is typed string, the whole guard is a no-op (only needed if called from JS or with any).
🟢 [nit] Mutating the parsed object
The function mutates result[k] in place. While safe here (freshly allocated from JSON.parse), it's an unnecessary side-effect pattern. An immutable transform (see suggestion above) would be more predictable.
Verification
Check whether useUnknownInCatchVariables is enabled in tsconfig.json. If it is (recommended by TS 5.x strictness), the catch {} without a binding is fine; if it's not, consider enabling it for better error handling practices.
Decision: 💬 Comment
The core improvement (error wrapping) is solid, but the silent catch needs addressing before this is production-safe. The type guard on result is a nice addition.
The fix is sound: try/catch now covers the whole decode pipeline (atob → TextDecoder → JSON.parse → mutation loop), and the new guard rejects null/primitives/arrays from JSON.parse, fixing a latent strict-mode TypeError when decoded JSON was "123"/"abc".
console.warn in catch (e) is idiomatic here (advancedParser.ts:51, sw.ts:55; no-console is off), and {} return is safe for the caller (...q spread at wortList.vue:66).
Follow-ups noted (non-blocking):
WorkList.vue:18 re-decodes inline on every render while decodedQuery computed already caches the same value — reuse the computed.
Function return type is implicit any; suggest Record<string, unknown>.
Pre-existing v.join('').includes(',') comma-split heuristic drops items in ["a,b","c"] — now silently masked by the try/catch.
No unit-test infra exists; a small regression test for invalid inputs would lock this in.
)** is consistent with existing patterns (advancedParser.ts:51, sw.ts:55) and no-console` is disabled in eslint config, so it won't
break CI.
1. Redundant double-decode in WorkList.vue (pre-existing, but this PR owns the flow)
WorkList.vue:18 calls decodeHrefToQueryObj(route.params.config) directly in the template on
every re-render, while decodedQuery computed (:38) already decodes the same value and is
cached. Since the PR touches exactly this decoding path, consider binding :q="decodedQuery" and
dropping the inline call — removes duplicated work per render and one source of truth.
2. No explicit return type
With multiple return {} paths added, the function still has an implicit any return
(from JSON.parse). Annotate : Record<string, unknown> (or a dedicated type) so callers don't
silently receive any — cheap insurance given the mutation loop edits values by index.
3. Comma-split heuristic is fragile (pre-existing, noted for follow-up)
v.join('').includes(',') then v[0].split(',') drops elements in multi-item arrays containing
a comma (["a,b","c"] → ["a","b"], "c" lost). Not introduced here, but the try/catch now
masks it as a silent {} for some inputs; consider v.some(s => s.includes(',')) + a stricter
split in a future pass.
4. Behavior change to document
Valid JSON that decodes to a non-object (number/string) now silently yields {} instead of the
old (undefined/throwy) behavior. This is correct for the worklist use-case, but worth a comment
in the JSDoc since it changes the contract for any future callers.
5. Tests (optional)
There is no unit-test runner (Playwright e2e only). A small node script / e2e case exercising
invalid base64, valid-base64-of-non-object, and Tags with commas would lock in this fix.
Verdict
Solid, minimal, defensive fix. The core try/catch + type guard correctly resolve the crash for
invalid shared queries, and the console.warn addition is idiomatic for this repo. No blocking
issues — items 1–2 are small follow-ups in the same area.
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
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.
Summary
Treat malformed work-list route payloads as an empty query instead of allowing
atobor JSON parsing to fail during rendering.Root cause
A public URL such as
/#/l/not-base64was decoded directly from the template and computed state. Invalid Base64/JSON threw a browser exception and surfaced an error dialog.Validation
npm run buildThis PR intentionally only handles malformed payloads; query-change pagination is a separate fix.