fix: stronger cache hash (FNV-1a 64-bit) and GeoIP abort on timeout#210
Open
Rau1CS wants to merge 1096 commits intokoala73:mainfrom
Open
fix: stronger cache hash (FNV-1a 64-bit) and GeoIP abort on timeout#210Rau1CS wants to merge 1096 commits intokoala73:mainfrom
Rau1CS wants to merge 1096 commits intokoala73:mainfrom
Conversation
…getCSSColor() - Replace 8+ hardcoded rgba/hex colors with getCSSColor() CSS variable reads - Convert tooltip, grid, axes, now-marker, empty labels, event circles - Add theme-changed event listener for automatic re-render on theme toggle - Keep semantic LANE_COLORS (protest/conflict/natural/military) unchanged Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update --map-country to warm cream (#f0e8d8) for Voyager-style land - Update --map-stroke to warm border (#c8b8a8) complementing cream land - Subtler blue grid (#b0c8d8) for light mode - Add theme-changed event listener in Map.ts resetting baseRendered flag - Dark theme map values unchanged Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace static COLORS constant with getOverlayColors() function - Refresh COLORS at top of buildLayers() on each render cycle - Conflict zone fills more transparent in light mode (alpha 60 vs 100) - Conflict zone line color reduced alpha in light mode (120 vs 180) - Displacement arc colors deeper/more saturated on light backgrounds - Threat dots remain identical in both modes (user locked decision) - Infrastructure markers unchanged (semantic category colors)
- Create 03-01-SUMMARY.md with execution results - Update STATE.md with Phase 3 completion, metrics, and decisions
- Add wildcard 200ms ease transition on background-color, color, border-color, box-shadow - Add .no-transition suppression rule with !important for FOUC prevention - Add canvas/maplibregl/deck-canvas transition exclusion to prevent rendering artifacts - Fix --text-muted in light theme from #8a8a8a to #767676 (WCAG AA 4.54:1 vs #f8f9fa) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- index.html and settings.html FOUC scripts add no-transition class to <html> - src/main.ts removes no-transition after first paint via requestAnimationFrame - src/settings-main.ts removes no-transition after first paint via requestAnimationFrame - Prevents transition sweep from dark-to-light on page load while enabling smooth theme toggles Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These are local development/planning files that should be gitignored. Already covered by .gitignore entries for .planning/ and .idea/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add light-mode overrides for 12 semantic CSS variables that had terrible contrast on light backgrounds (as low as 1.25:1 for #44ff88). Uses Tailwind's light-friendly palette (green-600/700, amber-600, orange-600/700, yellow-600, sky-600). Also darken DeckGL overlay marker colors (startup hub, accelerator, nuclear, datacenter) and their legend SVGs in light mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
overlay-heavy is rgba(255,255,255,0.2) in dark mode (lightening tint), but 11 places originally used rgba(0,0,0,x) (darkening tint). This caused visible regressions in dark mode (channel bar, CII cards, etc). Adds --darken-light/medium/heavy CSS variables that stay black-tinted in both themes, and applies them to the affected selectors.
…a73#84) ## Summary Adds a complete dual-theme system to WorldMonitor. Users can toggle between dark and light mode in Settings, with the preference persisted across sessions. Every panel, the map, charts, and all chrome are fully themed. **41 files changed, +1,591 / -1,128 lines** ## What's included ### CSS Foundation (Phase 1) - 124+ hardcoded colors centralized into CSS custom properties - Theme colors separated from semantic colors (threat reds, DEFCON, status badges stay identical) - `getCSSColor()` runtime utility with theme-aware cache for dynamic TS components ### Theme Core (Phase 2) - `ThemeManager` module with `get/set/apply` theme functions and localStorage persistence - FOUC prevention inline scripts in both HTML entry points - Dark/Light radio toggle in Settings → Appearance section ### Map & Visualization Theming (Phase 3) - Map auto-swaps between dark CARTO and light Voyager tiles (no flash) - Deck.GL overlay layers adjust opacity/saturation per theme for readability - D3 CountryTimeline chart colors converted to theme-aware `getCSSColor()` ### Polish & Accessibility (Phase 4) - Smooth 200ms CSS transitions for all theme switching - WCAG AA contrast compliance (`--text-muted` #767676, 4.54:1 ratio) - Both build variants (full geopolitical + tech/startup) verified working ## Demo ### Toggle dark ↔ light https://github.com/user-attachments/assets/ce8d3bbe-fb5e-49cb-9bbd-5da5d900a15a ### Dark mode (unchanged) <img width="5120" height="2648" alt="image" src="https://github.com/user-attachments/assets/6a055ae6-e9a9-4d85-b328-a035b7bcd165" /> ### Light mode <img width="5120" height="2650" alt="image" src="https://github.com/user-attachments/assets/3531c952-a801-43a5-8ef3-68c160fb85b8" /> ## Review focus areas 1. **`src/styles/main.css`** — Bulk of the CSS variable conversion (~12K lines). Check that `var()` references and `[data-theme="light"]` overrides look correct. 2. **`src/utils/theme-manager.ts`** — New module. Simple but critical: localStorage read/write, event dispatch, FOUC prevention. 3. **`src/utils/theme-colors.ts`** — `getCSSColor()` cache utility. Verify cache invalidation on theme change is correct. 4. **`src/components/DeckGLMap.ts`** — Basemap tile swap logic and `getOverlayColors()` per-theme adjustments. 5. **`index.html` / `settings.html`** — Inline FOUC prevention scripts. CSP updated with `unsafe-inline` for script-src. 6. **`src/App.ts`** — Theme toggle UI wiring in settings modal. Check event listener patterns. ## What NOT to worry about - ~99 remaining hardcoded colors are documented acceptable exclusions (canvas drawing, console.log, deprecated constants with migration paths, category identifier colors) - Dark mode is visually identical to before — no regressions ## Test plan - [x] Run `npm run build` — builds without errors for both variants - [x] Open app — dark mode loads by default, no FOUC - [x] Go to Settings → Appearance → select Light — all panels, header, sidebar switch smoothly - [x] Verify map switches from dark CARTO to light Voyager tiles (no blank flash) - [x] Refresh page — light mode persists, no FOUC - [x] Switch back to dark — everything returns to original look - [x] Check semantic colors (threat dots, DEFCON badges, LIVE indicators) identical in both themes - [x] Open DevTools → inspect text contrast in light mode (should be ≥4.5:1) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Remove the duplicate time display from the header bar and add a theme toggle button (sun/moon icon) that hooks into the existing theme-manager. Bidirectional sync with settings modal radios.
Now that the header has a sun/moon dark/light toggle, the Appearance section in the settings modal is redundant. Revert modal title from "Settings" back to "Panels" and remove theme radio buttons and CSS.
Full light mode theme, header dark/light toggle, desktop update checker, bundled Node.js in installer, CORS fixes, and panel defaults update.
Add get_all_secrets command that reads all 18 keys in a single IPC call. This triggers one Keychain prompt instead of 18 on fresh installs.
Differentiate missing API key, upstream down, and empty data states. Name the actual data source in error messages instead of generic text.
- Add missing RSS proxy domains (seekingalpha, coindesk, cointelegraph) - Fix operator precedence in finance marker zoom checks (explicit parens) - Add Number.isFinite() NaN guards on all finance marker projections - Include finance variant in aggregated test:e2e script
## Summary Add CSS `contain: content` property to panel elements to enable browser optimizations and improve rendering performance by establishing a new stacking context and limiting layout recalculations. ## Type of change - [x] Refactor / code cleanup ## Affected areas - [x] Other: CSS performance optimization ## Details This change adds the `contain: content` CSS property to panel elements (`.panel` class). This CSS containment property: - Enables the browser to optimize rendering by limiting the scope of layout, style, and paint calculations - Establishes a new stacking context, which can improve performance when panels are frequently repositioned or resized - Has no visual impact on the UI This is a low-risk performance optimization that leverages modern CSS capabilities to improve responsiveness, especially when dealing with multiple panels on the dashboard. ## Checklist - [x] No API keys or secrets committed - [x] TypeScript compiles without errors ## Testing No testing needed - this is a CSS-only performance optimization with no behavioral changes. https://claude.ai/code/session_01E9FpgiebjEuUPhNt8mwX9U
### Motivation - Panels can receive multiple content updates in quick succession, causing many DOM writes and janky re-renders during data bursts. - Pairing a debounce with the existing DOM diffing/RAF throttling reduces unnecessary work and smooths the UI. ### Description - Added a 150ms debounce to `Panel.setContent()` and new private fields (`contentDebounceMs`, `pendingContentHtml`, `contentDebounceTimer`) to buffer rapid updates and apply only the latest payload. - `setContent()` now skips no-op updates when the pending or current HTML already matches and resets the timer on rapid calls. - Introduced `setContentImmediate()` and switched `showLoading()`, `showError()`, and `showConfigError()` to use it so immediate UI states are not overwritten by stale debounced writes. - Extended `destroy()` to clear any pending debounce timers and pending content to avoid delayed updates after teardown. ### Testing - Ran `npm run typecheck` (i.e. `tsc --noEmit`) and it completed successfully. ------ [Codex Task](https://chatgpt.com/codex/tasks/task_e_699782a113a88333ab664a828cb00b02)
## Summary Optimize GPU memory usage by strategically applying and removing the `will-change` CSS property on animated elements. This prevents unnecessary GPU memory allocation for elements that don't require continuous optimization, while maintaining smooth animations through the transition/animation lifecycle. ## Type of change - [x] Refactor / code cleanup - [x] Performance optimization ## Affected areas - [x] Map / Globe - [x] Other: UI animations and modals ## Changes ### CSS Updates (`src/styles/main.css`) - Added `will-change: transform, opacity;` to `.panel-header` (hover state) - Added `will-change: transform, opacity;` to `.signal-modal` (entrance animation) - Added `will-change: transform;` to `.map-popup` (slide-in transition) - Added `will-change: transform, opacity;` to `.mobile-warning-modal` (entrance animation) - Added `will-change: transform;` to `.tech-event-marker` (transform animations) ### JavaScript Updates - **MapPopup.ts**: Added listener to remove `will-change` after slide-in transition completes - **MobileWarningModal.ts**: Added listener to remove `will-change` after entrance animation completes - **SignalModal.ts**: Added listener to remove `will-change` after entrance animation completes ## Rationale The `will-change` property hints to the browser to prepare for animations, but maintaining it indefinitely wastes GPU memory. By removing it after animations complete (via `transitionend` or `animationend` events), we free up resources while preserving animation performance. ## Checklist - [x] TypeScript compiles without errors - [x] No API keys or secrets committed https://claude.ai/code/session_01DDhT6Ex596eX1CtSb6mHdH
## Summary Adds a pre-rendered skeleton loading screen that displays instantly before JavaScript boots, eliminating flash of unstyled content (FOUC). The skeleton mimics the final layout with animated shimmer effects and automatically replaces when the app initializes. ## Type of change - [x] New feature - [ ] Bug fix - [ ] Refactor / code cleanup - [ ] Other ## Affected areas - [x] Other: Loading UX / Initial page render ## Details This change improves the perceived performance and user experience by: 1. **Inlining critical skeleton CSS** in the `<head>` to ensure it renders before any external stylesheets load 2. **Pre-rendering skeleton HTML** in the `#app` div that displays instantly on page load 3. **Supporting both themes** with dark mode as default and light mode variants via `[data-theme="light"]` selectors 4. **Adding shimmer animation** to skeleton lines for visual feedback that content is loading 5. **Marking skeleton as hidden from accessibility** with `aria-hidden="true"` so screen readers skip it The skeleton layout includes: - Header with logo, filters, and controls - Map section with toolbar - Grid of 6 data panels with headers and content lines When the Vue app initializes and calls `renderLayout()`, the skeleton is automatically replaced with the actual content. ## Checklist - [x] No API keys or secrets committed - [x] Tested theme switching (dark/light mode skeleton variants) - [x] Skeleton is properly hidden from screen readers https://claude.ai/code/session_01Fxk8GMRn2cEUq3ThC2a8e5
Closes koala73#169 — the `ml-*` pattern missed chunks without a hyphen, causing ~60 MB of ML code to be precached by the service worker.
Closes koala73#139 — pass DependencyGraph as parameter (no redundant rebuild), check direct edges first, then walk BFS dependency chain for indirect impacts (chokepoint → port → country). Returns 0 for truly unaffected.
…se caching (koala73#171) ### Motivation - Improve repeat-visit performance by persisting API responses and data-source payloads client-side so the dashboard can show cached data immediately while refreshing in the background (PERF-021). - Provide a robust multi-tier storage strategy: prefer desktop/Tauri storage, then IndexedDB in browser runtime, and fall back to `localStorage` if needed. ### Description - Upgrade `src/services/persistent-cache.ts` to use an IndexedDB store (`worldmonitor_persistent_cache`) with `getFromIndexedDb`/`setInIndexedDb` while keeping Tauri RPC and `localStorage` fallbacks. - Add stale-while-revalidate API response caching to `src/utils/proxy.ts` via `fetchWithProxy`, which returns cached `/api/*` responses immediately and refreshes them in the background (persisted under `api-response:<url>`). - Route key data-source fetchers through the new proxy cache by switching `fetch` -> `fetchWithProxy` in `src/services/arxiv.ts`, `src/services/hackernews.ts`, `src/services/github-trending.ts`, and `src/services/earthquakes.ts` so they inherit persistent response hydration. - Preserve existing behaviors and fallbacks (desktop storage first, IndexedDB where available, then `localStorage`) and avoid breaking existing circuit-breaker logic in services. ### Testing - Ran `npm run typecheck` (`tsc --noEmit`) and it succeeded. - Ran `npm run test:data` and the suite executed; most tests passed but one existing `deploy/cache` guardrail subtest failed (pre-existing assertion about a precache glob pattern), which is unrelated to the caching changes. ------ [Codex Task](https://chatgpt.com/codex/tasks/task_e_6997871eb7648333a131f041010684de)
Replace naive string concatenation for Vary header with appendVary() that parses existing tokens and deduplicates case-insensitively. Prevents duplicate Vary tokens when both Origin and Accept-Encoding are added. Closes koala73#170 Co-authored-by: Lawyered <4802498+lawyered0@users.noreply.github.com>
Add manual chunk rules for i18next → i18n, @sentry/* → sentry, and *Panel.ts → panels. Improves caching (stable vendor chunks) and reduces main bundle size via parallel loading. Closes koala73#148
…s (PERF-012) (koala73#154) Inline <style> blocks were re-injected on every render in 6 components, causing CSSOM recalc and GC pressure from repeated string allocation. Extracted all panel styles into src/styles/panels.css, imported once via main.css. Affected components: SatelliteFiresPanel, PopulationExposurePanel, ClimateAnomalyPanel, DisplacementPanel, UcdpEventsPanel, DownloadBanner. https://claude.ai/code/session_01Erkji3Bg2NwawE25NFC6vh Co-authored-by: Claude <noreply@anthropic.com>
…ll id - Add /webkitEnterFullscreen/ to ignoreErrors for Safari internal fullscreen crash - Add "id" to beforeSend property alternation for deck.gl _drawLayers null access
- Add AbortController to Panel base class, abort on destroy() - Wire signal into 7 panel fetch calls with AbortError guard - Add signal param to fetchCachedRiskScores/fetchCachedTheaterPosture - Add abort lifecycle to CountryBriefPage (show/hide) - Fix StrategicRiskPanel missing super.destroy() call Co-authored-by: koala73 <koala73@users.noreply.github.com>
Add dom-utils.ts with h(), replaceChildren(), fragment(), rawHtml() helpers. Convert 8 components from innerHTML string concatenation to type-safe DOM construction, eliminating XSS surface and HTML parsing. Components: Panel, CIIPanel, GdeltIntelPanel, MonitorPanel, PizzIntIndicator, ServiceStatusPanel, StatusPanel, TechEventsPanel. Event listeners now inline via onClick props (removes post-render querySelector+addEventListener pattern). Fix ServiceStatusPanel missing super.destroy() call.
Add broader filter: any TypeError where all in-app frames are in the maplibre map chunk is suppressed. Catches hash-parsing crashes like 'o.includes' that are entirely inside maplibre-gl internals.
Filter window.android.* TypeError from Huawei/Android WebView shell injections — not our code.
- InvestmentsPanel: replace per-element listeners (destroyed by debounced innerHTML) with event delegation on stable this.content - IntelligenceGapBadge: null guard on context.actionableInsight for environments where i18n is not initialized - keyword-spike test: restructure headlines so spike term appears mid-sentence (isLikelyProperNoun skips index-0), add initI18n - investments-panel test: add pollUntil helper, re-query DOM elements after debounced render cycles - map-harness tests: increase WebGL harness init and poll timeouts, relax golden screenshot pixel diff threshold
- cached-risk-scores/cached-theater-posture: shared fetch must not be canceled by one caller's AbortSignal; use withCallerAbort wrapper so individual callers can abort without killing the shared promise - StrategicPosturePanel: remove isMilitaryVesselTrackingConfigured guard that blocked USNI fleet data when AIS key was absent - Panel: use rawHtml for info tooltip to render HTML content correctly
…uilds - vercel.json: add ignoreCommand to skip builds when only docs/tests/CI change - service-status: extend edge cache 60s→300s (46 service checks, slow-moving) - cyber-threats: extend edge cache 5min→1hr (threat intel updates hourly) - theater-posture: extend edge cache 60s→300s, stale fallback 30s→120s - markets/crypto polling: 2min→4min (reduce edge requests by ~50%)
…config constant DRY extraction of identical map defined in both syncDataFreshnessWithLayers() and setupMapLayerHandlers(). Single source of truth in config/panels.ts. Supersedes PR koala73#145 which was based on stale main (missing gdelt_doc).
Block crawlers/scrapers from /api/* routes via Edge Middleware (403 for bot user-agents and missing/short UAs). Social preview bots (Twitter, Facebook, LinkedIn, Slack, Discord) are allowed on /api/story and /api/og-story for OG previews. robots.txt reinforces the same policy.
- fred-data: batch mode (comma-separated series_id) reduces 7 edge function invocations to 1; cap at 15 series; propagate upstream 502s instead of masking as empty 200; add X-Data-Status header - ucdp-events: parallelize page fetches; track failed pages and use short cache TTL for partial results instead of caching at full 6h - ucdp: add OPTIONS/method guard matching ucdp-events pattern - middleware: exact-match social bot paths instead of startsWith - vercel.json: use VERCEL_GIT_PREVIOUS_SHA for multi-commit diffs; add middleware.ts, settings.html, vercel.json to watch list - Panel.ts: use safeHtml() allowlist sanitizer for tooltip content - dom-utils: add safeHtml() with tag/attribute allowlist and javascript: URI blocking
…rs on timeout hashString() used a 32-bit DJB2 hash prone to collisions at scale; replaced with FNV-1a 64-bit (BigInt) for ~2^32 birthday-bound collision resistance while staying synchronous and edge-runtime compatible. GeoIP worker pool in cyber-threats used Promise.race without cancelling in-flight fetches on timeout. Now threads AbortController signal through workers → geolocateIp → fetchGeoIp → fetchJsonWithTimeout so all pending requests are aborted when the overall timeout fires. Closes koala73#180, closes koala73#196 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@Rau1CS is attempting to deploy a commit to the Elie Team on Vercel. A member of the Team first needs to authorize it. |
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.
Summary
hashString()in_upstash-cache.jswith FNV-1a 64-bit using BigInt. The birthday-bound collision threshold goes from ~65K to ~4B entries — a 65,000x improvement while remaining synchronous and edge-runtime compatible. All 5 caller files are unchanged.cyber-threats.jsusedPromise.raceto enforce an overall timeout, but the losing workers (and their in-flightfetchcalls) kept running. Now anAbortControllersignal is threaded throughhydrateThreatCoordinates → geolocateIp → fetchGeoIp → fetchJsonWithTimeout, so all pending requests are cancelled the moment the overall timeout fires.Changes
api/_upstash-cache.jshashString(): DJB2 32-bit → FNV-1a 64-bit (BigInt)api/cyber-threats.jshydrateThreatCoordinates: createAbortController, passsignalthrough worker chain;fetchJsonWithTimeout: forward external abort signal;fetchGeoIp/geolocateIp: accept + passsignalparameterChecklist
npx tsc --noEmitpassesnode:crypto, uses BigInt + standardAbortController)hashStringsignature unchanged; newsignalparams are optional)Closes #180, closes #196
🤖 Generated with Claude Code