TypeScript 55.4%
Python 43.2%
SQL 1.2%
1/**2 * WebSensor taxonomy. Event types are open (strings) so the set can grow without3 * migrations, but everything we emit ourselves comes from this list and carries an4 * intrinsic severity used by the importance model.5 */67export const SENSOR_TYPES = [8 "WEBHOOK",9 "WEBSOCKET",10 "SSE",11 "REST_API",12 "GRAPHQL",13 "RSS",14 "ATOM",15 "JSON",16 "XML",17 "SITEMAP",18 "HTML",19 "RENDERED_HTML",20 "PDF_INDEX",21 "GITHUB_RELEASE",22 "GITHUB_REPO",23 "STATUSPAGE",24 "DNS",25 "TLS",26 "HTTP_HEADERS",27 "FILE",28 "CUSTOM_CONNECTOR",29] as const;30export type SensorType = (typeof SENSOR_TYPES)[number];3132export const TIERS = ["S", "A", "B", "C", "D"] as const;33export type Tier = (typeof TIERS)[number];3435/** Base polling interval per tier (seconds). */36export const TIER_BASE_INTERVAL: Record<Tier, number> = {37 S: 60,38 A: 180,39 B: 900,40 C: 3600,41 D: 21600,42};43export const TIER_MIN_INTERVAL: Record<Tier, number> = {44 S: 15,45 A: 60,46 B: 300,47 C: 1800,48 D: 21600,49};50export const TIER_MAX_INTERVAL: Record<Tier, number> = {51 S: 300,52 A: 1800,53 B: 7200,54 C: 21600,55 D: 86400,56};5758export const CATEGORIES = [59 "ai",60 "cloud",61 "developer",62 "cyber",63 "consumer-tech",64 "semiconductors",65 "finance",66 "government",67 "statistics",68 "health",69 "pharma",70 "science",71 "space",72 "automotive",73 "commerce",74 "payments",75 "crypto",76 "enterprise",77 "internet",78 "standards",79 "technology",80 "news",81 "media",82 "politics",83] as const;84export type Category = (typeof CATEGORIES)[number] | string;8586/** Public feed channels → categories that map to them. */87export const FEED_CHANNELS: Record<string, string[]> = {88 ai: ["ai"],89 cyber: ["cyber"],90 finance: ["finance", "payments", "crypto", "commerce"],91 health: ["health", "pharma"],92 government: ["government", "statistics"],93 science: ["science", "space"],94 products: ["consumer-tech", "automotive", "semiconductors", "enterprise"],95 infrastructure: ["cloud", "developer", "internet", "standards"],96 news: ["news", "media"],97};9899export interface EventTypeSpec {100 /** Intrinsic severity 0–100 used as the 25 % component of importance. */101 severity: number;102 label: string;103 /** Does this type usually come with a public announcement? Used for silent-change detection. */104 usuallyAnnounced: boolean;105}106107export const EVENT_TYPES: Record<string, EventTypeSpec> = {108 announcement: { severity: 55, label: "Announcement", usuallyAnnounced: true },109 product_launch: { severity: 80, label: "Product launch", usuallyAnnounced: true },110 product_update: { severity: 55, label: "Product update", usuallyAnnounced: true },111 model_release: { severity: 88, label: "Model release", usuallyAnnounced: true },112 software_release: { severity: 55, label: "Software release", usuallyAnnounced: true },113 pricing_change: { severity: 82, label: "Pricing change", usuallyAnnounced: false },114 availability_change: { severity: 62, label: "Availability change", usuallyAnnounced: false },115 policy_change: { severity: 68, label: "Policy change", usuallyAnnounced: false },116 terms_change: { severity: 66, label: "Terms change", usuallyAnnounced: false },117 documentation_change: { severity: 30, label: "Documentation change", usuallyAnnounced: false },118 API_change: { severity: 62, label: "API change", usuallyAnnounced: false },119 security_advisory: { severity: 86, label: "Security advisory", usuallyAnnounced: true },120 vulnerability: { severity: 90, label: "Vulnerability", usuallyAnnounced: true },121 breach: { severity: 95, label: "Breach", usuallyAnnounced: true },122 incident: { severity: 78, label: "Incident", usuallyAnnounced: true },123 outage: { severity: 90, label: "Outage", usuallyAnnounced: true },124 maintenance: { severity: 35, label: "Maintenance", usuallyAnnounced: true },125 recall: { severity: 85, label: "Recall", usuallyAnnounced: true },126 drug_approval: { severity: 88, label: "Drug approval", usuallyAnnounced: true },127 clinical_trial: { severity: 60, label: "Clinical trial", usuallyAnnounced: true },128 scientific_publication: { severity: 45, label: "Scientific publication", usuallyAnnounced: true },129 regulatory_filing: { severity: 65, label: "Regulatory filing", usuallyAnnounced: true },130 financial_filing: { severity: 68, label: "Financial filing", usuallyAnnounced: true },131 earnings: { severity: 75, label: "Earnings", usuallyAnnounced: true },132 leadership_change: { severity: 72, label: "Leadership change", usuallyAnnounced: true },133 acquisition: { severity: 85, label: "Acquisition", usuallyAnnounced: true },134 funding: { severity: 70, label: "Funding", usuallyAnnounced: true },135 partnership: { severity: 60, label: "Partnership", usuallyAnnounced: true },136 job_expansion: { severity: 40, label: "Job expansion", usuallyAnnounced: false },137 layoffs: { severity: 78, label: "Layoffs", usuallyAnnounced: true },138 new_region: { severity: 62, label: "New region", usuallyAnnounced: true },139 new_country: { severity: 65, label: "New country", usuallyAnnounced: true },140 infrastructure_change: { severity: 50, label: "Infrastructure change", usuallyAnnounced: false },141 api_change: { severity: 62, label: "API change", usuallyAnnounced: false },142 dns_change: { severity: 48, label: "DNS change", usuallyAnnounced: false },143 domain_registration_change: { severity: 45, label: "Domain registration change", usuallyAnnounced: false },144 crawler_policy_change: { severity: 52, label: "Crawler policy change", usuallyAnnounced: false },145 DNS_change: { severity: 45, label: "DNS change", usuallyAnnounced: false },146 certificate_change: { severity: 30, label: "Certificate change", usuallyAnnounced: false },147 repository_release: { severity: 50, label: "Repository release", usuallyAnnounced: true },148 dataset_release: { severity: 55, label: "Dataset release", usuallyAnnounced: true },149 standard_update: { severity: 58, label: "Standard update", usuallyAnnounced: true },150 government_announcement: { severity: 65, label: "Government announcement", usuallyAnnounced: true },151 economic_release: { severity: 80, label: "Economic release", usuallyAnnounced: true },152 legal_change: { severity: 70, label: "Legal change", usuallyAnnounced: true },153 monetary_policy: { severity: 92, label: "Monetary policy", usuallyAnnounced: true },154 page_created: { severity: 35, label: "Page created", usuallyAnnounced: false },155 page_removed: { severity: 40, label: "Page removed", usuallyAnnounced: false },156 content_change: { severity: 25, label: "Content change", usuallyAnnounced: false },157 unknown: { severity: 20, label: "Unknown", usuallyAnnounced: false },158 // ---- 2026-09-11: cyber event classes ----159 zero_day: { severity: 97, label: "Zero-day", usuallyAnnounced: true },160 active_exploitation: { severity: 96, label: "Active exploitation", usuallyAnnounced: true },161 patch_release: { severity: 70, label: "Patch release", usuallyAnnounced: true },162 supply_chain_attack: { severity: 95, label: "Supply-chain attack", usuallyAnnounced: true },163 credential_leak: { severity: 88, label: "Credential leak", usuallyAnnounced: true },164 malware_campaign: { severity: 80, label: "Malware campaign", usuallyAnnounced: true },165 ransomware: { severity: 88, label: "Ransomware", usuallyAnnounced: true },166 // ---- finance ----167 merger: { severity: 85, label: "Merger", usuallyAnnounced: true },168 ipo: { severity: 80, label: "IPO", usuallyAnnounced: true },169 guidance: { severity: 78, label: "Guidance", usuallyAnnounced: true },170 dividend: { severity: 60, label: "Dividend", usuallyAnnounced: true },171 buyback: { severity: 62, label: "Buyback", usuallyAnnounced: true },172 bankruptcy: { severity: 92, label: "Bankruptcy", usuallyAnnounced: true },173 capital_raise: { severity: 70, label: "Capital raise", usuallyAnnounced: true },174 rating_change: { severity: 74, label: "Rating change", usuallyAnnounced: true },175 insider_transaction: { severity: 45, label: "Insider transaction", usuallyAnnounced: true },176 // ---- government / legal ----177 regulatory_action: { severity: 76, label: "Regulatory action", usuallyAnnounced: true },178 lawsuit: { severity: 70, label: "Lawsuit", usuallyAnnounced: true },179 court_decision: { severity: 74, label: "Court decision", usuallyAnnounced: true },180 sanction: { severity: 84, label: "Sanction", usuallyAnnounced: true },181 legislation: { severity: 72, label: "Legislation", usuallyAnnounced: true },182 budget: { severity: 74, label: "Budget", usuallyAnnounced: true },183 procurement: { severity: 45, label: "Procurement", usuallyAnnounced: true },184 appointment: { severity: 62, label: "Appointment", usuallyAnnounced: true },185 emergency_notice: { severity: 90, label: "Emergency notice", usuallyAnnounced: true },186 // ---- health / science ----187 outbreak: { severity: 90, label: "Outbreak", usuallyAnnounced: true },188 drug_warning: { severity: 82, label: "Drug warning", usuallyAnnounced: true },189 device_recall: { severity: 82, label: "Device recall", usuallyAnnounced: true },190 paper_release: { severity: 45, label: "Paper", usuallyAnnounced: true },191 retraction: { severity: 70, label: "Retraction", usuallyAnnounced: true },192 space_mission: { severity: 68, label: "Space mission", usuallyAnnounced: true },193 // ---- transport ----194 accident: { severity: 88, label: "Accident", usuallyAnnounced: true },195 grounding: { severity: 85, label: "Grounding", usuallyAnnounced: true },196 safety_bulletin: { severity: 72, label: "Safety bulletin", usuallyAnnounced: true },197 route_change: { severity: 50, label: "Route change", usuallyAnnounced: true },198 production_delay: { severity: 65, label: "Production delay", usuallyAnnounced: true },199 // ---- product / service ----200 service_launch: { severity: 70, label: "Service launch", usuallyAnnounced: true },201 service_shutdown: { severity: 78, label: "Service shutdown", usuallyAnnounced: false },202 feature_removed: { severity: 66, label: "Feature removed", usuallyAnnounced: false },203 domain_change: { severity: 50, label: "Domain change", usuallyAnnounced: false },204 sports_transaction: { severity: 40, label: "Transaction", usuallyAnnounced: true },205 sports_result: { severity: 25, label: "Result", usuallyAnnounced: true },206 suspension: { severity: 45, label: "Suspension", usuallyAnnounced: true },207 schedule_change: { severity: 35, label: "Schedule change", usuallyAnnounced: true },208};209210export function eventTypeSpec(type: string): EventTypeSpec {211 return EVENT_TYPES[type] ?? EVENT_TYPES.unknown!;212}213214/** Event types whose silent modification is a signal (pricing quietly changed, terms rewritten…). */215export const SILENT_ELIGIBLE_TYPES = new Set([216 "pricing_change",217 "terms_change",218 "policy_change",219 "API_change",220 "api_change",221 "availability_change",222 "documentation_change",223 "service_shutdown",224 "feature_removed",225 "leadership_change",226 "page_removed",227 "crawler_policy_change",228 "product_update",229 "infrastructure_change",230]);231232/** Groups used by filters, category desks and the explore page. */233export const EVENT_GROUPS: Record<string, { label: string; types: string[] }> = {234 security: { label: "Security", types: ["zero_day", "active_exploitation", "vulnerability", "security_advisory", "breach", "supply_chain_attack", "credential_leak", "malware_campaign", "ransomware", "patch_release"] },235 reliability: { label: "Reliability", types: ["outage", "incident", "maintenance", "infrastructure_change", "dns_change", "DNS_change", "certificate_change"] },236 product: { label: "Product & API", types: ["product_launch", "product_update", "model_release", "software_release", "repository_release", "service_launch", "service_shutdown", "feature_removed", "API_change", "api_change", "availability_change", "new_region", "new_country", "documentation_change"] },237 commercial: { label: "Pricing & terms", types: ["pricing_change", "terms_change", "policy_change", "crawler_policy_change"] },238 corporate: { label: "Corporate", types: ["earnings", "guidance", "financial_filing", "acquisition", "merger", "ipo", "funding", "capital_raise", "dividend", "buyback", "bankruptcy", "rating_change", "insider_transaction", "leadership_change", "appointment", "layoffs", "job_expansion", "partnership"] },239 government: { label: "Government & legal", types: ["government_announcement", "regulatory_filing", "regulatory_action", "legislation", "budget", "procurement", "sanction", "lawsuit", "court_decision", "legal_change", "emergency_notice", "monetary_policy", "economic_release"] },240 science: { label: "Science & health", types: ["scientific_publication", "paper_release", "retraction", "dataset_release", "clinical_trial", "drug_approval", "drug_warning", "recall", "device_recall", "outbreak", "space_mission", "standard_update"] },241 transport: { label: "Transport", types: ["accident", "grounding", "safety_bulletin", "route_change", "production_delay"] },242 sports: { label: "Sports", types: ["sports_transaction", "sports_result", "suspension", "schedule_change"] },243 web: { label: "Web", types: ["announcement", "page_created", "page_removed", "content_change", "domain_change", "domain_registration_change", "unknown"] },244};245246export function eventGroupOf(type: string): string {247 for (const [g, spec] of Object.entries(EVENT_GROUPS)) if (spec.types.includes(type)) return g;248 return "web";249}250251/** Semantic classes assigned to every raw change by the semantic diff stage. */252export const CHANGE_CLASSES = ["meaningful", "pricing", "policy", "product", "personnel", "cosmetic", "navigation", "timestamp", "advertisement", "boilerplate"] as const;253export type ChangeClass = (typeof CHANGE_CLASSES)[number];254export const NOISE_CLASSES = new Set<ChangeClass>(["cosmetic", "navigation", "timestamp", "advertisement", "boilerplate"]);255256/** Cluster / breaking states. */257export const CLUSTER_STATES = ["breaking", "developing", "confirmed", "watching", "closed"] as const;258export type ClusterState = (typeof CLUSTER_STATES)[number];259260/** Priority tiers for scheduling (spec §76). Derived from tier + category. */261export const PRIORITY_LABELS: Record<number, string> = { 0: "TIER 0 · critical", 1: "TIER 1 · major", 2: "TIER 2 · specialized", 3: "TIER 3 · low urgency" };262263/** Countries with dedicated desks. ISO 3166-1 alpha-2 (plus EU / INT). */264export const COUNTRIES: Record<string, { name: string; slug: string; flag: string }> = {265 CA: { name: "Canada", slug: "canada", flag: "🇨🇦" },266 US: { name: "United States", slug: "united-states", flag: "🇺🇸" },267 EU: { name: "European Union", slug: "european-union", flag: "🇪🇺" },268 GB: { name: "United Kingdom", slug: "united-kingdom", flag: "🇬🇧" },269 FR: { name: "France", slug: "france", flag: "🇫🇷" },270 DE: { name: "Germany", slug: "germany", flag: "🇩🇪" },271 IT: { name: "Italy", slug: "italy", flag: "🇮🇹" },272 ES: { name: "Spain", slug: "spain", flag: "🇪🇸" },273 JP: { name: "Japan", slug: "japan", flag: "🇯🇵" },274 KR: { name: "South Korea", slug: "south-korea", flag: "🇰🇷" },275 AU: { name: "Australia", slug: "australia", flag: "🇦🇺" },276 IN: { name: "India", slug: "india", flag: "🇮🇳" },277 BR: { name: "Brazil", slug: "brazil", flag: "🇧🇷" },278 MX: { name: "Mexico", slug: "mexico", flag: "🇲🇽" },279 CH: { name: "Switzerland", slug: "switzerland", flag: "🇨🇭" },280 NL: { name: "Netherlands", slug: "netherlands", flag: "🇳🇱" },281 SE: { name: "Sweden", slug: "sweden", flag: "🇸🇪" },282 NO: { name: "Norway", slug: "norway", flag: "🇳🇴" },283 FI: { name: "Finland", slug: "finland", flag: "🇫🇮" },284 DK: { name: "Denmark", slug: "denmark", flag: "🇩🇰" },285 IE: { name: "Ireland", slug: "ireland", flag: "🇮🇪" },286 BE: { name: "Belgium", slug: "belgium", flag: "🇧🇪" },287 AT: { name: "Austria", slug: "austria", flag: "🇦🇹" },288 PT: { name: "Portugal", slug: "portugal", flag: "🇵🇹" },289 PL: { name: "Poland", slug: "poland", flag: "🇵🇱" },290 CN: { name: "China", slug: "china", flag: "🇨🇳" },291 HK: { name: "Hong Kong", slug: "hong-kong", flag: "🇭🇰" },292 TW: { name: "Taiwan", slug: "taiwan", flag: "🇹🇼" },293 SG: { name: "Singapore", slug: "singapore", flag: "🇸🇬" },294 IL: { name: "Israel", slug: "israel", flag: "🇮🇱" },295 AE: { name: "United Arab Emirates", slug: "uae", flag: "🇦🇪" },296 SA: { name: "Saudi Arabia", slug: "saudi-arabia", flag: "🇸🇦" },297 QA: { name: "Qatar", slug: "qatar", flag: "🇶🇦" },298 ZA: { name: "South Africa", slug: "south-africa", flag: "🇿🇦" },299 NG: { name: "Nigeria", slug: "nigeria", flag: "🇳🇬" },300 KE: { name: "Kenya", slug: "kenya", flag: "🇰🇪" },301 AR: { name: "Argentina", slug: "argentina", flag: "🇦🇷" },302 CL: { name: "Chile", slug: "chile", flag: "🇨🇱" },303 CO: { name: "Colombia", slug: "colombia", flag: "🇨🇴" },304 NZ: { name: "New Zealand", slug: "new-zealand", flag: "🇳🇿" },305 RU: { name: "Russia", slug: "russia", flag: "🇷🇺" },306 TR: { name: "Türkiye", slug: "turkiye", flag: "🇹🇷" },307 ID: { name: "Indonesia", slug: "indonesia", flag: "🇮🇩" },308 TH: { name: "Thailand", slug: "thailand", flag: "🇹🇭" },309 VN: { name: "Vietnam", slug: "vietnam", flag: "🇻🇳" },310 MY: { name: "Malaysia", slug: "malaysia", flag: "🇲🇾" },311 PH: { name: "Philippines", slug: "philippines", flag: "🇵🇭" },312 EG: { name: "Egypt", slug: "egypt", flag: "🇪🇬" },313 UA: { name: "Ukraine", slug: "ukraine", flag: "🇺🇦" },314 CZ: { name: "Czechia", slug: "czechia", flag: "🇨🇿" },315 GR: { name: "Greece", slug: "greece", flag: "🇬🇷" },316 LU: { name: "Luxembourg", slug: "luxembourg", flag: "🇱🇺" },317 INT: { name: "International", slug: "international", flag: "🌐" },318};319320export function countryBySlug(slug: string): { code: string; name: string; flag: string } | null {321 const s = slug.toLowerCase();322 for (const [code, c] of Object.entries(COUNTRIES)) if (c.slug === s || code.toLowerCase() === s) return { code, name: c.name, flag: c.flag };323 return null;324}325326export const ENTITY_TYPES = [327 "organization",328 "company",329 "government",330 "agency",331 "product",332 "software",333 "AI_model",334 "API",335 "drug",336 "disease",337 "person",338 "country",339 "city",340 "stock",341 "crypto_asset",342 "repository",343 "standard",344 "technology",345 "dataset",346 "publication",347 "vulnerability",348] as const;349export type EntityType = (typeof ENTITY_TYPES)[number];350351export const EVIDENCE_LABELS = ["OBSERVED", "INFERRED", "CONFIRMED", "UNCONFIRMED"] as const;352export type EvidenceLabel = (typeof EVIDENCE_LABELS)[number];353354export const CONNECTOR_HEALTH = ["UP", "DEGRADED", "ERROR", "DISABLED", "RATE_LIMITED"] as const;355export type ConnectorHealth = (typeof CONNECTOR_HEALTH)[number];356