propline 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -93,6 +93,7 @@ Every odds response returns a `bookmakers` array so you can compare lines across
93
93
  | `pinnacle` | Pinnacle | MLB (game lines + props), NBA/NHL/soccer (game lines, goalie saves) |
94
94
  | `unibet` | Unibet | MLB/NBA/NHL + 6 soccer leagues — game lines; player props on NBA, NHL, soccer |
95
95
  | `prizepicks` | PrizePicks (DFS) | MLB, NBA, NHL, 9 soccer leagues — player props only; synthetic +100/+100 even-money pricing since DFS payouts scale with parlay correct-count, not per-pick odds |
96
+ | `underdog` | Underdog Fantasy (DFS) | MLB, NBA, NHL, tennis, UFC, 9 soccer leagues — player props with real two-way American prices and a `payout_multiplier` on boosted/discounted picks (`null` = standard 1.0 pick; e.g. `1.5` boost / `0.75` discount). Filter out non-null multipliers when comparing DFS lines to sportsbook consensus |
96
97
 
97
98
  ```ts
98
99
  import { PropLine, Bookmakers } from "propline";
package/dist/index.cjs CHANGED
@@ -713,7 +713,7 @@ var Bookmakers = {
713
713
  POLYMARKET: "polymarket",
714
714
  PRIZEPICKS: "prizepicks"
715
715
  };
716
- var VERSION = "0.15.0";
716
+ var VERSION = "0.16.0";
717
717
  // Annotate the CommonJS export names for ESM import in node:
718
718
  0 && (module.exports = {
719
719
  AuthError,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["/**\n * PropLine — Node/TypeScript SDK for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const events = await client.getEvents(\"basketball_nba\");\n * const odds = await client.getOdds(\"basketball_nba\", {\n * eventId: events[0].id,\n * markets: [\"player_points\", \"player_rebounds\"],\n * });\n * ```\n */\n\nexport { PropLine } from \"./client.js\";\nexport {\n PropLineError,\n AuthError,\n RateLimitError,\n} from \"./client.js\";\nexport type {\n PropLineOptions,\n GetOddsOptions,\n GetOddsHistoryOptions,\n GetOddsClosingOptions,\n PeriodFilter,\n GetScoresOptions,\n GetMlbGrandSalamiOptions,\n GetNhlDailyGoalsTotalOptions,\n GetStatsOptions,\n GetResultsOptions,\n GetPlayerHistoryOptions,\n GetPlayerTrendsOptions,\n GetEventEvOptions,\n GetEventBestLineOptions,\n CalcEventEvOptions,\n ExportResolvedPropsOptions,\n ExportOddsHistoryOptions,\n WebhookEventType,\n CreateWebhookOptions,\n UpdateWebhookOptions,\n ListWebhookDeliveriesOptions,\n VerifySignatureOptions,\n} from \"./client.js\";\n\nexport type {\n Sport,\n Event,\n Outcome,\n ResolvedOutcome,\n Market,\n Bookmaker,\n OddsResponse,\n MarketSummary,\n OutcomeSnapshot,\n OddsHistoryOutcome,\n OddsHistoryMarket,\n OddsHistoryBookmaker,\n OddsHistoryResponse,\n ClosingOutcome,\n ClosingMarket,\n ClosingBookmaker,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiBook,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalBook,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n ResolutionSummarySport,\n ResolutionSummaryMarket,\n PlayerStat,\n StatsResponse,\n WeatherInfo,\n ContextResponse,\n MovementOutcome,\n MovementMarket,\n MovementBookmaker,\n SteamMove,\n MovementResponse,\n ResultsMarket,\n ResultsResponse,\n PlayerHistoryEntry,\n PlayerHistoryResponse,\n HitRateSplit,\n TrendStreak,\n TrendLastGame,\n PlayerMarketTrend,\n PlayerTrends,\n EvOutcome,\n EvLine,\n EventEvResponse,\n EventEvCalcResponse,\n BestPrice,\n BestLineSide,\n BestLine,\n EventBestLineResponse,\n FuturesOutcome,\n FuturesMarket,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** String constants for bookmaker keys in odds responses. */\nexport const Bookmakers = {\n BOVADA: \"bovada\",\n DRAFTKINGS: \"draftkings\",\n FANDUEL: \"fanduel\",\n PINNACLE: \"pinnacle\",\n UNIBET: \"unibet\",\n UNDERDOG: \"underdog\",\n KALSHI: \"kalshi\",\n POLYMARKET: \"polymarket\",\n PRIZEPICKS: \"prizepicks\",\n} as const;\n\nexport type BookmakerKey = (typeof Bookmakers)[keyof typeof Bookmakers];\n\nexport const VERSION = \"0.15.0\";\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport type {\n Sport,\n Event as PropLineEvent,\n OddsResponse,\n MarketSummary,\n OddsHistoryResponse,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n StatsResponse,\n ContextResponse,\n MovementResponse,\n ResultsResponse,\n PlayerHistoryResponse,\n PlayerTrends,\n EventEvResponse,\n EventEvCalcResponse,\n EventBestLineResponse,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** Base error for all PropLine API failures. */\nexport class PropLineError extends Error {\n readonly statusCode: number;\n readonly detail: string;\n\n constructor(statusCode: number, detail: string) {\n super(`[${statusCode}] ${detail}`);\n this.name = \"PropLineError\";\n this.statusCode = statusCode;\n this.detail = detail;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the API key is missing or invalid (HTTP 401). */\nexport class AuthError extends PropLineError {\n constructor(detail = \"Invalid API key\") {\n super(401, detail);\n this.name = \"AuthError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the daily request limit is exceeded (HTTP 429). */\nexport class RateLimitError extends PropLineError {\n constructor(detail = \"Rate limit exceeded\") {\n super(429, detail);\n this.name = \"RateLimitError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport interface PropLineOptions {\n /** API base URL. Default: `https://api.prop-line.com/v1`. */\n baseUrl?: string;\n /** Request timeout in milliseconds. Default: 15000. */\n timeoutMs?: number;\n /** Custom fetch implementation. Defaults to global `fetch` (Node 18+). */\n fetch?: typeof fetch;\n}\n\n/**\n * Game-period filter. String of canonical codes, optionally\n * comma-separated, or the sentinel `\"all\"`. Omitted = full-game\n * markets only (backwards-compatible default).\n *\n * \"q1\" — 1st quarter\n * \"q1,q2\" — 1st and 2nd quarters\n * [\"q1\",\"q2\"] — same, as an array\n * \"h1\" — 1st half\n * \"p1\"|\"p2\"|\"p3\" — hockey periods\n * \"i6\" — 6th inning\n * \"f3\"|\"f5\"|\"f7\" — first N innings\n * \"all\" — every period including full game\n */\nexport type PeriodFilter = string | string[];\n\nexport interface GetOddsOptions {\n /** Specific event ID to get odds (with player props) for. Omit for bulk odds. */\n eventId?: number | string;\n /**\n * Market keys to filter by. If omitted, the bulk `/odds` endpoint\n * defaults to `h2h` and the per-event `/odds` endpoint defaults to\n * `h2h,spreads,totals` — game-line markets every book carries across\n * every sport. Pass an explicit list to fetch player props (e.g.\n * `[\"pitcher_strikeouts\", \"batter_home_runs\"]` for MLB,\n * `[\"player_points\", \"player_rebounds\"]` for NBA).\n */\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsHistoryOptions {\n markets?: string[];\n /** ISO timestamp; only include snapshots at or after this time. Mutually exclusive with `relativeFrom`. */\n from?: string;\n /** ISO timestamp; only include snapshots at or before this time. Mutually exclusive with `relativeTo`. */\n to?: string;\n /** Offset relative to commence_time, e.g. \"-3h\", \"-30m\", \"-90s\". Mutually exclusive with `from`. */\n relativeFrom?: string;\n /** Offset relative to commence_time, e.g. \"-1m\" or \"0\" for commence_time itself. Mutually exclusive with `to`. */\n relativeTo?: string;\n /** Downsample to one snapshot per bucket. Latest snapshot in each bucket wins. */\n interval?: \"30s\" | \"1m\" | \"5m\" | \"15m\" | \"30m\" | \"1h\";\n /** When true, drop snapshots whose (price, point) match the previous one. Opening line is always kept. */\n changesOnly?: boolean;\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsClosingOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetMovementOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nfunction _periodParam(p: PeriodFilter | undefined): string | undefined {\n if (p === undefined) return undefined;\n return typeof p === \"string\" ? p : p.join(\",\");\n}\n\nexport interface GetScoresOptions {\n /** Days back to include (default 3). */\n daysFrom?: number;\n}\n\nexport interface GetMlbGrandSalamiOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetNhlDailyGoalsTotalOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetStatsOptions {\n /** Stat types to filter by (e.g. `[\"strikeouts\", \"hits\"]`). */\n statType?: string[];\n}\n\nexport interface GetResultsOptions {\n markets?: string[];\n}\n\nexport interface GetPlayerHistoryOptions {\n /** Market key (e.g. `\"pitcher_strikeouts\"`). Required. */\n market: string;\n /** Restrict to a single bookmaker (e.g. `\"draftkings\"`). */\n bookmaker?: string;\n /** Max entries (1-100). Default 20. */\n limit?: number;\n}\n\nexport interface GetPlayerTrendsOptions {\n /** Market key (e.g. `\"batter_total_bases\"`). Omit for all markets. */\n market?: string;\n}\n\nexport interface GetEventEvOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"batter_hits\"]`).\n * Omit to evaluate every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface GetEventBestLineOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"h2h\"]`). Omit\n * to include every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface CalcEventEvOptions {\n /** Market key — h2h / spreads / totals / pitcher_strikeouts / etc. */\n market: string;\n /** Outcome name. Team for h2h/spreads; \"Over\" or \"Under\" for totals/props. */\n name: string;\n /** American odds at your book, e.g. -118 or 145. */\n price: number;\n /** Line/point for spreads, totals, player props. Sign matters for spreads (-1.5 favorite). Omit for h2h. */\n point?: number;\n /** Player name for player-prop markets. Omit for game-line markets. */\n description?: string;\n}\n\nexport interface ExportResolvedPropsOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `resolved_at`. */\n since?: string;\n /** ISO datetime upper bound on `resolved_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\nexport interface ExportOddsHistoryOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `recorded_at`. */\n since?: string;\n /** ISO datetime upper bound on `recorded_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\n/** Webhook event types. `steam` = cross-book sharp-money alert. */\nexport type WebhookEventType = \"line_movement\" | \"resolution\" | \"steam\";\n\nexport interface CreateWebhookOptions {\n /** HTTPS endpoint to receive POSTed events. Required. */\n url: string;\n /** Event types to subscribe to. Default: all. */\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n /** Minimum % change in American odds to fire a line_movement. Point-only shifts always pass. */\n minPriceChangePct?: number;\n /** Minimum 0-100 steam score to fire a `steam` event. Null = detector's global floor. */\n minSteamScore?: number;\n}\n\nexport interface UpdateWebhookOptions {\n url?: string;\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n minPriceChangePct?: number;\n minSteamScore?: number;\n active?: boolean;\n}\n\nexport interface ListWebhookDeliveriesOptions {\n /** Max deliveries to return. Default 50. */\n limit?: number;\n}\n\nexport interface VerifySignatureOptions {\n /** Webhook signing secret (returned once from `createWebhook`). */\n secret: string;\n /** Value of the `X-PropLine-Timestamp` header. */\n timestamp: string;\n /** Raw request body. */\n body: Uint8Array | Buffer | string;\n /** Value of the `X-PropLine-Signature` header. */\n signature: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.prop-line.com/v1\";\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\n/**\n * Client for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const sports = await client.getSports();\n * ```\n */\nexport class PropLine {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeoutMs: number;\n private readonly _fetch: typeof fetch;\n\n constructor(apiKey: string, options: PropLineOptions = {}) {\n if (!apiKey) {\n throw new Error(\"PropLine: apiKey is required\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this._fetch = options.fetch ?? globalThis.fetch;\n if (!this._fetch) {\n throw new Error(\n \"PropLine: global fetch is unavailable. Use Node 18+ or pass options.fetch.\"\n );\n }\n }\n\n // ------------------------------------------------------------------\n // Internals\n // ------------------------------------------------------------------\n\n private _buildUrl(path: string, params?: Record<string, string | number | undefined>): string {\n const url = new URL(`${this.baseUrl}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) {\n url.searchParams.set(k, String(v));\n }\n }\n }\n return url.toString();\n }\n\n private async _request<T>(\n method: string,\n path: string,\n init: { params?: Record<string, string | number | undefined>; body?: unknown } = {}\n ): Promise<T> {\n const url = this._buildUrl(path, init.params);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method,\n headers: {\n \"X-API-Key\": this.apiKey,\n ...(init.body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n },\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError(await readDetail(resp, \"Invalid API key\"));\n }\n if (resp.status === 429) {\n throw new RateLimitError(await readDetail(resp, \"Rate limit exceeded\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n if (resp.status === 204) {\n return undefined as T;\n }\n return (await resp.json()) as T;\n }\n\n // ------------------------------------------------------------------\n // Public API\n // ------------------------------------------------------------------\n\n /** List all available sports. */\n getSports(): Promise<Sport[]> {\n return this._request<Sport[]>(\"GET\", \"/sports\");\n }\n\n /** List upcoming events for a sport. */\n getEvents(sport: string): Promise<PropLineEvent[]> {\n return this._request<PropLineEvent[]>(\"GET\", `/sports/${encodeURIComponent(sport)}/events`);\n }\n\n /**\n * Get current odds. With `eventId`, returns single-event odds (including\n * player props). Without, returns bulk odds for all upcoming events.\n *\n * Each response carries a `bookmakers` array — iterate it to compare\n * lines across Bovada, DraftKings, FanDuel, Pinnacle, Unibet, and\n * PrizePicks (coverage varies by sport).\n */\n getOdds(\n sport: string,\n options: GetOddsOptions & { eventId: number | string }\n ): Promise<OddsResponse>;\n getOdds(\n sport: string,\n options?: Omit<GetOddsOptions, \"eventId\"> & { eventId?: undefined }\n ): Promise<OddsResponse[]>;\n getOdds(\n sport: string,\n options: GetOddsOptions = {}\n ): Promise<OddsResponse | OddsResponse[]> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam = _periodParam(options.period);\n if (periodParam !== undefined) params.period = periodParam;\n const sp = encodeURIComponent(sport);\n if (options.eventId !== undefined) {\n return this._request<OddsResponse>(\n \"GET\",\n `/sports/${sp}/events/${encodeURIComponent(String(options.eventId))}/odds`,\n { params }\n );\n }\n return this._request<OddsResponse[]>(\"GET\", `/sports/${sp}/odds`, { params });\n }\n\n /** List the available market types for an event. */\n getMarkets(sport: string, eventId: number | string): Promise<MarketSummary[]> {\n return this._request<MarketSummary[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/markets`\n );\n }\n\n /**\n * Get historical odds movement for an event.\n *\n * Hobby+: full snapshots. Free tier: redacted (snapshot counts only).\n *\n * Supports period-historical filters:\n * - `from` / `to` — absolute ISO timestamps\n * - `relativeFrom` / `relativeTo` — offsets to commence_time (\"-3h\", \"-30m\", \"0\")\n * - `interval` — downsample to a fixed bucket size\n * - `changesOnly` — drop unchanged adjacent snapshots\n */\n getOddsHistory(\n sport: string,\n eventId: number | string,\n options: GetOddsHistoryOptions = {}\n ): Promise<OddsHistoryResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n if (options.from !== undefined) params.from = options.from;\n if (options.to !== undefined) params.to = options.to;\n if (options.relativeFrom !== undefined) params.relative_from = options.relativeFrom;\n if (options.relativeTo !== undefined) params.relative_to = options.relativeTo;\n if (options.interval !== undefined) params.interval = options.interval;\n if (options.changesOnly) params.changes_only = \"true\";\n const periodParam2 = _periodParam(options.period);\n if (periodParam2 !== undefined) params.period = periodParam2;\n return this._request<OddsHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/history`,\n { params }\n );\n }\n\n /**\n * Get the closing line per `(book, market, outcome)` for an event —\n * the last snapshot at or before commence_time. Canonical CLV helper:\n * replaces \"fetch full history → find latest pre-game row\" with one\n * call. Each outcome carries a `closingAt` field with the snapshot's\n * recorded_at timestamp.\n *\n * Hobby+: full data. Free tier: redacted.\n */\n getOddsClosing(\n sport: string,\n eventId: number | string,\n options: GetOddsClosingOptions = {}\n ): Promise<OddsClosingResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam3 = _periodParam(options.period);\n if (periodParam3 !== undefined) params.period = periodParam3;\n return this._request<OddsClosingResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/closing`,\n { params }\n );\n }\n\n /** Get game scores and status (free tier). */\n getScores(sport: string, options: GetScoresOptions = {}): Promise<ScoreEvent[]> {\n return this._request<ScoreEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/scores`,\n { params: { days_from: options.daysFrom ?? 3 } }\n );\n }\n\n /**\n * Synthetic MLB Grand Salami for a given UTC date — total runs scored\n * across every MLB game on the slate, plus each book's implied Grand\n * Salami line (median of per-game primary totals across our MLB books).\n *\n * No retail sportsbook quotes this as a single market, so historical\n * cross-book Grand Salami data isn't available elsewhere. Free tier;\n * defaults to today (UTC).\n */\n getMlbGrandSalami(\n options: GetMlbGrandSalamiOptions = {}\n ): Promise<MlbGrandSalamiResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<MlbGrandSalamiResponse>(\n \"GET\",\n \"/sports/baseball_mlb/grand-salami\",\n { params }\n );\n }\n\n /**\n * Synthetic NHL Daily Goals Total for a given UTC date — total goals\n * scored (incl. OT/SO) across every NHL game on the slate, plus each\n * book's implied Daily Goals Total line (median of per-game primary\n * totals across our NHL books).\n *\n * Hockey's equivalent of the MLB Grand Salami. No retail sportsbook\n * quotes this as a single market. Free tier; defaults to today (UTC).\n */\n getNhlDailyGoalsTotal(\n options: GetNhlDailyGoalsTotalOptions = {}\n ): Promise<NhlDailyGoalsTotalResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<NhlDailyGoalsTotalResponse>(\n \"GET\",\n \"/sports/hockey_nhl/daily-goals-total\",\n { params }\n );\n }\n\n /**\n * Factual volume of graded player props over the last N days (free tier).\n *\n * Aggregated counts only — a coverage proof (every outcome counted was\n * graded against the real box score), never a profitability claim.\n *\n * @param days Look-back window, 1-90 (default 30).\n */\n getResolutionSummary(days = 30): Promise<ResolutionSummary> {\n return this._request<ResolutionSummary>(\n \"GET\",\n \"/markets/resolution-summary\",\n { params: { days: String(days) } }\n );\n }\n\n /**\n * Get raw player/team box-score stats (book-agnostic, free tier).\n *\n * Returns actual stat values decoupled from any bookmaker's lines.\n */\n getStats(\n sport: string,\n eventId: number | string,\n options: GetStatsOptions = {}\n ): Promise<StatsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.statType?.length) {\n params.stat_type = options.statType.join(\",\");\n }\n return this._request<StatsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/stats`,\n { params }\n );\n }\n\n /**\n * Get game context — the conditions a prop settles under.\n *\n * For MLB: probable starting pitchers and their throwing hand\n * (`home_probable_pitcher_hand` / `away_probable_pitcher_hand`, \"L\"/\"R\"/\"S\"\n * — platoon-split context for every batter prop), a confirmed-lineup flag,\n * the home-plate umpire, and first-pitch weather (outdoor / open-roof\n * venues; indoor venues return `weather: null` with `is_indoor: true`).\n * For NFL & NCAAF: the venue and kickoff weather (pitcher/umpire/lineup\n * fields are null for football). The same block is embedded in\n * {@link getResults}, so every graded prop carries its conditions — unique\n * to PropLine. Free tier. Rejects with a 404 when no context is on file\n * for the event yet.\n */\n getContext(\n sport: string,\n eventId: number | string\n ): Promise<ContextResponse> {\n return this._request<ContextResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/context`\n );\n }\n\n /**\n * Get line movement + steam detection from the snapshot tick history.\n *\n * Per (book, market, outcome): opening line, latest line, signed\n * implied-probability shift, point shift, direction. The `steam` array\n * flags outcomes multiple books moved the same direction — the\n * sharp-money signal across every book PropLine polls. When a book moves\n * the line itself, that outcome's `prob_shift` is null and `direction` is\n * `\"line_moved\"` (excluded from the steam signal). Unique to PropLine.\n * Hobby+ full; free tier redacted.\n */\n getMovement(\n sport: string,\n eventId: number | string,\n options: GetMovementOptions = {}\n ): Promise<MovementResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n params.period = _periodParam(options.period);\n return this._request<MovementResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/movement`,\n { params }\n );\n }\n\n /**\n * Get resolved prop outcomes with actual player stats.\n *\n * Pro tier: full data. Free tier: redacted (resolution + actual nulled).\n */\n getResults(\n sport: string,\n eventId: number | string,\n options: GetResultsOptions = {}\n ): Promise<ResultsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n return this._request<ResultsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/results`,\n { params }\n );\n }\n\n /**\n * Recent resolved prop history for a player on a market.\n *\n * One entry per (event, bookmaker) pair. Pro: full. Free: redacted.\n */\n getPlayerHistory(\n sport: string,\n playerName: string,\n options: GetPlayerHistoryOptions\n ): Promise<PlayerHistoryResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n limit: options.limit ?? 20,\n };\n if (options.bookmaker) {\n params.bookmaker = options.bookmaker;\n }\n return this._request<PlayerHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/players/${encodeURIComponent(playerName)}/history`,\n { params }\n );\n }\n\n /**\n * Rolling hit-rate trends for a player across one or all markets.\n *\n * Returns over/under/push splits over the last 5/10/20/50 graded games,\n * the current streak, and the most recent game per market. Pro: full.\n * Free: redacted.\n */\n getPlayerTrends(\n sportKey: string,\n playerName: string,\n options: GetPlayerTrendsOptions = {}\n ): Promise<PlayerTrends> {\n const params: Record<string, string | undefined> = {};\n if (options.market) {\n params.market = options.market;\n }\n return this._request<PlayerTrends>(\n \"GET\",\n `/sports/${encodeURIComponent(sportKey)}/players/${encodeURIComponent(playerName)}/trends`,\n { params }\n );\n }\n\n /**\n * Cross-book +EV analysis for a single event (Pro+ tier).\n *\n * Groups every outcome by (market, player, line) across the books we\n * carry, derives a no-vig fair line from a sharp anchor (Pinnacle\n * preferred, Bovada fallback), and returns EV% per book at the same\n * line. Outcomes are sorted with +EV plays floated to the top.\n *\n * PrizePicks is excluded — its synthetic +100/+100 prices aren't\n * payout odds. Lines without sharp-anchor coverage are dropped.\n *\n * @example\n * ```ts\n * const ev = await client.getEventEv(\"baseball_mlb\", 12345);\n * for (const line of ev.lines) {\n * const plus = line.outcomes.filter(o => o.is_plus_ev);\n * if (plus.length) console.log(line.market_key, line.description, plus);\n * }\n * ```\n */\n /**\n * List futures markets for a sport — championship winner, MVP,\n * division winner, etc. Each row is one (futures event, book,\n * market) with every team or player priced. Free tier; pulled from\n * each book's futures feed (Bovada today).\n *\n * @example\n * ```ts\n * const futures = await client.getFutures(\"baseball_mlb\");\n * for (const event of futures) {\n * console.log(`${event.title} @ ${event.commence_time}`);\n * for (const m of event.markets) {\n * const top3 = [...m.outcomes].sort((a, b) => a.price - b.price).slice(0, 3);\n * for (const o of top3) console.log(` ${o.name}: ${o.price}`);\n * }\n * }\n * ```\n */\n getFutures(sport: string): Promise<FuturesEvent[]> {\n return this._request<FuturesEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/futures`\n );\n }\n\n getEventEv(\n sport: string,\n eventId: number | string,\n options: GetEventEvOptions = {}\n ): Promise<EventEvResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventEvResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev`,\n { params }\n );\n }\n\n /**\n * Cross-book best-line lookup for a single event.\n *\n * For each (market, player, line) tuple, returns the single best\n * American price across every book we carry, with the book name\n * attached. Companion to `getEventEv`: best-line tells you which\n * book has the highest payout right now; +EV tells you whether\n * that price beats a sharp no-vig fair line. Most line shoppers\n * want both.\n *\n * PrizePicks is excluded from the comparison — its DFS payout\n * structure (synthetic +100/+100 quotes) isn't directly comparable\n * to traditional sportsbook odds.\n *\n * Hobby tier or higher required (returns 403 on free).\n *\n * @example\n * ```ts\n * const bl = await client.getEventBestLine(\"baseball_mlb\", 12345);\n * for (const line of bl.lines) {\n * for (const [side, info] of Object.entries(line.sides)) {\n * console.log(\n * `${line.description} ${side} ${line.point}: ` +\n * `${info.best.price} @ ${info.best.book_title}`\n * );\n * }\n * }\n * ```\n */\n getEventBestLine(\n sport: string,\n eventId: number | string,\n options: GetEventBestLineOptions = {}\n ): Promise<EventBestLineResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventBestLineResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/best-line`,\n { params }\n );\n }\n\n /**\n * Calculate EV% for a user-supplied price against the event's\n * no-vig fair anchor. Useful for books PropLine doesn't carry —\n * Caesars, BetMGM, Fanatics, BetUS, Hard Rock — where you have a\n * price in hand and want to know if it's +EV against the sharp\n * consensus we do carry.\n *\n * Same fair-line math as `getEventEv` (Pinnacle-preferred anchor,\n * no-vig devigging) but takes one user price as input. Pro tier.\n *\n * @example\n * ```ts\n * const r = await client.calcEventEv(\"baseball_mlb\", 12614, {\n * market: \"h2h\",\n * name: \"Pittsburgh Pirates\",\n * price: -118,\n * });\n * console.log(`EV ${r.ev_pct}% fair=${r.fair_prob}`);\n * ```\n */\n calcEventEv(\n sport: string,\n eventId: number | string,\n options: CalcEventEvOptions\n ): Promise<EventEvCalcResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n name: options.name,\n price: options.price,\n };\n if (options.point !== undefined) params.point = options.point;\n if (options.description) params.description = options.description;\n return this._request<EventEvCalcResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev/calc`,\n { params }\n );\n }\n\n /**\n * Bulk CSV export of resolved prop outcomes (Pro+ tier).\n *\n * If `outPath` is provided, streams the CSV to disk and resolves to the\n * path. Otherwise resolves to the full CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportResolvedProps({\n * sport: \"baseball_mlb\",\n * market: \"pitcher_strikeouts\",\n * since: \"2026-04-01T00:00:00Z\",\n * outPath: \"./mlb-strikeouts.csv\",\n * });\n * ```\n */\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath: string }\n ): Promise<string>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/resolved-props\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(403, await readDetail(resp, \"Pro tier required\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n /**\n * Bulk CSV export of the full line-movement time-series.\n *\n * One row per (outcome, snapshot): every recorded odds snapshot (price +\n * line, per book, including period markets), not just the closing line.\n * This is the raw tick history no subscription tier can pull in bulk —\n * Pro/Streaming get per-event {@link getOddsHistory} only; this bulk\n * firehose is exclusive to the one-time Historical Backfill pass and\n * Enterprise.\n *\n * A full archive runs to gigabytes per sport — page month by month with\n * `since`/`until`. If `outPath` is provided, streams to disk and resolves\n * to the path; otherwise resolves to the CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportOddsHistory({\n * sport: \"baseball_mlb\",\n * since: \"2026-04-01T00:00:00Z\",\n * until: \"2026-05-01T00:00:00Z\",\n * outPath: \"./mlb-line-history-apr.csv\",\n * });\n * ```\n */\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath: string }\n ): Promise<string>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/odds-history\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(\n 403,\n await readDetail(resp, \"Historical Backfill pass or Enterprise required\")\n );\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n // ------------------------------------------------------------------\n // Webhooks (Streaming tier)\n // ------------------------------------------------------------------\n\n /**\n * Register a webhook subscription. Streaming tier only.\n *\n * The returned object includes the full signing `secret` — this is the\n * ONLY time it's revealed. Store it securely.\n */\n createWebhook(options: CreateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"POST\", \"/webhooks\", {\n body: webhookBody(options),\n });\n }\n\n /** List your webhook subscriptions. Secrets are masked. */\n listWebhooks(): Promise<Webhook[]> {\n return this._request<Webhook[]>(\"GET\", \"/webhooks\");\n }\n\n /** Get a single webhook subscription. Secret is masked. */\n getWebhook(webhookId: number): Promise<Webhook> {\n return this._request<Webhook>(\"GET\", `/webhooks/${webhookId}`);\n }\n\n /** Update fields on a webhook. Only supplied fields are changed. */\n updateWebhook(webhookId: number, options: UpdateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"PATCH\", `/webhooks/${webhookId}`, {\n body: webhookBody(options),\n });\n }\n\n /** Delete a webhook (cascades its delivery history). */\n deleteWebhook(webhookId: number): Promise<{ ok: boolean } | unknown> {\n return this._request(\"DELETE\", `/webhooks/${webhookId}`);\n }\n\n /** Queue a sample `test` payload to the webhook's URL. */\n testWebhook(webhookId: number): Promise<unknown> {\n return this._request(\"POST\", `/webhooks/${webhookId}/test`);\n }\n\n /** Last 50 (default) delivery attempts for a webhook. */\n listWebhookDeliveries(\n webhookId: number,\n options: ListWebhookDeliveriesOptions = {}\n ): Promise<WebhookDelivery[]> {\n return this._request<WebhookDelivery[]>(\n \"GET\",\n `/webhooks/${webhookId}/deliveries`,\n { params: { limit: options.limit ?? 50 } }\n );\n }\n\n /**\n * Verify that an inbound webhook delivery was signed by PropLine.\n *\n * Compares HMAC-SHA256(secret, `${timestamp}.` + body) against the\n * `X-PropLine-Signature` header in constant time.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * app.post(\"/hooks/propline\", express.raw({ type: \"*\\/*\" }), (req, res) => {\n * const ok = PropLine.verifySignature({\n * secret: process.env.WEBHOOK_SECRET!,\n * timestamp: req.header(\"X-PropLine-Timestamp\")!,\n * body: req.body, // raw Buffer\n * signature: req.header(\"X-PropLine-Signature\")!,\n * });\n * if (!ok) return res.status(401).end();\n * // ...\n * });\n * ```\n */\n static verifySignature(options: VerifySignatureOptions): boolean {\n const { secret, timestamp, body, signature } = options;\n const bodyBuf =\n typeof body === \"string\"\n ? Buffer.from(body, \"utf8\")\n : body instanceof Buffer\n ? body\n : Buffer.from(body);\n const message = Buffer.concat([Buffer.from(`${timestamp}.`, \"utf8\"), bodyBuf]);\n const expected = createHmac(\"sha256\", secret).update(message).digest(\"hex\");\n if (expected.length !== signature.length) return false;\n try {\n return timingSafeEqual(Buffer.from(expected, \"hex\"), Buffer.from(signature, \"hex\"));\n } catch {\n return false;\n }\n }\n}\n\nfunction webhookBody(options: CreateWebhookOptions | UpdateWebhookOptions): Record<string, unknown> {\n const body: Record<string, unknown> = {};\n const map: Array<[keyof (CreateWebhookOptions & UpdateWebhookOptions), string]> = [\n [\"url\", \"url\"],\n [\"events\", \"events\"],\n [\"filterSportKey\", \"filter_sport_key\"],\n [\"filterEventId\", \"filter_event_id\"],\n [\"filterMarketKey\", \"filter_market_key\"],\n [\"filterPlayerName\", \"filter_player_name\"],\n [\"minPriceChangePct\", \"min_price_change_pct\"],\n [\"minSteamScore\", \"min_steam_score\"],\n [\"active\", \"active\"],\n ];\n for (const [src, dst] of map) {\n const v = (options as Record<string, unknown>)[src as string];\n if (v !== undefined) body[dst] = v;\n }\n return body;\n}\n\nasync function readDetail(resp: Response, fallback: string): Promise<string> {\n try {\n const text = await resp.text();\n if (!text) return fallback;\n try {\n const json = JSON.parse(text) as { detail?: unknown };\n if (typeof json.detail === \"string\") return json.detail;\n } catch {\n // not JSON\n }\n return text || fallback;\n } catch {\n return fallback;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["/**\n * PropLine — Node/TypeScript SDK for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const events = await client.getEvents(\"basketball_nba\");\n * const odds = await client.getOdds(\"basketball_nba\", {\n * eventId: events[0].id,\n * markets: [\"player_points\", \"player_rebounds\"],\n * });\n * ```\n */\n\nexport { PropLine } from \"./client.js\";\nexport {\n PropLineError,\n AuthError,\n RateLimitError,\n} from \"./client.js\";\nexport type {\n PropLineOptions,\n GetOddsOptions,\n GetOddsHistoryOptions,\n GetOddsClosingOptions,\n PeriodFilter,\n GetScoresOptions,\n GetMlbGrandSalamiOptions,\n GetNhlDailyGoalsTotalOptions,\n GetStatsOptions,\n GetResultsOptions,\n GetPlayerHistoryOptions,\n GetPlayerTrendsOptions,\n GetEventEvOptions,\n GetEventBestLineOptions,\n CalcEventEvOptions,\n ExportResolvedPropsOptions,\n ExportOddsHistoryOptions,\n WebhookEventType,\n CreateWebhookOptions,\n UpdateWebhookOptions,\n ListWebhookDeliveriesOptions,\n VerifySignatureOptions,\n} from \"./client.js\";\n\nexport type {\n Sport,\n Event,\n Outcome,\n ResolvedOutcome,\n Market,\n Bookmaker,\n OddsResponse,\n MarketSummary,\n OutcomeSnapshot,\n OddsHistoryOutcome,\n OddsHistoryMarket,\n OddsHistoryBookmaker,\n OddsHistoryResponse,\n ClosingOutcome,\n ClosingMarket,\n ClosingBookmaker,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiBook,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalBook,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n ResolutionSummarySport,\n ResolutionSummaryMarket,\n PlayerStat,\n StatsResponse,\n WeatherInfo,\n ContextResponse,\n MovementOutcome,\n MovementMarket,\n MovementBookmaker,\n SteamMove,\n MovementResponse,\n ResultsMarket,\n ResultsResponse,\n PlayerHistoryEntry,\n PlayerHistoryResponse,\n HitRateSplit,\n TrendStreak,\n TrendLastGame,\n PlayerMarketTrend,\n PlayerTrends,\n EvOutcome,\n EvLine,\n EventEvResponse,\n EventEvCalcResponse,\n BestPrice,\n BestLineSide,\n BestLine,\n EventBestLineResponse,\n FuturesOutcome,\n FuturesMarket,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** String constants for bookmaker keys in odds responses. */\nexport const Bookmakers = {\n BOVADA: \"bovada\",\n DRAFTKINGS: \"draftkings\",\n FANDUEL: \"fanduel\",\n PINNACLE: \"pinnacle\",\n UNIBET: \"unibet\",\n UNDERDOG: \"underdog\",\n KALSHI: \"kalshi\",\n POLYMARKET: \"polymarket\",\n PRIZEPICKS: \"prizepicks\",\n} as const;\n\nexport type BookmakerKey = (typeof Bookmakers)[keyof typeof Bookmakers];\n\nexport const VERSION = \"0.16.0\";\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport type {\n Sport,\n Event as PropLineEvent,\n OddsResponse,\n MarketSummary,\n OddsHistoryResponse,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n StatsResponse,\n ContextResponse,\n MovementResponse,\n ResultsResponse,\n PlayerHistoryResponse,\n PlayerTrends,\n EventEvResponse,\n EventEvCalcResponse,\n EventBestLineResponse,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** Base error for all PropLine API failures. */\nexport class PropLineError extends Error {\n readonly statusCode: number;\n readonly detail: string;\n\n constructor(statusCode: number, detail: string) {\n super(`[${statusCode}] ${detail}`);\n this.name = \"PropLineError\";\n this.statusCode = statusCode;\n this.detail = detail;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the API key is missing or invalid (HTTP 401). */\nexport class AuthError extends PropLineError {\n constructor(detail = \"Invalid API key\") {\n super(401, detail);\n this.name = \"AuthError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the daily request limit is exceeded (HTTP 429). */\nexport class RateLimitError extends PropLineError {\n constructor(detail = \"Rate limit exceeded\") {\n super(429, detail);\n this.name = \"RateLimitError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport interface PropLineOptions {\n /** API base URL. Default: `https://api.prop-line.com/v1`. */\n baseUrl?: string;\n /** Request timeout in milliseconds. Default: 15000. */\n timeoutMs?: number;\n /** Custom fetch implementation. Defaults to global `fetch` (Node 18+). */\n fetch?: typeof fetch;\n}\n\n/**\n * Game-period filter. String of canonical codes, optionally\n * comma-separated, or the sentinel `\"all\"`. Omitted = full-game\n * markets only (backwards-compatible default).\n *\n * \"q1\" — 1st quarter\n * \"q1,q2\" — 1st and 2nd quarters\n * [\"q1\",\"q2\"] — same, as an array\n * \"h1\" — 1st half\n * \"p1\"|\"p2\"|\"p3\" — hockey periods\n * \"i6\" — 6th inning\n * \"f3\"|\"f5\"|\"f7\" — first N innings\n * \"all\" — every period including full game\n */\nexport type PeriodFilter = string | string[];\n\nexport interface GetOddsOptions {\n /** Specific event ID to get odds (with player props) for. Omit for bulk odds. */\n eventId?: number | string;\n /**\n * Market keys to filter by. If omitted, the bulk `/odds` endpoint\n * defaults to `h2h` and the per-event `/odds` endpoint defaults to\n * `h2h,spreads,totals` — game-line markets every book carries across\n * every sport. Pass an explicit list to fetch player props (e.g.\n * `[\"pitcher_strikeouts\", \"batter_home_runs\"]` for MLB,\n * `[\"player_points\", \"player_rebounds\"]` for NBA).\n */\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsHistoryOptions {\n markets?: string[];\n /** ISO timestamp; only include snapshots at or after this time. Mutually exclusive with `relativeFrom`. */\n from?: string;\n /** ISO timestamp; only include snapshots at or before this time. Mutually exclusive with `relativeTo`. */\n to?: string;\n /** Offset relative to commence_time, e.g. \"-3h\", \"-30m\", \"-90s\". Mutually exclusive with `from`. */\n relativeFrom?: string;\n /** Offset relative to commence_time, e.g. \"-1m\" or \"0\" for commence_time itself. Mutually exclusive with `to`. */\n relativeTo?: string;\n /** Downsample to one snapshot per bucket. Latest snapshot in each bucket wins. */\n interval?: \"30s\" | \"1m\" | \"5m\" | \"15m\" | \"30m\" | \"1h\";\n /** When true, drop snapshots whose (price, point) match the previous one. Opening line is always kept. */\n changesOnly?: boolean;\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsClosingOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetMovementOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nfunction _periodParam(p: PeriodFilter | undefined): string | undefined {\n if (p === undefined) return undefined;\n return typeof p === \"string\" ? p : p.join(\",\");\n}\n\nexport interface GetScoresOptions {\n /** Days back to include (default 3). */\n daysFrom?: number;\n}\n\nexport interface GetMlbGrandSalamiOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetNhlDailyGoalsTotalOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetStatsOptions {\n /** Stat types to filter by (e.g. `[\"strikeouts\", \"hits\"]`). */\n statType?: string[];\n}\n\nexport interface GetResultsOptions {\n markets?: string[];\n}\n\nexport interface GetPlayerHistoryOptions {\n /** Market key (e.g. `\"pitcher_strikeouts\"`). Required. */\n market: string;\n /** Restrict to a single bookmaker (e.g. `\"draftkings\"`). */\n bookmaker?: string;\n /** Max entries (1-100). Default 20. */\n limit?: number;\n}\n\nexport interface GetPlayerTrendsOptions {\n /** Market key (e.g. `\"batter_total_bases\"`). Omit for all markets. */\n market?: string;\n}\n\nexport interface GetEventEvOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"batter_hits\"]`).\n * Omit to evaluate every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface GetEventBestLineOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"h2h\"]`). Omit\n * to include every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface CalcEventEvOptions {\n /** Market key — h2h / spreads / totals / pitcher_strikeouts / etc. */\n market: string;\n /** Outcome name. Team for h2h/spreads; \"Over\" or \"Under\" for totals/props. */\n name: string;\n /** American odds at your book, e.g. -118 or 145. */\n price: number;\n /** Line/point for spreads, totals, player props. Sign matters for spreads (-1.5 favorite). Omit for h2h. */\n point?: number;\n /** Player name for player-prop markets. Omit for game-line markets. */\n description?: string;\n}\n\nexport interface ExportResolvedPropsOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `resolved_at`. */\n since?: string;\n /** ISO datetime upper bound on `resolved_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\nexport interface ExportOddsHistoryOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `recorded_at`. */\n since?: string;\n /** ISO datetime upper bound on `recorded_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\n/** Webhook event types. `steam` = cross-book sharp-money alert. */\nexport type WebhookEventType = \"line_movement\" | \"resolution\" | \"steam\";\n\nexport interface CreateWebhookOptions {\n /** HTTPS endpoint to receive POSTed events. Required. */\n url: string;\n /** Event types to subscribe to. Default: all. */\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n /** Minimum % change in American odds to fire a line_movement. Point-only shifts always pass. */\n minPriceChangePct?: number;\n /** Minimum 0-100 steam score to fire a `steam` event. Null = detector's global floor. */\n minSteamScore?: number;\n}\n\nexport interface UpdateWebhookOptions {\n url?: string;\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n minPriceChangePct?: number;\n minSteamScore?: number;\n active?: boolean;\n}\n\nexport interface ListWebhookDeliveriesOptions {\n /** Max deliveries to return. Default 50. */\n limit?: number;\n}\n\nexport interface VerifySignatureOptions {\n /** Webhook signing secret (returned once from `createWebhook`). */\n secret: string;\n /** Value of the `X-PropLine-Timestamp` header. */\n timestamp: string;\n /** Raw request body. */\n body: Uint8Array | Buffer | string;\n /** Value of the `X-PropLine-Signature` header. */\n signature: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.prop-line.com/v1\";\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\n/**\n * Client for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const sports = await client.getSports();\n * ```\n */\nexport class PropLine {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeoutMs: number;\n private readonly _fetch: typeof fetch;\n\n constructor(apiKey: string, options: PropLineOptions = {}) {\n if (!apiKey) {\n throw new Error(\"PropLine: apiKey is required\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this._fetch = options.fetch ?? globalThis.fetch;\n if (!this._fetch) {\n throw new Error(\n \"PropLine: global fetch is unavailable. Use Node 18+ or pass options.fetch.\"\n );\n }\n }\n\n // ------------------------------------------------------------------\n // Internals\n // ------------------------------------------------------------------\n\n private _buildUrl(path: string, params?: Record<string, string | number | undefined>): string {\n const url = new URL(`${this.baseUrl}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) {\n url.searchParams.set(k, String(v));\n }\n }\n }\n return url.toString();\n }\n\n private async _request<T>(\n method: string,\n path: string,\n init: { params?: Record<string, string | number | undefined>; body?: unknown } = {}\n ): Promise<T> {\n const url = this._buildUrl(path, init.params);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method,\n headers: {\n \"X-API-Key\": this.apiKey,\n ...(init.body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n },\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError(await readDetail(resp, \"Invalid API key\"));\n }\n if (resp.status === 429) {\n throw new RateLimitError(await readDetail(resp, \"Rate limit exceeded\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n if (resp.status === 204) {\n return undefined as T;\n }\n return (await resp.json()) as T;\n }\n\n // ------------------------------------------------------------------\n // Public API\n // ------------------------------------------------------------------\n\n /** List all available sports. */\n getSports(): Promise<Sport[]> {\n return this._request<Sport[]>(\"GET\", \"/sports\");\n }\n\n /** List upcoming events for a sport. */\n getEvents(sport: string): Promise<PropLineEvent[]> {\n return this._request<PropLineEvent[]>(\"GET\", `/sports/${encodeURIComponent(sport)}/events`);\n }\n\n /**\n * Get current odds. With `eventId`, returns single-event odds (including\n * player props). Without, returns bulk odds for all upcoming events.\n *\n * Each response carries a `bookmakers` array — iterate it to compare\n * lines across Bovada, DraftKings, FanDuel, Pinnacle, Unibet, and\n * PrizePicks (coverage varies by sport).\n */\n getOdds(\n sport: string,\n options: GetOddsOptions & { eventId: number | string }\n ): Promise<OddsResponse>;\n getOdds(\n sport: string,\n options?: Omit<GetOddsOptions, \"eventId\"> & { eventId?: undefined }\n ): Promise<OddsResponse[]>;\n getOdds(\n sport: string,\n options: GetOddsOptions = {}\n ): Promise<OddsResponse | OddsResponse[]> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam = _periodParam(options.period);\n if (periodParam !== undefined) params.period = periodParam;\n const sp = encodeURIComponent(sport);\n if (options.eventId !== undefined) {\n return this._request<OddsResponse>(\n \"GET\",\n `/sports/${sp}/events/${encodeURIComponent(String(options.eventId))}/odds`,\n { params }\n );\n }\n return this._request<OddsResponse[]>(\"GET\", `/sports/${sp}/odds`, { params });\n }\n\n /** List the available market types for an event. */\n getMarkets(sport: string, eventId: number | string): Promise<MarketSummary[]> {\n return this._request<MarketSummary[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/markets`\n );\n }\n\n /**\n * Get historical odds movement for an event.\n *\n * Hobby+: full snapshots. Free tier: redacted (snapshot counts only).\n *\n * Supports period-historical filters:\n * - `from` / `to` — absolute ISO timestamps\n * - `relativeFrom` / `relativeTo` — offsets to commence_time (\"-3h\", \"-30m\", \"0\")\n * - `interval` — downsample to a fixed bucket size\n * - `changesOnly` — drop unchanged adjacent snapshots\n */\n getOddsHistory(\n sport: string,\n eventId: number | string,\n options: GetOddsHistoryOptions = {}\n ): Promise<OddsHistoryResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n if (options.from !== undefined) params.from = options.from;\n if (options.to !== undefined) params.to = options.to;\n if (options.relativeFrom !== undefined) params.relative_from = options.relativeFrom;\n if (options.relativeTo !== undefined) params.relative_to = options.relativeTo;\n if (options.interval !== undefined) params.interval = options.interval;\n if (options.changesOnly) params.changes_only = \"true\";\n const periodParam2 = _periodParam(options.period);\n if (periodParam2 !== undefined) params.period = periodParam2;\n return this._request<OddsHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/history`,\n { params }\n );\n }\n\n /**\n * Get the closing line per `(book, market, outcome)` for an event —\n * the last snapshot at or before commence_time. Canonical CLV helper:\n * replaces \"fetch full history → find latest pre-game row\" with one\n * call. Each outcome carries a `closingAt` field with the snapshot's\n * recorded_at timestamp.\n *\n * Hobby+: full data. Free tier: redacted.\n */\n getOddsClosing(\n sport: string,\n eventId: number | string,\n options: GetOddsClosingOptions = {}\n ): Promise<OddsClosingResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam3 = _periodParam(options.period);\n if (periodParam3 !== undefined) params.period = periodParam3;\n return this._request<OddsClosingResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/closing`,\n { params }\n );\n }\n\n /** Get game scores and status (free tier). */\n getScores(sport: string, options: GetScoresOptions = {}): Promise<ScoreEvent[]> {\n return this._request<ScoreEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/scores`,\n { params: { days_from: options.daysFrom ?? 3 } }\n );\n }\n\n /**\n * Synthetic MLB Grand Salami for a given UTC date — total runs scored\n * across every MLB game on the slate, plus each book's implied Grand\n * Salami line (median of per-game primary totals across our MLB books).\n *\n * No retail sportsbook quotes this as a single market, so historical\n * cross-book Grand Salami data isn't available elsewhere. Free tier;\n * defaults to today (UTC).\n */\n getMlbGrandSalami(\n options: GetMlbGrandSalamiOptions = {}\n ): Promise<MlbGrandSalamiResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<MlbGrandSalamiResponse>(\n \"GET\",\n \"/sports/baseball_mlb/grand-salami\",\n { params }\n );\n }\n\n /**\n * Synthetic NHL Daily Goals Total for a given UTC date — total goals\n * scored (incl. OT/SO) across every NHL game on the slate, plus each\n * book's implied Daily Goals Total line (median of per-game primary\n * totals across our NHL books).\n *\n * Hockey's equivalent of the MLB Grand Salami. No retail sportsbook\n * quotes this as a single market. Free tier; defaults to today (UTC).\n */\n getNhlDailyGoalsTotal(\n options: GetNhlDailyGoalsTotalOptions = {}\n ): Promise<NhlDailyGoalsTotalResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<NhlDailyGoalsTotalResponse>(\n \"GET\",\n \"/sports/hockey_nhl/daily-goals-total\",\n { params }\n );\n }\n\n /**\n * Factual volume of graded player props over the last N days (free tier).\n *\n * Aggregated counts only — a coverage proof (every outcome counted was\n * graded against the real box score), never a profitability claim.\n *\n * @param days Look-back window, 1-90 (default 30).\n */\n getResolutionSummary(days = 30): Promise<ResolutionSummary> {\n return this._request<ResolutionSummary>(\n \"GET\",\n \"/markets/resolution-summary\",\n { params: { days: String(days) } }\n );\n }\n\n /**\n * Get raw player/team box-score stats (book-agnostic, free tier).\n *\n * Returns actual stat values decoupled from any bookmaker's lines.\n */\n getStats(\n sport: string,\n eventId: number | string,\n options: GetStatsOptions = {}\n ): Promise<StatsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.statType?.length) {\n params.stat_type = options.statType.join(\",\");\n }\n return this._request<StatsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/stats`,\n { params }\n );\n }\n\n /**\n * Get game context — the conditions a prop settles under.\n *\n * For MLB: probable starting pitchers and their throwing hand\n * (`home_probable_pitcher_hand` / `away_probable_pitcher_hand`, \"L\"/\"R\"/\"S\"\n * — platoon-split context for every batter prop), a confirmed-lineup flag,\n * the home-plate umpire, and first-pitch weather (outdoor / open-roof\n * venues; indoor venues return `weather: null` with `is_indoor: true`).\n * For NFL & NCAAF: the venue and kickoff weather (pitcher/umpire/lineup\n * fields are null for football). The same block is embedded in\n * {@link getResults}, so every graded prop carries its conditions — unique\n * to PropLine. Free tier. Rejects with a 404 when no context is on file\n * for the event yet.\n */\n getContext(\n sport: string,\n eventId: number | string\n ): Promise<ContextResponse> {\n return this._request<ContextResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/context`\n );\n }\n\n /**\n * Get line movement + steam detection from the snapshot tick history.\n *\n * Per (book, market, outcome): opening line, latest line, signed\n * implied-probability shift, point shift, direction. The `steam` array\n * flags outcomes multiple books moved the same direction — the\n * sharp-money signal across every book PropLine polls. When a book moves\n * the line itself, that outcome's `prob_shift` is null and `direction` is\n * `\"line_moved\"` (excluded from the steam signal). Unique to PropLine.\n * Hobby+ full; free tier redacted.\n */\n getMovement(\n sport: string,\n eventId: number | string,\n options: GetMovementOptions = {}\n ): Promise<MovementResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n params.period = _periodParam(options.period);\n return this._request<MovementResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/movement`,\n { params }\n );\n }\n\n /**\n * Get resolved prop outcomes with actual player stats.\n *\n * Pro tier: full data. Free tier: redacted (resolution + actual nulled).\n */\n getResults(\n sport: string,\n eventId: number | string,\n options: GetResultsOptions = {}\n ): Promise<ResultsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n return this._request<ResultsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/results`,\n { params }\n );\n }\n\n /**\n * Recent resolved prop history for a player on a market.\n *\n * One entry per (event, bookmaker) pair. Pro: full. Free: redacted.\n */\n getPlayerHistory(\n sport: string,\n playerName: string,\n options: GetPlayerHistoryOptions\n ): Promise<PlayerHistoryResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n limit: options.limit ?? 20,\n };\n if (options.bookmaker) {\n params.bookmaker = options.bookmaker;\n }\n return this._request<PlayerHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/players/${encodeURIComponent(playerName)}/history`,\n { params }\n );\n }\n\n /**\n * Rolling hit-rate trends for a player across one or all markets.\n *\n * Returns over/under/push splits over the last 5/10/20/50 graded games,\n * the current streak, and the most recent game per market. Pro: full.\n * Free: redacted.\n */\n getPlayerTrends(\n sportKey: string,\n playerName: string,\n options: GetPlayerTrendsOptions = {}\n ): Promise<PlayerTrends> {\n const params: Record<string, string | undefined> = {};\n if (options.market) {\n params.market = options.market;\n }\n return this._request<PlayerTrends>(\n \"GET\",\n `/sports/${encodeURIComponent(sportKey)}/players/${encodeURIComponent(playerName)}/trends`,\n { params }\n );\n }\n\n /**\n * Cross-book +EV analysis for a single event (Pro+ tier).\n *\n * Groups every outcome by (market, player, line) across the books we\n * carry, derives a no-vig fair line from a sharp anchor (Pinnacle\n * preferred, Bovada fallback), and returns EV% per book at the same\n * line. Outcomes are sorted with +EV plays floated to the top.\n *\n * PrizePicks is excluded — its synthetic +100/+100 prices aren't\n * payout odds. Lines without sharp-anchor coverage are dropped.\n *\n * @example\n * ```ts\n * const ev = await client.getEventEv(\"baseball_mlb\", 12345);\n * for (const line of ev.lines) {\n * const plus = line.outcomes.filter(o => o.is_plus_ev);\n * if (plus.length) console.log(line.market_key, line.description, plus);\n * }\n * ```\n */\n /**\n * List futures markets for a sport — championship winner, MVP,\n * division winner, etc. Each row is one (futures event, book,\n * market) with every team or player priced. Free tier; pulled from\n * each book's futures feed (Bovada today).\n *\n * @example\n * ```ts\n * const futures = await client.getFutures(\"baseball_mlb\");\n * for (const event of futures) {\n * console.log(`${event.title} @ ${event.commence_time}`);\n * for (const m of event.markets) {\n * const top3 = [...m.outcomes].sort((a, b) => a.price - b.price).slice(0, 3);\n * for (const o of top3) console.log(` ${o.name}: ${o.price}`);\n * }\n * }\n * ```\n */\n getFutures(sport: string): Promise<FuturesEvent[]> {\n return this._request<FuturesEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/futures`\n );\n }\n\n getEventEv(\n sport: string,\n eventId: number | string,\n options: GetEventEvOptions = {}\n ): Promise<EventEvResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventEvResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev`,\n { params }\n );\n }\n\n /**\n * Cross-book best-line lookup for a single event.\n *\n * For each (market, player, line) tuple, returns the single best\n * American price across every book we carry, with the book name\n * attached. Companion to `getEventEv`: best-line tells you which\n * book has the highest payout right now; +EV tells you whether\n * that price beats a sharp no-vig fair line. Most line shoppers\n * want both.\n *\n * PrizePicks is excluded from the comparison — its DFS payout\n * structure (synthetic +100/+100 quotes) isn't directly comparable\n * to traditional sportsbook odds.\n *\n * Hobby tier or higher required (returns 403 on free).\n *\n * @example\n * ```ts\n * const bl = await client.getEventBestLine(\"baseball_mlb\", 12345);\n * for (const line of bl.lines) {\n * for (const [side, info] of Object.entries(line.sides)) {\n * console.log(\n * `${line.description} ${side} ${line.point}: ` +\n * `${info.best.price} @ ${info.best.book_title}`\n * );\n * }\n * }\n * ```\n */\n getEventBestLine(\n sport: string,\n eventId: number | string,\n options: GetEventBestLineOptions = {}\n ): Promise<EventBestLineResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventBestLineResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/best-line`,\n { params }\n );\n }\n\n /**\n * Calculate EV% for a user-supplied price against the event's\n * no-vig fair anchor. Useful for books PropLine doesn't carry —\n * Caesars, BetMGM, Fanatics, BetUS, Hard Rock — where you have a\n * price in hand and want to know if it's +EV against the sharp\n * consensus we do carry.\n *\n * Same fair-line math as `getEventEv` (Pinnacle-preferred anchor,\n * no-vig devigging) but takes one user price as input. Pro tier.\n *\n * @example\n * ```ts\n * const r = await client.calcEventEv(\"baseball_mlb\", 12614, {\n * market: \"h2h\",\n * name: \"Pittsburgh Pirates\",\n * price: -118,\n * });\n * console.log(`EV ${r.ev_pct}% fair=${r.fair_prob}`);\n * ```\n */\n calcEventEv(\n sport: string,\n eventId: number | string,\n options: CalcEventEvOptions\n ): Promise<EventEvCalcResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n name: options.name,\n price: options.price,\n };\n if (options.point !== undefined) params.point = options.point;\n if (options.description) params.description = options.description;\n return this._request<EventEvCalcResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev/calc`,\n { params }\n );\n }\n\n /**\n * Bulk CSV export of resolved prop outcomes (Pro+ tier).\n *\n * If `outPath` is provided, streams the CSV to disk and resolves to the\n * path. Otherwise resolves to the full CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportResolvedProps({\n * sport: \"baseball_mlb\",\n * market: \"pitcher_strikeouts\",\n * since: \"2026-04-01T00:00:00Z\",\n * outPath: \"./mlb-strikeouts.csv\",\n * });\n * ```\n */\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath: string }\n ): Promise<string>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/resolved-props\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(403, await readDetail(resp, \"Pro tier required\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n /**\n * Bulk CSV export of the full line-movement time-series.\n *\n * One row per (outcome, snapshot): every recorded odds snapshot (price +\n * line, per book, including period markets), not just the closing line.\n * This is the raw tick history no subscription tier can pull in bulk —\n * Pro/Streaming get per-event {@link getOddsHistory} only; this bulk\n * firehose is exclusive to the one-time Historical Backfill pass and\n * Enterprise.\n *\n * A full archive runs to gigabytes per sport — page month by month with\n * `since`/`until`. If `outPath` is provided, streams to disk and resolves\n * to the path; otherwise resolves to the CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportOddsHistory({\n * sport: \"baseball_mlb\",\n * since: \"2026-04-01T00:00:00Z\",\n * until: \"2026-05-01T00:00:00Z\",\n * outPath: \"./mlb-line-history-apr.csv\",\n * });\n * ```\n */\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath: string }\n ): Promise<string>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/odds-history\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(\n 403,\n await readDetail(resp, \"Historical Backfill pass or Enterprise required\")\n );\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n // ------------------------------------------------------------------\n // Webhooks (Streaming tier)\n // ------------------------------------------------------------------\n\n /**\n * Register a webhook subscription. Streaming tier only.\n *\n * The returned object includes the full signing `secret` — this is the\n * ONLY time it's revealed. Store it securely.\n */\n createWebhook(options: CreateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"POST\", \"/webhooks\", {\n body: webhookBody(options),\n });\n }\n\n /** List your webhook subscriptions. Secrets are masked. */\n listWebhooks(): Promise<Webhook[]> {\n return this._request<Webhook[]>(\"GET\", \"/webhooks\");\n }\n\n /** Get a single webhook subscription. Secret is masked. */\n getWebhook(webhookId: number): Promise<Webhook> {\n return this._request<Webhook>(\"GET\", `/webhooks/${webhookId}`);\n }\n\n /** Update fields on a webhook. Only supplied fields are changed. */\n updateWebhook(webhookId: number, options: UpdateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"PATCH\", `/webhooks/${webhookId}`, {\n body: webhookBody(options),\n });\n }\n\n /** Delete a webhook (cascades its delivery history). */\n deleteWebhook(webhookId: number): Promise<{ ok: boolean } | unknown> {\n return this._request(\"DELETE\", `/webhooks/${webhookId}`);\n }\n\n /** Queue a sample `test` payload to the webhook's URL. */\n testWebhook(webhookId: number): Promise<unknown> {\n return this._request(\"POST\", `/webhooks/${webhookId}/test`);\n }\n\n /** Last 50 (default) delivery attempts for a webhook. */\n listWebhookDeliveries(\n webhookId: number,\n options: ListWebhookDeliveriesOptions = {}\n ): Promise<WebhookDelivery[]> {\n return this._request<WebhookDelivery[]>(\n \"GET\",\n `/webhooks/${webhookId}/deliveries`,\n { params: { limit: options.limit ?? 50 } }\n );\n }\n\n /**\n * Verify that an inbound webhook delivery was signed by PropLine.\n *\n * Compares HMAC-SHA256(secret, `${timestamp}.` + body) against the\n * `X-PropLine-Signature` header in constant time.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * app.post(\"/hooks/propline\", express.raw({ type: \"*\\/*\" }), (req, res) => {\n * const ok = PropLine.verifySignature({\n * secret: process.env.WEBHOOK_SECRET!,\n * timestamp: req.header(\"X-PropLine-Timestamp\")!,\n * body: req.body, // raw Buffer\n * signature: req.header(\"X-PropLine-Signature\")!,\n * });\n * if (!ok) return res.status(401).end();\n * // ...\n * });\n * ```\n */\n static verifySignature(options: VerifySignatureOptions): boolean {\n const { secret, timestamp, body, signature } = options;\n const bodyBuf =\n typeof body === \"string\"\n ? Buffer.from(body, \"utf8\")\n : body instanceof Buffer\n ? body\n : Buffer.from(body);\n const message = Buffer.concat([Buffer.from(`${timestamp}.`, \"utf8\"), bodyBuf]);\n const expected = createHmac(\"sha256\", secret).update(message).digest(\"hex\");\n if (expected.length !== signature.length) return false;\n try {\n return timingSafeEqual(Buffer.from(expected, \"hex\"), Buffer.from(signature, \"hex\"));\n } catch {\n return false;\n }\n }\n}\n\nfunction webhookBody(options: CreateWebhookOptions | UpdateWebhookOptions): Record<string, unknown> {\n const body: Record<string, unknown> = {};\n const map: Array<[keyof (CreateWebhookOptions & UpdateWebhookOptions), string]> = [\n [\"url\", \"url\"],\n [\"events\", \"events\"],\n [\"filterSportKey\", \"filter_sport_key\"],\n [\"filterEventId\", \"filter_event_id\"],\n [\"filterMarketKey\", \"filter_market_key\"],\n [\"filterPlayerName\", \"filter_player_name\"],\n [\"minPriceChangePct\", \"min_price_change_pct\"],\n [\"minSteamScore\", \"min_steam_score\"],\n [\"active\", \"active\"],\n ];\n for (const [src, dst] of map) {\n const v = (options as Record<string, unknown>)[src as string];\n if (v !== undefined) body[dst] = v;\n }\n return body;\n}\n\nasync function readDetail(resp: Response, fallback: string): Promise<string> {\n try {\n const text = await resp.text();\n if (!text) return fallback;\n try {\n const json = JSON.parse(text) as { detail?: unknown };\n if (typeof json.detail === \"string\") return json.detail;\n } catch {\n // not JSON\n }\n return text || fallback;\n } catch {\n return fallback;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -24,6 +24,14 @@ interface Outcome {
24
24
  description?: string | null;
25
25
  price: number;
26
26
  point?: number | null;
27
+ /**
28
+ * DFS payout multiplier for boosted/discounted picks (Underdog Fantasy).
29
+ * `null`/absent = standard 1.0 pick whose `price` carries the full payout;
30
+ * e.g. `1.5` (boost) or `0.75` (discount) scales the effective payout.
31
+ * Skip outcomes with a non-null multiplier when comparing DFS lines to
32
+ * sportsbook consensus so a scaled payout doesn't read as a mispriced edge.
33
+ */
34
+ payout_multiplier?: number | null;
27
35
  [k: string]: unknown;
28
36
  }
29
37
  interface ResolvedOutcome extends Outcome {
@@ -1128,6 +1136,6 @@ declare const Bookmakers: {
1128
1136
  readonly PRIZEPICKS: "prizepicks";
1129
1137
  };
1130
1138
  type BookmakerKey = (typeof Bookmakers)[keyof typeof Bookmakers];
1131
- declare const VERSION = "0.15.0";
1139
+ declare const VERSION = "0.16.0";
1132
1140
 
1133
1141
  export { AuthError, type BestLine, type BestLineSide, type BestPrice, type Bookmaker, type BookmakerKey, Bookmakers, type CalcEventEvOptions, type ClosingBookmaker, type ClosingMarket, type ClosingOutcome, type ContextResponse, type CreateWebhookOptions, type EvLine, type EvOutcome, type Event, type EventBestLineResponse, type EventEvCalcResponse, type EventEvResponse, type ExportOddsHistoryOptions, type ExportResolvedPropsOptions, type FuturesEvent, type FuturesMarket, type FuturesOutcome, type GetEventBestLineOptions, type GetEventEvOptions, type GetMlbGrandSalamiOptions, type GetNhlDailyGoalsTotalOptions, type GetOddsClosingOptions, type GetOddsHistoryOptions, type GetOddsOptions, type GetPlayerHistoryOptions, type GetPlayerTrendsOptions, type GetResultsOptions, type GetScoresOptions, type GetStatsOptions, type HitRateSplit, type ListWebhookDeliveriesOptions, type Market, type MarketSummary, type MlbGrandSalamiBook, type MlbGrandSalamiResponse, type MovementBookmaker, type MovementMarket, type MovementOutcome, type MovementResponse, type NhlDailyGoalsTotalBook, type NhlDailyGoalsTotalResponse, type OddsClosingResponse, type OddsHistoryBookmaker, type OddsHistoryMarket, type OddsHistoryOutcome, type OddsHistoryResponse, type OddsResponse, type Outcome, type OutcomeSnapshot, type PeriodFilter, type PlayerHistoryEntry, type PlayerHistoryResponse, type PlayerMarketTrend, type PlayerStat, type PlayerTrends, PropLine, PropLineError, type PropLineOptions, RateLimitError, type ResolutionSummary, type ResolutionSummaryMarket, type ResolutionSummarySport, type ResolvedOutcome, type ResultsMarket, type ResultsResponse, type ScoreEvent, type Sport, type StatsResponse, type SteamMove, type TrendLastGame, type TrendStreak, type UpdateWebhookOptions, VERSION, type VerifySignatureOptions, type WeatherInfo, type Webhook, type WebhookDelivery, type WebhookEventType };
package/dist/index.d.ts CHANGED
@@ -24,6 +24,14 @@ interface Outcome {
24
24
  description?: string | null;
25
25
  price: number;
26
26
  point?: number | null;
27
+ /**
28
+ * DFS payout multiplier for boosted/discounted picks (Underdog Fantasy).
29
+ * `null`/absent = standard 1.0 pick whose `price` carries the full payout;
30
+ * e.g. `1.5` (boost) or `0.75` (discount) scales the effective payout.
31
+ * Skip outcomes with a non-null multiplier when comparing DFS lines to
32
+ * sportsbook consensus so a scaled payout doesn't read as a mispriced edge.
33
+ */
34
+ payout_multiplier?: number | null;
27
35
  [k: string]: unknown;
28
36
  }
29
37
  interface ResolvedOutcome extends Outcome {
@@ -1128,6 +1136,6 @@ declare const Bookmakers: {
1128
1136
  readonly PRIZEPICKS: "prizepicks";
1129
1137
  };
1130
1138
  type BookmakerKey = (typeof Bookmakers)[keyof typeof Bookmakers];
1131
- declare const VERSION = "0.15.0";
1139
+ declare const VERSION = "0.16.0";
1132
1140
 
1133
1141
  export { AuthError, type BestLine, type BestLineSide, type BestPrice, type Bookmaker, type BookmakerKey, Bookmakers, type CalcEventEvOptions, type ClosingBookmaker, type ClosingMarket, type ClosingOutcome, type ContextResponse, type CreateWebhookOptions, type EvLine, type EvOutcome, type Event, type EventBestLineResponse, type EventEvCalcResponse, type EventEvResponse, type ExportOddsHistoryOptions, type ExportResolvedPropsOptions, type FuturesEvent, type FuturesMarket, type FuturesOutcome, type GetEventBestLineOptions, type GetEventEvOptions, type GetMlbGrandSalamiOptions, type GetNhlDailyGoalsTotalOptions, type GetOddsClosingOptions, type GetOddsHistoryOptions, type GetOddsOptions, type GetPlayerHistoryOptions, type GetPlayerTrendsOptions, type GetResultsOptions, type GetScoresOptions, type GetStatsOptions, type HitRateSplit, type ListWebhookDeliveriesOptions, type Market, type MarketSummary, type MlbGrandSalamiBook, type MlbGrandSalamiResponse, type MovementBookmaker, type MovementMarket, type MovementOutcome, type MovementResponse, type NhlDailyGoalsTotalBook, type NhlDailyGoalsTotalResponse, type OddsClosingResponse, type OddsHistoryBookmaker, type OddsHistoryMarket, type OddsHistoryOutcome, type OddsHistoryResponse, type OddsResponse, type Outcome, type OutcomeSnapshot, type PeriodFilter, type PlayerHistoryEntry, type PlayerHistoryResponse, type PlayerMarketTrend, type PlayerStat, type PlayerTrends, PropLine, PropLineError, type PropLineOptions, RateLimitError, type ResolutionSummary, type ResolutionSummaryMarket, type ResolutionSummarySport, type ResolvedOutcome, type ResultsMarket, type ResultsResponse, type ScoreEvent, type Sport, type StatsResponse, type SteamMove, type TrendLastGame, type TrendStreak, type UpdateWebhookOptions, VERSION, type VerifySignatureOptions, type WeatherInfo, type Webhook, type WebhookDelivery, type WebhookEventType };
package/dist/index.js CHANGED
@@ -682,7 +682,7 @@ var Bookmakers = {
682
682
  POLYMARKET: "polymarket",
683
683
  PRIZEPICKS: "prizepicks"
684
684
  };
685
- var VERSION = "0.15.0";
685
+ var VERSION = "0.16.0";
686
686
  export {
687
687
  AuthError,
688
688
  Bookmakers,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/index.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport type {\n Sport,\n Event as PropLineEvent,\n OddsResponse,\n MarketSummary,\n OddsHistoryResponse,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n StatsResponse,\n ContextResponse,\n MovementResponse,\n ResultsResponse,\n PlayerHistoryResponse,\n PlayerTrends,\n EventEvResponse,\n EventEvCalcResponse,\n EventBestLineResponse,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** Base error for all PropLine API failures. */\nexport class PropLineError extends Error {\n readonly statusCode: number;\n readonly detail: string;\n\n constructor(statusCode: number, detail: string) {\n super(`[${statusCode}] ${detail}`);\n this.name = \"PropLineError\";\n this.statusCode = statusCode;\n this.detail = detail;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the API key is missing or invalid (HTTP 401). */\nexport class AuthError extends PropLineError {\n constructor(detail = \"Invalid API key\") {\n super(401, detail);\n this.name = \"AuthError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the daily request limit is exceeded (HTTP 429). */\nexport class RateLimitError extends PropLineError {\n constructor(detail = \"Rate limit exceeded\") {\n super(429, detail);\n this.name = \"RateLimitError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport interface PropLineOptions {\n /** API base URL. Default: `https://api.prop-line.com/v1`. */\n baseUrl?: string;\n /** Request timeout in milliseconds. Default: 15000. */\n timeoutMs?: number;\n /** Custom fetch implementation. Defaults to global `fetch` (Node 18+). */\n fetch?: typeof fetch;\n}\n\n/**\n * Game-period filter. String of canonical codes, optionally\n * comma-separated, or the sentinel `\"all\"`. Omitted = full-game\n * markets only (backwards-compatible default).\n *\n * \"q1\" — 1st quarter\n * \"q1,q2\" — 1st and 2nd quarters\n * [\"q1\",\"q2\"] — same, as an array\n * \"h1\" — 1st half\n * \"p1\"|\"p2\"|\"p3\" — hockey periods\n * \"i6\" — 6th inning\n * \"f3\"|\"f5\"|\"f7\" — first N innings\n * \"all\" — every period including full game\n */\nexport type PeriodFilter = string | string[];\n\nexport interface GetOddsOptions {\n /** Specific event ID to get odds (with player props) for. Omit for bulk odds. */\n eventId?: number | string;\n /**\n * Market keys to filter by. If omitted, the bulk `/odds` endpoint\n * defaults to `h2h` and the per-event `/odds` endpoint defaults to\n * `h2h,spreads,totals` — game-line markets every book carries across\n * every sport. Pass an explicit list to fetch player props (e.g.\n * `[\"pitcher_strikeouts\", \"batter_home_runs\"]` for MLB,\n * `[\"player_points\", \"player_rebounds\"]` for NBA).\n */\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsHistoryOptions {\n markets?: string[];\n /** ISO timestamp; only include snapshots at or after this time. Mutually exclusive with `relativeFrom`. */\n from?: string;\n /** ISO timestamp; only include snapshots at or before this time. Mutually exclusive with `relativeTo`. */\n to?: string;\n /** Offset relative to commence_time, e.g. \"-3h\", \"-30m\", \"-90s\". Mutually exclusive with `from`. */\n relativeFrom?: string;\n /** Offset relative to commence_time, e.g. \"-1m\" or \"0\" for commence_time itself. Mutually exclusive with `to`. */\n relativeTo?: string;\n /** Downsample to one snapshot per bucket. Latest snapshot in each bucket wins. */\n interval?: \"30s\" | \"1m\" | \"5m\" | \"15m\" | \"30m\" | \"1h\";\n /** When true, drop snapshots whose (price, point) match the previous one. Opening line is always kept. */\n changesOnly?: boolean;\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsClosingOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetMovementOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nfunction _periodParam(p: PeriodFilter | undefined): string | undefined {\n if (p === undefined) return undefined;\n return typeof p === \"string\" ? p : p.join(\",\");\n}\n\nexport interface GetScoresOptions {\n /** Days back to include (default 3). */\n daysFrom?: number;\n}\n\nexport interface GetMlbGrandSalamiOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetNhlDailyGoalsTotalOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetStatsOptions {\n /** Stat types to filter by (e.g. `[\"strikeouts\", \"hits\"]`). */\n statType?: string[];\n}\n\nexport interface GetResultsOptions {\n markets?: string[];\n}\n\nexport interface GetPlayerHistoryOptions {\n /** Market key (e.g. `\"pitcher_strikeouts\"`). Required. */\n market: string;\n /** Restrict to a single bookmaker (e.g. `\"draftkings\"`). */\n bookmaker?: string;\n /** Max entries (1-100). Default 20. */\n limit?: number;\n}\n\nexport interface GetPlayerTrendsOptions {\n /** Market key (e.g. `\"batter_total_bases\"`). Omit for all markets. */\n market?: string;\n}\n\nexport interface GetEventEvOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"batter_hits\"]`).\n * Omit to evaluate every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface GetEventBestLineOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"h2h\"]`). Omit\n * to include every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface CalcEventEvOptions {\n /** Market key — h2h / spreads / totals / pitcher_strikeouts / etc. */\n market: string;\n /** Outcome name. Team for h2h/spreads; \"Over\" or \"Under\" for totals/props. */\n name: string;\n /** American odds at your book, e.g. -118 or 145. */\n price: number;\n /** Line/point for spreads, totals, player props. Sign matters for spreads (-1.5 favorite). Omit for h2h. */\n point?: number;\n /** Player name for player-prop markets. Omit for game-line markets. */\n description?: string;\n}\n\nexport interface ExportResolvedPropsOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `resolved_at`. */\n since?: string;\n /** ISO datetime upper bound on `resolved_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\nexport interface ExportOddsHistoryOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `recorded_at`. */\n since?: string;\n /** ISO datetime upper bound on `recorded_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\n/** Webhook event types. `steam` = cross-book sharp-money alert. */\nexport type WebhookEventType = \"line_movement\" | \"resolution\" | \"steam\";\n\nexport interface CreateWebhookOptions {\n /** HTTPS endpoint to receive POSTed events. Required. */\n url: string;\n /** Event types to subscribe to. Default: all. */\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n /** Minimum % change in American odds to fire a line_movement. Point-only shifts always pass. */\n minPriceChangePct?: number;\n /** Minimum 0-100 steam score to fire a `steam` event. Null = detector's global floor. */\n minSteamScore?: number;\n}\n\nexport interface UpdateWebhookOptions {\n url?: string;\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n minPriceChangePct?: number;\n minSteamScore?: number;\n active?: boolean;\n}\n\nexport interface ListWebhookDeliveriesOptions {\n /** Max deliveries to return. Default 50. */\n limit?: number;\n}\n\nexport interface VerifySignatureOptions {\n /** Webhook signing secret (returned once from `createWebhook`). */\n secret: string;\n /** Value of the `X-PropLine-Timestamp` header. */\n timestamp: string;\n /** Raw request body. */\n body: Uint8Array | Buffer | string;\n /** Value of the `X-PropLine-Signature` header. */\n signature: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.prop-line.com/v1\";\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\n/**\n * Client for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const sports = await client.getSports();\n * ```\n */\nexport class PropLine {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeoutMs: number;\n private readonly _fetch: typeof fetch;\n\n constructor(apiKey: string, options: PropLineOptions = {}) {\n if (!apiKey) {\n throw new Error(\"PropLine: apiKey is required\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this._fetch = options.fetch ?? globalThis.fetch;\n if (!this._fetch) {\n throw new Error(\n \"PropLine: global fetch is unavailable. Use Node 18+ or pass options.fetch.\"\n );\n }\n }\n\n // ------------------------------------------------------------------\n // Internals\n // ------------------------------------------------------------------\n\n private _buildUrl(path: string, params?: Record<string, string | number | undefined>): string {\n const url = new URL(`${this.baseUrl}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) {\n url.searchParams.set(k, String(v));\n }\n }\n }\n return url.toString();\n }\n\n private async _request<T>(\n method: string,\n path: string,\n init: { params?: Record<string, string | number | undefined>; body?: unknown } = {}\n ): Promise<T> {\n const url = this._buildUrl(path, init.params);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method,\n headers: {\n \"X-API-Key\": this.apiKey,\n ...(init.body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n },\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError(await readDetail(resp, \"Invalid API key\"));\n }\n if (resp.status === 429) {\n throw new RateLimitError(await readDetail(resp, \"Rate limit exceeded\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n if (resp.status === 204) {\n return undefined as T;\n }\n return (await resp.json()) as T;\n }\n\n // ------------------------------------------------------------------\n // Public API\n // ------------------------------------------------------------------\n\n /** List all available sports. */\n getSports(): Promise<Sport[]> {\n return this._request<Sport[]>(\"GET\", \"/sports\");\n }\n\n /** List upcoming events for a sport. */\n getEvents(sport: string): Promise<PropLineEvent[]> {\n return this._request<PropLineEvent[]>(\"GET\", `/sports/${encodeURIComponent(sport)}/events`);\n }\n\n /**\n * Get current odds. With `eventId`, returns single-event odds (including\n * player props). Without, returns bulk odds for all upcoming events.\n *\n * Each response carries a `bookmakers` array — iterate it to compare\n * lines across Bovada, DraftKings, FanDuel, Pinnacle, Unibet, and\n * PrizePicks (coverage varies by sport).\n */\n getOdds(\n sport: string,\n options: GetOddsOptions & { eventId: number | string }\n ): Promise<OddsResponse>;\n getOdds(\n sport: string,\n options?: Omit<GetOddsOptions, \"eventId\"> & { eventId?: undefined }\n ): Promise<OddsResponse[]>;\n getOdds(\n sport: string,\n options: GetOddsOptions = {}\n ): Promise<OddsResponse | OddsResponse[]> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam = _periodParam(options.period);\n if (periodParam !== undefined) params.period = periodParam;\n const sp = encodeURIComponent(sport);\n if (options.eventId !== undefined) {\n return this._request<OddsResponse>(\n \"GET\",\n `/sports/${sp}/events/${encodeURIComponent(String(options.eventId))}/odds`,\n { params }\n );\n }\n return this._request<OddsResponse[]>(\"GET\", `/sports/${sp}/odds`, { params });\n }\n\n /** List the available market types for an event. */\n getMarkets(sport: string, eventId: number | string): Promise<MarketSummary[]> {\n return this._request<MarketSummary[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/markets`\n );\n }\n\n /**\n * Get historical odds movement for an event.\n *\n * Hobby+: full snapshots. Free tier: redacted (snapshot counts only).\n *\n * Supports period-historical filters:\n * - `from` / `to` — absolute ISO timestamps\n * - `relativeFrom` / `relativeTo` — offsets to commence_time (\"-3h\", \"-30m\", \"0\")\n * - `interval` — downsample to a fixed bucket size\n * - `changesOnly` — drop unchanged adjacent snapshots\n */\n getOddsHistory(\n sport: string,\n eventId: number | string,\n options: GetOddsHistoryOptions = {}\n ): Promise<OddsHistoryResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n if (options.from !== undefined) params.from = options.from;\n if (options.to !== undefined) params.to = options.to;\n if (options.relativeFrom !== undefined) params.relative_from = options.relativeFrom;\n if (options.relativeTo !== undefined) params.relative_to = options.relativeTo;\n if (options.interval !== undefined) params.interval = options.interval;\n if (options.changesOnly) params.changes_only = \"true\";\n const periodParam2 = _periodParam(options.period);\n if (periodParam2 !== undefined) params.period = periodParam2;\n return this._request<OddsHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/history`,\n { params }\n );\n }\n\n /**\n * Get the closing line per `(book, market, outcome)` for an event —\n * the last snapshot at or before commence_time. Canonical CLV helper:\n * replaces \"fetch full history → find latest pre-game row\" with one\n * call. Each outcome carries a `closingAt` field with the snapshot's\n * recorded_at timestamp.\n *\n * Hobby+: full data. Free tier: redacted.\n */\n getOddsClosing(\n sport: string,\n eventId: number | string,\n options: GetOddsClosingOptions = {}\n ): Promise<OddsClosingResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam3 = _periodParam(options.period);\n if (periodParam3 !== undefined) params.period = periodParam3;\n return this._request<OddsClosingResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/closing`,\n { params }\n );\n }\n\n /** Get game scores and status (free tier). */\n getScores(sport: string, options: GetScoresOptions = {}): Promise<ScoreEvent[]> {\n return this._request<ScoreEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/scores`,\n { params: { days_from: options.daysFrom ?? 3 } }\n );\n }\n\n /**\n * Synthetic MLB Grand Salami for a given UTC date — total runs scored\n * across every MLB game on the slate, plus each book's implied Grand\n * Salami line (median of per-game primary totals across our MLB books).\n *\n * No retail sportsbook quotes this as a single market, so historical\n * cross-book Grand Salami data isn't available elsewhere. Free tier;\n * defaults to today (UTC).\n */\n getMlbGrandSalami(\n options: GetMlbGrandSalamiOptions = {}\n ): Promise<MlbGrandSalamiResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<MlbGrandSalamiResponse>(\n \"GET\",\n \"/sports/baseball_mlb/grand-salami\",\n { params }\n );\n }\n\n /**\n * Synthetic NHL Daily Goals Total for a given UTC date — total goals\n * scored (incl. OT/SO) across every NHL game on the slate, plus each\n * book's implied Daily Goals Total line (median of per-game primary\n * totals across our NHL books).\n *\n * Hockey's equivalent of the MLB Grand Salami. No retail sportsbook\n * quotes this as a single market. Free tier; defaults to today (UTC).\n */\n getNhlDailyGoalsTotal(\n options: GetNhlDailyGoalsTotalOptions = {}\n ): Promise<NhlDailyGoalsTotalResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<NhlDailyGoalsTotalResponse>(\n \"GET\",\n \"/sports/hockey_nhl/daily-goals-total\",\n { params }\n );\n }\n\n /**\n * Factual volume of graded player props over the last N days (free tier).\n *\n * Aggregated counts only — a coverage proof (every outcome counted was\n * graded against the real box score), never a profitability claim.\n *\n * @param days Look-back window, 1-90 (default 30).\n */\n getResolutionSummary(days = 30): Promise<ResolutionSummary> {\n return this._request<ResolutionSummary>(\n \"GET\",\n \"/markets/resolution-summary\",\n { params: { days: String(days) } }\n );\n }\n\n /**\n * Get raw player/team box-score stats (book-agnostic, free tier).\n *\n * Returns actual stat values decoupled from any bookmaker's lines.\n */\n getStats(\n sport: string,\n eventId: number | string,\n options: GetStatsOptions = {}\n ): Promise<StatsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.statType?.length) {\n params.stat_type = options.statType.join(\",\");\n }\n return this._request<StatsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/stats`,\n { params }\n );\n }\n\n /**\n * Get game context — the conditions a prop settles under.\n *\n * For MLB: probable starting pitchers and their throwing hand\n * (`home_probable_pitcher_hand` / `away_probable_pitcher_hand`, \"L\"/\"R\"/\"S\"\n * — platoon-split context for every batter prop), a confirmed-lineup flag,\n * the home-plate umpire, and first-pitch weather (outdoor / open-roof\n * venues; indoor venues return `weather: null` with `is_indoor: true`).\n * For NFL & NCAAF: the venue and kickoff weather (pitcher/umpire/lineup\n * fields are null for football). The same block is embedded in\n * {@link getResults}, so every graded prop carries its conditions — unique\n * to PropLine. Free tier. Rejects with a 404 when no context is on file\n * for the event yet.\n */\n getContext(\n sport: string,\n eventId: number | string\n ): Promise<ContextResponse> {\n return this._request<ContextResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/context`\n );\n }\n\n /**\n * Get line movement + steam detection from the snapshot tick history.\n *\n * Per (book, market, outcome): opening line, latest line, signed\n * implied-probability shift, point shift, direction. The `steam` array\n * flags outcomes multiple books moved the same direction — the\n * sharp-money signal across every book PropLine polls. When a book moves\n * the line itself, that outcome's `prob_shift` is null and `direction` is\n * `\"line_moved\"` (excluded from the steam signal). Unique to PropLine.\n * Hobby+ full; free tier redacted.\n */\n getMovement(\n sport: string,\n eventId: number | string,\n options: GetMovementOptions = {}\n ): Promise<MovementResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n params.period = _periodParam(options.period);\n return this._request<MovementResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/movement`,\n { params }\n );\n }\n\n /**\n * Get resolved prop outcomes with actual player stats.\n *\n * Pro tier: full data. Free tier: redacted (resolution + actual nulled).\n */\n getResults(\n sport: string,\n eventId: number | string,\n options: GetResultsOptions = {}\n ): Promise<ResultsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n return this._request<ResultsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/results`,\n { params }\n );\n }\n\n /**\n * Recent resolved prop history for a player on a market.\n *\n * One entry per (event, bookmaker) pair. Pro: full. Free: redacted.\n */\n getPlayerHistory(\n sport: string,\n playerName: string,\n options: GetPlayerHistoryOptions\n ): Promise<PlayerHistoryResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n limit: options.limit ?? 20,\n };\n if (options.bookmaker) {\n params.bookmaker = options.bookmaker;\n }\n return this._request<PlayerHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/players/${encodeURIComponent(playerName)}/history`,\n { params }\n );\n }\n\n /**\n * Rolling hit-rate trends for a player across one or all markets.\n *\n * Returns over/under/push splits over the last 5/10/20/50 graded games,\n * the current streak, and the most recent game per market. Pro: full.\n * Free: redacted.\n */\n getPlayerTrends(\n sportKey: string,\n playerName: string,\n options: GetPlayerTrendsOptions = {}\n ): Promise<PlayerTrends> {\n const params: Record<string, string | undefined> = {};\n if (options.market) {\n params.market = options.market;\n }\n return this._request<PlayerTrends>(\n \"GET\",\n `/sports/${encodeURIComponent(sportKey)}/players/${encodeURIComponent(playerName)}/trends`,\n { params }\n );\n }\n\n /**\n * Cross-book +EV analysis for a single event (Pro+ tier).\n *\n * Groups every outcome by (market, player, line) across the books we\n * carry, derives a no-vig fair line from a sharp anchor (Pinnacle\n * preferred, Bovada fallback), and returns EV% per book at the same\n * line. Outcomes are sorted with +EV plays floated to the top.\n *\n * PrizePicks is excluded — its synthetic +100/+100 prices aren't\n * payout odds. Lines without sharp-anchor coverage are dropped.\n *\n * @example\n * ```ts\n * const ev = await client.getEventEv(\"baseball_mlb\", 12345);\n * for (const line of ev.lines) {\n * const plus = line.outcomes.filter(o => o.is_plus_ev);\n * if (plus.length) console.log(line.market_key, line.description, plus);\n * }\n * ```\n */\n /**\n * List futures markets for a sport — championship winner, MVP,\n * division winner, etc. Each row is one (futures event, book,\n * market) with every team or player priced. Free tier; pulled from\n * each book's futures feed (Bovada today).\n *\n * @example\n * ```ts\n * const futures = await client.getFutures(\"baseball_mlb\");\n * for (const event of futures) {\n * console.log(`${event.title} @ ${event.commence_time}`);\n * for (const m of event.markets) {\n * const top3 = [...m.outcomes].sort((a, b) => a.price - b.price).slice(0, 3);\n * for (const o of top3) console.log(` ${o.name}: ${o.price}`);\n * }\n * }\n * ```\n */\n getFutures(sport: string): Promise<FuturesEvent[]> {\n return this._request<FuturesEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/futures`\n );\n }\n\n getEventEv(\n sport: string,\n eventId: number | string,\n options: GetEventEvOptions = {}\n ): Promise<EventEvResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventEvResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev`,\n { params }\n );\n }\n\n /**\n * Cross-book best-line lookup for a single event.\n *\n * For each (market, player, line) tuple, returns the single best\n * American price across every book we carry, with the book name\n * attached. Companion to `getEventEv`: best-line tells you which\n * book has the highest payout right now; +EV tells you whether\n * that price beats a sharp no-vig fair line. Most line shoppers\n * want both.\n *\n * PrizePicks is excluded from the comparison — its DFS payout\n * structure (synthetic +100/+100 quotes) isn't directly comparable\n * to traditional sportsbook odds.\n *\n * Hobby tier or higher required (returns 403 on free).\n *\n * @example\n * ```ts\n * const bl = await client.getEventBestLine(\"baseball_mlb\", 12345);\n * for (const line of bl.lines) {\n * for (const [side, info] of Object.entries(line.sides)) {\n * console.log(\n * `${line.description} ${side} ${line.point}: ` +\n * `${info.best.price} @ ${info.best.book_title}`\n * );\n * }\n * }\n * ```\n */\n getEventBestLine(\n sport: string,\n eventId: number | string,\n options: GetEventBestLineOptions = {}\n ): Promise<EventBestLineResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventBestLineResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/best-line`,\n { params }\n );\n }\n\n /**\n * Calculate EV% for a user-supplied price against the event's\n * no-vig fair anchor. Useful for books PropLine doesn't carry —\n * Caesars, BetMGM, Fanatics, BetUS, Hard Rock — where you have a\n * price in hand and want to know if it's +EV against the sharp\n * consensus we do carry.\n *\n * Same fair-line math as `getEventEv` (Pinnacle-preferred anchor,\n * no-vig devigging) but takes one user price as input. Pro tier.\n *\n * @example\n * ```ts\n * const r = await client.calcEventEv(\"baseball_mlb\", 12614, {\n * market: \"h2h\",\n * name: \"Pittsburgh Pirates\",\n * price: -118,\n * });\n * console.log(`EV ${r.ev_pct}% fair=${r.fair_prob}`);\n * ```\n */\n calcEventEv(\n sport: string,\n eventId: number | string,\n options: CalcEventEvOptions\n ): Promise<EventEvCalcResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n name: options.name,\n price: options.price,\n };\n if (options.point !== undefined) params.point = options.point;\n if (options.description) params.description = options.description;\n return this._request<EventEvCalcResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev/calc`,\n { params }\n );\n }\n\n /**\n * Bulk CSV export of resolved prop outcomes (Pro+ tier).\n *\n * If `outPath` is provided, streams the CSV to disk and resolves to the\n * path. Otherwise resolves to the full CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportResolvedProps({\n * sport: \"baseball_mlb\",\n * market: \"pitcher_strikeouts\",\n * since: \"2026-04-01T00:00:00Z\",\n * outPath: \"./mlb-strikeouts.csv\",\n * });\n * ```\n */\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath: string }\n ): Promise<string>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/resolved-props\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(403, await readDetail(resp, \"Pro tier required\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n /**\n * Bulk CSV export of the full line-movement time-series.\n *\n * One row per (outcome, snapshot): every recorded odds snapshot (price +\n * line, per book, including period markets), not just the closing line.\n * This is the raw tick history no subscription tier can pull in bulk —\n * Pro/Streaming get per-event {@link getOddsHistory} only; this bulk\n * firehose is exclusive to the one-time Historical Backfill pass and\n * Enterprise.\n *\n * A full archive runs to gigabytes per sport — page month by month with\n * `since`/`until`. If `outPath` is provided, streams to disk and resolves\n * to the path; otherwise resolves to the CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportOddsHistory({\n * sport: \"baseball_mlb\",\n * since: \"2026-04-01T00:00:00Z\",\n * until: \"2026-05-01T00:00:00Z\",\n * outPath: \"./mlb-line-history-apr.csv\",\n * });\n * ```\n */\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath: string }\n ): Promise<string>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/odds-history\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(\n 403,\n await readDetail(resp, \"Historical Backfill pass or Enterprise required\")\n );\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n // ------------------------------------------------------------------\n // Webhooks (Streaming tier)\n // ------------------------------------------------------------------\n\n /**\n * Register a webhook subscription. Streaming tier only.\n *\n * The returned object includes the full signing `secret` — this is the\n * ONLY time it's revealed. Store it securely.\n */\n createWebhook(options: CreateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"POST\", \"/webhooks\", {\n body: webhookBody(options),\n });\n }\n\n /** List your webhook subscriptions. Secrets are masked. */\n listWebhooks(): Promise<Webhook[]> {\n return this._request<Webhook[]>(\"GET\", \"/webhooks\");\n }\n\n /** Get a single webhook subscription. Secret is masked. */\n getWebhook(webhookId: number): Promise<Webhook> {\n return this._request<Webhook>(\"GET\", `/webhooks/${webhookId}`);\n }\n\n /** Update fields on a webhook. Only supplied fields are changed. */\n updateWebhook(webhookId: number, options: UpdateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"PATCH\", `/webhooks/${webhookId}`, {\n body: webhookBody(options),\n });\n }\n\n /** Delete a webhook (cascades its delivery history). */\n deleteWebhook(webhookId: number): Promise<{ ok: boolean } | unknown> {\n return this._request(\"DELETE\", `/webhooks/${webhookId}`);\n }\n\n /** Queue a sample `test` payload to the webhook's URL. */\n testWebhook(webhookId: number): Promise<unknown> {\n return this._request(\"POST\", `/webhooks/${webhookId}/test`);\n }\n\n /** Last 50 (default) delivery attempts for a webhook. */\n listWebhookDeliveries(\n webhookId: number,\n options: ListWebhookDeliveriesOptions = {}\n ): Promise<WebhookDelivery[]> {\n return this._request<WebhookDelivery[]>(\n \"GET\",\n `/webhooks/${webhookId}/deliveries`,\n { params: { limit: options.limit ?? 50 } }\n );\n }\n\n /**\n * Verify that an inbound webhook delivery was signed by PropLine.\n *\n * Compares HMAC-SHA256(secret, `${timestamp}.` + body) against the\n * `X-PropLine-Signature` header in constant time.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * app.post(\"/hooks/propline\", express.raw({ type: \"*\\/*\" }), (req, res) => {\n * const ok = PropLine.verifySignature({\n * secret: process.env.WEBHOOK_SECRET!,\n * timestamp: req.header(\"X-PropLine-Timestamp\")!,\n * body: req.body, // raw Buffer\n * signature: req.header(\"X-PropLine-Signature\")!,\n * });\n * if (!ok) return res.status(401).end();\n * // ...\n * });\n * ```\n */\n static verifySignature(options: VerifySignatureOptions): boolean {\n const { secret, timestamp, body, signature } = options;\n const bodyBuf =\n typeof body === \"string\"\n ? Buffer.from(body, \"utf8\")\n : body instanceof Buffer\n ? body\n : Buffer.from(body);\n const message = Buffer.concat([Buffer.from(`${timestamp}.`, \"utf8\"), bodyBuf]);\n const expected = createHmac(\"sha256\", secret).update(message).digest(\"hex\");\n if (expected.length !== signature.length) return false;\n try {\n return timingSafeEqual(Buffer.from(expected, \"hex\"), Buffer.from(signature, \"hex\"));\n } catch {\n return false;\n }\n }\n}\n\nfunction webhookBody(options: CreateWebhookOptions | UpdateWebhookOptions): Record<string, unknown> {\n const body: Record<string, unknown> = {};\n const map: Array<[keyof (CreateWebhookOptions & UpdateWebhookOptions), string]> = [\n [\"url\", \"url\"],\n [\"events\", \"events\"],\n [\"filterSportKey\", \"filter_sport_key\"],\n [\"filterEventId\", \"filter_event_id\"],\n [\"filterMarketKey\", \"filter_market_key\"],\n [\"filterPlayerName\", \"filter_player_name\"],\n [\"minPriceChangePct\", \"min_price_change_pct\"],\n [\"minSteamScore\", \"min_steam_score\"],\n [\"active\", \"active\"],\n ];\n for (const [src, dst] of map) {\n const v = (options as Record<string, unknown>)[src as string];\n if (v !== undefined) body[dst] = v;\n }\n return body;\n}\n\nasync function readDetail(resp: Response, fallback: string): Promise<string> {\n try {\n const text = await resp.text();\n if (!text) return fallback;\n try {\n const json = JSON.parse(text) as { detail?: unknown };\n if (typeof json.detail === \"string\") return json.detail;\n } catch {\n // not JSON\n }\n return text || fallback;\n } catch {\n return fallback;\n }\n}\n","/**\n * PropLine — Node/TypeScript SDK for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const events = await client.getEvents(\"basketball_nba\");\n * const odds = await client.getOdds(\"basketball_nba\", {\n * eventId: events[0].id,\n * markets: [\"player_points\", \"player_rebounds\"],\n * });\n * ```\n */\n\nexport { PropLine } from \"./client.js\";\nexport {\n PropLineError,\n AuthError,\n RateLimitError,\n} from \"./client.js\";\nexport type {\n PropLineOptions,\n GetOddsOptions,\n GetOddsHistoryOptions,\n GetOddsClosingOptions,\n PeriodFilter,\n GetScoresOptions,\n GetMlbGrandSalamiOptions,\n GetNhlDailyGoalsTotalOptions,\n GetStatsOptions,\n GetResultsOptions,\n GetPlayerHistoryOptions,\n GetPlayerTrendsOptions,\n GetEventEvOptions,\n GetEventBestLineOptions,\n CalcEventEvOptions,\n ExportResolvedPropsOptions,\n ExportOddsHistoryOptions,\n WebhookEventType,\n CreateWebhookOptions,\n UpdateWebhookOptions,\n ListWebhookDeliveriesOptions,\n VerifySignatureOptions,\n} from \"./client.js\";\n\nexport type {\n Sport,\n Event,\n Outcome,\n ResolvedOutcome,\n Market,\n Bookmaker,\n OddsResponse,\n MarketSummary,\n OutcomeSnapshot,\n OddsHistoryOutcome,\n OddsHistoryMarket,\n OddsHistoryBookmaker,\n OddsHistoryResponse,\n ClosingOutcome,\n ClosingMarket,\n ClosingBookmaker,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiBook,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalBook,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n ResolutionSummarySport,\n ResolutionSummaryMarket,\n PlayerStat,\n StatsResponse,\n WeatherInfo,\n ContextResponse,\n MovementOutcome,\n MovementMarket,\n MovementBookmaker,\n SteamMove,\n MovementResponse,\n ResultsMarket,\n ResultsResponse,\n PlayerHistoryEntry,\n PlayerHistoryResponse,\n HitRateSplit,\n TrendStreak,\n TrendLastGame,\n PlayerMarketTrend,\n PlayerTrends,\n EvOutcome,\n EvLine,\n EventEvResponse,\n EventEvCalcResponse,\n BestPrice,\n BestLineSide,\n BestLine,\n EventBestLineResponse,\n FuturesOutcome,\n FuturesMarket,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** String constants for bookmaker keys in odds responses. */\nexport const Bookmakers = {\n BOVADA: \"bovada\",\n DRAFTKINGS: \"draftkings\",\n FANDUEL: \"fanduel\",\n PINNACLE: \"pinnacle\",\n UNIBET: \"unibet\",\n UNDERDOG: \"underdog\",\n KALSHI: \"kalshi\",\n POLYMARKET: \"polymarket\",\n PRIZEPICKS: \"prizepicks\",\n} as const;\n\nexport type BookmakerKey = (typeof Bookmakers)[keyof typeof Bookmakers];\n\nexport const VERSION = \"0.15.0\";\n"],"mappings":";AAAA,SAAS,YAAY,uBAAuB;AAC5C,SAAS,iBAAiB;AA4BnB,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAC9B;AAAA,EACA;AAAA,EAET,YAAY,YAAoB,QAAgB;AAC9C,UAAM,IAAI,UAAU,KAAK,MAAM,EAAE;AACjC,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,SAAS;AACd,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AAGO,IAAM,YAAN,cAAwB,cAAc;AAAA,EAC3C,YAAY,SAAS,mBAAmB;AACtC,UAAM,KAAK,MAAM;AACjB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AAGO,IAAM,iBAAN,cAA6B,cAAc;AAAA,EAChD,YAAY,SAAS,uBAAuB;AAC1C,UAAM,KAAK,MAAM;AACjB,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AAyEA,SAAS,aAAa,GAAiD;AACrE,MAAI,MAAM,OAAW,QAAO;AAC5B,SAAO,OAAO,MAAM,WAAW,IAAI,EAAE,KAAK,GAAG;AAC/C;AAmJA,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAapB,IAAM,WAAN,MAAe;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACQ;AAAA,EAEjB,YAAY,QAAgB,UAA2B,CAAC,GAAG;AACzD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AACA,SAAK,SAAS;AACd,SAAK,WAAW,QAAQ,WAAW,kBAAkB,QAAQ,OAAO,EAAE;AACtE,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,SAAS,QAAQ,SAAS,WAAW;AAC1C,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,MAAc,QAA8D;AAC5F,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,GAAG,IAAI,EAAE;AAC5C,QAAI,QAAQ;AACV,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,YAAI,MAAM,UAAa,MAAM,MAAM;AACjC,cAAI,aAAa,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA,EAEA,MAAc,SACZ,QACA,MACA,OAAiF,CAAC,GACtE;AACZ,UAAM,MAAM,KAAK,UAAU,MAAM,KAAK,MAAM;AAE5C,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,SAAS;AAEjE,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,KAAK;AAAA,QAC5B;AAAA,QACA,SAAS;AAAA,UACP,aAAa,KAAK;AAAA,UAClB,GAAI,KAAK,SAAS,SAAY,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,QAC1E;AAAA,QACA,MAAM,KAAK,SAAS,SAAY,KAAK,UAAU,KAAK,IAAI,IAAI;AAAA,QAC5D,QAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAEA,QAAI,KAAK,WAAW,KAAK;AACvB,YAAM,IAAI,UAAU,MAAM,WAAW,MAAM,iBAAiB,CAAC;AAAA,IAC/D;AACA,QAAI,KAAK,WAAW,KAAK;AACvB,YAAM,IAAI,eAAe,MAAM,WAAW,MAAM,qBAAqB,CAAC;AAAA,IACxE;AACA,QAAI,KAAK,UAAU,KAAK;AACtB,YAAM,IAAI,cAAc,KAAK,QAAQ,MAAM,WAAW,MAAM,KAAK,UAAU,CAAC;AAAA,IAC9E;AAEA,QAAI,KAAK,WAAW,KAAK;AACvB,aAAO;AAAA,IACT;AACA,WAAQ,MAAM,KAAK,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAA8B;AAC5B,WAAO,KAAK,SAAkB,OAAO,SAAS;AAAA,EAChD;AAAA;AAAA,EAGA,UAAU,OAAyC;AACjD,WAAO,KAAK,SAA0B,OAAO,WAAW,mBAAmB,KAAK,CAAC,SAAS;AAAA,EAC5F;AAAA,EAkBA,QACE,OACA,UAA0B,CAAC,GACa;AACxC,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAO,UAAU,QAAQ,QAAQ,KAAK,GAAG;AAAA,IAC3C;AACA,UAAM,cAAc,aAAa,QAAQ,MAAM;AAC/C,QAAI,gBAAgB,OAAW,QAAO,SAAS;AAC/C,UAAM,KAAK,mBAAmB,KAAK;AACnC,QAAI,QAAQ,YAAY,QAAW;AACjC,aAAO,KAAK;AAAA,QACV;AAAA,QACA,WAAW,EAAE,WAAW,mBAAmB,OAAO,QAAQ,OAAO,CAAC,CAAC;AAAA,QACnE,EAAE,OAAO;AAAA,MACX;AAAA,IACF;AACA,WAAO,KAAK,SAAyB,OAAO,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC;AAAA,EAC9E;AAAA;AAAA,EAGA,WAAW,OAAe,SAAoD;AAC5E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,IACpF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,eACE,OACA,SACA,UAAiC,CAAC,GACJ;AAC9B,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAO,UAAU,QAAQ,QAAQ,KAAK,GAAG;AAAA,IAC3C;AACA,QAAI,QAAQ,SAAS,OAAW,QAAO,OAAO,QAAQ;AACtD,QAAI,QAAQ,OAAO,OAAW,QAAO,KAAK,QAAQ;AAClD,QAAI,QAAQ,iBAAiB,OAAW,QAAO,gBAAgB,QAAQ;AACvE,QAAI,QAAQ,eAAe,OAAW,QAAO,cAAc,QAAQ;AACnE,QAAI,QAAQ,aAAa,OAAW,QAAO,WAAW,QAAQ;AAC9D,QAAI,QAAQ,YAAa,QAAO,eAAe;AAC/C,UAAM,eAAe,aAAa,QAAQ,MAAM;AAChD,QAAI,iBAAiB,OAAW,QAAO,SAAS;AAChD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,eACE,OACA,SACA,UAAiC,CAAC,GACJ;AAC9B,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAO,UAAU,QAAQ,QAAQ,KAAK,GAAG;AAAA,IAC3C;AACA,UAAM,eAAe,aAAa,QAAQ,MAAM;AAChD,QAAI,iBAAiB,OAAW,QAAO,SAAS;AAChD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA,EAGA,UAAU,OAAe,UAA4B,CAAC,GAA0B;AAC9E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC;AAAA,MACpC,EAAE,QAAQ,EAAE,WAAW,QAAQ,YAAY,EAAE,EAAE;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,kBACE,UAAoC,CAAC,GACJ;AACjC,UAAM,SAAiC,CAAC;AACxC,QAAI,QAAQ,KAAM,QAAO,OAAO,QAAQ;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,sBACE,UAAwC,CAAC,GACJ;AACrC,UAAM,SAAiC,CAAC;AACxC,QAAI,QAAQ,KAAM,QAAO,OAAO,QAAQ;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,qBAAqB,OAAO,IAAgC;AAC1D,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,EAAE,MAAM,OAAO,IAAI,EAAE,EAAE;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SACE,OACA,SACA,UAA2B,CAAC,GACJ;AACxB,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,UAAU,QAAQ;AAC5B,aAAO,YAAY,QAAQ,SAAS,KAAK,GAAG;AAAA,IAC9C;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,WACE,OACA,SAC0B;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,IACpF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,YACE,OACA,SACA,UAA8B,CAAC,GACJ;AAC3B,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAO,UAAU,QAAQ,QAAQ,KAAK,GAAG;AAAA,IAC3C;AACA,WAAO,SAAS,aAAa,QAAQ,MAAM;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WACE,OACA,SACA,UAA6B,CAAC,GACJ;AAC1B,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAO,UAAU,QAAQ,QAAQ,KAAK,GAAG;AAAA,IAC3C;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBACE,OACA,YACA,SACgC;AAChC,UAAM,SAAsD;AAAA,MAC1D,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ,SAAS;AAAA,IAC1B;AACA,QAAI,QAAQ,WAAW;AACrB,aAAO,YAAY,QAAQ;AAAA,IAC7B;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,YAAY,mBAAmB,UAAU,CAAC;AAAA,MAC9E,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,gBACE,UACA,YACA,UAAkC,CAAC,GACZ;AACvB,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,QAAQ;AAClB,aAAO,SAAS,QAAQ;AAAA,IAC1B;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,QAAQ,CAAC,YAAY,mBAAmB,UAAU,CAAC;AAAA,MACjF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwCA,WAAW,OAAwC;AACjD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,WACE,OACA,SACA,UAA6B,CAAC,GACJ;AAC1B,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,SAAS;AACnB,aAAO,UAAU,MAAM,QAAQ,QAAQ,OAAO,IAC1C,QAAQ,QAAQ,KAAK,GAAG,IACxB,QAAQ;AAAA,IACd;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+BA,iBACE,OACA,SACA,UAAmC,CAAC,GACJ;AAChC,UAAM,SAA6C,CAAC;AACpD,QAAI,QAAQ,SAAS;AACnB,aAAO,UAAU,MAAM,QAAQ,QAAQ,OAAO,IAC1C,QAAQ,QAAQ,KAAK,GAAG,IACxB,QAAQ;AAAA,IACd;AACA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,YACE,OACA,SACA,SAC8B;AAC9B,UAAM,SAAsD;AAAA,MAC1D,QAAQ,QAAQ;AAAA,MAChB,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ;AAAA,IACjB;AACA,QAAI,QAAQ,UAAU,OAAW,QAAO,QAAQ,QAAQ;AACxD,QAAI,QAAQ,YAAa,QAAO,cAAc,QAAQ;AACtD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC,WAAW,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAClF,EAAE,OAAO;AAAA,IACX;AAAA,EACF;AAAA,EAwBA,MAAM,oBACJ,SAC8B;AAC9B,UAAM,SAA6C,EAAE,OAAO,QAAQ,MAAM;AAC1E,QAAI,QAAQ,OAAQ,QAAO,SAAS,QAAQ;AAC5C,QAAI,QAAQ,UAAW,QAAO,YAAY,QAAQ;AAClD,QAAI,QAAQ,MAAO,QAAO,QAAQ,QAAQ;AAC1C,QAAI,QAAQ,MAAO,QAAO,QAAQ,QAAQ;AAE1C,UAAM,MAAM,KAAK,UAAU,2BAA2B,MAAM;AAC5D,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,SAAS;AAEjE,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,KAAK;AAAA,QAC5B,QAAQ;AAAA,QACR,SAAS,EAAE,aAAa,KAAK,OAAO;AAAA,QACpC,QAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAEA,QAAI,KAAK,WAAW,KAAK;AACvB,YAAM,IAAI,UAAU;AAAA,IACtB;AACA,QAAI,KAAK,WAAW,KAAK;AACvB,YAAM,IAAI,cAAc,KAAK,MAAM,WAAW,MAAM,mBAAmB,CAAC;AAAA,IAC1E;AACA,QAAI,KAAK,UAAU,KAAK;AACtB,YAAM,IAAI,cAAc,KAAK,QAAQ,MAAM,WAAW,MAAM,KAAK,UAAU,CAAC;AAAA,IAC9E;AAEA,UAAM,MAAM,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AACnD,QAAI,QAAQ,SAAS;AACnB,YAAM,UAAU,QAAQ,SAAS,GAAG;AACpC,aAAO,QAAQ;AAAA,IACjB;AACA,WAAO;AAAA,EACT;AAAA,EAgCA,MAAM,kBACJ,SAC8B;AAC9B,UAAM,SAA6C,EAAE,OAAO,QAAQ,MAAM;AAC1E,QAAI,QAAQ,OAAQ,QAAO,SAAS,QAAQ;AAC5C,QAAI,QAAQ,UAAW,QAAO,YAAY,QAAQ;AAClD,QAAI,QAAQ,MAAO,QAAO,QAAQ,QAAQ;AAC1C,QAAI,QAAQ,MAAO,QAAO,QAAQ,QAAQ;AAE1C,UAAM,MAAM,KAAK,UAAU,yBAAyB,MAAM;AAC1D,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,SAAS;AAEjE,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,KAAK;AAAA,QAC5B,QAAQ;AAAA,QACR,SAAS,EAAE,aAAa,KAAK,OAAO;AAAA,QACpC,QAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAEA,QAAI,KAAK,WAAW,KAAK;AACvB,YAAM,IAAI,UAAU;AAAA,IACtB;AACA,QAAI,KAAK,WAAW,KAAK;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,QACA,MAAM,WAAW,MAAM,iDAAiD;AAAA,MAC1E;AAAA,IACF;AACA,QAAI,KAAK,UAAU,KAAK;AACtB,YAAM,IAAI,cAAc,KAAK,QAAQ,MAAM,WAAW,MAAM,KAAK,UAAU,CAAC;AAAA,IAC9E;AAEA,UAAM,MAAM,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AACnD,QAAI,QAAQ,SAAS;AACnB,YAAM,UAAU,QAAQ,SAAS,GAAG;AACpC,aAAO,QAAQ;AAAA,IACjB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,cAAc,SAAiD;AAC7D,WAAO,KAAK,SAAkB,QAAQ,aAAa;AAAA,MACjD,MAAM,YAAY,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,eAAmC;AACjC,WAAO,KAAK,SAAoB,OAAO,WAAW;AAAA,EACpD;AAAA;AAAA,EAGA,WAAW,WAAqC;AAC9C,WAAO,KAAK,SAAkB,OAAO,aAAa,SAAS,EAAE;AAAA,EAC/D;AAAA;AAAA,EAGA,cAAc,WAAmB,SAAiD;AAChF,WAAO,KAAK,SAAkB,SAAS,aAAa,SAAS,IAAI;AAAA,MAC/D,MAAM,YAAY,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,cAAc,WAAuD;AACnE,WAAO,KAAK,SAAS,UAAU,aAAa,SAAS,EAAE;AAAA,EACzD;AAAA;AAAA,EAGA,YAAY,WAAqC;AAC/C,WAAO,KAAK,SAAS,QAAQ,aAAa,SAAS,OAAO;AAAA,EAC5D;AAAA;AAAA,EAGA,sBACE,WACA,UAAwC,CAAC,GACb;AAC5B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,aAAa,SAAS;AAAA,MACtB,EAAE,QAAQ,EAAE,OAAO,QAAQ,SAAS,GAAG,EAAE;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBA,OAAO,gBAAgB,SAA0C;AAC/D,UAAM,EAAE,QAAQ,WAAW,MAAM,UAAU,IAAI;AAC/C,UAAM,UACJ,OAAO,SAAS,WACZ,OAAO,KAAK,MAAM,MAAM,IACxB,gBAAgB,SACd,OACA,OAAO,KAAK,IAAI;AACxB,UAAM,UAAU,OAAO,OAAO,CAAC,OAAO,KAAK,GAAG,SAAS,KAAK,MAAM,GAAG,OAAO,CAAC;AAC7E,UAAM,WAAW,WAAW,UAAU,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAC1E,QAAI,SAAS,WAAW,UAAU,OAAQ,QAAO;AACjD,QAAI;AACF,aAAO,gBAAgB,OAAO,KAAK,UAAU,KAAK,GAAG,OAAO,KAAK,WAAW,KAAK,CAAC;AAAA,IACpF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,YAAY,SAA+E;AAClG,QAAM,OAAgC,CAAC;AACvC,QAAM,MAA4E;AAAA,IAChF,CAAC,OAAO,KAAK;AAAA,IACb,CAAC,UAAU,QAAQ;AAAA,IACnB,CAAC,kBAAkB,kBAAkB;AAAA,IACrC,CAAC,iBAAiB,iBAAiB;AAAA,IACnC,CAAC,mBAAmB,mBAAmB;AAAA,IACvC,CAAC,oBAAoB,oBAAoB;AAAA,IACzC,CAAC,qBAAqB,sBAAsB;AAAA,IAC5C,CAAC,iBAAiB,iBAAiB;AAAA,IACnC,CAAC,UAAU,QAAQ;AAAA,EACrB;AACA,aAAW,CAAC,KAAK,GAAG,KAAK,KAAK;AAC5B,UAAM,IAAK,QAAoC,GAAa;AAC5D,QAAI,MAAM,OAAW,MAAK,GAAG,IAAI;AAAA,EACnC;AACA,SAAO;AACT;AAEA,eAAe,WAAW,MAAgB,UAAmC;AAC3E,MAAI;AACF,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,UAAI,OAAO,KAAK,WAAW,SAAU,QAAO,KAAK;AAAA,IACnD,QAAQ;AAAA,IAER;AACA,WAAO,QAAQ;AAAA,EACjB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACr/BO,IAAM,aAAa;AAAA,EACxB,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY;AACd;AAIO,IAAM,UAAU;","names":[]}
1
+ {"version":3,"sources":["../src/client.ts","../src/index.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport type {\n Sport,\n Event as PropLineEvent,\n OddsResponse,\n MarketSummary,\n OddsHistoryResponse,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n StatsResponse,\n ContextResponse,\n MovementResponse,\n ResultsResponse,\n PlayerHistoryResponse,\n PlayerTrends,\n EventEvResponse,\n EventEvCalcResponse,\n EventBestLineResponse,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** Base error for all PropLine API failures. */\nexport class PropLineError extends Error {\n readonly statusCode: number;\n readonly detail: string;\n\n constructor(statusCode: number, detail: string) {\n super(`[${statusCode}] ${detail}`);\n this.name = \"PropLineError\";\n this.statusCode = statusCode;\n this.detail = detail;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the API key is missing or invalid (HTTP 401). */\nexport class AuthError extends PropLineError {\n constructor(detail = \"Invalid API key\") {\n super(401, detail);\n this.name = \"AuthError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when the daily request limit is exceeded (HTTP 429). */\nexport class RateLimitError extends PropLineError {\n constructor(detail = \"Rate limit exceeded\") {\n super(429, detail);\n this.name = \"RateLimitError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport interface PropLineOptions {\n /** API base URL. Default: `https://api.prop-line.com/v1`. */\n baseUrl?: string;\n /** Request timeout in milliseconds. Default: 15000. */\n timeoutMs?: number;\n /** Custom fetch implementation. Defaults to global `fetch` (Node 18+). */\n fetch?: typeof fetch;\n}\n\n/**\n * Game-period filter. String of canonical codes, optionally\n * comma-separated, or the sentinel `\"all\"`. Omitted = full-game\n * markets only (backwards-compatible default).\n *\n * \"q1\" — 1st quarter\n * \"q1,q2\" — 1st and 2nd quarters\n * [\"q1\",\"q2\"] — same, as an array\n * \"h1\" — 1st half\n * \"p1\"|\"p2\"|\"p3\" — hockey periods\n * \"i6\" — 6th inning\n * \"f3\"|\"f5\"|\"f7\" — first N innings\n * \"all\" — every period including full game\n */\nexport type PeriodFilter = string | string[];\n\nexport interface GetOddsOptions {\n /** Specific event ID to get odds (with player props) for. Omit for bulk odds. */\n eventId?: number | string;\n /**\n * Market keys to filter by. If omitted, the bulk `/odds` endpoint\n * defaults to `h2h` and the per-event `/odds` endpoint defaults to\n * `h2h,spreads,totals` — game-line markets every book carries across\n * every sport. Pass an explicit list to fetch player props (e.g.\n * `[\"pitcher_strikeouts\", \"batter_home_runs\"]` for MLB,\n * `[\"player_points\", \"player_rebounds\"]` for NBA).\n */\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsHistoryOptions {\n markets?: string[];\n /** ISO timestamp; only include snapshots at or after this time. Mutually exclusive with `relativeFrom`. */\n from?: string;\n /** ISO timestamp; only include snapshots at or before this time. Mutually exclusive with `relativeTo`. */\n to?: string;\n /** Offset relative to commence_time, e.g. \"-3h\", \"-30m\", \"-90s\". Mutually exclusive with `from`. */\n relativeFrom?: string;\n /** Offset relative to commence_time, e.g. \"-1m\" or \"0\" for commence_time itself. Mutually exclusive with `to`. */\n relativeTo?: string;\n /** Downsample to one snapshot per bucket. Latest snapshot in each bucket wins. */\n interval?: \"30s\" | \"1m\" | \"5m\" | \"15m\" | \"30m\" | \"1h\";\n /** When true, drop snapshots whose (price, point) match the previous one. Opening line is always kept. */\n changesOnly?: boolean;\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetOddsClosingOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nexport interface GetMovementOptions {\n markets?: string[];\n /** Game-period filter — see `PeriodFilter`. */\n period?: PeriodFilter;\n}\n\nfunction _periodParam(p: PeriodFilter | undefined): string | undefined {\n if (p === undefined) return undefined;\n return typeof p === \"string\" ? p : p.join(\",\");\n}\n\nexport interface GetScoresOptions {\n /** Days back to include (default 3). */\n daysFrom?: number;\n}\n\nexport interface GetMlbGrandSalamiOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetNhlDailyGoalsTotalOptions {\n /** YYYY-MM-DD UTC date. Defaults to today (UTC) when omitted. */\n date?: string;\n}\n\nexport interface GetStatsOptions {\n /** Stat types to filter by (e.g. `[\"strikeouts\", \"hits\"]`). */\n statType?: string[];\n}\n\nexport interface GetResultsOptions {\n markets?: string[];\n}\n\nexport interface GetPlayerHistoryOptions {\n /** Market key (e.g. `\"pitcher_strikeouts\"`). Required. */\n market: string;\n /** Restrict to a single bookmaker (e.g. `\"draftkings\"`). */\n bookmaker?: string;\n /** Max entries (1-100). Default 20. */\n limit?: number;\n}\n\nexport interface GetPlayerTrendsOptions {\n /** Market key (e.g. `\"batter_total_bases\"`). Omit for all markets. */\n market?: string;\n}\n\nexport interface GetEventEvOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"batter_hits\"]`).\n * Omit to evaluate every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface GetEventBestLineOptions {\n /**\n * Optional market filter. Pass a single comma-separated string or an\n * array of market keys (e.g. `[\"pitcher_strikeouts\", \"h2h\"]`). Omit\n * to include every market on the event.\n */\n markets?: string | string[];\n}\n\nexport interface CalcEventEvOptions {\n /** Market key — h2h / spreads / totals / pitcher_strikeouts / etc. */\n market: string;\n /** Outcome name. Team for h2h/spreads; \"Over\" or \"Under\" for totals/props. */\n name: string;\n /** American odds at your book, e.g. -118 or 145. */\n price: number;\n /** Line/point for spreads, totals, player props. Sign matters for spreads (-1.5 favorite). Omit for h2h. */\n point?: number;\n /** Player name for player-prop markets. Omit for game-line markets. */\n description?: string;\n}\n\nexport interface ExportResolvedPropsOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `resolved_at`. */\n since?: string;\n /** ISO datetime upper bound on `resolved_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\nexport interface ExportOddsHistoryOptions {\n /** Sport key (e.g. `\"baseball_mlb\"`). Required. */\n sport: string;\n /** Optional market filter. */\n market?: string;\n /** Optional bookmaker filter. */\n bookmaker?: string;\n /** ISO datetime lower bound on `recorded_at`. */\n since?: string;\n /** ISO datetime upper bound on `recorded_at`. */\n until?: string;\n /** If set, stream the CSV to this path and resolve to the path. Otherwise resolve to the CSV bytes. */\n outPath?: string;\n}\n\n/** Webhook event types. `steam` = cross-book sharp-money alert. */\nexport type WebhookEventType = \"line_movement\" | \"resolution\" | \"steam\";\n\nexport interface CreateWebhookOptions {\n /** HTTPS endpoint to receive POSTed events. Required. */\n url: string;\n /** Event types to subscribe to. Default: all. */\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n /** Minimum % change in American odds to fire a line_movement. Point-only shifts always pass. */\n minPriceChangePct?: number;\n /** Minimum 0-100 steam score to fire a `steam` event. Null = detector's global floor. */\n minSteamScore?: number;\n}\n\nexport interface UpdateWebhookOptions {\n url?: string;\n events?: WebhookEventType[];\n filterSportKey?: string;\n filterEventId?: number;\n filterMarketKey?: string;\n filterPlayerName?: string;\n minPriceChangePct?: number;\n minSteamScore?: number;\n active?: boolean;\n}\n\nexport interface ListWebhookDeliveriesOptions {\n /** Max deliveries to return. Default 50. */\n limit?: number;\n}\n\nexport interface VerifySignatureOptions {\n /** Webhook signing secret (returned once from `createWebhook`). */\n secret: string;\n /** Value of the `X-PropLine-Timestamp` header. */\n timestamp: string;\n /** Raw request body. */\n body: Uint8Array | Buffer | string;\n /** Value of the `X-PropLine-Signature` header. */\n signature: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.prop-line.com/v1\";\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\n/**\n * Client for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const sports = await client.getSports();\n * ```\n */\nexport class PropLine {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeoutMs: number;\n private readonly _fetch: typeof fetch;\n\n constructor(apiKey: string, options: PropLineOptions = {}) {\n if (!apiKey) {\n throw new Error(\"PropLine: apiKey is required\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this._fetch = options.fetch ?? globalThis.fetch;\n if (!this._fetch) {\n throw new Error(\n \"PropLine: global fetch is unavailable. Use Node 18+ or pass options.fetch.\"\n );\n }\n }\n\n // ------------------------------------------------------------------\n // Internals\n // ------------------------------------------------------------------\n\n private _buildUrl(path: string, params?: Record<string, string | number | undefined>): string {\n const url = new URL(`${this.baseUrl}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) {\n url.searchParams.set(k, String(v));\n }\n }\n }\n return url.toString();\n }\n\n private async _request<T>(\n method: string,\n path: string,\n init: { params?: Record<string, string | number | undefined>; body?: unknown } = {}\n ): Promise<T> {\n const url = this._buildUrl(path, init.params);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method,\n headers: {\n \"X-API-Key\": this.apiKey,\n ...(init.body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n },\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError(await readDetail(resp, \"Invalid API key\"));\n }\n if (resp.status === 429) {\n throw new RateLimitError(await readDetail(resp, \"Rate limit exceeded\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n if (resp.status === 204) {\n return undefined as T;\n }\n return (await resp.json()) as T;\n }\n\n // ------------------------------------------------------------------\n // Public API\n // ------------------------------------------------------------------\n\n /** List all available sports. */\n getSports(): Promise<Sport[]> {\n return this._request<Sport[]>(\"GET\", \"/sports\");\n }\n\n /** List upcoming events for a sport. */\n getEvents(sport: string): Promise<PropLineEvent[]> {\n return this._request<PropLineEvent[]>(\"GET\", `/sports/${encodeURIComponent(sport)}/events`);\n }\n\n /**\n * Get current odds. With `eventId`, returns single-event odds (including\n * player props). Without, returns bulk odds for all upcoming events.\n *\n * Each response carries a `bookmakers` array — iterate it to compare\n * lines across Bovada, DraftKings, FanDuel, Pinnacle, Unibet, and\n * PrizePicks (coverage varies by sport).\n */\n getOdds(\n sport: string,\n options: GetOddsOptions & { eventId: number | string }\n ): Promise<OddsResponse>;\n getOdds(\n sport: string,\n options?: Omit<GetOddsOptions, \"eventId\"> & { eventId?: undefined }\n ): Promise<OddsResponse[]>;\n getOdds(\n sport: string,\n options: GetOddsOptions = {}\n ): Promise<OddsResponse | OddsResponse[]> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam = _periodParam(options.period);\n if (periodParam !== undefined) params.period = periodParam;\n const sp = encodeURIComponent(sport);\n if (options.eventId !== undefined) {\n return this._request<OddsResponse>(\n \"GET\",\n `/sports/${sp}/events/${encodeURIComponent(String(options.eventId))}/odds`,\n { params }\n );\n }\n return this._request<OddsResponse[]>(\"GET\", `/sports/${sp}/odds`, { params });\n }\n\n /** List the available market types for an event. */\n getMarkets(sport: string, eventId: number | string): Promise<MarketSummary[]> {\n return this._request<MarketSummary[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/markets`\n );\n }\n\n /**\n * Get historical odds movement for an event.\n *\n * Hobby+: full snapshots. Free tier: redacted (snapshot counts only).\n *\n * Supports period-historical filters:\n * - `from` / `to` — absolute ISO timestamps\n * - `relativeFrom` / `relativeTo` — offsets to commence_time (\"-3h\", \"-30m\", \"0\")\n * - `interval` — downsample to a fixed bucket size\n * - `changesOnly` — drop unchanged adjacent snapshots\n */\n getOddsHistory(\n sport: string,\n eventId: number | string,\n options: GetOddsHistoryOptions = {}\n ): Promise<OddsHistoryResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n if (options.from !== undefined) params.from = options.from;\n if (options.to !== undefined) params.to = options.to;\n if (options.relativeFrom !== undefined) params.relative_from = options.relativeFrom;\n if (options.relativeTo !== undefined) params.relative_to = options.relativeTo;\n if (options.interval !== undefined) params.interval = options.interval;\n if (options.changesOnly) params.changes_only = \"true\";\n const periodParam2 = _periodParam(options.period);\n if (periodParam2 !== undefined) params.period = periodParam2;\n return this._request<OddsHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/history`,\n { params }\n );\n }\n\n /**\n * Get the closing line per `(book, market, outcome)` for an event —\n * the last snapshot at or before commence_time. Canonical CLV helper:\n * replaces \"fetch full history → find latest pre-game row\" with one\n * call. Each outcome carries a `closingAt` field with the snapshot's\n * recorded_at timestamp.\n *\n * Hobby+: full data. Free tier: redacted.\n */\n getOddsClosing(\n sport: string,\n eventId: number | string,\n options: GetOddsClosingOptions = {}\n ): Promise<OddsClosingResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n const periodParam3 = _periodParam(options.period);\n if (periodParam3 !== undefined) params.period = periodParam3;\n return this._request<OddsClosingResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/odds/closing`,\n { params }\n );\n }\n\n /** Get game scores and status (free tier). */\n getScores(sport: string, options: GetScoresOptions = {}): Promise<ScoreEvent[]> {\n return this._request<ScoreEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/scores`,\n { params: { days_from: options.daysFrom ?? 3 } }\n );\n }\n\n /**\n * Synthetic MLB Grand Salami for a given UTC date — total runs scored\n * across every MLB game on the slate, plus each book's implied Grand\n * Salami line (median of per-game primary totals across our MLB books).\n *\n * No retail sportsbook quotes this as a single market, so historical\n * cross-book Grand Salami data isn't available elsewhere. Free tier;\n * defaults to today (UTC).\n */\n getMlbGrandSalami(\n options: GetMlbGrandSalamiOptions = {}\n ): Promise<MlbGrandSalamiResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<MlbGrandSalamiResponse>(\n \"GET\",\n \"/sports/baseball_mlb/grand-salami\",\n { params }\n );\n }\n\n /**\n * Synthetic NHL Daily Goals Total for a given UTC date — total goals\n * scored (incl. OT/SO) across every NHL game on the slate, plus each\n * book's implied Daily Goals Total line (median of per-game primary\n * totals across our NHL books).\n *\n * Hockey's equivalent of the MLB Grand Salami. No retail sportsbook\n * quotes this as a single market. Free tier; defaults to today (UTC).\n */\n getNhlDailyGoalsTotal(\n options: GetNhlDailyGoalsTotalOptions = {}\n ): Promise<NhlDailyGoalsTotalResponse> {\n const params: Record<string, string> = {};\n if (options.date) params.date = options.date;\n return this._request<NhlDailyGoalsTotalResponse>(\n \"GET\",\n \"/sports/hockey_nhl/daily-goals-total\",\n { params }\n );\n }\n\n /**\n * Factual volume of graded player props over the last N days (free tier).\n *\n * Aggregated counts only — a coverage proof (every outcome counted was\n * graded against the real box score), never a profitability claim.\n *\n * @param days Look-back window, 1-90 (default 30).\n */\n getResolutionSummary(days = 30): Promise<ResolutionSummary> {\n return this._request<ResolutionSummary>(\n \"GET\",\n \"/markets/resolution-summary\",\n { params: { days: String(days) } }\n );\n }\n\n /**\n * Get raw player/team box-score stats (book-agnostic, free tier).\n *\n * Returns actual stat values decoupled from any bookmaker's lines.\n */\n getStats(\n sport: string,\n eventId: number | string,\n options: GetStatsOptions = {}\n ): Promise<StatsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.statType?.length) {\n params.stat_type = options.statType.join(\",\");\n }\n return this._request<StatsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/stats`,\n { params }\n );\n }\n\n /**\n * Get game context — the conditions a prop settles under.\n *\n * For MLB: probable starting pitchers and their throwing hand\n * (`home_probable_pitcher_hand` / `away_probable_pitcher_hand`, \"L\"/\"R\"/\"S\"\n * — platoon-split context for every batter prop), a confirmed-lineup flag,\n * the home-plate umpire, and first-pitch weather (outdoor / open-roof\n * venues; indoor venues return `weather: null` with `is_indoor: true`).\n * For NFL & NCAAF: the venue and kickoff weather (pitcher/umpire/lineup\n * fields are null for football). The same block is embedded in\n * {@link getResults}, so every graded prop carries its conditions — unique\n * to PropLine. Free tier. Rejects with a 404 when no context is on file\n * for the event yet.\n */\n getContext(\n sport: string,\n eventId: number | string\n ): Promise<ContextResponse> {\n return this._request<ContextResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/context`\n );\n }\n\n /**\n * Get line movement + steam detection from the snapshot tick history.\n *\n * Per (book, market, outcome): opening line, latest line, signed\n * implied-probability shift, point shift, direction. The `steam` array\n * flags outcomes multiple books moved the same direction — the\n * sharp-money signal across every book PropLine polls. When a book moves\n * the line itself, that outcome's `prob_shift` is null and `direction` is\n * `\"line_moved\"` (excluded from the steam signal). Unique to PropLine.\n * Hobby+ full; free tier redacted.\n */\n getMovement(\n sport: string,\n eventId: number | string,\n options: GetMovementOptions = {}\n ): Promise<MovementResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n params.period = _periodParam(options.period);\n return this._request<MovementResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/movement`,\n { params }\n );\n }\n\n /**\n * Get resolved prop outcomes with actual player stats.\n *\n * Pro tier: full data. Free tier: redacted (resolution + actual nulled).\n */\n getResults(\n sport: string,\n eventId: number | string,\n options: GetResultsOptions = {}\n ): Promise<ResultsResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets?.length) {\n params.markets = options.markets.join(\",\");\n }\n return this._request<ResultsResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/results`,\n { params }\n );\n }\n\n /**\n * Recent resolved prop history for a player on a market.\n *\n * One entry per (event, bookmaker) pair. Pro: full. Free: redacted.\n */\n getPlayerHistory(\n sport: string,\n playerName: string,\n options: GetPlayerHistoryOptions\n ): Promise<PlayerHistoryResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n limit: options.limit ?? 20,\n };\n if (options.bookmaker) {\n params.bookmaker = options.bookmaker;\n }\n return this._request<PlayerHistoryResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/players/${encodeURIComponent(playerName)}/history`,\n { params }\n );\n }\n\n /**\n * Rolling hit-rate trends for a player across one or all markets.\n *\n * Returns over/under/push splits over the last 5/10/20/50 graded games,\n * the current streak, and the most recent game per market. Pro: full.\n * Free: redacted.\n */\n getPlayerTrends(\n sportKey: string,\n playerName: string,\n options: GetPlayerTrendsOptions = {}\n ): Promise<PlayerTrends> {\n const params: Record<string, string | undefined> = {};\n if (options.market) {\n params.market = options.market;\n }\n return this._request<PlayerTrends>(\n \"GET\",\n `/sports/${encodeURIComponent(sportKey)}/players/${encodeURIComponent(playerName)}/trends`,\n { params }\n );\n }\n\n /**\n * Cross-book +EV analysis for a single event (Pro+ tier).\n *\n * Groups every outcome by (market, player, line) across the books we\n * carry, derives a no-vig fair line from a sharp anchor (Pinnacle\n * preferred, Bovada fallback), and returns EV% per book at the same\n * line. Outcomes are sorted with +EV plays floated to the top.\n *\n * PrizePicks is excluded — its synthetic +100/+100 prices aren't\n * payout odds. Lines without sharp-anchor coverage are dropped.\n *\n * @example\n * ```ts\n * const ev = await client.getEventEv(\"baseball_mlb\", 12345);\n * for (const line of ev.lines) {\n * const plus = line.outcomes.filter(o => o.is_plus_ev);\n * if (plus.length) console.log(line.market_key, line.description, plus);\n * }\n * ```\n */\n /**\n * List futures markets for a sport — championship winner, MVP,\n * division winner, etc. Each row is one (futures event, book,\n * market) with every team or player priced. Free tier; pulled from\n * each book's futures feed (Bovada today).\n *\n * @example\n * ```ts\n * const futures = await client.getFutures(\"baseball_mlb\");\n * for (const event of futures) {\n * console.log(`${event.title} @ ${event.commence_time}`);\n * for (const m of event.markets) {\n * const top3 = [...m.outcomes].sort((a, b) => a.price - b.price).slice(0, 3);\n * for (const o of top3) console.log(` ${o.name}: ${o.price}`);\n * }\n * }\n * ```\n */\n getFutures(sport: string): Promise<FuturesEvent[]> {\n return this._request<FuturesEvent[]>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/futures`\n );\n }\n\n getEventEv(\n sport: string,\n eventId: number | string,\n options: GetEventEvOptions = {}\n ): Promise<EventEvResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventEvResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev`,\n { params }\n );\n }\n\n /**\n * Cross-book best-line lookup for a single event.\n *\n * For each (market, player, line) tuple, returns the single best\n * American price across every book we carry, with the book name\n * attached. Companion to `getEventEv`: best-line tells you which\n * book has the highest payout right now; +EV tells you whether\n * that price beats a sharp no-vig fair line. Most line shoppers\n * want both.\n *\n * PrizePicks is excluded from the comparison — its DFS payout\n * structure (synthetic +100/+100 quotes) isn't directly comparable\n * to traditional sportsbook odds.\n *\n * Hobby tier or higher required (returns 403 on free).\n *\n * @example\n * ```ts\n * const bl = await client.getEventBestLine(\"baseball_mlb\", 12345);\n * for (const line of bl.lines) {\n * for (const [side, info] of Object.entries(line.sides)) {\n * console.log(\n * `${line.description} ${side} ${line.point}: ` +\n * `${info.best.price} @ ${info.best.book_title}`\n * );\n * }\n * }\n * ```\n */\n getEventBestLine(\n sport: string,\n eventId: number | string,\n options: GetEventBestLineOptions = {}\n ): Promise<EventBestLineResponse> {\n const params: Record<string, string | undefined> = {};\n if (options.markets) {\n params.markets = Array.isArray(options.markets)\n ? options.markets.join(\",\")\n : options.markets;\n }\n return this._request<EventBestLineResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/best-line`,\n { params }\n );\n }\n\n /**\n * Calculate EV% for a user-supplied price against the event's\n * no-vig fair anchor. Useful for books PropLine doesn't carry —\n * Caesars, BetMGM, Fanatics, BetUS, Hard Rock — where you have a\n * price in hand and want to know if it's +EV against the sharp\n * consensus we do carry.\n *\n * Same fair-line math as `getEventEv` (Pinnacle-preferred anchor,\n * no-vig devigging) but takes one user price as input. Pro tier.\n *\n * @example\n * ```ts\n * const r = await client.calcEventEv(\"baseball_mlb\", 12614, {\n * market: \"h2h\",\n * name: \"Pittsburgh Pirates\",\n * price: -118,\n * });\n * console.log(`EV ${r.ev_pct}% fair=${r.fair_prob}`);\n * ```\n */\n calcEventEv(\n sport: string,\n eventId: number | string,\n options: CalcEventEvOptions\n ): Promise<EventEvCalcResponse> {\n const params: Record<string, string | number | undefined> = {\n market: options.market,\n name: options.name,\n price: options.price,\n };\n if (options.point !== undefined) params.point = options.point;\n if (options.description) params.description = options.description;\n return this._request<EventEvCalcResponse>(\n \"GET\",\n `/sports/${encodeURIComponent(sport)}/events/${encodeURIComponent(String(eventId))}/ev/calc`,\n { params }\n );\n }\n\n /**\n * Bulk CSV export of resolved prop outcomes (Pro+ tier).\n *\n * If `outPath` is provided, streams the CSV to disk and resolves to the\n * path. Otherwise resolves to the full CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportResolvedProps({\n * sport: \"baseball_mlb\",\n * market: \"pitcher_strikeouts\",\n * since: \"2026-04-01T00:00:00Z\",\n * outPath: \"./mlb-strikeouts.csv\",\n * });\n * ```\n */\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath: string }\n ): Promise<string>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportResolvedProps(\n options: ExportResolvedPropsOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/resolved-props\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(403, await readDetail(resp, \"Pro tier required\"));\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n /**\n * Bulk CSV export of the full line-movement time-series.\n *\n * One row per (outcome, snapshot): every recorded odds snapshot (price +\n * line, per book, including period markets), not just the closing line.\n * This is the raw tick history no subscription tier can pull in bulk —\n * Pro/Streaming get per-event {@link getOddsHistory} only; this bulk\n * firehose is exclusive to the one-time Historical Backfill pass and\n * Enterprise.\n *\n * A full archive runs to gigabytes per sport — page month by month with\n * `since`/`until`. If `outPath` is provided, streams to disk and resolves\n * to the path; otherwise resolves to the CSV bytes as a `Uint8Array`.\n *\n * @example\n * ```ts\n * await client.exportOddsHistory({\n * sport: \"baseball_mlb\",\n * since: \"2026-04-01T00:00:00Z\",\n * until: \"2026-05-01T00:00:00Z\",\n * outPath: \"./mlb-line-history-apr.csv\",\n * });\n * ```\n */\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath: string }\n ): Promise<string>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions & { outPath?: undefined }\n ): Promise<Uint8Array>;\n async exportOddsHistory(\n options: ExportOddsHistoryOptions\n ): Promise<string | Uint8Array> {\n const params: Record<string, string | undefined> = { sport: options.sport };\n if (options.market) params.market = options.market;\n if (options.bookmaker) params.bookmaker = options.bookmaker;\n if (options.since) params.since = options.since;\n if (options.until) params.until = options.until;\n\n const url = this._buildUrl(\"/exports/odds-history\", params);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let resp: Response;\n try {\n resp = await this._fetch(url, {\n method: \"GET\",\n headers: { \"X-API-Key\": this.apiKey },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 401) {\n throw new AuthError();\n }\n if (resp.status === 403) {\n throw new PropLineError(\n 403,\n await readDetail(resp, \"Historical Backfill pass or Enterprise required\")\n );\n }\n if (resp.status >= 400) {\n throw new PropLineError(resp.status, await readDetail(resp, resp.statusText));\n }\n\n const buf = new Uint8Array(await resp.arrayBuffer());\n if (options.outPath) {\n await writeFile(options.outPath, buf);\n return options.outPath;\n }\n return buf;\n }\n\n // ------------------------------------------------------------------\n // Webhooks (Streaming tier)\n // ------------------------------------------------------------------\n\n /**\n * Register a webhook subscription. Streaming tier only.\n *\n * The returned object includes the full signing `secret` — this is the\n * ONLY time it's revealed. Store it securely.\n */\n createWebhook(options: CreateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"POST\", \"/webhooks\", {\n body: webhookBody(options),\n });\n }\n\n /** List your webhook subscriptions. Secrets are masked. */\n listWebhooks(): Promise<Webhook[]> {\n return this._request<Webhook[]>(\"GET\", \"/webhooks\");\n }\n\n /** Get a single webhook subscription. Secret is masked. */\n getWebhook(webhookId: number): Promise<Webhook> {\n return this._request<Webhook>(\"GET\", `/webhooks/${webhookId}`);\n }\n\n /** Update fields on a webhook. Only supplied fields are changed. */\n updateWebhook(webhookId: number, options: UpdateWebhookOptions): Promise<Webhook> {\n return this._request<Webhook>(\"PATCH\", `/webhooks/${webhookId}`, {\n body: webhookBody(options),\n });\n }\n\n /** Delete a webhook (cascades its delivery history). */\n deleteWebhook(webhookId: number): Promise<{ ok: boolean } | unknown> {\n return this._request(\"DELETE\", `/webhooks/${webhookId}`);\n }\n\n /** Queue a sample `test` payload to the webhook's URL. */\n testWebhook(webhookId: number): Promise<unknown> {\n return this._request(\"POST\", `/webhooks/${webhookId}/test`);\n }\n\n /** Last 50 (default) delivery attempts for a webhook. */\n listWebhookDeliveries(\n webhookId: number,\n options: ListWebhookDeliveriesOptions = {}\n ): Promise<WebhookDelivery[]> {\n return this._request<WebhookDelivery[]>(\n \"GET\",\n `/webhooks/${webhookId}/deliveries`,\n { params: { limit: options.limit ?? 50 } }\n );\n }\n\n /**\n * Verify that an inbound webhook delivery was signed by PropLine.\n *\n * Compares HMAC-SHA256(secret, `${timestamp}.` + body) against the\n * `X-PropLine-Signature` header in constant time.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * app.post(\"/hooks/propline\", express.raw({ type: \"*\\/*\" }), (req, res) => {\n * const ok = PropLine.verifySignature({\n * secret: process.env.WEBHOOK_SECRET!,\n * timestamp: req.header(\"X-PropLine-Timestamp\")!,\n * body: req.body, // raw Buffer\n * signature: req.header(\"X-PropLine-Signature\")!,\n * });\n * if (!ok) return res.status(401).end();\n * // ...\n * });\n * ```\n */\n static verifySignature(options: VerifySignatureOptions): boolean {\n const { secret, timestamp, body, signature } = options;\n const bodyBuf =\n typeof body === \"string\"\n ? Buffer.from(body, \"utf8\")\n : body instanceof Buffer\n ? body\n : Buffer.from(body);\n const message = Buffer.concat([Buffer.from(`${timestamp}.`, \"utf8\"), bodyBuf]);\n const expected = createHmac(\"sha256\", secret).update(message).digest(\"hex\");\n if (expected.length !== signature.length) return false;\n try {\n return timingSafeEqual(Buffer.from(expected, \"hex\"), Buffer.from(signature, \"hex\"));\n } catch {\n return false;\n }\n }\n}\n\nfunction webhookBody(options: CreateWebhookOptions | UpdateWebhookOptions): Record<string, unknown> {\n const body: Record<string, unknown> = {};\n const map: Array<[keyof (CreateWebhookOptions & UpdateWebhookOptions), string]> = [\n [\"url\", \"url\"],\n [\"events\", \"events\"],\n [\"filterSportKey\", \"filter_sport_key\"],\n [\"filterEventId\", \"filter_event_id\"],\n [\"filterMarketKey\", \"filter_market_key\"],\n [\"filterPlayerName\", \"filter_player_name\"],\n [\"minPriceChangePct\", \"min_price_change_pct\"],\n [\"minSteamScore\", \"min_steam_score\"],\n [\"active\", \"active\"],\n ];\n for (const [src, dst] of map) {\n const v = (options as Record<string, unknown>)[src as string];\n if (v !== undefined) body[dst] = v;\n }\n return body;\n}\n\nasync function readDetail(resp: Response, fallback: string): Promise<string> {\n try {\n const text = await resp.text();\n if (!text) return fallback;\n try {\n const json = JSON.parse(text) as { detail?: unknown };\n if (typeof json.detail === \"string\") return json.detail;\n } catch {\n // not JSON\n }\n return text || fallback;\n } catch {\n return fallback;\n }\n}\n","/**\n * PropLine — Node/TypeScript SDK for the PropLine player props API.\n *\n * @example\n * ```ts\n * import { PropLine } from \"propline\";\n *\n * const client = new PropLine(\"your_api_key\");\n * const events = await client.getEvents(\"basketball_nba\");\n * const odds = await client.getOdds(\"basketball_nba\", {\n * eventId: events[0].id,\n * markets: [\"player_points\", \"player_rebounds\"],\n * });\n * ```\n */\n\nexport { PropLine } from \"./client.js\";\nexport {\n PropLineError,\n AuthError,\n RateLimitError,\n} from \"./client.js\";\nexport type {\n PropLineOptions,\n GetOddsOptions,\n GetOddsHistoryOptions,\n GetOddsClosingOptions,\n PeriodFilter,\n GetScoresOptions,\n GetMlbGrandSalamiOptions,\n GetNhlDailyGoalsTotalOptions,\n GetStatsOptions,\n GetResultsOptions,\n GetPlayerHistoryOptions,\n GetPlayerTrendsOptions,\n GetEventEvOptions,\n GetEventBestLineOptions,\n CalcEventEvOptions,\n ExportResolvedPropsOptions,\n ExportOddsHistoryOptions,\n WebhookEventType,\n CreateWebhookOptions,\n UpdateWebhookOptions,\n ListWebhookDeliveriesOptions,\n VerifySignatureOptions,\n} from \"./client.js\";\n\nexport type {\n Sport,\n Event,\n Outcome,\n ResolvedOutcome,\n Market,\n Bookmaker,\n OddsResponse,\n MarketSummary,\n OutcomeSnapshot,\n OddsHistoryOutcome,\n OddsHistoryMarket,\n OddsHistoryBookmaker,\n OddsHistoryResponse,\n ClosingOutcome,\n ClosingMarket,\n ClosingBookmaker,\n OddsClosingResponse,\n ScoreEvent,\n MlbGrandSalamiBook,\n MlbGrandSalamiResponse,\n NhlDailyGoalsTotalBook,\n NhlDailyGoalsTotalResponse,\n ResolutionSummary,\n ResolutionSummarySport,\n ResolutionSummaryMarket,\n PlayerStat,\n StatsResponse,\n WeatherInfo,\n ContextResponse,\n MovementOutcome,\n MovementMarket,\n MovementBookmaker,\n SteamMove,\n MovementResponse,\n ResultsMarket,\n ResultsResponse,\n PlayerHistoryEntry,\n PlayerHistoryResponse,\n HitRateSplit,\n TrendStreak,\n TrendLastGame,\n PlayerMarketTrend,\n PlayerTrends,\n EvOutcome,\n EvLine,\n EventEvResponse,\n EventEvCalcResponse,\n BestPrice,\n BestLineSide,\n BestLine,\n EventBestLineResponse,\n FuturesOutcome,\n FuturesMarket,\n FuturesEvent,\n Webhook,\n WebhookDelivery,\n} from \"./types.js\";\n\n/** String constants for bookmaker keys in odds responses. */\nexport const Bookmakers = {\n BOVADA: \"bovada\",\n DRAFTKINGS: \"draftkings\",\n FANDUEL: \"fanduel\",\n PINNACLE: \"pinnacle\",\n UNIBET: \"unibet\",\n UNDERDOG: \"underdog\",\n KALSHI: \"kalshi\",\n POLYMARKET: \"polymarket\",\n PRIZEPICKS: \"prizepicks\",\n} as const;\n\nexport type BookmakerKey = (typeof Bookmakers)[keyof typeof Bookmakers];\n\nexport const VERSION = \"0.16.0\";\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propline",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Node.js / TypeScript SDK for the PropLine player props betting odds API",
5
5
  "keywords": [
6
6
  "sports",