@ufcalendar/sdk 0.2.0 → 0.2.1

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
@@ -49,6 +49,7 @@ List endpoints are **async generators** that follow `meta.pagination.next_cursor
49
49
  | `orgs()` / `org(slug)` | `GET /v1/orgs` / `…/{slug}` |
50
50
  | `events({ org, status, from, to, order, limit })` | `GET /v1/events` (paginated) |
51
51
  | `event(slug)` / `eventChanges(slug)` | `GET /v1/events/{slug}` / `…/changes` |
52
+ | `eventLive(slug)` | `GET /v1/events/{slug}/live` — real-time `LiveState` on fight night (Pro+); the same document streams over `wss://live.ufcalendar.com/v1?key=…` |
52
53
  | `fight(id)` / `fightStats(id)` / `fightRounds(id)` | `GET /v1/fights/{id}` / `…/stats` / `…/rounds` |
53
54
  | `fightScorecards(id)` | `GET /v1/fights/{id}/scorecards` — judges, rounds, totals, deductions |
54
55
  | `judges({ q, org, minFights })` / `judge(id)` / `judgeScorecards(id)` | `GET /v1/judges` / `…/{id}` / `…/{id}/scorecards` |
package/dist/index.cjs CHANGED
@@ -28,7 +28,7 @@ __export(index_exports, {
28
28
  module.exports = __toCommonJS(index_exports);
29
29
 
30
30
  // src/version.ts
31
- var VERSION = "0.2.0";
31
+ var VERSION = "0.2.1";
32
32
 
33
33
  // src/client.ts
34
34
  var DEFAULT_BASE_URL = "https://api.ufcalendar.com/v1";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/version.ts","../src/client.ts"],"sourcesContent":["export { FightAPI, FightAPIError, DEFAULT_BASE_URL } from './client';\nexport type { FightAPIOptions, Query, QueryValue } from './client';\nexport { VERSION } from './version';\nexport type * from './types';\n/** The generated OpenAPI path map, for anything the hand-written types above\n * do not cover. Regenerated by `pnpm gen:types` from apps/api/openapi.json. */\nexport type { paths, operations } from './schema';\n","/** Kept in lockstep with package.json and the User-Agent by\n * `apps/api/src/surfaces.test.ts`. Bump all three together. */\nexport const VERSION = '0.2.0';\n","/**\n * Thin, dependency-free client for https://api.ufcalendar.com/v1.\n *\n * Every method returns the parsed `data` value of the JSON envelope\n * (`{\"data\": ..., \"meta\": ...}`); list endpoints are async generators that\n * follow cursor pagination for you. Errors throw `FightAPIError` carrying\n * the API's `code`, `message` and `requestId` — quote the request id when\n * you write to api@ufcalendar.com.\n *\n * Mirrors sdk/python/ufcalendar/client.py one method per endpoint, in\n * camelCase. The two clients are kept in lockstep by\n * `apps/api/src/surfaces.test.ts`.\n *\n * The API serves no betting odds, by design. Fighter `images` are Wikimedia\n * Commons / Creative Commons files — the `license` and `artist` fields you\n * receive must be displayed as a credit.\n */\nimport { VERSION } from './version';\nimport type {\n BroadcastRight,\n CareerBout,\n CareerStats,\n Envelope,\n EventChange,\n EventDetail,\n EventSummary,\n Fight,\n Fighter,\n FighterSummary,\n Judge,\n Meta,\n Org,\n Plans,\n PowerIndex,\n RankingsBoard,\n RateLimit,\n Scorecards,\n Usage,\n Venue,\n WebhookEndpoint,\n LiveState,\n} from './types';\n\nexport const DEFAULT_BASE_URL = 'https://api.ufcalendar.com/v1';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface FightAPIOptions {\n /** `ufcalendar_…` key from https://www.ufcalendar.com/account/api. Falls back\n * to `UFCALENDAR_API_KEY` / `UFCAL_API_KEY` in the environment. Only\n * `plans()` works without one. */\n apiKey?: string;\n /** Override for testing; defaults to the production `/v1`. */\n baseUrl?: string;\n /** Inject a fetch (a test double, an instrumented fetch, undici). */\n fetch?: typeof fetch;\n /** Per-request timeout. Default 30s. */\n timeoutMs?: number;\n /** Extra headers on every request. */\n headers?: Record<string, string>;\n}\n\n/** An error response from the Fight API. */\nexport class FightAPIError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId: string | null;\n\n constructor(status: number, code: string, message: string, requestId: string | null = null) {\n super(`${status} ${code}: ${message}${requestId ? ` (request_id=${requestId})` : ''}`);\n this.name = 'FightAPIError';\n this.status = status;\n this.code = code;\n this.requestId = requestId;\n }\n}\n\nexport type QueryValue = string | number | boolean | null | undefined;\nexport type Query = Record<string, QueryValue>;\n\ninterface PageOptions {\n /** Stop after this many rows (across pages). */\n limit?: number;\n}\n\n/**\n * A browser forbids setting User-Agent on fetch, so we only set ours\n * off-browser. The test is `document`, NOT `navigator`: Node 21+ ships a\n * global `navigator`, so a navigator check would silently drop the header\n * on every modern Node runtime — which is the one place it works.\n */\nfunction canSetUserAgent(): boolean {\n return typeof document === 'undefined' && typeof window === 'undefined';\n}\n\nfunction envKey(): string | undefined {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n return env?.UFCALENDAR_API_KEY || env?.UFCAL_API_KEY;\n}\n\nexport class FightAPI {\n readonly baseUrl: string;\n readonly apiKey: string | undefined;\n\n /** `meta` of the most recent response (pagination cursor, generated_at …). */\n lastMeta: Meta | null = null;\n /** `X-RateLimit-*` of the most recent response. */\n lastRateLimit: RateLimit = { limit: null, remaining: null, reset: null };\n\n readonly #fetch: typeof fetch;\n readonly #timeoutMs: number;\n readonly #headers: Record<string, string>;\n\n constructor(apiKeyOrOptions?: string | FightAPIOptions, options: FightAPIOptions = {}) {\n const opts: FightAPIOptions =\n typeof apiKeyOrOptions === 'string'\n ? { ...options, apiKey: apiKeyOrOptions }\n : { ...options, ...(apiKeyOrOptions ?? {}) };\n this.apiKey = opts.apiKey ?? envKey();\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.#fetch = opts.fetch ?? globalThis.fetch;\n this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#headers = opts.headers ?? {};\n if (!this.#fetch) {\n throw new Error('No global fetch available. Use Node 18+ or pass { fetch }.');\n }\n }\n\n /* ---------------------------------------------------------------- core */\n\n #url(path: string, params?: Query): string {\n const url = new URL(`${this.baseUrl}/${path.replace(/^\\/+/, '')}`);\n for (const [k, v] of Object.entries(params ?? {})) {\n if (v === undefined || v === null) continue;\n url.searchParams.set(k, String(v));\n }\n return url.toString();\n }\n\n async #request<T>(\n method: string,\n path: string,\n { params, body, open = false }: { params?: Query; body?: unknown; open?: boolean } = {},\n ): Promise<Envelope<T>> {\n if (!this.apiKey && !open) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n const headers: Record<string, string> = { Accept: 'application/json', ...this.#headers };\n if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;\n if (canSetUserAgent()) headers['User-Agent'] = `ufcalendar-typescript/${VERSION}`;\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n\n let res: Response;\n try {\n res = await this.#fetch(this.#url(path, params), {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: AbortSignal.timeout(this.#timeoutMs),\n });\n } catch (e) {\n const err = e as { name?: string; message?: string };\n if (err?.name === 'TimeoutError') {\n throw new FightAPIError(0, 'timeout', `Request to ${path} timed out after ${this.#timeoutMs}ms`);\n }\n throw new FightAPIError(0, 'network_error', err?.message ?? String(e));\n }\n\n this.lastRateLimit = {\n limit: res.headers.get('X-RateLimit-Limit'),\n remaining: res.headers.get('X-RateLimit-Remaining'),\n reset: res.headers.get('X-RateLimit-Reset'),\n };\n\n if (res.status === 204) {\n this.lastMeta = null;\n return { data: undefined as T };\n }\n\n const text = await res.text();\n let parsed: unknown = undefined;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = undefined;\n }\n\n if (!res.ok) {\n const err = (parsed as { error?: { code?: string; message?: string; request_id?: string } } | undefined)?.error;\n if (err) {\n throw new FightAPIError(\n res.status,\n String(err.code ?? 'error'),\n String(err.message ?? text.slice(0, 200)),\n err.request_id ?? res.headers.get('x-request-id'),\n );\n }\n throw new FightAPIError(res.status, 'http_error', text.slice(0, 200), res.headers.get('x-request-id'));\n }\n\n const env = (parsed ?? {}) as Envelope<T>;\n this.lastMeta = env.meta ?? null;\n return env;\n }\n\n /** Raw GET returning the `data` value. Escape hatch for new endpoints. */\n async get<T = unknown>(path: string, params?: Query): Promise<T> {\n return (await this.#request<T>('GET', path, { params })).data;\n }\n\n /** Raw GET returning the whole `{data, meta}` envelope. */\n async getWithMeta<T = unknown>(path: string, params?: Query): Promise<Envelope<T>> {\n return this.#request<T>('GET', path, { params });\n }\n\n async *#paginate<T>(path: string, params: Query, opts: PageOptions = {}): AsyncGenerator<T, void, void> {\n // Never fetch a bigger page than the caller wants rows: `limit: 3` used\n // to pull 100 rows and throw 97 away, burning the caller's quota on a\n // request they did not ask for (and, on a trial key, a noticeable slice\n // of the 100 they get).\n const pageSize = Math.min(100, opts.limit ?? 100);\n const query: Query = { limit: pageSize, ...params };\n let seen = 0;\n for (;;) {\n const env = await this.#request<T[]>('GET', path, { params: query });\n for (const row of env.data ?? []) {\n yield row;\n seen += 1;\n if (opts.limit !== undefined && seen >= opts.limit) return;\n }\n const cursor = env.meta?.pagination?.next_cursor;\n if (!cursor) return;\n query.cursor = cursor;\n }\n }\n\n /* --------------------------------------------------------------- plans */\n\n /**\n * Plans, quotas, the free 1-day trial rule, the MCP endpoint and the doc\n * links. The only endpoint that answers without a credential.\n */\n async plans(): Promise<Plans> {\n return (await this.#request<Plans>('GET', 'plans', { open: true })).data;\n }\n\n /* ---------------------------------------------------------------- orgs */\n\n /** Launch orgs with capability flags (stats / rounds / rankings / broadcasts / predictions). */\n orgs(): Promise<Org[]> {\n return this.get<Org[]>('orgs');\n }\n\n org(slug: string): Promise<Org> {\n return this.get<Org>(`orgs/${encodeURIComponent(slug)}`);\n }\n\n /* -------------------------------------------------------------- events */\n\n /**\n * Schedule + results. Bare call = the upcoming calendar, soonest first.\n * `status: 'completed'` (or `order: 'desc'`) browses the archive\n * newest-first. `from` / `to` are `YYYY-MM-DD`.\n */\n events(\n opts: {\n org?: string;\n status?: string;\n from?: string;\n to?: string;\n order?: 'asc' | 'desc';\n limit?: number;\n } = {},\n ): AsyncGenerator<EventSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<EventSummary>('events', params as Query, { limit });\n }\n\n /** One event with its full fight card, venue and broadcasts. */\n event(idOrSlug: string | number): Promise<EventDetail> {\n return this.get<EventDetail>(`events/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Card-change diff log (fight added/removed, opponent swapped, date moved, profile merged). */\n eventChanges(idOrSlug: string | number): Promise<EventChange[]> {\n return this.get<EventChange[]>(`events/${encodeURIComponent(String(idOrSlug))}/changes`);\n }\n\n /** Latest real-time LiveState snapshot on fight night (Business+), or null\n * when nothing is being streamed. The WebSocket at wss://live.ufcalendar.com/v1\n * pushes the same document as it changes. */\n eventLive(idOrSlug: string | number): Promise<LiveState | null> {\n return this.get<LiveState | null>(`events/${encodeURIComponent(String(idOrSlug))}/live`);\n }\n\n /* -------------------------------------------------------------- fights */\n\n fight(fightId: number | string): Promise<Fight> {\n return this.get<Fight>(`fights/${encodeURIComponent(String(fightId))}`);\n }\n\n /** Per-fight totals for both corners. */\n fightStats(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/stats`);\n }\n\n /** Round-by-round stat lines for both corners. */\n fightRounds(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/rounds`);\n }\n\n /**\n * The judges' scorecards for a bout — the official commission record:\n * decision type, point deductions, and one card per judge with every\n * round, the totals and `winner_fighter_id`. Scores are oriented to\n * `fighter_a_id` / `fighter_b_id`, both repeated on the payload.\n *\n * Check `scores_known` on a card before charting totals: when it is false\n * the commission published only the outcome. Throws 404 for a bout that\n * did not go to the judges.\n */\n fightScorecards(fightId: number | string): Promise<Scorecards> {\n return this.get<Scorecards>(`fights/${encodeURIComponent(String(fightId))}/scorecards`);\n }\n\n /* -------------------------------------------------------------- judges */\n\n /**\n * Every official who has scored a launch-org bout, busiest first. Rates\n * mean little below ~10 fights; pass `minFights: 10`.\n */\n judges(\n opts: { q?: string; org?: string; minFights?: number; limit?: number } = {},\n ): AsyncGenerator<Judge, void, void> {\n const { limit, minFights, ...rest } = opts;\n return this.#paginate<Judge>('judges', { ...rest, min_fights: minFights } as Query, { limit });\n }\n\n judge(judgeId: number | string): Promise<Judge> {\n return this.get<Judge>(`judges/${encodeURIComponent(String(judgeId))}`);\n }\n\n /** Every card this judge has turned in, newest first. */\n judgeScorecards(\n judgeId: number | string,\n opts: { limit?: number } = {},\n ): AsyncGenerator<Record<string, unknown>, void, void> {\n return this.#paginate<Record<string, unknown>>(\n `judges/${encodeURIComponent(String(judgeId))}/scorecards`,\n {},\n opts,\n );\n }\n\n /* ------------------------------------------------------------ fighters */\n\n fighters(\n opts: { q?: string; org?: string; country?: string; limit?: number } = {},\n ): AsyncGenerator<FighterSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<FighterSummary>('fighters', params as Query, { limit });\n }\n\n /** Bio, records, career stats, Power Index and CC-licensed images. */\n fighter(idOrSlug: string | number): Promise<Fighter> {\n return this.get<Fighter>(`fighters/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Complete multi-promotion career timeline. */\n fighterHistory(idOrSlug: string | number): Promise<CareerBout[]> {\n return this.get<CareerBout[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/history`);\n }\n\n /** Career statistics, one source-stamped row per scope (`pro-mma`, `ufc-only` …). */\n fighterStats(idOrSlug: string | number): Promise<CareerStats[]> {\n return this.get<CareerStats[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/stats`);\n }\n\n /** Every official ranking row the fighter ever held, newest first. */\n fighterRankings(idOrSlug: string | number): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/rankings`);\n }\n\n fighterPowerIndex(idOrSlug: string | number): Promise<PowerIndex & Record<string, unknown>> {\n return this.get<PowerIndex & Record<string, unknown>>(\n `fighters/${encodeURIComponent(String(idOrSlug))}/power-index`,\n );\n }\n\n /* ------------------------------------------------------------ rankings */\n\n /**\n * Official board, point-in-time. `date: 'YYYY-MM-DD'` returns the board\n * that was valid on that day (UFC history back to 2013; rank 0 = champion).\n */\n rankings(org = 'ufc', opts: { date?: string; board?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(`rankings/${encodeURIComponent(org)}`, opts as Query);\n }\n\n divisionRankings(org: string, division: string, opts: { date?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(\n `rankings/${encodeURIComponent(org)}/${encodeURIComponent(division)}`,\n opts as Query,\n );\n }\n\n /** Current champions across every launch org. */\n champions(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('champions');\n }\n\n /** UFCalendar Power Index board. */\n powerIndex(org = 'ufc'): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>(`power-index/${encodeURIComponent(org)}`);\n }\n\n /* ---------------------------------------------------------------- misc */\n\n /** Model win probabilities for upcoming UFC bouts. */\n predictionsUpcoming(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('predictions/upcoming');\n }\n\n /** Who airs the promotion, per ISO-2 country. */\n broadcastRights(org = 'ufc', opts: { country?: string } = {}): Promise<BroadcastRight[]> {\n return this.get<BroadcastRight[]>(`broadcast-rights/${encodeURIComponent(org)}`, opts as Query);\n }\n\n venue(venueId: number | string): Promise<Venue> {\n return this.get<Venue>(`venues/${encodeURIComponent(String(venueId))}`);\n }\n\n /** Typeahead across fighters and events. */\n search(q: string): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>('search', { q });\n }\n\n /** Your key's month-to-date quota usage. */\n usage(): Promise<Usage> {\n return this.get<Usage>('usage');\n }\n\n /**\n * Subscribable ICS feed URL for calendar apps (authenticates via `?key=`).\n *\n * Throws without a key rather than returning `?key=`: that empty URL is\n * pasted into a calendar app, fails there hours later, and the failure\n * surfaces nowhere near this call.\n */\n calendarIcsUrl(org = 'ufc'): string {\n if (!this.apiKey) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n return `${this.baseUrl}/calendar/${encodeURIComponent(org)}.ics?key=${encodeURIComponent(this.apiKey)}`;\n }\n\n /* ------------------------------------------------------------ webhooks */\n\n webhookEndpoints(): Promise<WebhookEndpoint[]> {\n return this.get<WebhookEndpoint[]>('webhook-endpoints');\n }\n\n /**\n * Register a signed webhook (Pro and up). `events` ⊆ `event.announced`,\n * `fight.result`, `card.changed`, `event.completed`. The signing secret is\n * returned ONCE, in this response.\n */\n async createWebhookEndpoint(url: string, events?: string[]): Promise<WebhookEndpoint> {\n const body: Record<string, unknown> = { url };\n if (events?.length) body.events = events;\n return (await this.#request<WebhookEndpoint>('POST', 'webhook-endpoints', { body })).data;\n }\n\n async deleteWebhookEndpoint(endpointId: number | string): Promise<void> {\n await this.#request<unknown>('DELETE', `webhook-endpoints/${encodeURIComponent(String(endpointId))}`);\n }\n\n async rotateWebhookSecret(endpointId: number | string): Promise<WebhookEndpoint> {\n return (\n await this.#request<WebhookEndpoint>(\n 'POST',\n `webhook-endpoints/${encodeURIComponent(String(endpointId))}/rotate-secret`,\n )\n ).data;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,UAAU;;;ACyChB,IAAM,mBAAmB;AAChC,IAAM,qBAAqB;AAkBpB,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,QAAgB,MAAc,SAAiB,YAA2B,MAAM;AAC1F,UAAM,GAAG,MAAM,IAAI,IAAI,KAAK,OAAO,GAAG,YAAY,gBAAgB,SAAS,MAAM,EAAE,EAAE;AACrF,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACnB;AACF;AAgBA,SAAS,kBAA2B;AAClC,SAAO,OAAO,aAAa,eAAe,OAAO,WAAW;AAC9D;AAEA,SAAS,SAA6B;AACpC,QAAM,MAAO,WAA0E,SAAS;AAChG,SAAO,KAAK,sBAAsB,KAAK;AACzC;AAEO,IAAM,WAAN,MAAe;AAAA,EACX;AAAA,EACA;AAAA;AAAA,EAGT,WAAwB;AAAA;AAAA,EAExB,gBAA2B,EAAE,OAAO,MAAM,WAAW,MAAM,OAAO,KAAK;AAAA,EAE9D;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,iBAA4C,UAA2B,CAAC,GAAG;AACrF,UAAM,OACJ,OAAO,oBAAoB,WACvB,EAAE,GAAG,SAAS,QAAQ,gBAAgB,IACtC,EAAE,GAAG,SAAS,GAAI,mBAAmB,CAAC,EAAG;AAC/C,SAAK,SAAS,KAAK,UAAU,OAAO;AACpC,SAAK,WAAW,KAAK,WAAW,kBAAkB,QAAQ,QAAQ,EAAE;AACpE,SAAK,SAAS,KAAK,SAAS,WAAW;AACvC,SAAK,aAAa,KAAK,aAAa;AACpC,SAAK,WAAW,KAAK,WAAW,CAAC;AACjC,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AAAA,EACF;AAAA;AAAA,EAIA,KAAK,MAAc,QAAwB;AACzC,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,IAAI,KAAK,QAAQ,QAAQ,EAAE,CAAC,EAAE;AACjE,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,UAAU,CAAC,CAAC,GAAG;AACjD,UAAI,MAAM,UAAa,MAAM,KAAM;AACnC,UAAI,aAAa,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,IACnC;AACA,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA,EAEA,MAAM,SACJ,QACA,MACA,EAAE,QAAQ,MAAM,OAAO,MAAM,IAAwD,CAAC,GAChE;AACtB,QAAI,CAAC,KAAK,UAAU,CAAC,MAAM;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MAEF;AAAA,IACF;AACA,UAAM,UAAkC,EAAE,QAAQ,oBAAoB,GAAG,KAAK,SAAS;AACvF,QAAI,KAAK,OAAQ,SAAQ,gBAAgB,UAAU,KAAK,MAAM;AAC9D,QAAI,gBAAgB,EAAG,SAAQ,YAAY,IAAI,yBAAyB,OAAO;AAC/E,QAAI,SAAS,OAAW,SAAQ,cAAc,IAAI;AAElD,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,MAAM,GAAG;AAAA,QAC/C;AAAA,QACA;AAAA,QACA,MAAM,SAAS,SAAY,SAAY,KAAK,UAAU,IAAI;AAAA,QAC1D,QAAQ,YAAY,QAAQ,KAAK,UAAU;AAAA,MAC7C,CAAC;AAAA,IACH,SAAS,GAAG;AACV,YAAM,MAAM;AACZ,UAAI,KAAK,SAAS,gBAAgB;AAChC,cAAM,IAAI,cAAc,GAAG,WAAW,cAAc,IAAI,oBAAoB,KAAK,UAAU,IAAI;AAAA,MACjG;AACA,YAAM,IAAI,cAAc,GAAG,iBAAiB,KAAK,WAAW,OAAO,CAAC,CAAC;AAAA,IACvE;AAEA,SAAK,gBAAgB;AAAA,MACnB,OAAO,IAAI,QAAQ,IAAI,mBAAmB;AAAA,MAC1C,WAAW,IAAI,QAAQ,IAAI,uBAAuB;AAAA,MAClD,OAAO,IAAI,QAAQ,IAAI,mBAAmB;AAAA,IAC5C;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,WAAK,WAAW;AAChB,aAAO,EAAE,MAAM,OAAe;AAAA,IAChC;AAEA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,SAAkB;AACtB,QAAI;AACF,eAAS,OAAO,KAAK,MAAM,IAAI,IAAI;AAAA,IACrC,QAAQ;AACN,eAAS;AAAA,IACX;AAEA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,MAAO,QAA6F;AAC1G,UAAI,KAAK;AACP,cAAM,IAAI;AAAA,UACR,IAAI;AAAA,UACJ,OAAO,IAAI,QAAQ,OAAO;AAAA,UAC1B,OAAO,IAAI,WAAW,KAAK,MAAM,GAAG,GAAG,CAAC;AAAA,UACxC,IAAI,cAAc,IAAI,QAAQ,IAAI,cAAc;AAAA,QAClD;AAAA,MACF;AACA,YAAM,IAAI,cAAc,IAAI,QAAQ,cAAc,KAAK,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,IAAI,cAAc,CAAC;AAAA,IACvG;AAEA,UAAM,MAAO,UAAU,CAAC;AACxB,SAAK,WAAW,IAAI,QAAQ;AAC5B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,IAAiB,MAAc,QAA4B;AAC/D,YAAQ,MAAM,KAAK,SAAY,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAM,YAAyB,MAAc,QAAsC;AACjF,WAAO,KAAK,SAAY,OAAO,MAAM,EAAE,OAAO,CAAC;AAAA,EACjD;AAAA,EAEA,OAAO,UAAa,MAAc,QAAe,OAAoB,CAAC,GAAkC;AAKtG,UAAM,WAAW,KAAK,IAAI,KAAK,KAAK,SAAS,GAAG;AAChD,UAAM,QAAe,EAAE,OAAO,UAAU,GAAG,OAAO;AAClD,QAAI,OAAO;AACX,eAAS;AACP,YAAM,MAAM,MAAM,KAAK,SAAc,OAAO,MAAM,EAAE,QAAQ,MAAM,CAAC;AACnE,iBAAW,OAAO,IAAI,QAAQ,CAAC,GAAG;AAChC,cAAM;AACN,gBAAQ;AACR,YAAI,KAAK,UAAU,UAAa,QAAQ,KAAK,MAAO;AAAA,MACtD;AACA,YAAM,SAAS,IAAI,MAAM,YAAY;AACrC,UAAI,CAAC,OAAQ;AACb,YAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAwB;AAC5B,YAAQ,MAAM,KAAK,SAAgB,OAAO,SAAS,EAAE,MAAM,KAAK,CAAC,GAAG;AAAA,EACtE;AAAA;AAAA;AAAA,EAKA,OAAuB;AACrB,WAAO,KAAK,IAAW,MAAM;AAAA,EAC/B;AAAA,EAEA,IAAI,MAA4B;AAC9B,WAAO,KAAK,IAAS,QAAQ,mBAAmB,IAAI,CAAC,EAAE;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OACE,OAOI,CAAC,GACqC;AAC1C,UAAM,EAAE,OAAO,GAAG,OAAO,IAAI;AAC7B,WAAO,KAAK,UAAwB,UAAU,QAAiB,EAAE,MAAM,CAAC;AAAA,EAC1E;AAAA;AAAA,EAGA,MAAM,UAAiD;AACrD,WAAO,KAAK,IAAiB,UAAU,mBAAmB,OAAO,QAAQ,CAAC,CAAC,EAAE;AAAA,EAC/E;AAAA;AAAA,EAGA,aAAa,UAAmD;AAC9D,WAAO,KAAK,IAAmB,UAAU,mBAAmB,OAAO,QAAQ,CAAC,CAAC,UAAU;AAAA,EACzF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,UAAsD;AAC9D,WAAO,KAAK,IAAsB,UAAU,mBAAmB,OAAO,QAAQ,CAAC,CAAC,OAAO;AAAA,EACzF;AAAA;AAAA,EAIA,MAAM,SAA0C;AAC9C,WAAO,KAAK,IAAW,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,EAAE;AAAA,EACxE;AAAA;AAAA,EAGA,WAAW,SAA8D;AACvE,WAAO,KAAK,IAA+B,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,QAAQ;AAAA,EAClG;AAAA;AAAA,EAGA,YAAY,SAA8D;AACxE,WAAO,KAAK,IAA+B,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,SAAS;AAAA,EACnG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,gBAAgB,SAA+C;AAC7D,WAAO,KAAK,IAAgB,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,aAAa;AAAA,EACxF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OACE,OAAyE,CAAC,GACvC;AACnC,UAAM,EAAE,OAAO,WAAW,GAAG,KAAK,IAAI;AACtC,WAAO,KAAK,UAAiB,UAAU,EAAE,GAAG,MAAM,YAAY,UAAU,GAAY,EAAE,MAAM,CAAC;AAAA,EAC/F;AAAA,EAEA,MAAM,SAA0C;AAC9C,WAAO,KAAK,IAAW,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,EAAE;AAAA,EACxE;AAAA;AAAA,EAGA,gBACE,SACA,OAA2B,CAAC,GACyB;AACrD,WAAO,KAAK;AAAA,MACV,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAC7C,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,SACE,OAAuE,CAAC,GAC5B;AAC5C,UAAM,EAAE,OAAO,GAAG,OAAO,IAAI;AAC7B,WAAO,KAAK,UAA0B,YAAY,QAAiB,EAAE,MAAM,CAAC;AAAA,EAC9E;AAAA;AAAA,EAGA,QAAQ,UAA6C;AACnD,WAAO,KAAK,IAAa,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,EAAE;AAAA,EAC7E;AAAA;AAAA,EAGA,eAAe,UAAkD;AAC/D,WAAO,KAAK,IAAkB,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,UAAU;AAAA,EAC1F;AAAA;AAAA,EAGA,aAAa,UAAmD;AAC9D,WAAO,KAAK,IAAmB,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,QAAQ;AAAA,EACzF;AAAA;AAAA,EAGA,gBAAgB,UAA+D;AAC7E,WAAO,KAAK,IAA+B,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,WAAW;AAAA,EACxG;AAAA,EAEA,kBAAkB,UAA0E;AAC1F,WAAO,KAAK;AAAA,MACV,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,MAAM,OAAO,OAA0C,CAAC,GAA2B;AAC1F,WAAO,KAAK,IAAmB,YAAY,mBAAmB,GAAG,CAAC,IAAI,IAAa;AAAA,EACrF;AAAA,EAEA,iBAAiB,KAAa,UAAkB,OAA0B,CAAC,GAA2B;AACpG,WAAO,KAAK;AAAA,MACV,YAAY,mBAAmB,GAAG,CAAC,IAAI,mBAAmB,QAAQ,CAAC;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,YAAgD;AAC9C,WAAO,KAAK,IAA+B,WAAW;AAAA,EACxD;AAAA;AAAA,EAGA,WAAW,MAAM,OAAyC;AACxD,WAAO,KAAK,IAA6B,eAAe,mBAAmB,GAAG,CAAC,EAAE;AAAA,EACnF;AAAA;AAAA;AAAA,EAKA,sBAA0D;AACxD,WAAO,KAAK,IAA+B,sBAAsB;AAAA,EACnE;AAAA;AAAA,EAGA,gBAAgB,MAAM,OAAO,OAA6B,CAAC,GAA8B;AACvF,WAAO,KAAK,IAAsB,oBAAoB,mBAAmB,GAAG,CAAC,IAAI,IAAa;AAAA,EAChG;AAAA,EAEA,MAAM,SAA0C;AAC9C,WAAO,KAAK,IAAW,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,EAAE;AAAA,EACxE;AAAA;AAAA,EAGA,OAAO,GAA6C;AAClD,WAAO,KAAK,IAA6B,UAAU,EAAE,EAAE,CAAC;AAAA,EAC1D;AAAA;AAAA,EAGA,QAAwB;AACtB,WAAO,KAAK,IAAW,OAAO;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAe,MAAM,OAAe;AAClC,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MAEF;AAAA,IACF;AACA,WAAO,GAAG,KAAK,OAAO,aAAa,mBAAmB,GAAG,CAAC,YAAY,mBAAmB,KAAK,MAAM,CAAC;AAAA,EACvG;AAAA;AAAA,EAIA,mBAA+C;AAC7C,WAAO,KAAK,IAAuB,mBAAmB;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBAAsB,KAAa,QAA6C;AACpF,UAAM,OAAgC,EAAE,IAAI;AAC5C,QAAI,QAAQ,OAAQ,MAAK,SAAS;AAClC,YAAQ,MAAM,KAAK,SAA0B,QAAQ,qBAAqB,EAAE,KAAK,CAAC,GAAG;AAAA,EACvF;AAAA,EAEA,MAAM,sBAAsB,YAA4C;AACtE,UAAM,KAAK,SAAkB,UAAU,qBAAqB,mBAAmB,OAAO,UAAU,CAAC,CAAC,EAAE;AAAA,EACtG;AAAA,EAEA,MAAM,oBAAoB,YAAuD;AAC/E,YACE,MAAM,KAAK;AAAA,MACT;AAAA,MACA,qBAAqB,mBAAmB,OAAO,UAAU,CAAC,CAAC;AAAA,IAC7D,GACA;AAAA,EACJ;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/version.ts","../src/client.ts"],"sourcesContent":["export { FightAPI, FightAPIError, DEFAULT_BASE_URL } from './client';\nexport type { FightAPIOptions, Query, QueryValue } from './client';\nexport { VERSION } from './version';\nexport type * from './types';\n/** The generated OpenAPI path map, for anything the hand-written types above\n * do not cover. Regenerated by `pnpm gen:types` from apps/api/openapi.json. */\nexport type { paths, operations } from './schema';\n","/** Kept in lockstep with package.json and the User-Agent by\n * `apps/api/src/surfaces.test.ts`. Bump all three together. */\nexport const VERSION = '0.2.1';\n","/**\n * Thin, dependency-free client for https://api.ufcalendar.com/v1.\n *\n * Every method returns the parsed `data` value of the JSON envelope\n * (`{\"data\": ..., \"meta\": ...}`); list endpoints are async generators that\n * follow cursor pagination for you. Errors throw `FightAPIError` carrying\n * the API's `code`, `message` and `requestId` — quote the request id when\n * you write to api@ufcalendar.com.\n *\n * Mirrors sdk/python/ufcalendar/client.py one method per endpoint, in\n * camelCase. The two clients are kept in lockstep by\n * `apps/api/src/surfaces.test.ts`.\n *\n * The API serves no betting odds, by design. Fighter `images` are Wikimedia\n * Commons / Creative Commons files — the `license` and `artist` fields you\n * receive must be displayed as a credit.\n */\nimport { VERSION } from './version';\nimport type {\n BroadcastRight,\n CareerBout,\n CareerStats,\n Envelope,\n EventChange,\n EventDetail,\n EventSummary,\n Fight,\n Fighter,\n FighterSummary,\n Judge,\n Meta,\n Org,\n Plans,\n PowerIndex,\n RankingsBoard,\n RateLimit,\n Scorecards,\n Usage,\n Venue,\n WebhookEndpoint,\n LiveState,\n} from './types';\n\nexport const DEFAULT_BASE_URL = 'https://api.ufcalendar.com/v1';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface FightAPIOptions {\n /** `ufcalendar_…` key from https://www.ufcalendar.com/account/api. Falls back\n * to `UFCALENDAR_API_KEY` / `UFCAL_API_KEY` in the environment. Only\n * `plans()` works without one. */\n apiKey?: string;\n /** Override for testing; defaults to the production `/v1`. */\n baseUrl?: string;\n /** Inject a fetch (a test double, an instrumented fetch, undici). */\n fetch?: typeof fetch;\n /** Per-request timeout. Default 30s. */\n timeoutMs?: number;\n /** Extra headers on every request. */\n headers?: Record<string, string>;\n}\n\n/** An error response from the Fight API. */\nexport class FightAPIError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId: string | null;\n\n constructor(status: number, code: string, message: string, requestId: string | null = null) {\n super(`${status} ${code}: ${message}${requestId ? ` (request_id=${requestId})` : ''}`);\n this.name = 'FightAPIError';\n this.status = status;\n this.code = code;\n this.requestId = requestId;\n }\n}\n\nexport type QueryValue = string | number | boolean | null | undefined;\nexport type Query = Record<string, QueryValue>;\n\ninterface PageOptions {\n /** Stop after this many rows (across pages). */\n limit?: number;\n}\n\n/**\n * A browser forbids setting User-Agent on fetch, so we only set ours\n * off-browser. The test is `document`, NOT `navigator`: Node 21+ ships a\n * global `navigator`, so a navigator check would silently drop the header\n * on every modern Node runtime — which is the one place it works.\n */\nfunction canSetUserAgent(): boolean {\n return typeof document === 'undefined' && typeof window === 'undefined';\n}\n\nfunction envKey(): string | undefined {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n return env?.UFCALENDAR_API_KEY || env?.UFCAL_API_KEY;\n}\n\nexport class FightAPI {\n readonly baseUrl: string;\n readonly apiKey: string | undefined;\n\n /** `meta` of the most recent response (pagination cursor, generated_at …). */\n lastMeta: Meta | null = null;\n /** `X-RateLimit-*` of the most recent response. */\n lastRateLimit: RateLimit = { limit: null, remaining: null, reset: null };\n\n readonly #fetch: typeof fetch;\n readonly #timeoutMs: number;\n readonly #headers: Record<string, string>;\n\n constructor(apiKeyOrOptions?: string | FightAPIOptions, options: FightAPIOptions = {}) {\n const opts: FightAPIOptions =\n typeof apiKeyOrOptions === 'string'\n ? { ...options, apiKey: apiKeyOrOptions }\n : { ...options, ...(apiKeyOrOptions ?? {}) };\n this.apiKey = opts.apiKey ?? envKey();\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.#fetch = opts.fetch ?? globalThis.fetch;\n this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#headers = opts.headers ?? {};\n if (!this.#fetch) {\n throw new Error('No global fetch available. Use Node 18+ or pass { fetch }.');\n }\n }\n\n /* ---------------------------------------------------------------- core */\n\n #url(path: string, params?: Query): string {\n const url = new URL(`${this.baseUrl}/${path.replace(/^\\/+/, '')}`);\n for (const [k, v] of Object.entries(params ?? {})) {\n if (v === undefined || v === null) continue;\n url.searchParams.set(k, String(v));\n }\n return url.toString();\n }\n\n async #request<T>(\n method: string,\n path: string,\n { params, body, open = false }: { params?: Query; body?: unknown; open?: boolean } = {},\n ): Promise<Envelope<T>> {\n if (!this.apiKey && !open) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n const headers: Record<string, string> = { Accept: 'application/json', ...this.#headers };\n if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;\n if (canSetUserAgent()) headers['User-Agent'] = `ufcalendar-typescript/${VERSION}`;\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n\n let res: Response;\n try {\n res = await this.#fetch(this.#url(path, params), {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: AbortSignal.timeout(this.#timeoutMs),\n });\n } catch (e) {\n const err = e as { name?: string; message?: string };\n if (err?.name === 'TimeoutError') {\n throw new FightAPIError(0, 'timeout', `Request to ${path} timed out after ${this.#timeoutMs}ms`);\n }\n throw new FightAPIError(0, 'network_error', err?.message ?? String(e));\n }\n\n this.lastRateLimit = {\n limit: res.headers.get('X-RateLimit-Limit'),\n remaining: res.headers.get('X-RateLimit-Remaining'),\n reset: res.headers.get('X-RateLimit-Reset'),\n };\n\n if (res.status === 204) {\n this.lastMeta = null;\n return { data: undefined as T };\n }\n\n const text = await res.text();\n let parsed: unknown = undefined;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = undefined;\n }\n\n if (!res.ok) {\n const err = (parsed as { error?: { code?: string; message?: string; request_id?: string } } | undefined)?.error;\n if (err) {\n throw new FightAPIError(\n res.status,\n String(err.code ?? 'error'),\n String(err.message ?? text.slice(0, 200)),\n err.request_id ?? res.headers.get('x-request-id'),\n );\n }\n throw new FightAPIError(res.status, 'http_error', text.slice(0, 200), res.headers.get('x-request-id'));\n }\n\n const env = (parsed ?? {}) as Envelope<T>;\n this.lastMeta = env.meta ?? null;\n return env;\n }\n\n /** Raw GET returning the `data` value. Escape hatch for new endpoints. */\n async get<T = unknown>(path: string, params?: Query): Promise<T> {\n return (await this.#request<T>('GET', path, { params })).data;\n }\n\n /** Raw GET returning the whole `{data, meta}` envelope. */\n async getWithMeta<T = unknown>(path: string, params?: Query): Promise<Envelope<T>> {\n return this.#request<T>('GET', path, { params });\n }\n\n async *#paginate<T>(path: string, params: Query, opts: PageOptions = {}): AsyncGenerator<T, void, void> {\n // Never fetch a bigger page than the caller wants rows: `limit: 3` used\n // to pull 100 rows and throw 97 away, burning the caller's quota on a\n // request they did not ask for (and, on a trial key, a noticeable slice\n // of the 100 they get).\n const pageSize = Math.min(100, opts.limit ?? 100);\n const query: Query = { limit: pageSize, ...params };\n let seen = 0;\n for (;;) {\n const env = await this.#request<T[]>('GET', path, { params: query });\n for (const row of env.data ?? []) {\n yield row;\n seen += 1;\n if (opts.limit !== undefined && seen >= opts.limit) return;\n }\n const cursor = env.meta?.pagination?.next_cursor;\n if (!cursor) return;\n query.cursor = cursor;\n }\n }\n\n /* --------------------------------------------------------------- plans */\n\n /**\n * Plans, quotas, the free 1-day trial rule, the MCP endpoint and the doc\n * links. The only endpoint that answers without a credential.\n */\n async plans(): Promise<Plans> {\n return (await this.#request<Plans>('GET', 'plans', { open: true })).data;\n }\n\n /* ---------------------------------------------------------------- orgs */\n\n /** Launch orgs with capability flags (stats / rounds / rankings / broadcasts / predictions). */\n orgs(): Promise<Org[]> {\n return this.get<Org[]>('orgs');\n }\n\n org(slug: string): Promise<Org> {\n return this.get<Org>(`orgs/${encodeURIComponent(slug)}`);\n }\n\n /* -------------------------------------------------------------- events */\n\n /**\n * Schedule + results. Bare call = the upcoming calendar, soonest first.\n * `status: 'completed'` (or `order: 'desc'`) browses the archive\n * newest-first. `from` / `to` are `YYYY-MM-DD`.\n */\n events(\n opts: {\n org?: string;\n status?: string;\n from?: string;\n to?: string;\n order?: 'asc' | 'desc';\n limit?: number;\n } = {},\n ): AsyncGenerator<EventSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<EventSummary>('events', params as Query, { limit });\n }\n\n /** One event with its full fight card, venue and broadcasts. */\n event(idOrSlug: string | number): Promise<EventDetail> {\n return this.get<EventDetail>(`events/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Card-change diff log (fight added/removed, opponent swapped, date moved, profile merged). */\n eventChanges(idOrSlug: string | number): Promise<EventChange[]> {\n return this.get<EventChange[]>(`events/${encodeURIComponent(String(idOrSlug))}/changes`);\n }\n\n /** Latest real-time LiveState snapshot on fight night (Business+), or null\n * when nothing is being streamed. The WebSocket at wss://live.ufcalendar.com/v1\n * pushes the same document as it changes. */\n eventLive(idOrSlug: string | number): Promise<LiveState | null> {\n return this.get<LiveState | null>(`events/${encodeURIComponent(String(idOrSlug))}/live`);\n }\n\n /* -------------------------------------------------------------- fights */\n\n fight(fightId: number | string): Promise<Fight> {\n return this.get<Fight>(`fights/${encodeURIComponent(String(fightId))}`);\n }\n\n /** Per-fight totals for both corners. */\n fightStats(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/stats`);\n }\n\n /** Round-by-round stat lines for both corners. */\n fightRounds(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/rounds`);\n }\n\n /**\n * The judges' scorecards for a bout — the official commission record:\n * decision type, point deductions, and one card per judge with every\n * round, the totals and `winner_fighter_id`. Scores are oriented to\n * `fighter_a_id` / `fighter_b_id`, both repeated on the payload.\n *\n * Check `scores_known` on a card before charting totals: when it is false\n * the commission published only the outcome. Throws 404 for a bout that\n * did not go to the judges.\n */\n fightScorecards(fightId: number | string): Promise<Scorecards> {\n return this.get<Scorecards>(`fights/${encodeURIComponent(String(fightId))}/scorecards`);\n }\n\n /* -------------------------------------------------------------- judges */\n\n /**\n * Every official who has scored a launch-org bout, busiest first. Rates\n * mean little below ~10 fights; pass `minFights: 10`.\n */\n judges(\n opts: { q?: string; org?: string; minFights?: number; limit?: number } = {},\n ): AsyncGenerator<Judge, void, void> {\n const { limit, minFights, ...rest } = opts;\n return this.#paginate<Judge>('judges', { ...rest, min_fights: minFights } as Query, { limit });\n }\n\n judge(judgeId: number | string): Promise<Judge> {\n return this.get<Judge>(`judges/${encodeURIComponent(String(judgeId))}`);\n }\n\n /** Every card this judge has turned in, newest first. */\n judgeScorecards(\n judgeId: number | string,\n opts: { limit?: number } = {},\n ): AsyncGenerator<Record<string, unknown>, void, void> {\n return this.#paginate<Record<string, unknown>>(\n `judges/${encodeURIComponent(String(judgeId))}/scorecards`,\n {},\n opts,\n );\n }\n\n /* ------------------------------------------------------------ fighters */\n\n fighters(\n opts: { q?: string; org?: string; country?: string; limit?: number } = {},\n ): AsyncGenerator<FighterSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<FighterSummary>('fighters', params as Query, { limit });\n }\n\n /** Bio, records, career stats, Power Index and CC-licensed images. */\n fighter(idOrSlug: string | number): Promise<Fighter> {\n return this.get<Fighter>(`fighters/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Complete multi-promotion career timeline. */\n fighterHistory(idOrSlug: string | number): Promise<CareerBout[]> {\n return this.get<CareerBout[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/history`);\n }\n\n /** Career statistics, one source-stamped row per scope (`pro-mma`, `ufc-only` …). */\n fighterStats(idOrSlug: string | number): Promise<CareerStats[]> {\n return this.get<CareerStats[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/stats`);\n }\n\n /** Every official ranking row the fighter ever held, newest first. */\n fighterRankings(idOrSlug: string | number): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/rankings`);\n }\n\n fighterPowerIndex(idOrSlug: string | number): Promise<PowerIndex & Record<string, unknown>> {\n return this.get<PowerIndex & Record<string, unknown>>(\n `fighters/${encodeURIComponent(String(idOrSlug))}/power-index`,\n );\n }\n\n /* ------------------------------------------------------------ rankings */\n\n /**\n * Official board, point-in-time. `date: 'YYYY-MM-DD'` returns the board\n * that was valid on that day (UFC history back to 2013; rank 0 = champion).\n */\n rankings(org = 'ufc', opts: { date?: string; board?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(`rankings/${encodeURIComponent(org)}`, opts as Query);\n }\n\n divisionRankings(org: string, division: string, opts: { date?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(\n `rankings/${encodeURIComponent(org)}/${encodeURIComponent(division)}`,\n opts as Query,\n );\n }\n\n /** Current champions across every launch org. */\n champions(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('champions');\n }\n\n /** UFCalendar Power Index board. */\n powerIndex(org = 'ufc'): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>(`power-index/${encodeURIComponent(org)}`);\n }\n\n /* ---------------------------------------------------------------- misc */\n\n /** Model win probabilities for upcoming UFC bouts. */\n predictionsUpcoming(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('predictions/upcoming');\n }\n\n /** Who airs the promotion, per ISO-2 country. */\n broadcastRights(org = 'ufc', opts: { country?: string } = {}): Promise<BroadcastRight[]> {\n return this.get<BroadcastRight[]>(`broadcast-rights/${encodeURIComponent(org)}`, opts as Query);\n }\n\n venue(venueId: number | string): Promise<Venue> {\n return this.get<Venue>(`venues/${encodeURIComponent(String(venueId))}`);\n }\n\n /** Typeahead across fighters and events. */\n search(q: string): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>('search', { q });\n }\n\n /** Your key's month-to-date quota usage. */\n usage(): Promise<Usage> {\n return this.get<Usage>('usage');\n }\n\n /**\n * Subscribable ICS feed URL for calendar apps (authenticates via `?key=`).\n *\n * Throws without a key rather than returning `?key=`: that empty URL is\n * pasted into a calendar app, fails there hours later, and the failure\n * surfaces nowhere near this call.\n */\n calendarIcsUrl(org = 'ufc'): string {\n if (!this.apiKey) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n return `${this.baseUrl}/calendar/${encodeURIComponent(org)}.ics?key=${encodeURIComponent(this.apiKey)}`;\n }\n\n /* ------------------------------------------------------------ webhooks */\n\n webhookEndpoints(): Promise<WebhookEndpoint[]> {\n return this.get<WebhookEndpoint[]>('webhook-endpoints');\n }\n\n /**\n * Register a signed webhook (Pro and up). `events` ⊆ `event.announced`,\n * `fight.result`, `card.changed`, `event.completed`. The signing secret is\n * returned ONCE, in this response.\n */\n async createWebhookEndpoint(url: string, events?: string[]): Promise<WebhookEndpoint> {\n const body: Record<string, unknown> = { url };\n if (events?.length) body.events = events;\n return (await this.#request<WebhookEndpoint>('POST', 'webhook-endpoints', { body })).data;\n }\n\n async deleteWebhookEndpoint(endpointId: number | string): Promise<void> {\n await this.#request<unknown>('DELETE', `webhook-endpoints/${encodeURIComponent(String(endpointId))}`);\n }\n\n async rotateWebhookSecret(endpointId: number | string): Promise<WebhookEndpoint> {\n return (\n await this.#request<WebhookEndpoint>(\n 'POST',\n `webhook-endpoints/${encodeURIComponent(String(endpointId))}/rotate-secret`,\n )\n ).data;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -558,7 +558,7 @@ declare class FightAPI {
558
558
 
559
559
  /** Kept in lockstep with package.json and the User-Agent by
560
560
  * `apps/api/src/surfaces.test.ts`. Bump all three together. */
561
- declare const VERSION = "0.2.0";
561
+ declare const VERSION = "0.2.1";
562
562
 
563
563
  /**
564
564
  * This file was auto-generated by openapi-typescript.
@@ -992,8 +992,8 @@ interface paths {
992
992
  cookie?: never;
993
993
  };
994
994
  /**
995
- * Live snapshot (Business+)
996
- * @description The latest real-time document for an event on fight night — the same `LiveState` the WebSocket pushes: card order and statuses, the bout in progress (`current`: phase, round, running clock, unofficial totals and per-round stats, referee, a timestamped action timeline), and the last result. `data` is `null` with `meta.live: false` when nothing is being streamed. Poll it at most every few seconds, or connect to the WebSocket in `meta.websocket` (`?key=` on the URL, then send `{"action":"subscribe","event":"<slug>"}`) and receive every change as it lands. UFC only in v1. Requires Business or Enterprise (403 `tier_required` otherwise).
995
+ * Live snapshot (Pro+)
996
+ * @description The latest real-time document for an event on fight night — the same `LiveState` the WebSocket pushes: card order and statuses, the bout in progress (`current`: phase, round, running clock, unofficial totals and per-round stats, referee, a timestamped action timeline), and the last result. `data` is `null` with `meta.live: false` when nothing is being streamed. Poll it at most every few seconds, or connect to the WebSocket in `meta.websocket` (`?key=` on the URL, then send `{"action":"subscribe","event":"<slug>"}`) and receive every change as it lands. UFC only in v1. Requires Pro or higher (403 `tier_required` otherwise).
997
997
  */
998
998
  get: {
999
999
  parameters: {
package/dist/index.d.ts CHANGED
@@ -558,7 +558,7 @@ declare class FightAPI {
558
558
 
559
559
  /** Kept in lockstep with package.json and the User-Agent by
560
560
  * `apps/api/src/surfaces.test.ts`. Bump all three together. */
561
- declare const VERSION = "0.2.0";
561
+ declare const VERSION = "0.2.1";
562
562
 
563
563
  /**
564
564
  * This file was auto-generated by openapi-typescript.
@@ -992,8 +992,8 @@ interface paths {
992
992
  cookie?: never;
993
993
  };
994
994
  /**
995
- * Live snapshot (Business+)
996
- * @description The latest real-time document for an event on fight night — the same `LiveState` the WebSocket pushes: card order and statuses, the bout in progress (`current`: phase, round, running clock, unofficial totals and per-round stats, referee, a timestamped action timeline), and the last result. `data` is `null` with `meta.live: false` when nothing is being streamed. Poll it at most every few seconds, or connect to the WebSocket in `meta.websocket` (`?key=` on the URL, then send `{"action":"subscribe","event":"<slug>"}`) and receive every change as it lands. UFC only in v1. Requires Business or Enterprise (403 `tier_required` otherwise).
995
+ * Live snapshot (Pro+)
996
+ * @description The latest real-time document for an event on fight night — the same `LiveState` the WebSocket pushes: card order and statuses, the bout in progress (`current`: phase, round, running clock, unofficial totals and per-round stats, referee, a timestamped action timeline), and the last result. `data` is `null` with `meta.live: false` when nothing is being streamed. Poll it at most every few seconds, or connect to the WebSocket in `meta.websocket` (`?key=` on the URL, then send `{"action":"subscribe","event":"<slug>"}`) and receive every change as it lands. UFC only in v1. Requires Pro or higher (403 `tier_required` otherwise).
997
997
  */
998
998
  get: {
999
999
  parameters: {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "0.2.0";
2
+ var VERSION = "0.2.1";
3
3
 
4
4
  // src/client.ts
5
5
  var DEFAULT_BASE_URL = "https://api.ufcalendar.com/v1";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts","../src/client.ts"],"sourcesContent":["/** Kept in lockstep with package.json and the User-Agent by\n * `apps/api/src/surfaces.test.ts`. Bump all three together. */\nexport const VERSION = '0.2.0';\n","/**\n * Thin, dependency-free client for https://api.ufcalendar.com/v1.\n *\n * Every method returns the parsed `data` value of the JSON envelope\n * (`{\"data\": ..., \"meta\": ...}`); list endpoints are async generators that\n * follow cursor pagination for you. Errors throw `FightAPIError` carrying\n * the API's `code`, `message` and `requestId` — quote the request id when\n * you write to api@ufcalendar.com.\n *\n * Mirrors sdk/python/ufcalendar/client.py one method per endpoint, in\n * camelCase. The two clients are kept in lockstep by\n * `apps/api/src/surfaces.test.ts`.\n *\n * The API serves no betting odds, by design. Fighter `images` are Wikimedia\n * Commons / Creative Commons files — the `license` and `artist` fields you\n * receive must be displayed as a credit.\n */\nimport { VERSION } from './version';\nimport type {\n BroadcastRight,\n CareerBout,\n CareerStats,\n Envelope,\n EventChange,\n EventDetail,\n EventSummary,\n Fight,\n Fighter,\n FighterSummary,\n Judge,\n Meta,\n Org,\n Plans,\n PowerIndex,\n RankingsBoard,\n RateLimit,\n Scorecards,\n Usage,\n Venue,\n WebhookEndpoint,\n LiveState,\n} from './types';\n\nexport const DEFAULT_BASE_URL = 'https://api.ufcalendar.com/v1';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface FightAPIOptions {\n /** `ufcalendar_…` key from https://www.ufcalendar.com/account/api. Falls back\n * to `UFCALENDAR_API_KEY` / `UFCAL_API_KEY` in the environment. Only\n * `plans()` works without one. */\n apiKey?: string;\n /** Override for testing; defaults to the production `/v1`. */\n baseUrl?: string;\n /** Inject a fetch (a test double, an instrumented fetch, undici). */\n fetch?: typeof fetch;\n /** Per-request timeout. Default 30s. */\n timeoutMs?: number;\n /** Extra headers on every request. */\n headers?: Record<string, string>;\n}\n\n/** An error response from the Fight API. */\nexport class FightAPIError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId: string | null;\n\n constructor(status: number, code: string, message: string, requestId: string | null = null) {\n super(`${status} ${code}: ${message}${requestId ? ` (request_id=${requestId})` : ''}`);\n this.name = 'FightAPIError';\n this.status = status;\n this.code = code;\n this.requestId = requestId;\n }\n}\n\nexport type QueryValue = string | number | boolean | null | undefined;\nexport type Query = Record<string, QueryValue>;\n\ninterface PageOptions {\n /** Stop after this many rows (across pages). */\n limit?: number;\n}\n\n/**\n * A browser forbids setting User-Agent on fetch, so we only set ours\n * off-browser. The test is `document`, NOT `navigator`: Node 21+ ships a\n * global `navigator`, so a navigator check would silently drop the header\n * on every modern Node runtime — which is the one place it works.\n */\nfunction canSetUserAgent(): boolean {\n return typeof document === 'undefined' && typeof window === 'undefined';\n}\n\nfunction envKey(): string | undefined {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n return env?.UFCALENDAR_API_KEY || env?.UFCAL_API_KEY;\n}\n\nexport class FightAPI {\n readonly baseUrl: string;\n readonly apiKey: string | undefined;\n\n /** `meta` of the most recent response (pagination cursor, generated_at …). */\n lastMeta: Meta | null = null;\n /** `X-RateLimit-*` of the most recent response. */\n lastRateLimit: RateLimit = { limit: null, remaining: null, reset: null };\n\n readonly #fetch: typeof fetch;\n readonly #timeoutMs: number;\n readonly #headers: Record<string, string>;\n\n constructor(apiKeyOrOptions?: string | FightAPIOptions, options: FightAPIOptions = {}) {\n const opts: FightAPIOptions =\n typeof apiKeyOrOptions === 'string'\n ? { ...options, apiKey: apiKeyOrOptions }\n : { ...options, ...(apiKeyOrOptions ?? {}) };\n this.apiKey = opts.apiKey ?? envKey();\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.#fetch = opts.fetch ?? globalThis.fetch;\n this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#headers = opts.headers ?? {};\n if (!this.#fetch) {\n throw new Error('No global fetch available. Use Node 18+ or pass { fetch }.');\n }\n }\n\n /* ---------------------------------------------------------------- core */\n\n #url(path: string, params?: Query): string {\n const url = new URL(`${this.baseUrl}/${path.replace(/^\\/+/, '')}`);\n for (const [k, v] of Object.entries(params ?? {})) {\n if (v === undefined || v === null) continue;\n url.searchParams.set(k, String(v));\n }\n return url.toString();\n }\n\n async #request<T>(\n method: string,\n path: string,\n { params, body, open = false }: { params?: Query; body?: unknown; open?: boolean } = {},\n ): Promise<Envelope<T>> {\n if (!this.apiKey && !open) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n const headers: Record<string, string> = { Accept: 'application/json', ...this.#headers };\n if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;\n if (canSetUserAgent()) headers['User-Agent'] = `ufcalendar-typescript/${VERSION}`;\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n\n let res: Response;\n try {\n res = await this.#fetch(this.#url(path, params), {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: AbortSignal.timeout(this.#timeoutMs),\n });\n } catch (e) {\n const err = e as { name?: string; message?: string };\n if (err?.name === 'TimeoutError') {\n throw new FightAPIError(0, 'timeout', `Request to ${path} timed out after ${this.#timeoutMs}ms`);\n }\n throw new FightAPIError(0, 'network_error', err?.message ?? String(e));\n }\n\n this.lastRateLimit = {\n limit: res.headers.get('X-RateLimit-Limit'),\n remaining: res.headers.get('X-RateLimit-Remaining'),\n reset: res.headers.get('X-RateLimit-Reset'),\n };\n\n if (res.status === 204) {\n this.lastMeta = null;\n return { data: undefined as T };\n }\n\n const text = await res.text();\n let parsed: unknown = undefined;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = undefined;\n }\n\n if (!res.ok) {\n const err = (parsed as { error?: { code?: string; message?: string; request_id?: string } } | undefined)?.error;\n if (err) {\n throw new FightAPIError(\n res.status,\n String(err.code ?? 'error'),\n String(err.message ?? text.slice(0, 200)),\n err.request_id ?? res.headers.get('x-request-id'),\n );\n }\n throw new FightAPIError(res.status, 'http_error', text.slice(0, 200), res.headers.get('x-request-id'));\n }\n\n const env = (parsed ?? {}) as Envelope<T>;\n this.lastMeta = env.meta ?? null;\n return env;\n }\n\n /** Raw GET returning the `data` value. Escape hatch for new endpoints. */\n async get<T = unknown>(path: string, params?: Query): Promise<T> {\n return (await this.#request<T>('GET', path, { params })).data;\n }\n\n /** Raw GET returning the whole `{data, meta}` envelope. */\n async getWithMeta<T = unknown>(path: string, params?: Query): Promise<Envelope<T>> {\n return this.#request<T>('GET', path, { params });\n }\n\n async *#paginate<T>(path: string, params: Query, opts: PageOptions = {}): AsyncGenerator<T, void, void> {\n // Never fetch a bigger page than the caller wants rows: `limit: 3` used\n // to pull 100 rows and throw 97 away, burning the caller's quota on a\n // request they did not ask for (and, on a trial key, a noticeable slice\n // of the 100 they get).\n const pageSize = Math.min(100, opts.limit ?? 100);\n const query: Query = { limit: pageSize, ...params };\n let seen = 0;\n for (;;) {\n const env = await this.#request<T[]>('GET', path, { params: query });\n for (const row of env.data ?? []) {\n yield row;\n seen += 1;\n if (opts.limit !== undefined && seen >= opts.limit) return;\n }\n const cursor = env.meta?.pagination?.next_cursor;\n if (!cursor) return;\n query.cursor = cursor;\n }\n }\n\n /* --------------------------------------------------------------- plans */\n\n /**\n * Plans, quotas, the free 1-day trial rule, the MCP endpoint and the doc\n * links. The only endpoint that answers without a credential.\n */\n async plans(): Promise<Plans> {\n return (await this.#request<Plans>('GET', 'plans', { open: true })).data;\n }\n\n /* ---------------------------------------------------------------- orgs */\n\n /** Launch orgs with capability flags (stats / rounds / rankings / broadcasts / predictions). */\n orgs(): Promise<Org[]> {\n return this.get<Org[]>('orgs');\n }\n\n org(slug: string): Promise<Org> {\n return this.get<Org>(`orgs/${encodeURIComponent(slug)}`);\n }\n\n /* -------------------------------------------------------------- events */\n\n /**\n * Schedule + results. Bare call = the upcoming calendar, soonest first.\n * `status: 'completed'` (or `order: 'desc'`) browses the archive\n * newest-first. `from` / `to` are `YYYY-MM-DD`.\n */\n events(\n opts: {\n org?: string;\n status?: string;\n from?: string;\n to?: string;\n order?: 'asc' | 'desc';\n limit?: number;\n } = {},\n ): AsyncGenerator<EventSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<EventSummary>('events', params as Query, { limit });\n }\n\n /** One event with its full fight card, venue and broadcasts. */\n event(idOrSlug: string | number): Promise<EventDetail> {\n return this.get<EventDetail>(`events/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Card-change diff log (fight added/removed, opponent swapped, date moved, profile merged). */\n eventChanges(idOrSlug: string | number): Promise<EventChange[]> {\n return this.get<EventChange[]>(`events/${encodeURIComponent(String(idOrSlug))}/changes`);\n }\n\n /** Latest real-time LiveState snapshot on fight night (Business+), or null\n * when nothing is being streamed. The WebSocket at wss://live.ufcalendar.com/v1\n * pushes the same document as it changes. */\n eventLive(idOrSlug: string | number): Promise<LiveState | null> {\n return this.get<LiveState | null>(`events/${encodeURIComponent(String(idOrSlug))}/live`);\n }\n\n /* -------------------------------------------------------------- fights */\n\n fight(fightId: number | string): Promise<Fight> {\n return this.get<Fight>(`fights/${encodeURIComponent(String(fightId))}`);\n }\n\n /** Per-fight totals for both corners. */\n fightStats(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/stats`);\n }\n\n /** Round-by-round stat lines for both corners. */\n fightRounds(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/rounds`);\n }\n\n /**\n * The judges' scorecards for a bout — the official commission record:\n * decision type, point deductions, and one card per judge with every\n * round, the totals and `winner_fighter_id`. Scores are oriented to\n * `fighter_a_id` / `fighter_b_id`, both repeated on the payload.\n *\n * Check `scores_known` on a card before charting totals: when it is false\n * the commission published only the outcome. Throws 404 for a bout that\n * did not go to the judges.\n */\n fightScorecards(fightId: number | string): Promise<Scorecards> {\n return this.get<Scorecards>(`fights/${encodeURIComponent(String(fightId))}/scorecards`);\n }\n\n /* -------------------------------------------------------------- judges */\n\n /**\n * Every official who has scored a launch-org bout, busiest first. Rates\n * mean little below ~10 fights; pass `minFights: 10`.\n */\n judges(\n opts: { q?: string; org?: string; minFights?: number; limit?: number } = {},\n ): AsyncGenerator<Judge, void, void> {\n const { limit, minFights, ...rest } = opts;\n return this.#paginate<Judge>('judges', { ...rest, min_fights: minFights } as Query, { limit });\n }\n\n judge(judgeId: number | string): Promise<Judge> {\n return this.get<Judge>(`judges/${encodeURIComponent(String(judgeId))}`);\n }\n\n /** Every card this judge has turned in, newest first. */\n judgeScorecards(\n judgeId: number | string,\n opts: { limit?: number } = {},\n ): AsyncGenerator<Record<string, unknown>, void, void> {\n return this.#paginate<Record<string, unknown>>(\n `judges/${encodeURIComponent(String(judgeId))}/scorecards`,\n {},\n opts,\n );\n }\n\n /* ------------------------------------------------------------ fighters */\n\n fighters(\n opts: { q?: string; org?: string; country?: string; limit?: number } = {},\n ): AsyncGenerator<FighterSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<FighterSummary>('fighters', params as Query, { limit });\n }\n\n /** Bio, records, career stats, Power Index and CC-licensed images. */\n fighter(idOrSlug: string | number): Promise<Fighter> {\n return this.get<Fighter>(`fighters/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Complete multi-promotion career timeline. */\n fighterHistory(idOrSlug: string | number): Promise<CareerBout[]> {\n return this.get<CareerBout[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/history`);\n }\n\n /** Career statistics, one source-stamped row per scope (`pro-mma`, `ufc-only` …). */\n fighterStats(idOrSlug: string | number): Promise<CareerStats[]> {\n return this.get<CareerStats[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/stats`);\n }\n\n /** Every official ranking row the fighter ever held, newest first. */\n fighterRankings(idOrSlug: string | number): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/rankings`);\n }\n\n fighterPowerIndex(idOrSlug: string | number): Promise<PowerIndex & Record<string, unknown>> {\n return this.get<PowerIndex & Record<string, unknown>>(\n `fighters/${encodeURIComponent(String(idOrSlug))}/power-index`,\n );\n }\n\n /* ------------------------------------------------------------ rankings */\n\n /**\n * Official board, point-in-time. `date: 'YYYY-MM-DD'` returns the board\n * that was valid on that day (UFC history back to 2013; rank 0 = champion).\n */\n rankings(org = 'ufc', opts: { date?: string; board?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(`rankings/${encodeURIComponent(org)}`, opts as Query);\n }\n\n divisionRankings(org: string, division: string, opts: { date?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(\n `rankings/${encodeURIComponent(org)}/${encodeURIComponent(division)}`,\n opts as Query,\n );\n }\n\n /** Current champions across every launch org. */\n champions(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('champions');\n }\n\n /** UFCalendar Power Index board. */\n powerIndex(org = 'ufc'): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>(`power-index/${encodeURIComponent(org)}`);\n }\n\n /* ---------------------------------------------------------------- misc */\n\n /** Model win probabilities for upcoming UFC bouts. */\n predictionsUpcoming(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('predictions/upcoming');\n }\n\n /** Who airs the promotion, per ISO-2 country. */\n broadcastRights(org = 'ufc', opts: { country?: string } = {}): Promise<BroadcastRight[]> {\n return this.get<BroadcastRight[]>(`broadcast-rights/${encodeURIComponent(org)}`, opts as Query);\n }\n\n venue(venueId: number | string): Promise<Venue> {\n return this.get<Venue>(`venues/${encodeURIComponent(String(venueId))}`);\n }\n\n /** Typeahead across fighters and events. */\n search(q: string): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>('search', { q });\n }\n\n /** Your key's month-to-date quota usage. */\n usage(): Promise<Usage> {\n return this.get<Usage>('usage');\n }\n\n /**\n * Subscribable ICS feed URL for calendar apps (authenticates via `?key=`).\n *\n * Throws without a key rather than returning `?key=`: that empty URL is\n * pasted into a calendar app, fails there hours later, and the failure\n * surfaces nowhere near this call.\n */\n calendarIcsUrl(org = 'ufc'): string {\n if (!this.apiKey) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n return `${this.baseUrl}/calendar/${encodeURIComponent(org)}.ics?key=${encodeURIComponent(this.apiKey)}`;\n }\n\n /* ------------------------------------------------------------ webhooks */\n\n webhookEndpoints(): Promise<WebhookEndpoint[]> {\n return this.get<WebhookEndpoint[]>('webhook-endpoints');\n }\n\n /**\n * Register a signed webhook (Pro and up). `events` ⊆ `event.announced`,\n * `fight.result`, `card.changed`, `event.completed`. The signing secret is\n * returned ONCE, in this response.\n */\n async createWebhookEndpoint(url: string, events?: string[]): Promise<WebhookEndpoint> {\n const body: Record<string, unknown> = { url };\n if (events?.length) body.events = events;\n return (await this.#request<WebhookEndpoint>('POST', 'webhook-endpoints', { body })).data;\n }\n\n async deleteWebhookEndpoint(endpointId: number | string): Promise<void> {\n await this.#request<unknown>('DELETE', `webhook-endpoints/${encodeURIComponent(String(endpointId))}`);\n }\n\n async rotateWebhookSecret(endpointId: number | string): Promise<WebhookEndpoint> {\n return (\n await this.#request<WebhookEndpoint>(\n 'POST',\n `webhook-endpoints/${encodeURIComponent(String(endpointId))}/rotate-secret`,\n )\n ).data;\n }\n}\n"],"mappings":";AAEO,IAAM,UAAU;;;ACyChB,IAAM,mBAAmB;AAChC,IAAM,qBAAqB;AAkBpB,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,QAAgB,MAAc,SAAiB,YAA2B,MAAM;AAC1F,UAAM,GAAG,MAAM,IAAI,IAAI,KAAK,OAAO,GAAG,YAAY,gBAAgB,SAAS,MAAM,EAAE,EAAE;AACrF,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACnB;AACF;AAgBA,SAAS,kBAA2B;AAClC,SAAO,OAAO,aAAa,eAAe,OAAO,WAAW;AAC9D;AAEA,SAAS,SAA6B;AACpC,QAAM,MAAO,WAA0E,SAAS;AAChG,SAAO,KAAK,sBAAsB,KAAK;AACzC;AAEO,IAAM,WAAN,MAAe;AAAA,EACX;AAAA,EACA;AAAA;AAAA,EAGT,WAAwB;AAAA;AAAA,EAExB,gBAA2B,EAAE,OAAO,MAAM,WAAW,MAAM,OAAO,KAAK;AAAA,EAE9D;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,iBAA4C,UAA2B,CAAC,GAAG;AACrF,UAAM,OACJ,OAAO,oBAAoB,WACvB,EAAE,GAAG,SAAS,QAAQ,gBAAgB,IACtC,EAAE,GAAG,SAAS,GAAI,mBAAmB,CAAC,EAAG;AAC/C,SAAK,SAAS,KAAK,UAAU,OAAO;AACpC,SAAK,WAAW,KAAK,WAAW,kBAAkB,QAAQ,QAAQ,EAAE;AACpE,SAAK,SAAS,KAAK,SAAS,WAAW;AACvC,SAAK,aAAa,KAAK,aAAa;AACpC,SAAK,WAAW,KAAK,WAAW,CAAC;AACjC,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AAAA,EACF;AAAA;AAAA,EAIA,KAAK,MAAc,QAAwB;AACzC,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,IAAI,KAAK,QAAQ,QAAQ,EAAE,CAAC,EAAE;AACjE,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,UAAU,CAAC,CAAC,GAAG;AACjD,UAAI,MAAM,UAAa,MAAM,KAAM;AACnC,UAAI,aAAa,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,IACnC;AACA,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA,EAEA,MAAM,SACJ,QACA,MACA,EAAE,QAAQ,MAAM,OAAO,MAAM,IAAwD,CAAC,GAChE;AACtB,QAAI,CAAC,KAAK,UAAU,CAAC,MAAM;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MAEF;AAAA,IACF;AACA,UAAM,UAAkC,EAAE,QAAQ,oBAAoB,GAAG,KAAK,SAAS;AACvF,QAAI,KAAK,OAAQ,SAAQ,gBAAgB,UAAU,KAAK,MAAM;AAC9D,QAAI,gBAAgB,EAAG,SAAQ,YAAY,IAAI,yBAAyB,OAAO;AAC/E,QAAI,SAAS,OAAW,SAAQ,cAAc,IAAI;AAElD,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,MAAM,GAAG;AAAA,QAC/C;AAAA,QACA;AAAA,QACA,MAAM,SAAS,SAAY,SAAY,KAAK,UAAU,IAAI;AAAA,QAC1D,QAAQ,YAAY,QAAQ,KAAK,UAAU;AAAA,MAC7C,CAAC;AAAA,IACH,SAAS,GAAG;AACV,YAAM,MAAM;AACZ,UAAI,KAAK,SAAS,gBAAgB;AAChC,cAAM,IAAI,cAAc,GAAG,WAAW,cAAc,IAAI,oBAAoB,KAAK,UAAU,IAAI;AAAA,MACjG;AACA,YAAM,IAAI,cAAc,GAAG,iBAAiB,KAAK,WAAW,OAAO,CAAC,CAAC;AAAA,IACvE;AAEA,SAAK,gBAAgB;AAAA,MACnB,OAAO,IAAI,QAAQ,IAAI,mBAAmB;AAAA,MAC1C,WAAW,IAAI,QAAQ,IAAI,uBAAuB;AAAA,MAClD,OAAO,IAAI,QAAQ,IAAI,mBAAmB;AAAA,IAC5C;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,WAAK,WAAW;AAChB,aAAO,EAAE,MAAM,OAAe;AAAA,IAChC;AAEA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,SAAkB;AACtB,QAAI;AACF,eAAS,OAAO,KAAK,MAAM,IAAI,IAAI;AAAA,IACrC,QAAQ;AACN,eAAS;AAAA,IACX;AAEA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,MAAO,QAA6F;AAC1G,UAAI,KAAK;AACP,cAAM,IAAI;AAAA,UACR,IAAI;AAAA,UACJ,OAAO,IAAI,QAAQ,OAAO;AAAA,UAC1B,OAAO,IAAI,WAAW,KAAK,MAAM,GAAG,GAAG,CAAC;AAAA,UACxC,IAAI,cAAc,IAAI,QAAQ,IAAI,cAAc;AAAA,QAClD;AAAA,MACF;AACA,YAAM,IAAI,cAAc,IAAI,QAAQ,cAAc,KAAK,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,IAAI,cAAc,CAAC;AAAA,IACvG;AAEA,UAAM,MAAO,UAAU,CAAC;AACxB,SAAK,WAAW,IAAI,QAAQ;AAC5B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,IAAiB,MAAc,QAA4B;AAC/D,YAAQ,MAAM,KAAK,SAAY,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAM,YAAyB,MAAc,QAAsC;AACjF,WAAO,KAAK,SAAY,OAAO,MAAM,EAAE,OAAO,CAAC;AAAA,EACjD;AAAA,EAEA,OAAO,UAAa,MAAc,QAAe,OAAoB,CAAC,GAAkC;AAKtG,UAAM,WAAW,KAAK,IAAI,KAAK,KAAK,SAAS,GAAG;AAChD,UAAM,QAAe,EAAE,OAAO,UAAU,GAAG,OAAO;AAClD,QAAI,OAAO;AACX,eAAS;AACP,YAAM,MAAM,MAAM,KAAK,SAAc,OAAO,MAAM,EAAE,QAAQ,MAAM,CAAC;AACnE,iBAAW,OAAO,IAAI,QAAQ,CAAC,GAAG;AAChC,cAAM;AACN,gBAAQ;AACR,YAAI,KAAK,UAAU,UAAa,QAAQ,KAAK,MAAO;AAAA,MACtD;AACA,YAAM,SAAS,IAAI,MAAM,YAAY;AACrC,UAAI,CAAC,OAAQ;AACb,YAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAwB;AAC5B,YAAQ,MAAM,KAAK,SAAgB,OAAO,SAAS,EAAE,MAAM,KAAK,CAAC,GAAG;AAAA,EACtE;AAAA;AAAA;AAAA,EAKA,OAAuB;AACrB,WAAO,KAAK,IAAW,MAAM;AAAA,EAC/B;AAAA,EAEA,IAAI,MAA4B;AAC9B,WAAO,KAAK,IAAS,QAAQ,mBAAmB,IAAI,CAAC,EAAE;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OACE,OAOI,CAAC,GACqC;AAC1C,UAAM,EAAE,OAAO,GAAG,OAAO,IAAI;AAC7B,WAAO,KAAK,UAAwB,UAAU,QAAiB,EAAE,MAAM,CAAC;AAAA,EAC1E;AAAA;AAAA,EAGA,MAAM,UAAiD;AACrD,WAAO,KAAK,IAAiB,UAAU,mBAAmB,OAAO,QAAQ,CAAC,CAAC,EAAE;AAAA,EAC/E;AAAA;AAAA,EAGA,aAAa,UAAmD;AAC9D,WAAO,KAAK,IAAmB,UAAU,mBAAmB,OAAO,QAAQ,CAAC,CAAC,UAAU;AAAA,EACzF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,UAAsD;AAC9D,WAAO,KAAK,IAAsB,UAAU,mBAAmB,OAAO,QAAQ,CAAC,CAAC,OAAO;AAAA,EACzF;AAAA;AAAA,EAIA,MAAM,SAA0C;AAC9C,WAAO,KAAK,IAAW,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,EAAE;AAAA,EACxE;AAAA;AAAA,EAGA,WAAW,SAA8D;AACvE,WAAO,KAAK,IAA+B,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,QAAQ;AAAA,EAClG;AAAA;AAAA,EAGA,YAAY,SAA8D;AACxE,WAAO,KAAK,IAA+B,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,SAAS;AAAA,EACnG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,gBAAgB,SAA+C;AAC7D,WAAO,KAAK,IAAgB,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,aAAa;AAAA,EACxF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OACE,OAAyE,CAAC,GACvC;AACnC,UAAM,EAAE,OAAO,WAAW,GAAG,KAAK,IAAI;AACtC,WAAO,KAAK,UAAiB,UAAU,EAAE,GAAG,MAAM,YAAY,UAAU,GAAY,EAAE,MAAM,CAAC;AAAA,EAC/F;AAAA,EAEA,MAAM,SAA0C;AAC9C,WAAO,KAAK,IAAW,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,EAAE;AAAA,EACxE;AAAA;AAAA,EAGA,gBACE,SACA,OAA2B,CAAC,GACyB;AACrD,WAAO,KAAK;AAAA,MACV,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC;AAAA,MAC7C,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,SACE,OAAuE,CAAC,GAC5B;AAC5C,UAAM,EAAE,OAAO,GAAG,OAAO,IAAI;AAC7B,WAAO,KAAK,UAA0B,YAAY,QAAiB,EAAE,MAAM,CAAC;AAAA,EAC9E;AAAA;AAAA,EAGA,QAAQ,UAA6C;AACnD,WAAO,KAAK,IAAa,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,EAAE;AAAA,EAC7E;AAAA;AAAA,EAGA,eAAe,UAAkD;AAC/D,WAAO,KAAK,IAAkB,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,UAAU;AAAA,EAC1F;AAAA;AAAA,EAGA,aAAa,UAAmD;AAC9D,WAAO,KAAK,IAAmB,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,QAAQ;AAAA,EACzF;AAAA;AAAA,EAGA,gBAAgB,UAA+D;AAC7E,WAAO,KAAK,IAA+B,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC,WAAW;AAAA,EACxG;AAAA,EAEA,kBAAkB,UAA0E;AAC1F,WAAO,KAAK;AAAA,MACV,YAAY,mBAAmB,OAAO,QAAQ,CAAC,CAAC;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,MAAM,OAAO,OAA0C,CAAC,GAA2B;AAC1F,WAAO,KAAK,IAAmB,YAAY,mBAAmB,GAAG,CAAC,IAAI,IAAa;AAAA,EACrF;AAAA,EAEA,iBAAiB,KAAa,UAAkB,OAA0B,CAAC,GAA2B;AACpG,WAAO,KAAK;AAAA,MACV,YAAY,mBAAmB,GAAG,CAAC,IAAI,mBAAmB,QAAQ,CAAC;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,YAAgD;AAC9C,WAAO,KAAK,IAA+B,WAAW;AAAA,EACxD;AAAA;AAAA,EAGA,WAAW,MAAM,OAAyC;AACxD,WAAO,KAAK,IAA6B,eAAe,mBAAmB,GAAG,CAAC,EAAE;AAAA,EACnF;AAAA;AAAA;AAAA,EAKA,sBAA0D;AACxD,WAAO,KAAK,IAA+B,sBAAsB;AAAA,EACnE;AAAA;AAAA,EAGA,gBAAgB,MAAM,OAAO,OAA6B,CAAC,GAA8B;AACvF,WAAO,KAAK,IAAsB,oBAAoB,mBAAmB,GAAG,CAAC,IAAI,IAAa;AAAA,EAChG;AAAA,EAEA,MAAM,SAA0C;AAC9C,WAAO,KAAK,IAAW,UAAU,mBAAmB,OAAO,OAAO,CAAC,CAAC,EAAE;AAAA,EACxE;AAAA;AAAA,EAGA,OAAO,GAA6C;AAClD,WAAO,KAAK,IAA6B,UAAU,EAAE,EAAE,CAAC;AAAA,EAC1D;AAAA;AAAA,EAGA,QAAwB;AACtB,WAAO,KAAK,IAAW,OAAO;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAe,MAAM,OAAe;AAClC,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MAEF;AAAA,IACF;AACA,WAAO,GAAG,KAAK,OAAO,aAAa,mBAAmB,GAAG,CAAC,YAAY,mBAAmB,KAAK,MAAM,CAAC;AAAA,EACvG;AAAA;AAAA,EAIA,mBAA+C;AAC7C,WAAO,KAAK,IAAuB,mBAAmB;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBAAsB,KAAa,QAA6C;AACpF,UAAM,OAAgC,EAAE,IAAI;AAC5C,QAAI,QAAQ,OAAQ,MAAK,SAAS;AAClC,YAAQ,MAAM,KAAK,SAA0B,QAAQ,qBAAqB,EAAE,KAAK,CAAC,GAAG;AAAA,EACvF;AAAA,EAEA,MAAM,sBAAsB,YAA4C;AACtE,UAAM,KAAK,SAAkB,UAAU,qBAAqB,mBAAmB,OAAO,UAAU,CAAC,CAAC,EAAE;AAAA,EACtG;AAAA,EAEA,MAAM,oBAAoB,YAAuD;AAC/E,YACE,MAAM,KAAK;AAAA,MACT;AAAA,MACA,qBAAqB,mBAAmB,OAAO,UAAU,CAAC,CAAC;AAAA,IAC7D,GACA;AAAA,EACJ;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/version.ts","../src/client.ts"],"sourcesContent":["/** Kept in lockstep with package.json and the User-Agent by\n * `apps/api/src/surfaces.test.ts`. Bump all three together. */\nexport const VERSION = '0.2.1';\n","/**\n * Thin, dependency-free client for https://api.ufcalendar.com/v1.\n *\n * Every method returns the parsed `data` value of the JSON envelope\n * (`{\"data\": ..., \"meta\": ...}`); list endpoints are async generators that\n * follow cursor pagination for you. Errors throw `FightAPIError` carrying\n * the API's `code`, `message` and `requestId` — quote the request id when\n * you write to api@ufcalendar.com.\n *\n * Mirrors sdk/python/ufcalendar/client.py one method per endpoint, in\n * camelCase. The two clients are kept in lockstep by\n * `apps/api/src/surfaces.test.ts`.\n *\n * The API serves no betting odds, by design. Fighter `images` are Wikimedia\n * Commons / Creative Commons files — the `license` and `artist` fields you\n * receive must be displayed as a credit.\n */\nimport { VERSION } from './version';\nimport type {\n BroadcastRight,\n CareerBout,\n CareerStats,\n Envelope,\n EventChange,\n EventDetail,\n EventSummary,\n Fight,\n Fighter,\n FighterSummary,\n Judge,\n Meta,\n Org,\n Plans,\n PowerIndex,\n RankingsBoard,\n RateLimit,\n Scorecards,\n Usage,\n Venue,\n WebhookEndpoint,\n LiveState,\n} from './types';\n\nexport const DEFAULT_BASE_URL = 'https://api.ufcalendar.com/v1';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface FightAPIOptions {\n /** `ufcalendar_…` key from https://www.ufcalendar.com/account/api. Falls back\n * to `UFCALENDAR_API_KEY` / `UFCAL_API_KEY` in the environment. Only\n * `plans()` works without one. */\n apiKey?: string;\n /** Override for testing; defaults to the production `/v1`. */\n baseUrl?: string;\n /** Inject a fetch (a test double, an instrumented fetch, undici). */\n fetch?: typeof fetch;\n /** Per-request timeout. Default 30s. */\n timeoutMs?: number;\n /** Extra headers on every request. */\n headers?: Record<string, string>;\n}\n\n/** An error response from the Fight API. */\nexport class FightAPIError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId: string | null;\n\n constructor(status: number, code: string, message: string, requestId: string | null = null) {\n super(`${status} ${code}: ${message}${requestId ? ` (request_id=${requestId})` : ''}`);\n this.name = 'FightAPIError';\n this.status = status;\n this.code = code;\n this.requestId = requestId;\n }\n}\n\nexport type QueryValue = string | number | boolean | null | undefined;\nexport type Query = Record<string, QueryValue>;\n\ninterface PageOptions {\n /** Stop after this many rows (across pages). */\n limit?: number;\n}\n\n/**\n * A browser forbids setting User-Agent on fetch, so we only set ours\n * off-browser. The test is `document`, NOT `navigator`: Node 21+ ships a\n * global `navigator`, so a navigator check would silently drop the header\n * on every modern Node runtime — which is the one place it works.\n */\nfunction canSetUserAgent(): boolean {\n return typeof document === 'undefined' && typeof window === 'undefined';\n}\n\nfunction envKey(): string | undefined {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n return env?.UFCALENDAR_API_KEY || env?.UFCAL_API_KEY;\n}\n\nexport class FightAPI {\n readonly baseUrl: string;\n readonly apiKey: string | undefined;\n\n /** `meta` of the most recent response (pagination cursor, generated_at …). */\n lastMeta: Meta | null = null;\n /** `X-RateLimit-*` of the most recent response. */\n lastRateLimit: RateLimit = { limit: null, remaining: null, reset: null };\n\n readonly #fetch: typeof fetch;\n readonly #timeoutMs: number;\n readonly #headers: Record<string, string>;\n\n constructor(apiKeyOrOptions?: string | FightAPIOptions, options: FightAPIOptions = {}) {\n const opts: FightAPIOptions =\n typeof apiKeyOrOptions === 'string'\n ? { ...options, apiKey: apiKeyOrOptions }\n : { ...options, ...(apiKeyOrOptions ?? {}) };\n this.apiKey = opts.apiKey ?? envKey();\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.#fetch = opts.fetch ?? globalThis.fetch;\n this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#headers = opts.headers ?? {};\n if (!this.#fetch) {\n throw new Error('No global fetch available. Use Node 18+ or pass { fetch }.');\n }\n }\n\n /* ---------------------------------------------------------------- core */\n\n #url(path: string, params?: Query): string {\n const url = new URL(`${this.baseUrl}/${path.replace(/^\\/+/, '')}`);\n for (const [k, v] of Object.entries(params ?? {})) {\n if (v === undefined || v === null) continue;\n url.searchParams.set(k, String(v));\n }\n return url.toString();\n }\n\n async #request<T>(\n method: string,\n path: string,\n { params, body, open = false }: { params?: Query; body?: unknown; open?: boolean } = {},\n ): Promise<Envelope<T>> {\n if (!this.apiKey && !open) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n const headers: Record<string, string> = { Accept: 'application/json', ...this.#headers };\n if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;\n if (canSetUserAgent()) headers['User-Agent'] = `ufcalendar-typescript/${VERSION}`;\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n\n let res: Response;\n try {\n res = await this.#fetch(this.#url(path, params), {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: AbortSignal.timeout(this.#timeoutMs),\n });\n } catch (e) {\n const err = e as { name?: string; message?: string };\n if (err?.name === 'TimeoutError') {\n throw new FightAPIError(0, 'timeout', `Request to ${path} timed out after ${this.#timeoutMs}ms`);\n }\n throw new FightAPIError(0, 'network_error', err?.message ?? String(e));\n }\n\n this.lastRateLimit = {\n limit: res.headers.get('X-RateLimit-Limit'),\n remaining: res.headers.get('X-RateLimit-Remaining'),\n reset: res.headers.get('X-RateLimit-Reset'),\n };\n\n if (res.status === 204) {\n this.lastMeta = null;\n return { data: undefined as T };\n }\n\n const text = await res.text();\n let parsed: unknown = undefined;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = undefined;\n }\n\n if (!res.ok) {\n const err = (parsed as { error?: { code?: string; message?: string; request_id?: string } } | undefined)?.error;\n if (err) {\n throw new FightAPIError(\n res.status,\n String(err.code ?? 'error'),\n String(err.message ?? text.slice(0, 200)),\n err.request_id ?? res.headers.get('x-request-id'),\n );\n }\n throw new FightAPIError(res.status, 'http_error', text.slice(0, 200), res.headers.get('x-request-id'));\n }\n\n const env = (parsed ?? {}) as Envelope<T>;\n this.lastMeta = env.meta ?? null;\n return env;\n }\n\n /** Raw GET returning the `data` value. Escape hatch for new endpoints. */\n async get<T = unknown>(path: string, params?: Query): Promise<T> {\n return (await this.#request<T>('GET', path, { params })).data;\n }\n\n /** Raw GET returning the whole `{data, meta}` envelope. */\n async getWithMeta<T = unknown>(path: string, params?: Query): Promise<Envelope<T>> {\n return this.#request<T>('GET', path, { params });\n }\n\n async *#paginate<T>(path: string, params: Query, opts: PageOptions = {}): AsyncGenerator<T, void, void> {\n // Never fetch a bigger page than the caller wants rows: `limit: 3` used\n // to pull 100 rows and throw 97 away, burning the caller's quota on a\n // request they did not ask for (and, on a trial key, a noticeable slice\n // of the 100 they get).\n const pageSize = Math.min(100, opts.limit ?? 100);\n const query: Query = { limit: pageSize, ...params };\n let seen = 0;\n for (;;) {\n const env = await this.#request<T[]>('GET', path, { params: query });\n for (const row of env.data ?? []) {\n yield row;\n seen += 1;\n if (opts.limit !== undefined && seen >= opts.limit) return;\n }\n const cursor = env.meta?.pagination?.next_cursor;\n if (!cursor) return;\n query.cursor = cursor;\n }\n }\n\n /* --------------------------------------------------------------- plans */\n\n /**\n * Plans, quotas, the free 1-day trial rule, the MCP endpoint and the doc\n * links. The only endpoint that answers without a credential.\n */\n async plans(): Promise<Plans> {\n return (await this.#request<Plans>('GET', 'plans', { open: true })).data;\n }\n\n /* ---------------------------------------------------------------- orgs */\n\n /** Launch orgs with capability flags (stats / rounds / rankings / broadcasts / predictions). */\n orgs(): Promise<Org[]> {\n return this.get<Org[]>('orgs');\n }\n\n org(slug: string): Promise<Org> {\n return this.get<Org>(`orgs/${encodeURIComponent(slug)}`);\n }\n\n /* -------------------------------------------------------------- events */\n\n /**\n * Schedule + results. Bare call = the upcoming calendar, soonest first.\n * `status: 'completed'` (or `order: 'desc'`) browses the archive\n * newest-first. `from` / `to` are `YYYY-MM-DD`.\n */\n events(\n opts: {\n org?: string;\n status?: string;\n from?: string;\n to?: string;\n order?: 'asc' | 'desc';\n limit?: number;\n } = {},\n ): AsyncGenerator<EventSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<EventSummary>('events', params as Query, { limit });\n }\n\n /** One event with its full fight card, venue and broadcasts. */\n event(idOrSlug: string | number): Promise<EventDetail> {\n return this.get<EventDetail>(`events/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Card-change diff log (fight added/removed, opponent swapped, date moved, profile merged). */\n eventChanges(idOrSlug: string | number): Promise<EventChange[]> {\n return this.get<EventChange[]>(`events/${encodeURIComponent(String(idOrSlug))}/changes`);\n }\n\n /** Latest real-time LiveState snapshot on fight night (Business+), or null\n * when nothing is being streamed. The WebSocket at wss://live.ufcalendar.com/v1\n * pushes the same document as it changes. */\n eventLive(idOrSlug: string | number): Promise<LiveState | null> {\n return this.get<LiveState | null>(`events/${encodeURIComponent(String(idOrSlug))}/live`);\n }\n\n /* -------------------------------------------------------------- fights */\n\n fight(fightId: number | string): Promise<Fight> {\n return this.get<Fight>(`fights/${encodeURIComponent(String(fightId))}`);\n }\n\n /** Per-fight totals for both corners. */\n fightStats(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/stats`);\n }\n\n /** Round-by-round stat lines for both corners. */\n fightRounds(fightId: number | string): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fights/${encodeURIComponent(String(fightId))}/rounds`);\n }\n\n /**\n * The judges' scorecards for a bout — the official commission record:\n * decision type, point deductions, and one card per judge with every\n * round, the totals and `winner_fighter_id`. Scores are oriented to\n * `fighter_a_id` / `fighter_b_id`, both repeated on the payload.\n *\n * Check `scores_known` on a card before charting totals: when it is false\n * the commission published only the outcome. Throws 404 for a bout that\n * did not go to the judges.\n */\n fightScorecards(fightId: number | string): Promise<Scorecards> {\n return this.get<Scorecards>(`fights/${encodeURIComponent(String(fightId))}/scorecards`);\n }\n\n /* -------------------------------------------------------------- judges */\n\n /**\n * Every official who has scored a launch-org bout, busiest first. Rates\n * mean little below ~10 fights; pass `minFights: 10`.\n */\n judges(\n opts: { q?: string; org?: string; minFights?: number; limit?: number } = {},\n ): AsyncGenerator<Judge, void, void> {\n const { limit, minFights, ...rest } = opts;\n return this.#paginate<Judge>('judges', { ...rest, min_fights: minFights } as Query, { limit });\n }\n\n judge(judgeId: number | string): Promise<Judge> {\n return this.get<Judge>(`judges/${encodeURIComponent(String(judgeId))}`);\n }\n\n /** Every card this judge has turned in, newest first. */\n judgeScorecards(\n judgeId: number | string,\n opts: { limit?: number } = {},\n ): AsyncGenerator<Record<string, unknown>, void, void> {\n return this.#paginate<Record<string, unknown>>(\n `judges/${encodeURIComponent(String(judgeId))}/scorecards`,\n {},\n opts,\n );\n }\n\n /* ------------------------------------------------------------ fighters */\n\n fighters(\n opts: { q?: string; org?: string; country?: string; limit?: number } = {},\n ): AsyncGenerator<FighterSummary, void, void> {\n const { limit, ...params } = opts;\n return this.#paginate<FighterSummary>('fighters', params as Query, { limit });\n }\n\n /** Bio, records, career stats, Power Index and CC-licensed images. */\n fighter(idOrSlug: string | number): Promise<Fighter> {\n return this.get<Fighter>(`fighters/${encodeURIComponent(String(idOrSlug))}`);\n }\n\n /** Complete multi-promotion career timeline. */\n fighterHistory(idOrSlug: string | number): Promise<CareerBout[]> {\n return this.get<CareerBout[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/history`);\n }\n\n /** Career statistics, one source-stamped row per scope (`pro-mma`, `ufc-only` …). */\n fighterStats(idOrSlug: string | number): Promise<CareerStats[]> {\n return this.get<CareerStats[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/stats`);\n }\n\n /** Every official ranking row the fighter ever held, newest first. */\n fighterRankings(idOrSlug: string | number): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>(`fighters/${encodeURIComponent(String(idOrSlug))}/rankings`);\n }\n\n fighterPowerIndex(idOrSlug: string | number): Promise<PowerIndex & Record<string, unknown>> {\n return this.get<PowerIndex & Record<string, unknown>>(\n `fighters/${encodeURIComponent(String(idOrSlug))}/power-index`,\n );\n }\n\n /* ------------------------------------------------------------ rankings */\n\n /**\n * Official board, point-in-time. `date: 'YYYY-MM-DD'` returns the board\n * that was valid on that day (UFC history back to 2013; rank 0 = champion).\n */\n rankings(org = 'ufc', opts: { date?: string; board?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(`rankings/${encodeURIComponent(org)}`, opts as Query);\n }\n\n divisionRankings(org: string, division: string, opts: { date?: string } = {}): Promise<RankingsBoard> {\n return this.get<RankingsBoard>(\n `rankings/${encodeURIComponent(org)}/${encodeURIComponent(division)}`,\n opts as Query,\n );\n }\n\n /** Current champions across every launch org. */\n champions(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('champions');\n }\n\n /** UFCalendar Power Index board. */\n powerIndex(org = 'ufc'): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>(`power-index/${encodeURIComponent(org)}`);\n }\n\n /* ---------------------------------------------------------------- misc */\n\n /** Model win probabilities for upcoming UFC bouts. */\n predictionsUpcoming(): Promise<Record<string, unknown>[]> {\n return this.get<Record<string, unknown>[]>('predictions/upcoming');\n }\n\n /** Who airs the promotion, per ISO-2 country. */\n broadcastRights(org = 'ufc', opts: { country?: string } = {}): Promise<BroadcastRight[]> {\n return this.get<BroadcastRight[]>(`broadcast-rights/${encodeURIComponent(org)}`, opts as Query);\n }\n\n venue(venueId: number | string): Promise<Venue> {\n return this.get<Venue>(`venues/${encodeURIComponent(String(venueId))}`);\n }\n\n /** Typeahead across fighters and events. */\n search(q: string): Promise<Record<string, unknown>> {\n return this.get<Record<string, unknown>>('search', { q });\n }\n\n /** Your key's month-to-date quota usage. */\n usage(): Promise<Usage> {\n return this.get<Usage>('usage');\n }\n\n /**\n * Subscribable ICS feed URL for calendar apps (authenticates via `?key=`).\n *\n * Throws without a key rather than returning `?key=`: that empty URL is\n * pasted into a calendar app, fails there hours later, and the failure\n * surfaces nowhere near this call.\n */\n calendarIcsUrl(org = 'ufc'): string {\n if (!this.apiKey) {\n throw new FightAPIError(\n 401,\n 'no_api_key',\n 'No API key. Pass new FightAPI(\"ufcalendar_...\") or set UFCALENDAR_API_KEY. ' +\n 'Keys (and the free 1-day trial) live at https://www.ufcalendar.com/account/api',\n );\n }\n return `${this.baseUrl}/calendar/${encodeURIComponent(org)}.ics?key=${encodeURIComponent(this.apiKey)}`;\n }\n\n /* ------------------------------------------------------------ webhooks */\n\n webhookEndpoints(): Promise<WebhookEndpoint[]> {\n return this.get<WebhookEndpoint[]>('webhook-endpoints');\n }\n\n /**\n * Register a signed webhook (Pro and up). `events` ⊆ `event.announced`,\n * `fight.result`, `card.changed`, `event.completed`. The signing secret is\n * returned ONCE, in this response.\n */\n async createWebhookEndpoint(url: string, events?: string[]): Promise<WebhookEndpoint> {\n const body: Record<string, unknown> = { url };\n if (events?.length) body.events = events;\n return (await this.#request<WebhookEndpoint>('POST', 'webhook-endpoints', { body })).data;\n }\n\n async deleteWebhookEndpoint(endpointId: number | string): Promise<void> {\n await this.#request<unknown>('DELETE', `webhook-endpoints/${encodeURIComponent(String(endpointId))}`);\n }\n\n async rotateWebhookSecret(endpointId: number | string): Promise<WebhookEndpoint> {\n return (\n await this.#request<WebhookEndpoint>(\n 'POST',\n `webhook-endpoints/${encodeURIComponent(String(endpointId))}/rotate-secret`,\n )\n ).data;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ufcalendar/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "TypeScript client for the UFCalendar Fight API: UFC, PFL, OKTAGON, BKFC and RIZIN events, fight cards, results, per-round stats, fighter careers, judges' scorecards and UFC rankings history since 2013.",
5
5
  "type": "module",
6
6
  "license": "MIT",