Railway deploys with rootDirectory=scripts/, so ../shared/ resolves to
/shared/ which doesn't exist. Move the canonical file to scripts/data/
and update all four consumers.
- Move GEOPOLITICAL_TAGS, TECH_TAGS, FINANCE_TAGS, and EXCLUDE_KEYWORDS
to shared/prediction-tags.json so seed, RPC handler, and client all
reference a single source of truth
- Remove open_interest proto field (always 0 for Polymarket, never
displayed in UI) and corresponding openInterest assignments
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Elie Habib <elie.habib@gmail.com>
Adding a new item (crypto, ETF, stablecoin, gulf symbol, etc.) previously
required editing 2-4 files because the same list was hardcoded independently
in seed scripts, RPC handlers, and frontend config. Following the proven
shared/crypto.json pattern, extract 6 new shared JSON configs so each list
has a single source of truth.
New shared configs:
- shared/stablecoins.json (ids + coinpaprika mappings)
- shared/etfs.json (BTC spot ETF tickers + issuers)
- shared/gulf.json (GCC indices, currencies, oil benchmarks)
- shared/sectors.json (sector ETF symbols + names)
- shared/commodities.json (VIX, gold, oil, gas, silver, copper)
- shared/stocks.json (market symbols + yahoo-only set)
All seed scripts, RPC handlers, and frontend config now import from
these shared JSON files instead of maintaining independent copies.
* fix: three panel issues — Tech Readiness toggle, Crypto top 10, FIRMS key check
1. #1132 — Add tech-readiness to FULL_PANELS so it appears in the
Settings toggle list for Full/Geopolitical variant users.
2. #979 — Expand crypto panel from 4 coins to top 10 by market cap
(BTC, ETH, USDT, BNB, SOL, XRP, USDC, ADA, DOGE, TRX) across
client config, server metadata, CoinPaprika fallback map, and
seed script.
3. #997 — Check isFeatureAvailable('nasaFirms') before loading FIRMS
data. When the API key is missing, show a clear "not configured"
message instead of the generic "No fire data available".
Closes#1132, closes#979, closes#997
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace stablecoins with AVAX/LINK, remove duplicate key, revert FIRMS change
- Replace USDT/USDC (stablecoins pegged ~$1) with AVAX and LINK
- Remove duplicate 'usd-coin' key in COINPAPRIKA_ID_MAP
- Add CoinPaprika fallback IDs for avalanche-2 and chainlink
- Revert FIRMS API key gating (handled differently now)
- Add sync comments across the 3 crypto config locations
* fix: update AIS relay + seed CoinPaprika fallback for all 10 coins
The AIS relay (primary seeder) still had the old 4-coin list.
The seed script's CoinPaprika fallback map was also missing the
new coins. Both now have all 10 entries.
* refactor: DRY crypto config into shared/crypto.json
Single source of truth for crypto IDs, metadata, and CoinPaprika
fallback mappings. All 4 consumers now import from shared/crypto.json:
- src/config/markets.ts (client)
- server/worldmonitor/market/v1/_shared.ts (server)
- scripts/seed-crypto-quotes.mjs (seed script)
- scripts/ais-relay.cjs (primary relay seeder)
Adding a new coin now requires editing only shared/crypto.json.
* chore: fix pre-existing markdown lint errors in README.md
Add blank lines between headings and lists per MD022/MD032 rules.
* fix: correct CoinPaprika XRP mapping and add crypto config test
- Fix xrp-ripple → xrp-xrp (current CoinPaprika id)
- Add tests/crypto-config.test.mjs: validates every coin has meta,
coinpaprika mapping, unique symbols, no stablecoins, and valid
id format — bad fallback ids now fail fast
* test: validate CoinPaprika ids against live API
The regex-only check wouldn't have caught the xrp-ripple typo.
New test fetches /v1/coins from CoinPaprika and asserts every
configured id exists. Gracefully skips if API is unreachable.
* fix(test): handle network failures in CoinPaprika API validation
Wrap fetch in try-catch so DNS failures, timeouts, and rate limits
skip gracefully instead of failing the test suite.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Elie Habib <elie.habib@gmail.com>
* Revert "feat(feeds): add MTV Lebanon News YouTube feed to Middle East region (#1121)"
This reverts commit 5bee51ab79.
* feat(webcams): add MTV Lebanon News live stream to Middle East region
- Add 7 RSS feed categories for happy variant: positive, science, nature,
health, inspiring, community with sources like Mongabay, Yes! Magazine,
Shareable, Conservation Optimism, My Modern Met, GNN subcategories
- Switch GPS jamming layer from ScatterplotLayer (circles) to
H3HexagonLayer (tessellated hexagons) matching industry standard
- Fix layer toggle not visually updating by adding triggerRepaint()
after all deck.gl setProps() calls — MapboxOverlay in interleaved
mode requires MapLibre to repaint for changes to appear
* feat: Implement comprehensive aviation monitoring service with flight search, status, news, and tracking.
* feat: Introduce Airline Intelligence Panel with aviation data tabs, map components, and localization.
* feat: Implement DeckGL-based map for advanced visualization, D3/SVG fallback, i18n support, and aircraft tracking.
* Update server/worldmonitor/aviation/v1/get-carrier-ops.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update server/worldmonitor/aviation/v1/search-flight-prices.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update server/worldmonitor/aviation/v1/track-aircraft.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update server/worldmonitor/aviation/v1/get-airport-ops-summary.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update proto/worldmonitor/aviation/v1/position_sample.proto
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update server/worldmonitor/aviation/v1/list-airport-flights.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update proto/worldmonitor/aviation/v1/price_quote.proto
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: Add server-side endpoints for aviation news and aircraft tracking, and introduce a new DeckGLMap component for map visualization.
* Update server/worldmonitor/aviation/v1/list-airport-flights.ts
The cache key for listAirportFlights excludes limit, but the upstream fetch/simulated generator uses limit to determine how many flights to return. If the first request within TTL uses a small limit, larger subsequent requests will be incorrectly capped until cache expiry. Include limit (or a normalized bucket/max) in cacheKey, or always fetch/cache a fixed max then slice per request.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update server/worldmonitor/aviation/v1/get-flight-status.ts
getFlightStatus accepts origin, but cacheKey does not include it. This can serve cached results from an origin-less query to an origin-filtered query (or vice versa). Add origin (normalized) to the cache key or apply filtering after fetch to ensure cache correctness.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: Implement DeckGL map for advanced visualization and new aviation data services.
* fix(aviation): prevent cache poisoning and keyboard shortcut in inputs
- get-carrier-ops: move minFlights filter post-cache to avoid cache
fragmentation (different callers sharing cached full result)
- AviationCommandBar: guard Ctrl+J shortcut so it does not fire when
focus is inside an INPUT or TEXTAREA element
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: introduce AviationCommandBar component for parsing user commands, fetching aviation data, and displaying results.
* feat: Implement aircraft tracking service with OpenSky and simulated data sources.
* feat: introduce DeckGLMap component for WebGL-accelerated map visualizations using deck.gl and maplibre-gl.
* fix(aviation): address code review findings for PR #907
Proto: add missing (sebuf.http.query) annotations on all GET request
fields across 6 proto files; add currency/market fields to
SearchFlightPricesRequest.
Server: add parseStringArray to aviation _shared.ts and apply to
get-airport-ops-summary, get-carrier-ops, list-aviation-news handlers
to prevent crash on comma-separated query params; remove leaked API
token from URL params in travelpayouts_data; fix identical simulated
flight statuses in list-airport-flights; remove unused endDate var;
normalize cache key entity casing in list-aviation-news.
Client: refactor AirlineIntelPanel to extend Panel base class and
register in DEFAULT_PANELS for full/tech/finance variants; fix
AviationCommandBar reference leak with proper destroy() cleanup in
panel-layout; rename priceUsd→priceAmount in display type and all
usages; change auto-refresh to call refresh() instead of loadOps().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: introduce aviation command bar component with aircraft tracking and flight information services.
* feat: Add `AirlineIntelPanel` component for displaying airline operations, flights, carriers, tracking, news, and prices in a tabbed interface.
* feat: Add endpoints for listing airport flights and fetching aviation news.
* Update proto/worldmonitor/aviation/v1/search_flight_prices.proto
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: Add server endpoint for listing airport flights and client-side MapPopup types and utilities.
* feat: Introduce MapPopup component with support for various data types and responsive positioning for map features.
* feat: Add initial English localization file (en.json).
* fix(aviation): address PR review findings across aviation stack
- Add User-Agent header to Travelpayouts provider (server convention)
- Use URLSearchParams for API keys instead of raw URL interpolation
- Add input length validation on flightNumber (max 10 chars)
- Replace regex XML parsing with fast-xml-parser in aviation news
- Fix (f as any)._airport type escape with typed Map<FI, string>
- Extract DEFAULT_WATCHED_AIRPORTS constant from hardcoded arrays
- Use event delegation for AirlineIntelPanel price search listener
- Add bootstrap hydration key for flight delays
- Bump OpenSky cache TTL to 120s (anonymous tier rate limit)
- Match DeckGLMap aircraft poll interval to server cache (120s)
- Fix GeoJSON polygon winding order (shoelace check + auto-reversal)
* docs: add aviation env vars to .env.example
AVIATIONSTACK_API, ICAO_API_KEY, TRAVELPAYOUTS_API_TOKEN
* feat: Add aviation news listing API and introduce shared RSS allowed domains.
* fix: add trailing newline to rss-allowed-domains.json, remove unused ringIsClockwise
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Elie Habib <elie.habib@gmail.com>
* perf(rss): route RSS direct to Railway, skip Vercel middleman
Vercel /api/rss-proxy has 65% error rate (207K failed invocations/12h).
Route browser RSS requests directly to Railway (proxy.worldmonitor.app)
via Cloudflare CDN, eliminating Vercel as middleman.
- Add VITE_RSS_DIRECT_TO_RELAY feature flag (default off) for staged rollout
- Centralize RSS proxy URL in rssProxyUrl() with desktop/dev/prod routing
- Make Railway /rss public (skip auth, keep rate limiting with CF-Connecting-IP)
- Add wildcard *.worldmonitor.app CORS + always emit Vary: Origin on /rss
- Extract ~290 RSS domains to shared/rss-allowed-domains.cjs (single source of truth)
- Convert Railway domain check to Set for O(1) lookups
- Remove rss-proxy from KEYED_CLOUD_API_PATTERN (no longer needs API key header)
- Add edge function test for shared domain list import
* fix(edge): replace node:module with JSON import for edge-compatible RSS domains
api/_rss-allowed-domains.js used createRequire from node:module which is
unsupported in Vercel Edge Runtime, breaking all edge functions (including
api/gpsjam). Replaced with JSON import attribute syntax that works in both
esbuild (Vercel build) and Node.js 22+ (tests).
Also fixed middleware.ts TS18048 error where VARIANT_OG[variant] could be
undefined.
* test(edge): add guard against node: built-in imports in api/ files
Scans ALL api/*.js files (including _ helpers) for node: module imports
which are unsupported in Vercel Edge Runtime. This would have caught the
createRequire(node:module) bug before it reached Vercel.
* fix(edge): inline domain array and remove NextResponse reference
- Replace `import ... with { type: 'json' }` in _rss-allowed-domains.js
with inline array — Vercel esbuild doesn't support import attributes
- Replace `NextResponse.next()` with bare `return` in middleware.ts —
NextResponse was never imported
* ci(pre-push): add esbuild bundle check and edge function tests
The pre-push hook now catches Vercel build failures locally:
- esbuild bundles each api/*.js entrypoint (catches import attribute
syntax, missing modules, and other bundler errors)
- runs edge function test suite (node: imports, module isolation)