Commit Graph

35 Commits

Author SHA1 Message Date
Elie Habib
408d5d3374 security: harden IPC, gate DevTools, isolate external windows, exempt /api/version (#348)
* security: harden IPC commands, gate DevTools, and isolate external windows

- Remove devtools from default Tauri features; gate behind opt-in
  Cargo feature so production builds never expose DevTools
- Add IPC origin validation (require_trusted_window) to 9 sensitive
  commands: get_secret, get_all_secrets, set_secret, delete_secret,
  get_local_api_token, read/write/delete_cache_entry, fetch_polymarket
- Isolate youtube-login window into restricted capability (core:window
  only) — prevents external-origin webview from invoking app commands
- Add 5-minute TTL to cached sidecar auth token in fetch patch closure
- Document renderer trust boundary threat model in runtime.ts

* docs: add contributors, security acknowledgments, and desktop security policy

- Add Contributors section to README with all 16 GitHub contributors
- Add Security Acknowledgments crediting Cody Richard for 3 disclosures
- Update SECURITY.md with desktop runtime security model (Tauri IPC
  origin validation, DevTools gating, sidecar auth, capability isolation,
  fetch patch trust boundary)
- Add Tauri-specific items to security report scope
- Correct API key storage description to cover both web and desktop

* fix: exempt /api/version from bot-blocking middleware

The desktop update check and sidecar requests were getting 403'd by the
middleware's bot UA filter (curl/) and short UA check.
2026-02-25 06:14:16 +00:00
Elie Habib
9ef3cd8402 perf: defer YouTube/map init and stagger data loads to reduce blocking time (#287) (#345)
- Defer YouTube player init via IntersectionObserver + requestIdleCallback
  gate with clickable placeholder (no eager iframe_api load)
- Stagger loadAllData() into 3 priority tiers: critical (immediate),
  important (after rAF yield), deferred (requestIdleCallback fire-and-forget)
- Move DeckGL supercluster rebuilds into map 'load' callback
- Cancel deferred tier-3 callbacks on App destroy (prevents post-teardown work)
- Add bot-check detection with YouTube sign-in window for desktop (Tauri)
- Safe DOM construction for all new UI paths (no innerHTML with user data)
2026-02-24 23:54:40 +00:00
Elie Habib
e35f0f70e9 Security hardening: SSRF protection, auth gating, and token generation (#343)
* security: block SSRF and enforce global auth on sidecar endpoints

Addresses trust boundary vulnerabilities in the desktop sidecar's
locally-exposed API server (127.0.0.1:46123) reported in
"Breaking the Trust Boundary in a 14k Star OSINT Dashboard":

- SSRF protection on /api/rss-proxy: block private/reserved IPs
  (127.x, 10.x, 172.16-31.x, 192.168.x, 169.254.x, multicast),
  validate DNS resolution to prevent rebinding, reject non-http(s)
  protocols and URLs with embedded credentials

- Global auth gate: move LOCAL_API_TOKEN check above ALL endpoints
  so /api/rss-proxy, /api/local-status, /api/local-traffic-log,
  /api/local-debug-toggle, and /api/register-interest now require
  authentication (only /api/service-status health check is exempt)

- Cryptographic token generation: replace RandomState-based token
  in main.rs with getrandom crate (OS-backed CSPRNG, 32 bytes)

- Traffic log privacy: strip query strings from logged paths to
  prevent leaking feed URLs and user research patterns

- CORS hardening: tighten worldmonitor.app origin regex from
  (.*\.)? to ([a-z0-9-]+\.)? to block multi-level subdomain spoofing

- 10 new security tests covering auth enforcement on every endpoint,
  SSRF blocking for private IPs/localhost/non-http/credentials,
  health check exemption, and traffic log sanitization

https://claude.ai/code/session_018vNVfwPh25tbZmtiX66KxP

* security: pin resolved IP in rss-proxy to close TOCTOU DNS rebinding window

isSafeUrl() now returns the resolved addresses, and fetchWithTimeout()
accepts a resolvedAddress option that bypasses runtime DNS via a custom
lookup callback (HTTPS) or URL rewrite with Host header (HTTP).
The rss-proxy handler threads the first validated IPv4 through, so the
TCP connection is guaranteed to reach the same IP that passed the
private-range check.

https://claude.ai/code/session_018vNVfwPh25tbZmtiX66KxP

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 23:01:19 +00:00
Elie Habib
d593fbf413 fix: increase live channels window size to fit channel grid (#301) 2026-02-24 06:53:42 +00:00
Elie Habib
6271fafd40 feat(live): custom channel management with review fixes (#282)
* feat(live): custom channel management — add/remove/reorder, standalone window, i18n

- Standalone channel management window (?live-channels=1) with list, add form, restore defaults
- LIVE panel: gear icon opens channel management; channel tabs reorderable via DnD
- Row click to edit; custom modal for delete confirmation (no window.confirm)
- i18n for all locales (manage, addChannel, youtubeHandle, displayName, etc.)
- UI: margin between channel list and add form in management window
- settings-window: panel display settings comment in English

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(tauri): channel management in desktop app, dev base_url fix

- Add live-channels.html and live-channels-main.ts for standalone window
- Tauri: open_live_channels_window_command, close_live_channels_window, open live-channels window (WebviewUrl::App or External from base_url)
- LiveNewsPanel: in desktop runtime invoke Tauri command with base_url (window.location.origin) so dev works when Vite runs on a different port than devUrl
- Vite: add liveChannels entry to build input
- capabilities: add live-channels window
- tauri.conf: devUrl 3000 to match vite server.port
- docs: PR_LIVE_CHANNEL_MANAGEMENT.md for PR #276

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: address review issues in live channel management PR

- Revert settings button to open modal (not window.open popup)
- Revert devUrl from localhost:3000 to localhost:5173
- Guard activeChannel against empty channels (fall back to defaults)
- Escape i18n strings in innerHTML with escapeHtml() to prevent XSS
- Only store displayNameOverrides for actually renamed channels
- Use URL constructor for live-channels window URL
- Add CSP meta tag to live-channels.html
- Remove unused i18n keys (edit, editMode, done) from all locales
- Remove unused CSS classes (live-news-manage-btn/panel/wrap)
- Delete PR instruction doc (PR_LIVE_CHANNEL_MANAGEMENT.md)

---------

Co-authored-by: Masaki <yukkurihakutaku@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-23 22:51:44 +00:00
Elie Habib
a37dced84e fix: circuit breaker persistent cache with safety fixes (#281)
* fix: persist circuit breaker cache to IndexedDB across page reloads

On page reload, all 28+ circuit breaker in-memory caches are lost,
triggering 20-30 simultaneous POST requests to Vercel edge functions.

Wire the existing persistent-cache.ts (IndexedDB + localStorage +
Tauri fallback) into CircuitBreaker so every breaker automatically:

- Hydrates from IndexedDB on first execute() call (~1-5ms read)
- Writes to IndexedDB fire-and-forget on every recordSuccess()
- Falls back to stale persistent data on network failure
- Auto-disables for breakers with cacheTtlMs=0 (live pricing)

Zero consumer code changes -- all 28+ breaker call sites untouched.
Reloads within the cache TTL (default 10min) serve instantly from
IndexedDB with zero network calls.

Also adds deletePersistentCache() to persistent-cache.ts for clean
cache invalidation via clearCache().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add Playwright e2e tests for circuit breaker persistent cache

7 tests covering: IndexedDB persistence on success, hydration on new
instance, TTL expiry forcing fresh fetch, 24h stale ceiling rejection,
clearCache cleanup, cacheTtlMs=0 auto-disable, and network failure
fallback to stale persistent data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: desktop cache deletion + clearCache race condition

P1: deletePersistentCache sent empty string to write_cache_entry,
which fails Rust's serde_json::from_str (not valid JSON). Add
dedicated delete_cache_entry Tauri command that removes the key
from the in-memory HashMap and flushes to disk.

P2: clearCache() set persistentLoaded=false, allowing a concurrent
execute() to re-hydrate stale data from IndexedDB before the async
delete completed. Remove the reset — after explicit clear there is
no reason to re-hydrate from persistent storage.

* fix: default persistCache to false, fix falsy data guard

P1b: 6 breakers store Date objects (weather, aviation, ACLED,
military-flights, military-vessels, GDACS) which become strings
after JSON round-trip. Callers like MapPopup.getTimeUntil() call
date.getTime() on hydrated strings → TypeError. Change default
to false (opt-in) so persistence requires explicit confirmation
that the payload is JSON-safe.

P2: `if (!entry?.data) return` drops valid falsy payloads (0,
false, empty string). Use explicit null/undefined check instead.

* fix: address blocking review issues on circuit breaker persistence

- clearCache() nulls persistentLoadPromise to orphan in-flight hydration
- delete_cache_entry defers disk flush to exit handler (avoids 14MB sync write)
- hydratePersistentCache checks TTL before setting lastDataState to 'cached'
- deletePersistentCache resets cacheDbPromise on IDB error + logs warning
- hydration catch logs warning instead of silently swallowing
- deletePersistentCache respects isStorageQuotaExceeded() for localStorage

---------

Co-authored-by: Elias El Khoury <efk@anghami.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:35:45 +00:00
Elie Habib
f06acd3c88 Fix GLib symbol mismatch when running as AppImage on newer distros (#263)
* fix: resolve AppImage crash on Ubuntu 25.10+ (GLib symbol mismatch)

The AppImage bundles GLib from the build system, but host GIO modules
(e.g. GVFS libgvfsdbus.so) compiled against a newer GLib reference
symbols like g_task_set_static_name that don't exist in the older
bundled copy, causing "undefined symbol" errors and WebKit crashes.

Set GIO_MODULE_DIR="" when running as AppImage to prevent host GIO
modules from loading against the incompatible bundled GLib. GVFS
features (network mounts, trash, MTP) are unused by this app.

Note: the CI should also be upgraded from ubuntu-22.04 to ubuntu-24.04
in .github/workflows/build-desktop.yml to ship GLib 2.80+ and extend
forward-compatibility. This requires workflows permission to push.

https://claude.ai/code/session_01J8HBrfb26GJm22MFCeGoAA

* fix(appimage): keep bundled GIO modules for Ubuntu 25.10

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 17:07:37 +00:00
Elie Habib
d24d61f333 Fix Linux rendering issues and improve monospace font fallbacks (#243)
* fix: resolve AppImage blank white screen and font crash on Linux (#238)

Disable WebKitGTK DMA-BUF renderer by default on Linux to prevent blank
white screens caused by GPU buffer allocation failures (common with
NVIDIA drivers and immutable distros like Bazzite). Add Linux-native
monospace font fallbacks (DejaVu Sans Mono, Liberation Mono) to all font
stacks so WebKitGTK font resolution doesn't hit out-of-bounds vector
access when macOS-only fonts (SF Mono, Monaco) are unavailable.

https://claude.ai/code/session_01TF2NPgSSjgenmLT2XuR5b9

* fix: consolidate monospace font stacks into --font-mono variable

- Define --font-mono in :root (main.css) and .settings-shell (settings-window.css)
- Align font stack: SF Mono, Monaco, Cascadia Code, Fira Code, DejaVu Sans Mono, Liberation Mono
- Replace 3 hardcoded JetBrains Mono stacks with var(--font-mono)
- Replace 4 hardcoded settings-window stacks with var(--font-mono)
- Fix pre-existing bug: var(--font-mono) used in 4 places but never defined
- Match index.html skeleton font stack to --font-mono

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 07:16:48 +00:00
Elie Habib
63a4c9ab9c feat: Upstash Redis shared caching + cache key contamination fixes (#232)
* fix(sentry): add noise filters for 5 non-actionable error patterns

Filter dynamic import alt phrasing, script parse errors, maplibre
style/WebGL crashes, and CustomEvent promise rejections. Also fix
beforeSend to catch short Firefox null messages like "E is null".

* fix: cache write race, settings stale key status, yahoo gate concurrency

P1: Replace async background thread cache write with synchronous fs::write
to prevent out-of-order writes and dirty flag cleared before persistence.

P2: Add WorldMonitorTab.refresh() called after loadDesktopSecrets() so
the API key badge reflects actual keychain state.

P3: Replace timestamp-based Yahoo gate with promise queue to ensure
sequential execution under concurrent callers.

* feat: add Upstash Redis shared caching to all RPC handlers + fix cache key contamination

- Add Redis L2 cache (getCachedJson/setCachedJson) to 28 RPC handlers
  across all service domains (market, conflict, cyber, economic, etc.)
- Fix 10 P1 cache key contamination bugs where under-specified keys
  caused cross-request data pollution (e.g. filtered requests returning
  unfiltered cached data)
- Restructure list-internet-outages to cache-then-filter pattern so
  country/timeRange filters always apply after cache read
- Add write_lock mutex to PersistentCache in main.rs to prevent
  desktop cache write-race conditions
- Document FMP (Financial Modeling Prep) as Yahoo Finance fallback TODO
  in market/v1/_shared.ts

* fix: cache-key contamination and PizzINT/GDELT partial-failure regression

- tech-events: fetch with limit=0 and cache full result, apply limit
  slice after cache read to prevent low-limit requests poisoning cache
- pizzint: restore try-catch around PizzINT fetch so GDELT tension
  pairs are still returned when PizzINT API is down

* fix: remove extra closing brace in pizzint try-catch

* fix: recompute conferenceCount/mappableCount after limit slice

* fix: bypass WM API key gate for registration endpoint

/api/register-interest must reach cloud without a WorldMonitor API key,
otherwise desktop users can never register (circular dependency).
2026-02-23 10:09:12 +04:00
Elie Habib
8f8b0c843b Format Rust code and fix Windows focus handling (#242)
* chore: apply cargo fmt formatting to main.rs

Pure formatting normalization with no logic changes. Separated from
the behavioral fix to keep git blame clean.

https://claude.ai/code/session_01RPQ1PEqxTSEG6rB5XadzEz

* fix: restrict settings-window re-focus to macOS to avoid Windows focus churn

On Windows, the Focused(true) handler on the main window calls
show()+set_focus() on the settings window, which steals focus back,
retriggering the event in a tight loop and presenting as a UI hang.

Gate the match arm with #[cfg(target_os = "macos")] (compile-time
attribute) instead of cfg!() (runtime macro) to match the convention
used by the adjacent macOS-only handlers and eliminate dead code on
non-macOS builds entirely.

https://claude.ai/code/session_01RPQ1PEqxTSEG6rB5XadzEz

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 05:29:49 +00:00
Elie Habib
8699dae5e5 fix: registration via direct Convex call + compact WM tab layout
- Sidecar calls Convex HTTP API directly (Vercel Attack Challenge Mode
  blocks server-side proxy). CONVEX_URL read from env, not hardcoded.
- Rust injects CONVEX_URL into sidecar via option_env! (CI) / env var (dev)
- GitHub Actions passes CONVEX_URL secret to all 4 build steps
- Tighten WM tab CSS spacing so all content fits in one viewport
2026-02-21 11:36:03 +00:00
Elie Habib
a388afe400 feat: API key gating for desktop cloud fallback + registration (#215)
* feat: API key gating for desktop cloud fallback + registration system

Gate desktop cloud fallback behind WORLDMONITOR_API_KEY — desktop users
need a valid key for cloud access, otherwise operate local-only (sidecar).
Add email registration system via Convex DB for future key distribution.

Client-side: installRuntimeFetchPatch() checks key presence before
allowing cloud fallback, with secretsReady promise + 2s timeout.
Server-side: origin-aware validation in sebuf gateway — desktop origins
require key, web origins pass through.

- Add WORLDMONITOR_API_KEY to 3-place secret system (Rust, TS, sidecar)
- New "World Monitor" settings tab with key input + registration form
- New api/_api-key.js server-side validation (origin-aware)
- New api/register-interest.js edge function with rate limiting
- Convex DB schema + mutation for email registration storage
- CORS headers updated for X-WorldMonitor-Key + Authorization
- E2E tests for key gate (blocked without key, allowed with key)
- Deployment docs (API_KEY_DEPLOYMENT.md) + updated desktop config docs

* fix: harden worldmonitor key + registration input handling

* fix: show invalid WorldMonitor API key status

* fix: simplify key validation, trim registration checks, add env example vars

- Inline getValidKeys() in _api-key.js
- Remove redundant type checks in register-interest.js
- Simplify WorldMonitorTab status to present/missing
- Add WORLDMONITOR_VALID_KEYS and CONVEX_URL to .env.example

* feat(sidecar): integrate proto gateway bundle into desktop build

The sidecar's buildRouteTable() only discovers .js files, so the proto
gateway at api/[domain]/v1/[rpc].ts was invisible — all 45 sebuf RPCs
returned 404 in the desktop app. Wire the existing build script into
Tauri's build commands and add esbuild as an explicit devDependency.
2026-02-21 10:36:23 +00:00
Elie Habib
6c3d2770f7 feat: split settings into LLMs and API Keys tabs, fix keychain vault and Ollama UX
- Split settings window into 3 tabs: LLMs (Ollama/Groq/OpenRouter),
  API Keys (data feeds), and Debug & Logs
- Add featureFilter option to RuntimeConfigPanel for rendering subsets
- Consolidate keychain to single JSON vault entry (1 macOS prompt vs 20)
- Add Ollama model discovery with /api/tags + /v1/models fallback
- Strip <think> reasoning tokens from Ollama responses
- Suppress thinking with think:false in Ollama request body
- Parallel secret verification with 15s global timeout
- Fix manual model input overlapping dropdown (CSS grid-area + hidden-input class)
- Add loading spinners to settings tab panels
- Suppress notification popups when settings window is open
- Filter embed models from Ollama dropdown
- Fix settings window black screen flash with inline dark background
2026-02-20 00:02:48 +04:00
Elie Habib
bb14f0e9a8 fix: resolve TS build errors and add missing Ollama keys to Rust keyring
- Use for...of entries() instead of index-based loops in summarization.ts
  to satisfy strict noUncheckedIndexedAccess (7 TS18048/TS2345 errors)
- Replace fragile API_PROVIDERS[1] with .find(p => p.name === groq)
- Add OLLAMA_API_URL and OLLAMA_MODEL to SUPPORTED_SECRET_KEYS in main.rs
  so keychain secrets are injected into sidecar on desktop startup
2026-02-19 19:33:40 +04:00
Elie Habib
65dea2e4f9 fix(desktop): batch keychain reads to reduce macOS password prompts
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.
2026-02-17 00:24:44 +04:00
Elie Habib
c94ec0b4ad Adding Node in the Tauri Installer 2026-02-16 23:30:19 +04:00
Elie Habib
cccfdac0f9 feat(update): add desktop update check with architecture-aware download links 2026-02-16 23:13:10 +04:00
Elie Habib
60cec92a16 fix(windows): preserve UNC paths when sanitizing sidecar script path 2026-02-16 23:09:30 +04:00
Elie Habib
700132adad fix: hide node.exe console window on Windows & bump v2.3.6
Add CREATE_NO_WINDOW (0x08000000) creation flag to the sidecar
Command::new() spawn on Windows. Without this, node.exe inherits
a visible console window that overlays the Tauri GUI.
2026-02-16 09:00:16 +04:00
Elie Habib
7d3b600364 fix: strip UNC path prefix for Windows sidecar, set explicit CWD & bump v2.3.4
Tauri resource_dir() on Windows returns \\?\ extended-length paths that
Node.js module resolution cannot handle, causing EISDIR: lstat 'C:'.
Strip the prefix before passing to Node.js, set current_dir to the
sidecar directory, and add package.json with "type": "module" to prevent
ESM scope walk-up to drive root.
2026-02-16 00:47:02 +04:00
Elie Habib
fb51b5bf40 fix: desktop settings UX overhaul & IPv4-safe fetch for sidecar
- Show "Staged" status/pill for buffered secrets instead of "Missing"
- Add macOS Edit menu (Cmd+C/V/X/Z) for WKWebView clipboard support
- Raise settings window when main gains focus (prevent hide-behind)
- Fix Cloudflare verification to probe Radar API (not token/verify)
- Fix EIA verification URL to valid v2 endpoint
- Force IPv4 globally: monkey-patch fetch() to avoid IPv6 ETIMEDOUT
  on government APIs (EIA, NASA FIRMS) with broken AAAA records
- Soft-pass on network errors during secret verification (don't block save)
- Add desktopRequiredSecrets to skip relay URLs on desktop
- Cross-window sync for secrets and feature toggles via localStorage events
- Add @tauri-apps/cli devDependency
2026-02-15 22:35:21 +04:00
Elie Habib
f64af4c571 fix: harden CORS patterns & URL validation
- Allow hyphens in Vercel preview URL patterns (worldmonitor-xxx-yyy)
- Harden open_url command with proper URL parsing via reqwest::Url
- Update YouTube embed test assertions for quote style change
2026-02-15 21:34:00 +04:00
Elie Habib
a9224254a5 fix: security hardening — CORS, auth bypass, origin validation & bump v2.2.7
- Tighten CORS regex to block worldmonitorEVIL.vercel.app spoofing
- Move sidecar /api/local-env-update behind token auth + add key allowlist
- Add postMessage origin/source validation in LiveNewsPanel
- Replace postMessage wildcard '*' targetOrigin with specific origin
- Add isDisallowedOrigin() check to 25 API endpoints missing it
- Migrate gdelt-geo & EIA from custom CORS to shared _cors.js
- Add CORS to firms-fires, stock-index, youtube/live endpoints
- Tighten youtube/embed.js ALLOWED_ORIGINS regex
- Remove 'unsafe-inline' from CSP script-src
- Add iframe sandbox attribute to YouTube embed
- Validate meta-tags URL query params with regex allowlist
2026-02-15 20:33:20 +04:00
Elie Habib
5facae7105 feat: add cyber threat map layer with Feodo Tracker + URLhaus integration
Plot live botnet C2 servers, malware distribution nodes, and malicious IPs
on the globe using free abuse.ch APIs (Feodo Tracker + URLhaus).

- Vercel edge API with triple-layer caching (Redis → memory → stale fallback)
- IP geolocation via ipwho.is + ipapi.co (HTTPS-compatible with Edge runtime)
- Severity-based color coding (critical=red, high=orange, medium=amber, low=yellow)
- Feature-gated behind VITE_ENABLE_CYBER_LAYER=true env var
- Frontend circuit breaker, data sanitization, 10min auto-refresh
- Tauri desktop support: 3 new secret keys (URLHAUS, OTX, AbuseIPDB)
- Full test suite (6 unit tests), e2e harness updates, popup + tooltip rendering
2026-02-15 16:52:24 +04:00
Elie Habib
77fc5fe4bd fix(macos): hide window on close instead of quitting
Standard macOS behavior — app stays in dock, reopens on dock click.
2026-02-15 10:26:43 +04:00
Elie Habib
5b1f980b70 Fix Windows settings window: async command, no menu bar, no white flash
- Make open_settings_window_command async to prevent WebView2 deadlock on Windows
- Create settings window with visible(false) to avoid white flash before content loads
- Remove menu bar from settings window on Windows/Linux (macOS uses screen-level menu)
- Frontend calls plugin:window|show + set_focus after init completes
2026-02-15 00:15:23 +04:00
Elie Habib
2c2a6dfbc3 Fix YouTube CSP, add devtools menu, improve desktop channel switching
- Add worldmonitor.app to frame-src CSP in index.html (was only in
  tauri.conf.json, causing iframe block)
- Add devtools feature and Help > Toggle Developer Tools menu item
- Try native YouTube JS API first, fall back to cloud bridge on Error 153
- Add pause-then-play workaround for WKWebView channel switching
2026-02-14 21:09:55 +04:00
Elie Habib
ea4fe718aa Add token-based auth for local API sidecar
Prevents unauthorized local processes from accessing the sidecar on
localhost:46123. Token is generated at Tauri startup using RandomState
hasher, injected into sidecar env, and lazy-loaded by the frontend
fetch patch via get_local_api_token command.

Service-status endpoint remains public for health checks.

Co-authored-by: RinZ27 <RinZ27@users.noreply.github.com>
2026-02-14 20:05:17 +04:00
Elie Habib
c353cf2070 Reduce egress costs, add PWA support, fix Polymarket and Railway relay
Egress optimization:
- Add s-maxage + stale-while-revalidate to all API endpoints for Vercel CDN caching
- Add vercel.json with immutable caching for hashed assets
- Add gzip compression to sidecar responses >1KB
- Add gzip to Railway RSS responses (4 paths previously uncompressed)
- Increase polling intervals: markets/crypto 60s→120s, ETF/macro/stablecoins 60s→180s
- Remove hardcoded Railway URL from theater-posture.js (now env-var only)

PWA / Service Worker:
- Add vite-plugin-pwa with autoUpdate strategy
- Cache map tiles (CacheFirst), fonts (StaleWhileRevalidate), static assets
- NetworkOnly for all /api/* routes (real-time data must be fresh)
- Manual SW registration (web only, skip Tauri)
- Add offline fallback page
- Replace manual manifest with plugin-generated manifest

Polymarket fix:
- Route dev proxy through production Vercel (bypasses JA3 blocking)
- Add 4th fallback tier: production URL as absolute fallback

Desktop/Sidecar:
- Dual-backend cache (_upstash-cache.js): Redis cloud + in-memory+file desktop
- Settings window OK/Cancel redesign
- Runtime config and secret injection improvements
2026-02-14 19:53:04 +04:00
Elie Habib
75a85ebafc Fix desktop app reliability: YouTube embeds, panel failures, circuit breakers
- Fix YouTube Error 153 by serving embed bridge from cloud URL (origin match)
- Fix channel switching when playerContainer detached from DOM
- Fix Fires panel infinite spinner when API returns 0 or fails
- Make TECH variant button open web URL instead of being disabled
- Fix circuit breaker caching empty results as success in 6 services
  (polymarket, wingbits, military-flights, outages, conflicts, protests)
- Improve sidecar: cloud-preferred routing, failed import caching, log dedup
- Add FINNHUB_API_KEY and NASA_FIRMS_API_KEY to Tauri secret keys
- Add early 503 for missing ACLED token in risk-scores
2026-02-14 00:25:02 +04:00
Elie Habib
ad4e52caee Fix Tauri desktop runtime reliability and settings UX 2026-02-13 23:05:51 +04:00
Elie Habib
4f6d3396de Add desktop offline cache persistence and freshness badges 2026-02-13 09:46:11 +04:00
Elie Habib
124683090d Add desktop runtime config panel and secure secret vault hooks 2026-02-13 09:22:14 +04:00
Elie Habib
b7ee69dbb7 Add Tauri local API sidecar with desktop routing fallback 2026-02-13 08:59:22 +04:00
Elie Habib
eb0f396d16 Add Tauri v2 desktop scaffold and runtime bridge 2026-02-13 08:47:12 +04:00