SPB Git
18.7 KB · 752 lines typescript
1/**2 * TypeScript mirror of `docs/API.md` (contract v1). Keep in sync with the FastAPI routers; never widen a shape here to3 * paper over an API gap — document it in `docs/FRONTEND.md` instead.4 */56export type Num = number | string | null;78export type Metric =9  | 'activity_score'10  | 'hiring_momentum_7d'11  | 'hiring_momentum_30d'12  | 'hiring_momentum_90d'13  | 'open_jobs'14  | 'ai_adoption'15  | 'product_velocity'16  | 'geo_expansion'17  | 'developer_momentum'18  | 'communication_activity'19  | 'pricing_activity'20  | 'leadership_activity'21  | 'corporate_change_index'22  | 'anomaly_score'23  | 'historical_coverage';2425export type ConfidenceLabel = 'VERIFIED' | 'HIGH_CONFIDENCE' | 'LIKELY' | 'INFERRED' | 'LOW_CONFIDENCE';2627export interface Page<T> {28  items: T[];29  page: number;30  per_page: number;31  total: number;32  pages: number;33  meta?: Record<string, unknown>;34}3536export interface CompanyRef {37  id: string;38  slug: string;39  display_name: string;40  canonical_domain: string;41  country: string | null;42  logo_url: string | null;43}4445export interface CompanyCounts {46  sensors: number;47  observations: number;48  changes: number;49  events: number;50  jobs_open: number;51}5253export interface CompanyCard {54  id: string;55  slug: string;56  display_name: string;57  legal_name: string | null;58  canonical_domain: string;59  website: string;60  description: string | null;61  industries: string[];62  industry_primary: string | null;63  country: string | null;64  hq_city: string | null;65  hq_region: string | null;66  public_company: boolean;67  ticker: string | null;68  exchange: string | null;69  founded_year: number | null;70  employees_band: string | null;71  logo_url: string | null;72  status: string;73  onboarding_status: string;74  importance: number;75  tier: 1 | 2 | 3 | 4;76  metrics: Partial<Record<Metric, number>>;77  counts: CompanyCounts;78  last_event_at: string | null;79  last_observed_at: string | null;80  sparkline?: number[];81}8283export interface MetricDetail {84  metric: Metric | string;85  value: number;86  confidence: number;87  computed_at: string;88  inputs: Record<string, unknown>;89  formula_version?: string;90}9192export interface Relationship {93  kind: string;94  company: { slug: string; display_name: string } | null;95  to_name: string | null;96  valid_from: string | null;97  valid_to: string | null;98  confidence: number;99}100101export interface CompanyDetail extends CompanyCard {102  aliases: string[];103  domains: { domain: string; kind: string }[];104  relationships: Relationship[];105  metrics_detail: MetricDetail[];106  sensors_by_surface: Record<string, number>;107  coverage: { historical_coverage: number | null; first_observed_at: string | null; days_observed: number; sensor_uptime: number | null };108  signals: Signal[];109  sparklines: { activity_30d: number[]; hiring_90d: number[] };110}111112export interface EventSource {113  source_url: string;114  surface: string | null;115  detected_at: string;116  kind: string;117  sensor_id: string | null;118}119120export type EventOrigin = 'deterministic' | 'llm' | 'hybrid' | 'backfill';121export type EventStatus = 'active' | 'retracted' | 'duplicate' | 'review';122123export interface Event {124  id: string;125  company: CompanyRef;126  event_type: string;127  event_subtype: string;128  importance: number;129  confidence: number;130  confidence_label: ConfidenceLabel | string;131  title: string;132  summary: string | null;133  old_value: string | null;134  new_value: string | null;135  payload: Record<string, unknown>;136  entities: Record<string, unknown>;137  tags: string[];138  detected_at: string;139  effective_at: string | null;140  published_at: string | null;141  source_url: string | null;142  surface: string | null;143  sensor_id: string | null;144  change_id: string | null;145  cluster_id: string | null;146  origin: EventOrigin;147  model_name: string | null;148  prompt_version: string | null;149  status: EventStatus;150  sources?: EventSource[];151}152153export interface EventDetail extends Event {154  sources: EventSource[];155  change: Change | null;156}157158export type SensorTier = 'A' | 'B' | 'C' | 'D' | 'E';159160export interface Sensor {161  id: string;162  company_id: string;163  surface: string;164  connector_id: string;165  url: string;166  canonical_url: string;167  domain: string;168  status: string;169  tier: SensorTier;170  quality_score: number;171  discovery_confidence: number;172  discovery_method: string | null;173  current_interval_s: number;174  next_run_at: string;175  last_run_at: string | null;176  last_success_at: string | null;177  last_change_at: string | null;178  last_status: number | null;179  last_failure_class: string | null;180  consecutive_failures: number;181  observation_count: number;182  snapshot_count: number;183  change_count: number;184  meaningful_change_count: number;185  event_count: number;186  created_at: string;187}188189export interface SensorDetail extends Sensor {190  company: CompanyRef;191  latest_snapshot: Snapshot | null;192}193194export interface Snapshot {195  id: string;196  sensor_id: string;197  version_no: number;198  fetched_at: string;199  title: string | null;200  language: string | null;201  text_length: number | null;202  block_count: number | null;203  extracted_summary: Record<string, number>;204  content_hash: string;205  previous_snapshot_id: string | null;206}207208export interface Block {209  key: string;210  kind: string;211  path: string;212  text: string;213}214215export interface SnapshotDetail extends Snapshot {216  text: string;217  blocks: Block[];218  extracted: Record<string, unknown>;219}220221export interface BlockDelta {222  key: string;223  kind: string;224  path: string;225  before: string | null;226  after: string | null;227  weight: number;228  similarity: number | null;229}230231export interface DiffPayload {232  added: BlockDelta[];233  removed: BlockDelta[];234  modified: BlockDelta[];235  moved: string[];236  counts: Record<string, number>;237  text_delta_ratio: number;238  similarity: number;239  reasons: string[];240}241242export interface Change {243  id: string;244  sensor_id: string;245  surface: string;246  company_id: string;247  detected_at: string;248  significance: number;249  kind: string;250  blocks_added: number;251  blocks_removed: number;252  blocks_modified: number;253  text_delta_ratio: number;254  similarity: number | null;255  snapshot_before: string | null;256  snapshot_after: string;257  diff?: DiffPayload;258  structured_delta?: Record<string, unknown>;259}260261export interface ChangeDetail extends Change {262  diff: DiffPayload;263  structured_delta: Record<string, unknown>;264  events: Event[];265  company?: CompanyRef;266}267268export interface SnapshotDiff {269  before: Snapshot;270  after: Snapshot;271  diff: DiffPayload;272}273274export interface Job {275  id: string;276  title: string;277  department: string | null;278  location_text: string | null;279  city: string | null;280  country: string | null;281  remote: boolean | null;282  employment_type: string | null;283  seniority: string | null;284  url: string | null;285  posted_at: string | null;286  first_seen_at: string;287  last_seen_at: string;288  removed_at: string | null;289  status: 'open' | 'no_longer_listed';290  is_ai: boolean;291}292293export interface JobsSummary {294  open: number;295  new_7d: number;296  removed_7d: number;297  ai_open: number;298  by_country: { country: string; n: number }[];299  by_department: { department: string; n: number }[];300  remote_ratio: number | null;301}302303export interface JobsPage extends Page<Job> {304  meta?: { summary?: JobsSummary } & Record<string, unknown>;305  summary?: JobsSummary;306}307308export interface Person {309  id: string;310  name: string;311  title: string | null;312  role_category: string | null;313  is_executive: boolean;314  first_seen_at: string;315  last_seen_at: string;316  removed_at: string | null;317  status: string;318  source_url: string | null;319}320321export interface Product {322  id: string;323  name: string;324  category: string | null;325  description: string | null;326  url: string | null;327  first_seen_at: string;328  last_seen_at: string;329  removed_at: string | null;330  status: string;331}332333export interface Plan {334  id: string;335  plan_name: string;336  price: number | null;337  price_text: string | null;338  currency: string | null;339  billing_period: string | null;340  unit: string | null;341  features: string[];342  contact_sales: boolean;343  version_no: number;344  valid_from: string;345  valid_to: string | null;346  status: string;347  source_url: string | null;348}349350export interface Location {351  id: string;352  kind: string;353  name: string | null;354  city: string | null;355  region: string | null;356  country: string | null;357  lat: number | null;358  lon: number | null;359  first_seen_at: string;360  last_seen_at: string;361  removed_at: string | null;362  status: string;363  source_url: string | null;364}365366export interface NewsItem {367  id: string;368  title: string;369  url: string;370  summary: string | null;371  category: string | null;372  published_at: string | null;373  first_seen_at: string;374  language: string | null;375}376377export interface MetricPoint {378  day: string;379  value: number;380  confidence: number;381}382383export interface Signal {384  id: string;385  company_id: string | null;386  scope: string;387  scope_key: string | null;388  kind: string;389  strength: number;390  confidence: number;391  title: string;392  explanation: string | null;393  evidence: Record<string, unknown>;394  window_days: number;395  detected_at: string;396  status: string;397}398399// ---------------------------------------------------------------------------------------------------------- platform400export interface Stats {401  companies: number;402  companies_active: number;403  sensors: number;404  sensors_active: number;405  observations: number;406  snapshots: number;407  changes: number;408  meaningful_changes: number;409  events: number;410  jobs_open: number;411  countries: number;412  industries: number;413  observations_today: number;414  changes_today: number;415  events_today: number;416  dataset_started_at: string | null;417  dataset_age_days: number | null;418  oldest_history_days: number | null;419  last_observation_at: string | null;420  archive: { objects: number; bytes: number };421}422423export interface GlobalDaily {424  day: string;425  companies_active: number;426  sensors_active: number;427  observations: number;428  changes: number;429  meaningful_changes: number;430  events: number;431  events_by_type: Record<string, number>;432  jobs_open: number;433  jobs_new: number;434  jobs_removed: number;435  activity_index: number | null;436}437438export interface SystemHealth {439  sensors_online: number;440  sensors_failing: number;441  observations_today: number;442  events_today: number;443  countries_covered: number;444  queue_lag_s: number | null;445  scheduler_last_tick_at: string | null;446  fetch_per_min: number | null;447  success_rate_24h: number | null;448}449450export interface IndustryRow {451  slug: string;452  name: string;453  parent_slug: string | null;454  companies: number;455  events_7d: number;456  events_30d: number;457  hiring_momentum_30d: number | null;458  activity_score: number | null;459  ai_adoption: number | null;460  top_event_types: string[];461}462463export interface IndustryDetail extends IndustryRow {464  description: string | null;465  companies_list?: CompanyCard[];466  events: Event[];467  hiring: { open: number; new_30d: number; removed_30d: number; momentum_30d: number | null };468  series: MetricPoint[];469  countries: { country: string; companies: number }[];470  trending: TrendRow[];471}472/** `/industries/{slug}` returns `companies: CompanyCard[]` while the row uses `companies: number` — see docs/FRONTEND.md. */473export type IndustryDetailRaw = Omit<IndustryDetail, 'companies' | 'companies_list'> & { companies: CompanyCard[] | number };474475export interface CountryRow {476  code: string;477  name: string;478  region: string | null;479  companies: number;480  events_7d: number;481  events_30d: number;482  hiring_momentum_30d: number | null;483  activity_score: number | null;484  industry_mix: { industry: string; companies: number }[];485  lat: number | null;486  lon: number | null;487}488489export interface CountryDetail extends CountryRow {490  companies_list?: CompanyCard[];491  events: Event[];492  movers: CompanyCard[];493  new_entrants: CompanyCard[];494  series: MetricPoint[];495  industries: IndustryRow[];496}497export type CountryDetailRaw = Omit<CountryDetail, 'companies' | 'companies_list'> & { companies: CompanyCard[] | number };498499export interface TrendRow {500  term: string;501  mentions: number;502  companies: number;503  momentum: number | null;504  series: number[];505}506507export interface MapBucket {508  lat: number;509  lon: number;510  country: string;511  city: string | null;512  companies: number;513  events_30d: number;514  jobs_open: number;515  top: { slug: string; display_name: string }[];516}517518export interface ActivityIndex {519  value: number | null;520  baseline: number;521  delta_7d: number | null;522  delta_30d: number | null;523  series: MetricPoint[];524  by_type: Record<string, number>;525  by_country: { key: string; value: number }[];526  by_industry: { key: string; value: number }[];527  formula_version: string;528}529530export interface Pulse {531  stats: Stats;532  live: Event[];533  movers: CompanyCard[];534  hiring: CompanyCard[];535  launches: Event[];536  pricing: Event[];537  ai: CompanyCard[];538  industries: IndustryRow[];539  countries: CountryRow[];540  trending: TrendRow[];541  activity_index: { value: number | null; delta_7d: number | null; series: MetricPoint[] };542  map: MapBucket[];543}544545export type RankingKind = 'most_active' | 'hiring_growth' | 'hiring_decline' | 'product_velocity' | 'ai_active' | 'geo_expansion' | 'developer_momentum' | 'pricing_changes' | 'unusual_activity';546export type RankingWindow = '24h' | '7d' | '30d' | '90d' | '1y';547548export interface RankingItem extends CompanyCard {549  rank: number;550  value: number;551  delta: number | null;552}553export interface Rankings {554  kind: RankingKind | string;555  window: RankingWindow | string;556  items: RankingItem[];557}558559export interface TimelinePayload {560  items: (Event & { day: string })[];561  days: { day: string; count: number }[];562}563564export interface CompanyMetrics {565  current: MetricDetail[];566  series: Partial<Record<Metric, MetricPoint[]>>;567}568569export interface ComparePayload {570  companies: CompanyCard[];571  metrics: Partial<Record<Metric, Record<string, number>>>;572  series: Record<string, MetricPoint[]>;573  events_30d: Record<string, Record<string, number>>;574  jobs: Record<string, { open: number; ai_open: number; new_30d: number }>;575  locations: Record<string, number>;576}577578export interface HistoryPayload {579  sensors: (Sensor & { versions: Snapshot[] })[];580}581582export interface EventTypes {583  types: { event_type: string; subtypes: { event_subtype: string; count_30d: number }[]; count_30d: number }[];584}585export interface EventSummary {586  items: { key: string; count: number; delta_pct: number | null }[];587}588589export interface SearchPayload {590  query: string;591  companies: CompanyCard[];592  events: Event[];593  industries: IndustryRow[];594  countries: CountryRow[];595  people: (Person & { company: CompanyRef })[];596  products: (Product & { company: CompanyRef })[];597  took_ms: number;598}599export interface Suggestion {600  kind: 'company' | 'industry' | 'country' | 'event_type';601  label: string;602  sublabel: string | null;603  href: string;604}605export interface AskPayload {606  interpretation: Record<string, unknown>;607  answer: string;608  companies: CompanyCard[];609  events: Event[];610  sources: string[];611}612613export interface WatchlistPayload {614  items: CompanyCard[];615  events: Event[];616}617export interface AlertCondition {618  event_types?: string[];619  min_importance?: number;620  metrics?: Partial<Record<string, { gt?: number; lt?: number }>>;621}622export interface Alert {623  id: string;624  name: string;625  company: string | null;626  condition: AlertCondition;627  channel: 'web' | 'webhook';628  target: string | null;629  created_at: string;630  status?: string;631}632export interface AlertDelivery {633  id: string;634  alert_id: string;635  alert_name?: string;636  event_id: string | null;637  event?: Event | null;638  channel: string;639  status: string;640  delivered_at: string;641}642643export interface SitemapPayload {644  items: { slug: string; updated_at: string | null }[];645  pages: number;646}647648export interface Methodology {649  metrics: { metric: string; formula_version: string; description: string; inputs: string[] }[];650  significance_bands: Record<string, [number, number]> | { label: string; min: number; max: number }[];651  event_types: string[];652  confidence_labels: Record<string, string> | (string | { label: string; min_confidence?: number | null })[];653}654655// ---------------------------------------------------------------------------------------------------------- admin656export interface AdminOverview {657  companies_by_status: Record<string, number>;658  sensors_by_status: Record<string, number>;659  sensors_by_tier: Record<string, number>;660  queue: { pending: number; running: number; dead: number; oldest_pending_s: number | null };661  llm: { pending: number; done_today: number; failed_today: number; budget_left: number | null };662  failures_24h_by_class: Record<string, number>;663  fetch_rate_1h: number | null;664  change_rate_1h: number | null;665  meaningful_rate_1h: number | null;666  storage: { objects: number; bytes: number };667  workers: { name: string; last_seen_at: string; inflight: number }[];668  cost_today: { fetch: number; browser: number; llm: number };669}670export interface AdminConnector {671  id: string;672  name: string;673  version: string;674  category: string;675  enabled: boolean;676  sensors_active: number;677  sensors_failing: number;678  success_rate_24h: number | null;679  avg_latency_ms: number | null;680  change_rate_24h: number | null;681  errors_24h: number;682  last_run_at: string | null;683}684export type AdminSensor = Sensor & { company: CompanyRef };685export interface AdminFailure {686  id: string;687  sensor_id: string | null;688  company?: CompanyRef | null;689  domain: string | null;690  failure_class: string;691  status_code: number | null;692  message: string | null;693  occurred_at: string;694  retry_at: string | null;695}696export interface AdminQueueItem {697  id: string;698  kind: string;699  status: string;700  priority: number;701  attempts: number;702  scheduled_at: string;703  started_at: string | null;704  finished_at: string | null;705  worker: string | null;706  ref: string | null;707  error: string | null;708}709export interface AdminLlmJob {710  id: string;711  kind: string;712  status: string;713  model: string | null;714  prompt_version: string | null;715  change_id: string | null;716  event_id: string | null;717  tokens_in: number | null;718  tokens_out: number | null;719  cost_estimate: number | null;720  created_at: string;721  finished_at: string | null;722  error: string | null;723}724export interface AdminReview {725  id: string;726  kind: string;727  status: string;728  subject: string;729  ref_id: string | null;730  company?: CompanyRef | null;731  reason: string | null;732  created_at: string;733  resolved_at: string | null;734  resolution: string | null;735}736export interface AdminQuality {737  coverage: { companies_active_pct: number | null; sensors_active_pct: number | null };738  freshness: { sensors_checked_24h_pct: number | null; stale: number };739  duplicate_rate: number | null;740  event_confidence_avg: number | null;741  unknown_surfaces: number;742  failed_sensors: number;743  calibration: { correct: number; duplicate: number; noise: number; misclassified: number };744}745export interface AdminCosts {746  items: { day: string; dimension: string; key: string; units: number; cost_estimate: number }[];747  per_1000_companies: number | null;748  per_million_observations: number | null;749  per_meaningful_event: number | null;750}751export type AdminCompany = CompanyCard;752
Files · 29c7c57991d673047cedee8dbbb57153879cc875
Menu

Theme