* docs: add Data Sources attribution table to README
* docs: link README data sources table to full catalog, clarify 30+ sources
* docs: replace data sources table with single link to catalog (no duplication)
* docs: add Provider Credits section to data-sources catalog with linked attributions
* feat(community): add Discord link to footer across pro, blog, and docs
Adds https://discord.gg/re63kWKxaz to:
- pro-test/src/App.tsx — main Footer component and enterprise page footer
- blog-site/src/layouts/Base.astro — site-wide blog footer
- docs/docs.json — Mintlify socials icon + Community footer links section
* docs(readme): add Discord badge to header badges
Removed detailed feature lists, architecture, self-hosting, API access,
security model, and environment variables sections. All now live at
docs.worldmonitor.app. README retains badges, screenshot, concise
feature summary, quick start, tech stack, and license.
Extract license content from contributing.mdx into its own first-class
docs/license.mdx page. Add prominent warnings about rebranding/renaming
being prohibited without a commercial license, an enforcement section,
and expanded commercial use restrictions.
Update README.md license section to reflect the dual-license model
(AGPL-3.0 for non-commercial, commercial license required for business
use). Previously it incorrectly stated commercial use was allowed under
AGPL alone.
Update cross-references in documentation.mdx and getting-started.mdx to
point to the new /license page.
Railway auto-detects Dockerfiles at repo root and uses them for ALL
services, even those set to NIXPACKS. This caused all seed services
(ais-relay, seed-gpsjam, etc.) to build nginx-only containers with
no node binary, breaking every Railway service.
Move Dockerfile and related files to docker/ subdirectory. Railway
only checks the repo root for Dockerfiles, so this prevents
accidental detection. GHA workflow updated with explicit file: path.
* feat: publish official Docker image on release #1260 solved
* docker image changes
* fixes fix
* all fixes
* things changed according to suggestions
* fixed
* Add premium finance stock analysis suite
* docs: link premium finance from README
Add Premium Stock Analysis entry to the Finance & Markets section
with a link to docs/PREMIUM_FINANCE.md.
* fix: address review feedback on premium finance suite
- Chunk Redis pipelines into batches of 200 (Upstash limit)
- Add try-catch around cachedFetchJson in backtest handler
- Log warnings on Redis pipeline HTTP failures
- Include name in analyze-stock cache key to avoid collisions
- Change analyze-stock and backtest-stock gateway cache to 'slow'
- Add dedup guard for concurrent ledger generation
- Add SerpAPI date pre-filter (tbs=qdr:d/w)
- Extract sanitizeSymbol to shared module
- Extract buildEmptyAnalysisResponse helper
- Fix RSI to use Wilder's smoothing (matches TradingView)
- Add console.warn for daily brief summarization errors
- Fall back to stale data in loadStockBacktest on error
- Make daily-market-brief premium on all platforms
- Use word boundaries for short token headline matching
- Add stock-analysis 15-min refresh interval
- Stagger stock-analysis and backtest requests (200ms)
- Rename signalTone to stockSignalTone
Track ~80-120 intelligence-relevant satellites on the 3D globe using CelesTrak
TLE data and client-side SGP4 propagation (satellite.js). Satellites render at
actual orbital altitude with country-coded colors, 15-min orbit trails, and
ground footprint projections.
Architecture: Railway seeds TLEs every 2h → Redis → Vercel CDN (1h cache) →
browser does SGP4 math every 3s (zero server cost for real-time movement).
- New relay seed loop (ais-relay.cjs) fetching military + resource groups
- New edge handler (api/satellites.js) with 10min cache + negative cache
- Frontend service with circuit breaker and propagation lifecycle
- GlobeMap integration: markers, trails (pathsData), footprints, tooltips
- Layer registry as globe-only "Orbital Surveillance" with i18n (21 locales)
- Full documentation at docs/ORBITAL_SURVEILLANCE.md with roadmap
- Fix pre-existing SearchModal TS error (non-null assertion)
* feat(pro): restructure landing page with hybrid draft/current layout
Reorganize the Pro landing page into a 13-section structure that combines
the best of the external copy draft with existing high-value components:
New sections added:
- Two-path split (Pro vs Enterprise) right after social proof
- "Why upgrade" value props (Less noise, Faster, Control, Deeper)
- Audience personas (Journalists, Investors, Researchers, Security, Teams)
- Final dual CTA ("Get Pro" + "Talk to Sales")
Kept from current page:
- Live dashboard iframe embed
- Source marquee (43 scrolling sources)
- Slack morning brief mock
- API section with code example (separate tier)
- Enterprise specifics (air-gapped, MCP, white-label, satellite)
Copy updates:
- Hero: "for serious users and organizations" + mission line
- FAQ: warmer tone, 8 questions including "Is this only for conflict monitoring?"
- Schema markup updated to match new FAQ
* fix(pro): CRO quick wins — unified CTA, benefit-first hero, invisible Turnstile
- Unify all CTAs to "Reserve Your Early Access"
- Hero subtitle rewritten benefit-first ("Understand global events faster")
- Add "Launching March 2026" timeline badge
- Make Turnstile CAPTCHA invisible (size: 'invisible')
- Replace Enterprise mailto with inline contact form
- Move audience personas higher, add Gov & Energy traders, remove Journalists
- Update FAQ structured data in source template
- Remove unused Newspaper import
* fix(pro): update README image to jpg + add iframe fallback image
- README: reference worldmonitor-7-mar-2026.jpg instead of png
- Pro landing: add fallback image behind iframe for loading state
* feat(pro): dedicated enterprise page with contact form via hash routing
- Move enterprise contact form to dedicated #enterprise page
- Enterprise page has: hero, feature grid, use cases, and contact form
- Pro page enterprise section now links to #enterprise instead of inline form
- Hash routing: #enterprise → EnterprisePage, everything else → Pro landing
- Re-render Turnstile widgets on page transitions
* fix(pro): use Vite asset import for iframe fallback image (cached path)
Import dashboard fallback image via Vite so it gets content-hashed
into /pro/assets/ — hits CF 1-month immutable cache rule.
Placeholder jpg included; replace with real screenshot before deploy.
* fix(pro): add real dashboard screenshot for iframe fallback + README
Replace placeholder with actual 326K screenshot. Vite content-hashes
it to /pro/assets/worldmonitor-7-mar-2026-[hash].jpg (CF 1mo cache).
Also added to docs/images/ for README reference.
* fix(sw): remove 206 from cacheable statuses for PMTiles
The Cache API spec forbids storing partial responses (HTTP 206).
Workbox's cacheableResponse plugin passes them through, but the
browser's Cache.put() throws TypeError. PMTiles Range responses
are already cached by the browser HTTP cache and CF edge.
* fix(map): enable CORS fallback for Carto basemap + fix README lint
Carto provider was incorrectly marked as usedFallbackStyle on init,
preventing the error monitor from switching to OpenFreeMap when Carto
returns CORS 403. Also fix markdownlint errors (blank lines around
headings/lists) in README.md.
* feat(map): migrate basemap from CARTO to self-hosted PMTiles on Cloudflare R2
Replace CARTO tile provider (frequent 403 errors) with self-hosted PMTiles
served from Cloudflare R2. Uses @protomaps/basemaps for style generation
with OpenFreeMap as automatic fallback when VITE_PMTILES_URL is unset.
- Add pmtiles and @protomaps/basemaps dependencies
- Create src/config/basemap.ts for PMTiles protocol registration and style building
- Update DeckGLMap.ts to use PMTiles styles (non-happy variants)
- Fix fallback detection using data event instead of style.load
- Update SW cache rules: replace CARTO/MapTiler with PMTiles NetworkFirst
- Add Protomaps preconnect hints in index.html
- Bundle pmtiles + @protomaps/basemaps in maplibre chunk
- Upload 3.4GB world tiles (zoom 0-10) to R2 bucket worldmonitor-maps
* fix(map): use CDN custom domain maps.worldmonitor.app for PMTiles
Replace r2.dev URL with custom domain backed by Cloudflare CDN edge.
Update preconnect hint and .env.example with production URL.
* fix(map): harden PMTiles fallback detection to prevent false triggers
- Require 2+ network errors before triggering OpenFreeMap fallback
- Use persistent data listener instead of once (clears timeout on first tile load)
- Increase fallback timeout to 10s for PMTiles header + initial tile fetch
- Add console.warn for map errors to aid debugging
- Remove redundant style.load listener (fires immediately for inline styles)
* feat(settings): add Map Tile Provider selector in settings
Add dropdown in Settings → Map section to switch between:
- Auto (PMTiles → OpenFreeMap fallback)
- PMTiles (self-hosted)
- OpenFreeMap
- CARTO
Choice persists in localStorage and reloads basemap instantly.
* fix(map): make OSS-friendly — default to free OpenFreeMap, hide PMTiles when unconfigured
- Default to OpenFreeMap when VITE_PMTILES_URL is unset (zero config for OSS users)
- Hide PMTiles/Auto options from settings dropdown when no PMTiles URL configured
- If user previously selected PMTiles but env var is removed, gracefully fall back
- Remove production URL from .env.example to avoid exposing hosted tiles
- Add docs link for self-hosting PMTiles in .env.example
* docs: add map tile provider documentation to README and MAP_ENGINE.md
Document the tile provider system (OpenFreeMap, CARTO, PMTiles) in
MAP_ENGINE.md with self-hosting instructions, fallback behavior, and
OSS-friendly defaults. Update README to reference tile providers in
the feature list, tech stack, and environment variables table.
* fix: resolve rebase conflicts and fix markdown lint errors
- Restore OSS-friendly basemap defaults (MAP_PROVIDER_OPTIONS as IIFE,
getMapProvider with hasTilesUrl check)
- Fix markdown lint: add blank lines after ### headings in README
- Reconcile UnifiedSettings import with MAP_PROVIDER_OPTIONS constant
* enhance supply chain panel
* fix(supply-chain): resolve P1 threat zeroing and P2 geo-first misclassification
P1: threat baseline is now always applied regardless of config
staleness — stale config only adds a review-recommended note,
never zeros the score.
P2: resolveChokepointId now checks text evidence first and only
falls back to proximity when text has no confident match.
Adds regression test: text "Bab el-Mandeb" with location near
Suez correctly resolves to bab_el_mandeb.
---------
Co-authored-by: fayez bast <fayezbast15@gmail.com>
- Remove PostHog analytics runtime and configuration
- Add API rate limiting (api/_rate-limit.js)
- Harden traffic controls across edge functions
- Add runtime fallback controls and data-loader improvements
- Add military base data scripts (fetch-mirta-bases, fetch-osm-bases)
- Gitignore large raw data files
- Settings playground prototypes
* fix: sort tariff datapoints newest-first in trade policy panel
* fix: update tests broken by cachedFetchJson migration
- Restore "Strip unterminated" comment in summarize-article.ts that
tests use to locate the unterminated tag stripping section
- Update ACLED tests to check for cachedFetchJson instead of removed
getCachedJson/setCachedJson patterns
* chore: bump version to 2.5.9 and make pre-push hook executable
* docs: update README with supply chain intel, universal CII, Happy Monitor, security hardening, and recent features
Update data layer count to 36+, add Happy Monitor variant to Live Demos,
expand Cmd+K command palette description, and add trade routes to
Infrastructure section.
* feat: make intelligence alert popup opt-in via dropdown toggle
Auto-popup was interrupting users every 10s refresh cycle. Badge still
counts and pulses silently. New toggle in dropdown (default OFF) lets
users explicitly opt in to auto-popup behavior.
* chore: bump version to 2.5.5
## Changelog
### Features
- Intelligence alert popup is now opt-in (default OFF) — badge counts silently, toggle in dropdown to enable auto-popup
### Bug Fixes
- Linux: disable DMA-BUF renderer on WebKitGTK to prevent blank white screen (NVIDIA/immutable distros)
- Linux: add DejaVu Sans Mono + Liberation Mono font fallbacks for monospace rendering
- Consolidate monospace font stacks into --font-mono CSS variable (fixes undefined var bug)
- Reduce dedup coordinate rounding from 0.5° to 0.1° (~10km precision)
- Vercel build: handle missing previous deploy SHA
- Panel base class: add missing showRetrying method
- Vercel ignoreCommand shortened to fit 256-char limit
### Infrastructure
- Upstash Redis shared caching for all RPC handlers + cache key contamination fix
- Format Rust code and fix Windows focus handling
### Docs
- Community guidelines: contributing, code of conduct, security policy
- Updated .env.example
* chore: track Cargo.lock for reproducible Rust builds
* fix: update layer help popup with all current map layers
Added missing layers to the ? help popup across all 3 variants:
- Full: UCDP Events, Displacement, Spaceports, Cyber Threats, Fires,
Climate Anomalies, Critical Minerals; renamed Shipping→Ship Traffic
- Tech: Tech Events, Cyber Threats, Fires
- Finance: GCC Investments
* docs: update README with crypto prices, analytics, typography, and dedup grid fix
* fix: add /ingest to service worker NetworkOnly routes
The SW was intercepting PostHog /ingest/* requests and returning
no-response (404) because no cache match existed. Adding NetworkOnly
ensures analytics requests pass through to Vercel's rewrite proxy.
* chore: update Cargo.lock for v2.5.5
* fix: use explicit colors for findings toggle switch visibility
* 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).
### Motivation
- Reduce sidecar API egress by preferring Brotli (br) for clients that
support it while keeping gzip as a fallback for broad compatibility.
- Ensure the sidecar negotiates compression consistently (set
`Content-Encoding`, append `Vary: Accept-Encoding`) and avoids sending
stale `Content-Length` when responses are compressed.
- Provide an Nginx proxy baseline that preserves client
`Accept-Encoding` and prefers Brotli at the proxy layer.
### Description
- Updated `src-tauri/sidecar/local-api-server.mjs` to negotiate response
compression via a new `maybeCompressResponseBody` routine that prefers
Brotli (`br`) and falls back to gzip for payloads > 1KB, preserves
existing `Content-Encoding` from handlers, and appends `Vary:
Accept-Encoding` when compressing.
- Added a small helper `canCompress` and promisified `brotliCompress` so
Brotli compression runs asynchronously while gzip remains synchronous
for fallback.
- Ensure `Content-Length` is removed when `Content-Encoding` is applied
so downstream callers/proxies don't see stale lengths.
- Added tests to `src-tauri/sidecar/local-api-server.test.mjs` that
verify Brotli is preferred when `Accept-Encoding` includes `br` and gzip
is used when `br` is not present, including decompression checks with
`brotliDecompressSync`/`gunzipSync`.
- Added `deploy/nginx/brotli-api-proxy.conf` as an example Nginx
configuration enabling Brotli with gzip fallback and forwarding
`Accept-Encoding` while disabling upstream decompression (`gunzip off`).
- Updated `README.md` to reflect the sidecar now advertising `br/gzip`
behavior and adjusted the expected payload reduction notes.
### Testing
- Ran the sidecar unit tests with `node --test
src-tauri/sidecar/local-api-server.test.mjs`, which executed 19 tests
and all passed (`# pass 19`, `# fail 0`).
- No other automated test suites were modified; the new tests are
self-contained under the sidecar test file and validated the compression
behavior.
------
[Codex
Task](https://chatgpt.com/codex/tasks/task_e_6997871302188333bb1ecb20714d2ad3)
- Ollama/LM Studio integration with auto model discovery and 4-tier fallback chain
- Settings window split into LLMs, API Keys, and Debug tabs
- Consolidated keychain vault (1 OS prompt instead of 20+)
- README expanded with privacy architecture, summarization chain docs
- CHANGELOG updated with full v2.5.0 release notes
- 5 new defense/intel RSS feeds, Koeberg nuclear plant added
Add Turkish (tr) as the 14th supported language with full translation
of all 1,134 locale keys, locale loader, tr-TR formatting, and flag
mapping. Update documentation to reflect 14 languages.
- Replace MIT with AGPL-3.0-only to enforce attribution on derivatives
- Move hardcoded Sentry DSN to VITE_SENTRY_DSN env var
- Add null-coalesce guards for i18n legend keys and SVG viewBox
- Extend Sentry ignoreErrors with 7 additional noise patterns
MD012 / no-multiple-blanks Multiple consecutive blank lines
MD022 / blanks-around-headings Headings should be surrounded by blank lines
MD032 / blanks-around-lists Lists should be surrounded by blank lines
- Expand SUPPRESSED_TRENDING_TERMS from 13 to ~170 entries to filter
common English words (department, state, news, etc.) from intelligence
findings
- Move sidecar admin endpoints (debug-toggle, traffic-log, env-update,
local-status) before LOCAL_API_TOKEN auth gate — settings window sends
bare fetch without token, causing silent 401 failures
- Restore Market Radar and Economic Indicators panels to tech variant
- Remove stale Documentation section from README
- Clean up .env.example cyber threat keys (handled internally)
- Bump v2.2.6
Update README with 5 new How It Works sections and 10 inline updates
reflecting implemented features. Data layer count 29→30+, data sources
14→22, new Tech Stack and Roadmap entries.
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
Shield.io badges for Windows, macOS ARM, and macOS Intel desktop downloads
pointing to the new /api/download redirect. Web app links restyled as badges.