Skip to content

fix(frontend): live-panel correctness — wrong series, oldest-12 slice, dead preflight, double-escaped hrefs - #64

Merged
arnoldcastro5000 merged 1 commit into
mainfrom
fix/frontend-js-correctness
Jul 7, 2026
Merged

arnoldcastro5000 merged 1 commit into
mainfrom
fix/frontend-js-correctness

Conversation

@loonvault-agent

Copy link
Copy Markdown
Contributor

Summary

Audit of every first-party JS file (both Cloudflare workers + the four frontend assets) ahead of the demo. Four functional bugs, all demo-relevant:

  1. runtime.js — defaultSeries: "CPI" can never work. db-init only seeds FXCADUSD (runbook), so the live fetch 404s and falls back regardless of the API worker being wired. This re-lands stranded commit 35de446 (its branch missed the fix(frontend): parked-state fixes — WAF-safe runtime.js rename + opt-in live panel #46 squash). The liveData gate from that commit is deliberately dropped: with the api- route/DNS permanent (issue 011), a parked backend produces a caught 502 → snapshot fallback, which is the resilience story.
  2. app.js — panel showed the 12 oldest observations. Both the read lambda (ORDER BY observed_on DESC) and the snapshot (sorted(..., reverse=True)) are newest-first; .slice(-12) took the tail. Now .slice(0, 12).
  3. cloudflare/api-worker.js — preflight handler was functionally dead. OPTIONS returned 204 with no Access-Control-Allow-Origin, failing any preflighted request. Now forwards OPTIONS (+ Access-Control-Request-*) to API Gateway, which owns the CORS allowlist (feat(frontend): Cloudflare API worker — browser live-API path never worked #63) and auto-answers preflights. Today's panel fetch is a simple GET (no preflight), so this is latent — but it becomes live the moment any header/param is added.
  4. md-renderer.js — link hrefs double-escaped. inline() escapes the line before link parsing, then safeHref escaped again: ?a=1&b=2 rendered as a literal amp;b param. Entities are now unescaped before the single escape; javascript: blocking and attribute-injection escaping verified unchanged.

Verification

  • Node harness against the worker module (17 checks): origin rewrite, secret injection, ACAO passthrough, preflight forwarding, and 405/404/414/400/421/502 rejections all pass.
  • Renderer: query-string hrefs singly-escaped; javascript: scheme still blocked; attribute injection still escaped; plain relative links unchanged.
  • node --check clean on all six JS files.

⚠️ After merge: re-paste cloudflare/api-worker.js into the Cloudflare dashboard worker (it is deployed by copy-paste) and redeploy the frontend (just deploy-frontend + purge Cloudflare cache).

🤖 Generated with Claude Code

…, dead preflight, double-escaped hrefs

Four functional bugs found auditing the JS before the demo:

- runtime.js: defaultSeries was "CPI", a series db-init never seeds — the live
  fetch 404s and the panel can never show live data even with the API worker
  wired. Set to FXCADUSD (the seeded series). This re-lands the fix from
  35de446, which was stranded on fix/rename-config-js-waf when PR #46 was
  squash-merged before that commit was pushed (the liveData gate from the same
  commit is deliberately NOT re-landed: once the api- route/DNS is permanent,
  a parked backend yields a caught 502 + snapshot fallback, which is the
  demo's resilience story — no console noise, no gate needed).

- app.js: observations arrive newest-first from BOTH sources (read lambda
  ORDER BY observed_on DESC; snapshot sorted reverse=True), so .slice(-12)
  rendered the 12 OLDEST of 90 observations. Take the first 12.

- api-worker.js: the OPTIONS branch answered preflights with 204 and no
  Access-Control-Allow-Origin — any preflighted request would fail CORS.
  Forward OPTIONS (plus Access-Control-Request-*) to API Gateway, which owns
  the CORS allowlist and auto-answers preflights. Verified with a node harness
  (17 checks: rewrite/secret/ACAO passthrough, preflight forwarding, 405/404/
  414/400/421/502 rejections).

- md-renderer.js: inline() escapes the whole line before link parsing, then
  safeHref escaped the href AGAIN, so ?a=1&b=2 rendered as a=1&b=2 (literal
  "amp;b" param). Unescape entities before the single escape; javascript:
  blocking and attribute-injection escaping verified unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arnoldcastro5000
arnoldcastro5000 merged commit 74ce6d9 into main Jul 7, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant