SPB Git forge
15commits 1branches 0releases
29.7 MBsize
maindefault branch
10 days agolast push
TypeScript 36.3% Python 31.8% Go 18% JavaScript 9.8% Shell 1.9% SQL 1.4% CSS 0.5%
17.4 KB · 648 lines typescript
Raw Blame History
1/**2 * TypeScript mirror of docs/API.md (public v1 + admin). Field names and shapes follow the contract exactly;3 * nothing here is invented — if the UI needs a field that is not in API.md it is listed in the README instead.4 */56export type LevelId = 'calm' | 'normal' | 'elevated' | 'stressed' | 'high' | 'severe' | 'extreme';7export type Trend = 'rising' | 'falling' | 'stable';8export type InternalStatus = 'ok' | 'degraded' | 'stale';9export type ComponentId = 'routing' | 'latency' | 'dns' | 'availability' | 'http_tls' | 'path' | 'corroboration';10export type IncidentStatus = 'detected' | 'developing' | 'active' | 'recovering' | 'resolved';11export type IncidentType =12  | 'regional_latency'13  | 'dns_disruption'14  | 'routing_instability'15  | 'service_degradation'16  | 'availability_loss'17  | 'path_instability'18  | 'global_pressure';19export type ScopeType = 'global' | 'region' | 'country' | 'asn' | 'service' | 'component' | 'bgp' | 'signal' | 'target';20export type HistoryRange = '1h' | '6h' | '24h' | '7d' | '30d' | '1y';2122export interface Status {23  ok: boolean;24  ts: string;25  internal_status: InternalStatus;26  engine: { last_run: string; cycle_ms: number; cycle_seconds: number };27  ingest: { last_batch: string; batches_5m: number; measurements_5m: number };28  probes: { fresh: number; total: number; excluded: string[] };29  bgp: { fresh: boolean; last_message: string; collectors: number };30  stores: { clickhouse: boolean; postgres: boolean; redis: boolean };31  version: string;32}3334export interface Driver {35  label: string;36  points: number;37  scope_type: string;38  scope_id: string | null;39}4041export interface Component {42  id: ComponentId;43  label: string;44  score: number;45  weight: number;46  contribution: number;47  trend: Trend;48  delta_1h: number;49  confidence: number;50  drivers: Driver[];51}5253export interface ExplainRow {54  text: string;55  points: number;56  component: ComponentId;57  scope_type: string;58  scope_id: string | null;59}6061export interface Coverage {62  probes_active: number;63  probes_total: number;64  probe_regions: number;65  targets: number;66  measurements_5m: number;67  bgp_collectors: number;68  baseline_days: number;69}7071export interface GlobalPressure {72  ts: string;73  pressure: number;74  level: LevelId;75  level_label: string;76  delta_1h: number;77  delta_24h: number;78  velocity_per_h: number;79  acceleration_per_h2: number;80  volatility_1h: number;81  trend: Trend;82  confidence: number;83  stale: boolean;84  internal_status: InternalStatus;85  coverage: Coverage;86  components: Component[];87  explain: ExplainRow[];88  sparkline_1h: (number | null)[];89}9091export type ComponentScores = Partial<Record<ComponentId, number | null>>;9293export interface HistoryPoint {94  ts: string;95  pressure: number;96  components: ComponentScores;97  confidence: number;98}99export interface History {100  scope_type: string;101  scope_id: string | null;102  range: HistoryRange;103  step_seconds: number;104  points: HistoryPoint[];105  summary: { min: number; max: number; avg: number; max_ts: string };106}107108export interface SimpleSeries {109  step_seconds: number;110  points: { ts: string; pressure: number }[];111}112113export interface Region {114  id: string;115  name: string;116  continent: string;117  lat: number;118  lon: number;119  pressure: number;120  level: LevelId;121  level_label: string;122  delta_1h: number;123  trend: Trend;124  confidence: number;125  components: ComponentScores;126  probes: number;127  targets: number;128  incidents: number;129  coverage_ok: boolean;130  role: 'probe' | 'target' | 'both';131}132133export interface Probe {134  probe_id: string;135  name: string;136  region: string;137  country: string;138  city: string;139  provider: string;140  asn: number;141  lat: number;142  lon: number;143  status: 'online' | 'stale' | 'offline' | 'excluded';144  last_seen: string;145  version: string;146  measurements_1h: number;147  uptime_24h: number;148  clock_offset_ms: number;149  capabilities: string[];150}151152export interface LatencyPair {153  from: string;154  to: string;155  rtt_ms: number;156  rtt_ms_baseline: number;157  ttfb_ms: number;158  loss_pct: number;159  z: number;160  pairs: number;161}162export interface Latency {163  ts: string;164  global: { rtt_ms_median: number; rtt_ms_baseline: number; ttfb_ms_median: number; ttfb_ms_baseline: number; packet_loss_pct: number };165  matrix: LatencyPair[];166  by_probe: { probe_id: string; rtt_ms_median: number; ttfb_ms_median: number; loss_pct: number; z: number }[];167}168169export interface TargetRow {170  target_id: string;171  name: string;172  pressure: number;173  ok_ratio_1h: number;174  ttfb_ms_median: number;175}176export interface CountryTargetRow extends TargetRow {177  category: string;178}179180// `probes`/`incidents` are counts in the list object and lists in the detail object (API.md §region/{id}).181export type RegionDetailResponse = Omit<Region, 'probes' | 'incidents'> & {182  history_24h: SimpleSeries;183  baseline_7d: { median: number; p90: number };184  incidents: Incident[];185  top_asns: { asn: number; name: string; pressure: number }[];186  top_services: { slug: string; name: string; pressure: number; observed_availability_24h: number }[];187  probes: Probe[];188  matrix: LatencyPair[];189};190191export interface Country {192  cc: string;193  name: string;194  region: string;195  lat: number;196  lon: number;197  pressure: number;198  level: LevelId;199  level_label: string;200  delta_1h: number;201  trend: Trend;202  components: ComponentScores;203  probes: number;204  targets: number;205  role: 'probe' | 'target' | 'both';206  coverage_ok: boolean;207}208export type CountryDetailResponse = Omit<Country, 'probes' | 'targets'> & {209  history_24h: SimpleSeries;210  baseline_7d: { median: number; p90: number };211  incidents: Incident[];212  asns: { asn: number; name: string; pressure: number }[];213  services: { slug: string; name: string; pressure: number; observed_availability_24h: number }[];214  probes: Probe[];215  targets: CountryTargetRow[];216};217218export interface AsnRow {219  asn: number;220  name: string;221  country: string;222  pressure: number;223  level: LevelId;224  routing: number;225  latency: number;226  availability: number;227  targets: number;228  prefixes_observed: number;229  importance: number;230}231export interface AsnDetail {232  asn: number;233  name: string;234  country: string;235  importance: number;236  ts: string;237  pressure: number;238  level: LevelId;239  level_label: string;240  delta_1h: number;241  trend: Trend;242  confidence: number;243  components: ComponentScores;244  bgp: {245    prefixes_observed_24h: number;246    announcements_1h: number;247    withdrawals_1h: number;248    churn_ratio: number;249    origin_changes_1h: number;250    path_stability: number;251    series_24h: { ts: string; announcements: number; withdrawals: number }[];252  };253  regions_observed: string[];254  targets: TargetRow[];255  history_24h: SimpleSeries;256  incidents: Incident[];257}258259export interface VendorStatus {260  indicator: string;261  incidents: number;262  source: string;263  checked_at: string;264  titles?: string[];265  url?: string;266}267export interface ServiceRow {268  slug: string;269  name: string;270  category: string;271  pressure: number;272  level: LevelId;273  observed_availability_24h: number;274  targets: number;275  affected_regions: string[];276  vendor_status: VendorStatus | null;277}278export interface MatrixCell {279  target_id: string;280  ok: boolean;281  ttfb_ms: number;282  z: number;283  ts: string;284}285export interface ServiceDetail extends Omit<ServiceRow, 'affected_regions' | 'targets'> {286  observed: {287    availability_24h: number;288    availability_1h: number;289    ttfb_ms_median_1h: number;290    ttfb_ms_baseline: number;291    tls_ms_median_1h: number;292    failures_1h: number;293  };294  affected_regions: { id: string; name: string; observation: string }[];295  discrepancy: string | null;296  matrix: { probe_id: string; probe_region: string; targets: MatrixCell[] }[];297  targets: TargetRow[];298  history_24h: SimpleSeries;299  incidents: Incident[];300}301302export interface Target {303  target_id: string;304  name: string;305  hostname: string;306  category: string;307  provider: string;308  service_id: string;309  country: string;310  region: string;311  importance: number;312  tier: number;313  pressure: number;314  ok_ratio_1h: number;315  ttfb_ms_median_1h: number;316}317export interface TargetDetail extends Target {318  latest_by_probe: {319    probe_id: string;320    kind: string;321    ts: string;322    ok: boolean;323    error: string | null;324    dns_ms: number | null;325    tcp_ms: number | null;326    tls_ms: number | null;327    ttfb_ms: number | null;328    http_status: number | null;329    resolved_ip: string | null;330    packet_loss: number | null;331    rtt_avg_ms: number | null;332    z: number;333  }[];334  series_24h: { step_seconds: number; points: { ts: string; ttfb_ms_p50: number; ok_ratio: number }[] };335  dns: { resolvers: { resolver: string; rcode: string; answers: number; ms: number }[]; disagreement: boolean };336}337338export interface Hypothesis {339  text: string;340  confidence: number;341  evidence: string[];342}343export interface Incident {344  event_id: string;345  slug: string;346  type: IncidentType;347  title: string;348  summary: string;349  status: IncidentStatus;350  scope_type: string;351  scope_id: string | null;352  scope_label: string;353  started_at: string;354  updated_at: string;355  ended_at: string | null;356  duration_s: number;357  peak_pressure: number;358  current_pressure: number;359  confidence: number;360  affected_probes: number;361  affected_targets: number;362  affected_asns: number[];363  affected_services: string[];364  hypotheses: Hypothesis[];365}366export interface IncidentDetail extends Incident {367  timeline: { ts: string; status: IncidentStatus; pressure: number; note: string }[];368  evidence: {369    signal_id: string;370    label: string;371    scope_type: string;372    scope_id: string | null;373    current: number;374    baseline: number;375    robust_z: number;376    samples: number;377    ts: string;378  }[];379  series: { step_seconds: number; points: { ts: string; pressure: number; global_pressure: number }[] };380  probes: { probe_id: string; region: string; observation: string }[];381  targets: { target_id: string; name: string; service_id: string; observation: string }[];382  bgp: { withdrawals_ratio: number; announcements_ratio: number; origin_changes: number } | null;383  annotations: { ts: string; author: string; text: string }[];384}385export interface IncidentList {386  total: number;387  incidents: Incident[];388}389390export interface Front {391  id: string;392  name: string;393  status: string;394  intensity: number;395  confidence: number;396  direction: string;397  since: string;398  from: { region: string; name: string; lat: number; lon: number };399  to: { region: string; name: string; lat: number; lon: number };400  observed: { latency_pct: number; churn_x: number; loss_pct: number; pairs: number; targets: number; route_changes: number };401}402403export interface BgpCollector {404  id: string;405  location: string;406  announcements_per_s: number;407  withdrawals_per_s: number;408  peers: number;409  last_message: string;410  fresh: boolean;411}412export interface BgpStats {413  ts: string;414  fresh: boolean;415  updates_per_s: number;416  announcements_per_s: number;417  withdrawals_per_s: number;418  baseline: { announcements_per_s: number; withdrawals_per_s: number };419  ratio: { announcements: number; withdrawals: number };420  unique_prefixes_1m: number;421  unique_origins_1m: number;422  origin_changes_1m: number;423  peers: number;424  collectors: BgpCollector[];425  series_1h: { ts: string; announcements: number; withdrawals: number }[];426  top_origins_1h: { asn: number; name: string; announcements: number; withdrawals: number }[];427}428export type BgpStatsEvent = Pick<BgpStats, 'ts' | 'updates_per_s' | 'announcements_per_s' | 'withdrawals_per_s' | 'ratio' | 'fresh'>;429430export interface Ticker {431  ts: string;432  bgp_updates_per_s: number;433  bgp_withdrawals_per_s: number;434  bgp_updates_per_min: number;435  probes_active: number;436  probes_total: number;437  measurements_per_s: number;438  measurements_per_min: number;439  targets_degraded: number;440  targets_total: number;441  regions_elevated: number;442  regions_normal: number;443  regions_severe: number;444  dns_failures_per_min: number;445  median_global_rtt_ms: number;446  route_changes_per_min: number;447  active_incidents: number;448  internal_status: InternalStatus;449}450451export interface Hop {452  n: number;453  ip: string;454  asn: number | null;455  asn_name: string | null;456  rtt_ms: number | null;457  private: boolean;458}459export interface RouteResponse {460  probe: { probe_id: string; name: string; asn: number };461  target: { target_id: string; name: string; hostname: string; asn: number };462  current: { ts: string; route_hash: string; reached: boolean; total_ms: number; hops: Hop[] };463  baseline: { route_hash: string; share_7d: number; first_seen: string; last_seen: string; hops: Hop[] };464  diff: {465    changed: boolean;466    added: { n: number; ip: string; asn: number | null }[];467    removed: { n: number; ip: string; asn: number | null }[];468    asn_path_current: number[];469    asn_path_baseline: number[];470    latency_shift_ms: number;471    hop_delta: number;472  };473  history_24h: { ts: string; route_hash: string; hop_count: number; total_ms: number }[];474  route_share_7d: { route_hash: string; share: number; asn_path: number[] }[];475}476export interface RoutePair {477  probe_id: string;478  target_id: string;479  changed_24h: number;480  current_route_hash: string;481  stable: boolean;482}483484export interface HistoryDay {485  date: string;486  min: number;487  max: number;488  avg: number;489  events: number;490}491export interface HistoryMonthRow {492  month: string;493  min: number;494  max: number;495  avg: number;496  events: number;497}498export interface HistorySummary {499  year?: number;500  month?: number;501  days?: HistoryDay[];502  months?: HistoryMonthRow[];503  top_events: Incident[];504  top_asns: { asn: number; name: string; events: number; max_pressure: number }[];505  top_regions: { id: string; name: string; events: number; max_pressure: number; hours_elevated: number }[];506  largest: { pressure: Incident | null; routing: Incident | null; dns: Incident | null; latency: Incident | null };507  available_months: string[];508}509510export interface ExplainSignal {511  signal_id: string;512  label: string;513  scope_type: string;514  scope_id: string | null;515  current: number;516  baseline_median: number;517  mad: number;518  robust_z: number;519  samples: number;520  stress: number;521  contribution: number;522}523export interface Explain {524  ts: string;525  pressure: number;526  components: { id: ComponentId; score: number; weight: number; contribution: number; signals: ExplainSignal[] }[];527  excluded_probes: string[];528  notes: string[];529}530531export interface Methodology {532  weights: Record<string, number>;533  levels: { max: number; id: LevelId; label: string }[];534  engine: Record<string, number | string>;535  components?: Record<string, { signals: { id: string; label: string; weight: number }[] }>;536  events?: Record<string, number>;537  fronts?: Record<string, number>;538  version: number;539  updated_at: string | null;540  source?: string;541}542543export interface SearchResult {544  type: 'country' | 'asn' | 'service' | 'region' | 'target' | 'incident';545  id: string;546  label: string;547  href: string;548  pressure: number | null;549}550551// ---- SSE payloads552export interface Snapshot {553  global: GlobalPressure;554  ticker: Ticker;555  regions: Region[];556  fronts: Front[];557  incidents: Incident[];558}559export interface RegionalUpdate {560  ts: string;561  regions: Region[];562  countries: { cc: string; pressure: number; level: LevelId; delta_1h: number }[];563}564export interface ProbeStats {565  ts: string;566  probes_active: number;567  probes_total: number;568  measurements_per_s: number;569  excluded: string[];570}571export interface InternalStatusEvent {572  ts: string;573  internal_status: InternalStatus;574  reason: string;575}576export interface ServiceDegradationEvent {577  ts: string;578  slug: string;579  name: string;580  pressure: number;581  regions: string[];582  observation: string;583}584585// ---- admin586export interface AdminProbe extends Probe {587  enabled?: boolean;588  health?: {589    uptime_24h: number;590    clock_offset_ms: number;591    missing_ratio_1h: number;592    error_rate_1h: number;593    buffered: number;594    spool_bytes: number;595    version: string;596    last_health: string;597  };598  key?: string;599}600export interface AdminOverview {601  probes: AdminProbe[];602  ingest: { batches_per_min: number; measurements_per_min: number; rejected_per_min: number; last_batch: string };603  stores: {604    clickhouse: { ok: boolean; inserts_per_s: number; tables: { name: string; rows: number; bytes: number; oldest: string; newest: string }[] };605    postgres: { ok: boolean; size_bytes: number };606    redis: { ok: boolean; used_memory_bytes: number; keys: number };607  };608  bgp: { collectors: BgpCollector[]; messages_per_s: number; fresh: boolean; reconnects_24h: number };609  engine: { last_run: string; cycle_ms_p50: number; cycle_ms_max: number; runs_1h: number; errors_1h: number; internal_status: InternalStatus; excluded_probes: string[] };610  corroboration: { id: string; name: string; ok: boolean; last_fetch: string; incidents: number }[];611}612export interface AdminTarget extends Target {613  enabled?: boolean;614}615export interface AdminBaselines {616  signal_id: string;617  points: { ts: string; value: number; median: number; mad: number; z: number }[];618  samples: number;619  baseline_days: number;620}621export interface AdminRaw {622  columns: string[];623  rows: unknown[][];624}625export interface AdminIncident extends Incident {626  review?: 'confirmed' | 'dismissed' | 'unreviewed';627  note?: string | null;628}629export interface AdminAnnotation {630  id?: string;631  ts: string;632  author?: string;633  scope_type: string;634  scope_id: string | null;635  text: string;636}637export interface AdminReplay {638  step_seconds: number;639  points: { ts: string; pressure_original: number; pressure_replayed: number }[];640}641export interface AdminConfig {642  version: number;643  pressure_weights: Record<string, number>;644  levels: { max: number; id: string; label: string }[];645  engine: Record<string, number | string>;646  [key: string]: unknown;647}648