File size: 5,696 Bytes
9d2d895
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Base configuration shared across all variants
import type { PanelConfig, MapLayers } from '@/types';

// Shared exports (re-exported by all variants)
export { SECTORS, COMMODITIES, MARKET_SYMBOLS } from '../markets';
// UNDERSEA_CABLES + AI_DATA_CENTERS intentionally not re-exported (kept off the
// eager @/config barrel); consumers import directly from '@/config/geo-map' and
// '@/config/ai-datacenters'. (#4404)
export { IDLE_PAUSE_MS } from '../idle';

// Refresh intervals (ms) - shared across all variants
export const REFRESH_INTERVALS = {
  feeds: 20 * 60 * 1000,
  markets: 12 * 60 * 1000,
  crypto: 12 * 60 * 1000,
  predictions: 15 * 60 * 1000,
  forecasts: 30 * 60 * 1000,
  ais: 15 * 60 * 1000,
  pizzint: 10 * 60 * 1000,
  natural: 60 * 60 * 1000,
  weather: 10 * 60 * 1000,
  fred: 6 * 60 * 60 * 1000,
  oil: 6 * 60 * 60 * 1000,
  spending: 6 * 60 * 60 * 1000,
  bis: 6 * 60 * 60 * 1000,
  firms: 30 * 60 * 1000,
  cables: 30 * 60 * 1000,
  cableHealth: 2 * 60 * 60 * 1000,
  flights: 2 * 60 * 60 * 1000,
  cyberThreats: 10 * 60 * 1000,
  stockAnalysis: 15 * 60 * 1000,
  dailyMarketBrief: 60 * 60 * 1000,
  marketImplications: 3 * 60 * 60 * 1000,
  stockBacktest: 4 * 60 * 60 * 1000,
  serviceStatus: 3 * 60 * 1000,
  stablecoins: 15 * 60 * 1000,
  etfFlows: 15 * 60 * 1000,
  macroSignals: 15 * 60 * 1000,
  fearGreed: 30 * 60 * 1000,
  strategicPosture: 15 * 60 * 1000,
  strategicRisk: 5 * 60 * 1000,
  // Seed cadences are 6-24h and badge decay is computed client-side from
  // lastUpdate, so 5min loses nothing vs 60s; must stay under the 15min
  // FRESH_THRESHOLD or synthesized-OK sources (compact health carries no age
  // for healthy checks) would decay to stale between polls (#4907).
  healthFreshness: 5 * 60 * 1000,
  temporalBaseline: 10 * 60 * 1000,
  tradePolicy: 60 * 60 * 1000,
  supplyChain: 60 * 60 * 1000,
  chinaCorridors: 15 * 60 * 1000,
  chinaActivityNowcast: 15 * 60 * 1000,
  telegramIntel: 60 * 1000,
  gulfEconomies: 10 * 60 * 1000,
  groceryBasket: 6 * 60 * 60 * 1000,
  fuelPrices: 6 * 60 * 60 * 1000,
  faoFoodPriceIndex: 24 * 60 * 60 * 1000, // monthly data; refresh daily is sufficient
  oilInventories: 5 * 60 * 1000, // EIA weekly + EU gas daily; 5min refresh
  climateNews: 30 * 60 * 1000, // seeded every 30min; match cadence
  intelligence: 15 * 60 * 1000,
  correlationEngine: 5 * 60 * 1000,
  defensePatents: 24 * 60 * 60 * 1000, // 24h — data is weekly, daily poll is sufficient
  wsbTickers: 10 * 60 * 1000,
  crossSourceSignals: 15 * 60 * 1000,
  hormuzTracker: 60 * 60 * 1000, // 1h — data updates daily
  hyperliquidFlow: 5 * 60 * 1000, // 5min — matches Railway seed cadence
  energyCrisis: 6 * 60 * 60 * 1000, // 6h — policy data updates infrequently
  pipelineStatus: 24 * 60 * 60 * 1000, // curated registry reseeds weekly; daily poll keeps long-lived sessions fresh
  storageFacilityMap: 24 * 60 * 60 * 1000, // curated registry reseeds weekly; daily poll keeps long-lived sessions fresh
  fuelShortages: 60 * 60 * 1000, // active shortage alerts can change intra-day
  energyDisruptions: 60 * 60 * 1000, // disruption log is low-volume but needs intra-day freshness
  energyRiskOverview: 15 * 60 * 1000, // mixed market + supply-chain overview; refresh more often than the underlying weekly registries
  chokepointStrip: 90 * 60 * 1000, // matches chokepoint client cache TTL / freshness budget
  macroTiles: 30 * 60 * 1000,
  fsi: 30 * 60 * 1000,
  yieldCurve: 30 * 60 * 1000,
  earningsCalendar: 60 * 60 * 1000,
  economicCalendar: 60 * 60 * 1000,
  cotPositioning: 60 * 60 * 1000,
  goldIntelligence: 5 * 60 * 1000,
  aaiiSentiment: 60 * 60 * 1000, // weekly data; hourly refresh is sufficient
  marketBreadth: 60 * 60 * 1000, // seeded daily; hourly refresh is sufficient
};

// Monitor colors - shared
export const MONITOR_COLORS = [
  '#44ff88',
  '#ff8844',
  '#4488ff',
  '#ff44ff',
  '#ffff44',
  '#ff4444',
  '#44ffff',
  '#88ff44',
  '#ff88ff',
  '#88ffff',
];

// Storage keys - shared
export const STORAGE_KEYS = {
  panels: 'worldmonitor-panels',
  monitors: 'worldmonitor-monitors',
  mapLayers: 'worldmonitor-layers',
  disabledFeeds: 'worldmonitor-disabled-feeds',
  // Schema version for the disabledFeeds set. Bumped on each migration that
  // mutates the set in a backwards-incompatible way. Currently:
  //   missing/0 → pre-2026-05-01 alphabetical-cap state. Eligible for
  //               one-time recovery of fully-disabled categories.
  //   1 → recovery has run; the set is post-migration and must NOT be
  //       re-recovered on subsequent loads (otherwise user-explicit
  //       full-category disabling would be silently undone forever).
  disabledFeedsSchema: 'worldmonitor-disabled-feeds-schema',
  // `{ [customCategoryKey]: rotationCycle }`. A custom news category is never
  // in the per-variant server digest, so its capped per-feed fetch rotates
  // through its sources a window at a time (#5873). The cycle has to survive a
  // reload or short sessions would replay window 0 forever and the rotation
  // would never reach sources 4..N — the exact defect it exists to fix.
  newsFeedRotation: 'worldmonitor-news-feed-rotation',
  liveChannels: 'worldmonitor-live-channels',
  mapMode: 'worldmonitor-map-mode',          // 'flat' | 'globe'
  activeChannel: 'worldmonitor-active-channel',
  webcamPrefs: 'worldmonitor-webcam-prefs',
} as const;

export type MapModePreference = 'flat' | 'globe';
export const DEFAULT_MAP_MODE: MapModePreference = 'flat';

// Type definitions for variant configs
export interface VariantConfig {
  name: string;
  description: string;
  panels: Record<string, PanelConfig>;
  mapLayers: MapLayers;
  mobileMapLayers: MapLayers;
}