| 1 | |
| 2 | |
| 3 | export type Category = "concert" | "sports" | "festival" | "theater" | "other"; |
| 4 | export type Sport = "nfl" | "nba" | "nhl" | "mlb" | "tennis" | "f1" | "soccer" | "other"; |
| 5 | export type EventStatus = "announced" | "presale" | "onsale" | "soldout" | "cancelled"; |
| 6 | export type DropType = "new" | "status" | "price" | "inventory" | "announcement"; |
| 7 | export type SourceCategory = "primary" | "resale" | "scraper"; |
| 8 | export type SourceStatus = "healthy" | "degraded" | "down" | "disabled"; |
| 9 | export type WatchlistKind = |
| 10 | | "artist" |
| 11 | | "team" |
| 12 | | "venue" |
| 13 | | "sport" |
| 14 | | "category" |
| 15 | | "keyword" |
| 16 | | "twitter_account"; |
| 17 | export type Priority = "low" | "normal" | "high" | "critical"; |
| 18 | |
| 19 | export interface ApiMeta { |
| 20 | request_id: string; |
| 21 | version: string; |
| 22 | page?: number; |
| 23 | per_page?: number; |
| 24 | total?: number; |
| 25 | total_pages?: number; |
| 26 | } |
| 27 | |
| 28 | export interface ApiCollection<T> { |
| 29 | data: T[]; |
| 30 | meta: ApiMeta; |
| 31 | } |
| 32 | |
| 33 | export interface ApiResource<T> { |
| 34 | data: T; |
| 35 | meta: ApiMeta; |
| 36 | } |
| 37 | |
| 38 | export interface ApiErrorBody { |
| 39 | error: { |
| 40 | code: string; |
| 41 | message: string; |
| 42 | request_id: string; |
| 43 | details?: { fields?: Array<{ field: string; message: string }> } & Record<string, unknown>; |
| 44 | }; |
| 45 | } |
| 46 | |
| 47 | export interface TicketEvent { |
| 48 | id: number; |
| 49 | source_id: string; |
| 50 | source_event_id: string; |
| 51 | title: string; |
| 52 | subtitle: string | null; |
| 53 | category: Category; |
| 54 | sport: Sport | null; |
| 55 | starts_at: string | null; |
| 56 | venue_name: string | null; |
| 57 | city: string | null; |
| 58 | country: string | null; |
| 59 | latitude: number | null; |
| 60 | longitude: number | null; |
| 61 | image_url: string | null; |
| 62 | on_sale_at: string | null; |
| 63 | presale_on_sale_at: string | null; |
| 64 | status: EventStatus; |
| 65 | price_min: number | null; |
| 66 | price_max: number | null; |
| 67 | currency: string; |
| 68 | inventory_remaining: number | null; |
| 69 | buy_url: string; |
| 70 | seatmap_url: string | null; |
| 71 | first_seen_at: string; |
| 72 | updated_at: string; |
| 73 | } |
| 74 | |
| 75 | export interface Drop { |
| 76 | id: number; |
| 77 | event_id: number; |
| 78 | drop_type: DropType; |
| 79 | from_state: Record<string, unknown> | null; |
| 80 | to_state: Record<string, unknown> | null; |
| 81 | detected_at: string; |
| 82 | notified: boolean; |
| 83 | notified_at: string | null; |
| 84 | event: TicketEvent; |
| 85 | } |
| 86 | |
| 87 | export interface WatchlistRule { |
| 88 | id: number; |
| 89 | kind: WatchlistKind; |
| 90 | pattern: string; |
| 91 | label: string; |
| 92 | active: boolean; |
| 93 | priority: Priority; |
| 94 | matches_30d: number; |
| 95 | created_at: string; |
| 96 | } |
| 97 | |
| 98 | export interface WatchlistCreate { |
| 99 | kind: WatchlistKind; |
| 100 | pattern: string; |
| 101 | label: string; |
| 102 | priority?: Priority; |
| 103 | } |
| 104 | |
| 105 | export interface Source { |
| 106 | id: string; |
| 107 | name: string; |
| 108 | category: SourceCategory; |
| 109 | enabled: boolean; |
| 110 | status: SourceStatus; |
| 111 | last_poll_at: string | null; |
| 112 | last_success_at: string | null; |
| 113 | last_error: string | null; |
| 114 | consecutive_failures: number; |
| 115 | poll_interval_s: number; |
| 116 | tight_interval_s: number; |
| 117 | latency_ms_p50: number | null; |
| 118 | latency_ms_p95: number | null; |
| 119 | events_seen_24h: number; |
| 120 | } |
| 121 | |
| 122 | export interface Stats { |
| 123 | drops_24h: number; |
| 124 | drops_7d: number; |
| 125 | sources_healthy: number; |
| 126 | sources_total: number; |
| 127 | sources_down: number; |
| 128 | watchlist_matches_24h: number; |
| 129 | detection_latency_ms_p50: number; |
| 130 | detection_latency_ms_p99: number; |
| 131 | events_tracked: number; |
| 132 | events_onsale_now: number; |
| 133 | } |
| 134 | |
| 135 | export type StreamEventName = |
| 136 | | "drop.new" |
| 137 | | "drop.status" |
| 138 | | "drop.price" |
| 139 | | "drop.inventory" |
| 140 | | "drop.announcement" |
| 141 | | "source.health" |
| 142 | | "system.info"; |