From b0171601ae61b1d4553e69a43157090677382f1f Mon Sep 17 00:00:00 2001 From: Ayush7614 Date: Sun, 5 Jul 2026 17:32:58 +0530 Subject: [PATCH 1/9] feat(api_sports): add API-Sports plugin with 67 sports operations Implement Corsair OSS plugin for API-Sports across football, NBA, basketball, AFL, baseball, F1, MMA, and NFL APIs with x-apisports-key auth, sport-specific base URLs, live-tested endpoints, and demo registration. Closes #358 --- demo/testing/package.json | 1 + demo/testing/src/server/corsair.ts | 4 + packages/api_sports/api.test.ts | 49 ++ packages/api_sports/client.ts | 107 +++ packages/api_sports/endpoints/afl.ts | 65 ++ packages/api_sports/endpoints/baseball.ts | 17 + packages/api_sports/endpoints/basketball.ts | 89 ++ packages/api_sports/endpoints/core.ts | 173 ++++ packages/api_sports/endpoints/fixtures.ts | 89 ++ packages/api_sports/endpoints/formula1.ts | 101 +++ packages/api_sports/endpoints/index.ts | 12 + packages/api_sports/endpoints/mma.ts | 77 ++ packages/api_sports/endpoints/odds.ts | 77 ++ packages/api_sports/endpoints/players.ts | 113 +++ packages/api_sports/endpoints/routes.ts | 79 ++ packages/api_sports/endpoints/standings.ts | 53 ++ packages/api_sports/endpoints/types.ts | 316 +++++++ packages/api_sports/error-handlers.ts | 64 ++ packages/api_sports/index.ts | 833 ++++++++++++++++++ packages/api_sports/jest.config.cjs | 29 + packages/api_sports/package.json | 45 + packages/api_sports/schema/database.ts | 9 + packages/api_sports/schema/index.ts | 8 + .../api_sports/scripts/generate-endpoints.py | 409 +++++++++ packages/api_sports/tsconfig.json | 20 + packages/api_sports/tsup.config.ts | 15 + packages/corsair/core/constants.ts | 3 + pnpm-lock.yaml | 204 +++-- 28 files changed, 2974 insertions(+), 87 deletions(-) create mode 100644 packages/api_sports/api.test.ts create mode 100644 packages/api_sports/client.ts create mode 100644 packages/api_sports/endpoints/afl.ts create mode 100644 packages/api_sports/endpoints/baseball.ts create mode 100644 packages/api_sports/endpoints/basketball.ts create mode 100644 packages/api_sports/endpoints/core.ts create mode 100644 packages/api_sports/endpoints/fixtures.ts create mode 100644 packages/api_sports/endpoints/formula1.ts create mode 100644 packages/api_sports/endpoints/index.ts create mode 100644 packages/api_sports/endpoints/mma.ts create mode 100644 packages/api_sports/endpoints/odds.ts create mode 100644 packages/api_sports/endpoints/players.ts create mode 100644 packages/api_sports/endpoints/routes.ts create mode 100644 packages/api_sports/endpoints/standings.ts create mode 100644 packages/api_sports/endpoints/types.ts create mode 100644 packages/api_sports/error-handlers.ts create mode 100644 packages/api_sports/index.ts create mode 100644 packages/api_sports/jest.config.cjs create mode 100644 packages/api_sports/package.json create mode 100644 packages/api_sports/schema/database.ts create mode 100644 packages/api_sports/schema/index.ts create mode 100644 packages/api_sports/scripts/generate-endpoints.py create mode 100644 packages/api_sports/tsconfig.json create mode 100644 packages/api_sports/tsup.config.ts diff --git a/demo/testing/package.json b/demo/testing/package.json index 3dcf0da17..cf8ba887b 100644 --- a/demo/testing/package.json +++ b/demo/testing/package.json @@ -26,6 +26,7 @@ "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.0", "@corsair-dev/agentql": "workspace:*", + "@corsair-dev/api_sports": "workspace:*", "@corsair-dev/bitwarden": "workspace:*", "@corsair-dev/cursor": "workspace:*", "@corsair-dev/firecrawl": "workspace:*", diff --git a/demo/testing/src/server/corsair.ts b/demo/testing/src/server/corsair.ts index 3755c8b3e..00105335b 100644 --- a/demo/testing/src/server/corsair.ts +++ b/demo/testing/src/server/corsair.ts @@ -3,6 +3,7 @@ import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); import { agentql } from '@corsair-dev/agentql'; +import { apiSports } from '@corsair-dev/api_sports'; import { gmail } from '@corsair-dev/gmail'; import { googlecalendar } from '@corsair-dev/googlecalendar'; import { googlesheets } from '@corsair-dev/googlesheets'; @@ -58,6 +59,9 @@ export const corsair = createCorsair({ agentql({ key: process.env.AGENTQL_API_KEY, }), + apiSports({ + key: process.env.API_SPORTS_API_KEY, + }), twilio(), vapi({ key: process.env.VAPI_API_KEY, diff --git a/packages/api_sports/api.test.ts b/packages/api_sports/api.test.ts new file mode 100644 index 000000000..803aa4492 --- /dev/null +++ b/packages/api_sports/api.test.ts @@ -0,0 +1,49 @@ +import 'dotenv/config'; +import { makeApiSportsRequest } from './client'; +import { ApiSportsEndpointOutputSchemas, ApiSportsResponseSchema, type ApiSportsResponse } from './endpoints/types'; + +const TEST_API_KEY = process.env.API_SPORTS_API_KEY; + +describe('API-Sports API Type Tests', () => { + it('football countries returns correct type', async () => { + if (!TEST_API_KEY) { + console.warn('Skipping: API_SPORTS_API_KEY not set'); + return; + } + + const response = await makeApiSportsRequest( + 'football', + '/countries', + { apiKey: TEST_API_KEY }, + ); + + ApiSportsEndpointOutputSchemas.getCountries.parse(response); + expect(response.response).toBeDefined(); + }); + + it('football timezone returns correct type', async () => { + if (!TEST_API_KEY) return; + + const response = await makeApiSportsRequest( + 'football', + '/timezone', + { apiKey: TEST_API_KEY }, + ); + + ApiSportsEndpointOutputSchemas.getTimezone.parse(response); + expect(response.response).toBeDefined(); + }); + + it('nba status returns correct type', async () => { + if (!TEST_API_KEY) return; + + const response = await makeApiSportsRequest( + 'nba', + '/status', + { apiKey: TEST_API_KEY }, + ); + + ApiSportsResponseSchema.parse(response); + expect(response.response).toBeDefined(); + }); +}); diff --git a/packages/api_sports/client.ts b/packages/api_sports/client.ts new file mode 100644 index 000000000..06bac1322 --- /dev/null +++ b/packages/api_sports/client.ts @@ -0,0 +1,107 @@ +import type { ApiRequestOptions, OpenAPIConfig } from 'corsair/http'; +import { ApiError, request } from 'corsair/http'; + +export class ApiSportsAPIError extends Error { + public readonly status?: number; + public readonly statusText?: string; + // API error bodies vary by sport endpoint; unknown forces callers to narrow before use. + public readonly body?: unknown; + public readonly retryAfter?: number; + + constructor( + message: string, + public readonly code?: number, + options?: { cause?: Error }, + ) { + super(message, options); + this.name = 'ApiSportsAPIError'; + + if (options?.cause instanceof ApiError) { + this.status = options.cause.status; + this.statusText = options.cause.statusText; + this.body = options.cause.body; + this.retryAfter = options.cause.retryAfter; + } + } +} + +export type ApiSport = + | 'football' + | 'basketball' + | 'nba' + | 'afl' + | 'baseball' + | 'formula1' + | 'mma' + | 'nfl'; + +export const API_SPORTS_BASE_URLS: Record = { + football: 'https://v3.football.api-sports.io', + basketball: 'https://v1.basketball.api-sports.io', + nba: 'https://v2.nba.api-sports.io', + afl: 'https://v1.afl.api-sports.io', + baseball: 'https://v1.baseball.api-sports.io', + formula1: 'https://v1.formula-1.api-sports.io', + mma: 'https://v1.mma.api-sports.io', + nfl: 'https://v1.american-football.api-sports.io', +}; + +export type ApiSportsQueryValue = + | string + | number + | boolean + | Array + | undefined; + +// Catch values are untyped at runtime; narrow to ApiError/Error before rethrowing. +async function handleRequestError(error: unknown): Promise { + if (error instanceof ApiError) { + throw new ApiSportsAPIError(error.message, error.status, { + cause: error, + }); + } + if (error instanceof Error) { + throw new ApiSportsAPIError(error.message, undefined, { cause: error }); + } + throw new ApiSportsAPIError('Unknown error'); +} + +/** + * Performs a GET request to a sport-specific API-Sports REST API. + * + * Auth: API key via the `x-apisports-key` request header. + */ +export async function makeApiSportsRequest( + sport: ApiSport, + path: string, + options: { + apiKey?: string; + query?: Record; + } = {}, +): Promise { + const { apiKey, query = {} } = options; + + const config: OpenAPIConfig = { + BASE: API_SPORTS_BASE_URLS[sport], + VERSION: '1.0.0', + WITH_CREDENTIALS: false, + CREDENTIALS: 'omit', + TOKEN: undefined, + HEADERS: { + Accept: 'application/json', + ...(apiKey ? { 'x-apisports-key': apiKey } : {}), + }, + }; + + const requestOptions: ApiRequestOptions = { + method: 'GET', + url: path, + query, + }; + + try { + return await request(config, requestOptions); + } catch (error) { + return handleRequestError(error); + } +} diff --git a/packages/api_sports/endpoints/afl.ts b/packages/api_sports/endpoints/afl.ts new file mode 100644 index 000000000..6d8231301 --- /dev/null +++ b/packages/api_sports/endpoints/afl.ts @@ -0,0 +1,65 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get AFL Seasons */ +export const getAflSeasons: ApiSportsEndpoints['getAflSeasons'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getAflSeasons; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.afl.getAflSeasons', input ?? {}, 'completed'); + return response; +}; + +/** Get AFL Games */ +export const getAflGames: ApiSportsEndpoints['getAflGames'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getAflGames; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.afl.getAflGames', input ?? {}, 'completed'); + return response; +}; + +/** Get AFL Games Quarters */ +export const getAflGamesQuarters: ApiSportsEndpoints['getAflGamesQuarters'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getAflGamesQuarters; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.afl.getAflGamesQuarters', input ?? {}, 'completed'); + return response; +}; + +/** Get AFL Game Player Statistics */ +export const getAflGamePlayerStatistics: ApiSportsEndpoints['getAflGamePlayerStatistics'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getAflGamePlayerStatistics; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.afl.getAflGamePlayerStatistics', input ?? {}, 'completed'); + return response; +}; + +/** Get AFL Standings */ +export const getAflStandings: ApiSportsEndpoints['getAflStandings'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getAflStandings; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.afl.getAflStandings', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/baseball.ts b/packages/api_sports/endpoints/baseball.ts new file mode 100644 index 000000000..a44ae2b2d --- /dev/null +++ b/packages/api_sports/endpoints/baseball.ts @@ -0,0 +1,17 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Baseball Games Head-to-Head */ +export const getBaseballGamesHeadToHead: ApiSportsEndpoints['getBaseballGamesHeadToHead'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBaseballGamesHeadToHead; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.baseball.getBaseballGamesHeadToHead', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/basketball.ts b/packages/api_sports/endpoints/basketball.ts new file mode 100644 index 000000000..946496cd6 --- /dev/null +++ b/packages/api_sports/endpoints/basketball.ts @@ -0,0 +1,89 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Basketball Statistics */ +export const getBasketballStatistics: ApiSportsEndpoints['getBasketballStatistics'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBasketballStatistics; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.basketball.getBasketballStatistics', input ?? {}, 'completed'); + return response; +}; + +/** Get Basketball Bets */ +export const getBasketballBets: ApiSportsEndpoints['getBasketballBets'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBasketballBets; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.basketball.getBasketballBets', input ?? {}, 'completed'); + return response; +}; + +/** Get Basketball Bookmakers */ +export const getBasketballBookmakers: ApiSportsEndpoints['getBasketballBookmakers'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBasketballBookmakers; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.basketball.getBasketballBookmakers', input ?? {}, 'completed'); + return response; +}; + +/** Get NBA Game Statistics */ +export const getNbaGameStatistics: ApiSportsEndpoints['getNbaGameStatistics'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getNbaGameStatistics; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.basketball.getNbaGameStatistics', input ?? {}, 'completed'); + return response; +}; + +/** Get Player Statistics */ +export const getPlayerStatistics: ApiSportsEndpoints['getPlayerStatistics'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayerStatistics; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.basketball.getPlayerStatistics', input ?? {}, 'completed'); + return response; +}; + +/** Get Game Statistics by Teams */ +export const getGameStatisticsByTeams: ApiSportsEndpoints['getGameStatisticsByTeams'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getGameStatisticsByTeams; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.basketball.getGameStatisticsByTeams', input ?? {}, 'completed'); + return response; +}; + +/** Get Games Events */ +export const getGamesEvents: ApiSportsEndpoints['getGamesEvents'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getGamesEvents; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.basketball.getGamesEvents', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/core.ts b/packages/api_sports/endpoints/core.ts new file mode 100644 index 000000000..11933ddac --- /dev/null +++ b/packages/api_sports/endpoints/core.ts @@ -0,0 +1,173 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Countries */ +export const getCountries: ApiSportsEndpoints['getCountries'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getCountries; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getCountries', input ?? {}, 'completed'); + return response; +}; + +/** Get Timezone */ +export const getTimezone: ApiSportsEndpoints['getTimezone'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getTimezone; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getTimezone', input ?? {}, 'completed'); + return response; +}; + +/** Get Leagues */ +export const getLeagues: ApiSportsEndpoints['getLeagues'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getLeagues; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getLeagues', input ?? {}, 'completed'); + return response; +}; + +/** Get League Seasons */ +export const getLeagueSeasons: ApiSportsEndpoints['getLeagueSeasons'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getLeagueSeasons; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getLeagueSeasons', input ?? {}, 'completed'); + return response; +}; + +/** Get Teams */ +export const getTeams: ApiSportsEndpoints['getTeams'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getTeams; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getTeams', input ?? {}, 'completed'); + return response; +}; + +/** Get Team Seasons */ +export const getTeamSeasons: ApiSportsEndpoints['getTeamSeasons'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getTeamSeasons; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getTeamSeasons', input ?? {}, 'completed'); + return response; +}; + +/** Get Team Statistics */ +export const getTeamStatistics: ApiSportsEndpoints['getTeamStatistics'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getTeamStatistics; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getTeamStatistics', input ?? {}, 'completed'); + return response; +}; + +/** Get Venues */ +export const getVenues: ApiSportsEndpoints['getVenues'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getVenues; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getVenues', input ?? {}, 'completed'); + return response; +}; + +/** Get Coaches */ +export const getCoaches: ApiSportsEndpoints['getCoaches'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getCoaches; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getCoaches', input ?? {}, 'completed'); + return response; +}; + +/** Get Injuries */ +export const getInjuries: ApiSportsEndpoints['getInjuries'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getInjuries; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getInjuries', input ?? {}, 'completed'); + return response; +}; + +/** Get Sidelined */ +export const getSidelined: ApiSportsEndpoints['getSidelined'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getSidelined; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getSidelined', input ?? {}, 'completed'); + return response; +}; + +/** Get Transfers */ +export const getTransfers: ApiSportsEndpoints['getTransfers'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getTransfers; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getTransfers', input ?? {}, 'completed'); + return response; +}; + +/** Get Trophies */ +export const getTrophies: ApiSportsEndpoints['getTrophies'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getTrophies; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getTrophies', input ?? {}, 'completed'); + return response; +}; + +/** Get Predictions */ +export const getPredictions: ApiSportsEndpoints['getPredictions'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPredictions; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.core.getPredictions', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/fixtures.ts b/packages/api_sports/endpoints/fixtures.ts new file mode 100644 index 000000000..85d644bd7 --- /dev/null +++ b/packages/api_sports/endpoints/fixtures.ts @@ -0,0 +1,89 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Fixtures */ +export const getFixtures: ApiSportsEndpoints['getFixtures'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixtures; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.fixtures.getFixtures', input ?? {}, 'completed'); + return response; +}; + +/** Get Fixtures Rounds */ +export const getFixturesRounds: ApiSportsEndpoints['getFixturesRounds'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixturesRounds; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.fixtures.getFixturesRounds', input ?? {}, 'completed'); + return response; +}; + +/** Get Head-to-Head Fixtures */ +export const getHeadToHeadFixtures: ApiSportsEndpoints['getHeadToHeadFixtures'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getHeadToHeadFixtures; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.fixtures.getHeadToHeadFixtures', input ?? {}, 'completed'); + return response; +}; + +/** Get Fixture Lineups */ +export const getFixtureLineups: ApiSportsEndpoints['getFixtureLineups'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixtureLineups; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.fixtures.getFixtureLineups', input ?? {}, 'completed'); + return response; +}; + +/** Get Fixture Statistics */ +export const getFixtureStatistics: ApiSportsEndpoints['getFixtureStatistics'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixtureStatistics; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.fixtures.getFixtureStatistics', input ?? {}, 'completed'); + return response; +}; + +/** Get Fixtures Events */ +export const getFixturesEvents: ApiSportsEndpoints['getFixturesEvents'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixturesEvents; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.fixtures.getFixturesEvents', input ?? {}, 'completed'); + return response; +}; + +/** Get Fixtures Players */ +export const getFixturesPlayers: ApiSportsEndpoints['getFixturesPlayers'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixturesPlayers; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.fixtures.getFixturesPlayers', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/formula1.ts b/packages/api_sports/endpoints/formula1.ts new file mode 100644 index 000000000..996e0fe68 --- /dev/null +++ b/packages/api_sports/endpoints/formula1.ts @@ -0,0 +1,101 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Formula 1 Circuits */ +export const getFormula1Circuits: ApiSportsEndpoints['getFormula1Circuits'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1Circuits; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getFormula1Circuits', input ?? {}, 'completed'); + return response; +}; + +/** Get Formula 1 Competitions */ +export const getFormula1Competitions: ApiSportsEndpoints['getFormula1Competitions'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1Competitions; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getFormula1Competitions', input ?? {}, 'completed'); + return response; +}; + +/** Get Formula 1 Races */ +export const getFormula1Races: ApiSportsEndpoints['getFormula1Races'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1Races; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getFormula1Races', input ?? {}, 'completed'); + return response; +}; + +/** Get Formula 1 Driver Rankings */ +export const getFormula1DriverRankings: ApiSportsEndpoints['getFormula1DriverRankings'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1DriverRankings; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getFormula1DriverRankings', input ?? {}, 'completed'); + return response; +}; + +/** Get Formula 1 Team Rankings */ +export const getFormula1TeamRankings: ApiSportsEndpoints['getFormula1TeamRankings'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1TeamRankings; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getFormula1TeamRankings', input ?? {}, 'completed'); + return response; +}; + +/** Get Formula 1 Starting Grid */ +export const getFormula1StartingGrid: ApiSportsEndpoints['getFormula1StartingGrid'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1StartingGrid; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getFormula1StartingGrid', input ?? {}, 'completed'); + return response; +}; + +/** Get Fastest Laps Rankings */ +export const getFastestLapsRankings: ApiSportsEndpoints['getFastestLapsRankings'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFastestLapsRankings; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getFastestLapsRankings', input ?? {}, 'completed'); + return response; +}; + +/** Get Race Rankings */ +export const getRaceRankings: ApiSportsEndpoints['getRaceRankings'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getRaceRankings; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.formula1.getRaceRankings', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/index.ts b/packages/api_sports/endpoints/index.ts new file mode 100644 index 000000000..8da6cab4e --- /dev/null +++ b/packages/api_sports/endpoints/index.ts @@ -0,0 +1,12 @@ +export * as Afl from './afl'; +export * as Baseball from './baseball'; +export * as Basketball from './basketball'; +export * as Core from './core'; +export * as Fixtures from './fixtures'; +export * as Formula1 from './formula1'; +export * as Mma from './mma'; +export * as Odds from './odds'; +export * as Players from './players'; +export * as Standings from './standings'; +export * from './types'; +export * from './routes'; diff --git a/packages/api_sports/endpoints/mma.ts b/packages/api_sports/endpoints/mma.ts new file mode 100644 index 000000000..ddf0399ff --- /dev/null +++ b/packages/api_sports/endpoints/mma.ts @@ -0,0 +1,77 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get MMA Categories */ +export const getMmaCategories: ApiSportsEndpoints['getMmaCategories'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getMmaCategories; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.mma.getMmaCategories', input ?? {}, 'completed'); + return response; +}; + +/** Get MMA Fighters */ +export const getMmaFighters: ApiSportsEndpoints['getMmaFighters'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getMmaFighters; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.mma.getMmaFighters', input ?? {}, 'completed'); + return response; +}; + +/** Get MMA Fights */ +export const getMmaFights: ApiSportsEndpoints['getMmaFights'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getMmaFights; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.mma.getMmaFights', input ?? {}, 'completed'); + return response; +}; + +/** Get MMA Fight Results */ +export const getMmaFightResults: ApiSportsEndpoints['getMmaFightResults'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getMmaFightResults; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.mma.getMmaFightResults', input ?? {}, 'completed'); + return response; +}; + +/** Get MMA Fighter Statistics */ +export const getMmaFighterStatistics: ApiSportsEndpoints['getMmaFighterStatistics'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getMmaFighterStatistics; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.mma.getMmaFighterStatistics', input ?? {}, 'completed'); + return response; +}; + +/** Get Fighters Records */ +export const getFightersRecords: ApiSportsEndpoints['getFightersRecords'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFightersRecords; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.mma.getFightersRecords', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/odds.ts b/packages/api_sports/endpoints/odds.ts new file mode 100644 index 000000000..79544ad9d --- /dev/null +++ b/packages/api_sports/endpoints/odds.ts @@ -0,0 +1,77 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Odds */ +export const getOdds: ApiSportsEndpoints['getOdds'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getOdds; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.odds.getOdds', input ?? {}, 'completed'); + return response; +}; + +/** Get Odds Bets */ +export const getOddsBets: ApiSportsEndpoints['getOddsBets'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getOddsBets; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.odds.getOddsBets', input ?? {}, 'completed'); + return response; +}; + +/** Get Odds Bookmakers */ +export const getOddsBookmakers: ApiSportsEndpoints['getOddsBookmakers'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getOddsBookmakers; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.odds.getOddsBookmakers', input ?? {}, 'completed'); + return response; +}; + +/** Get Odds Mapping */ +export const getOddsMapping: ApiSportsEndpoints['getOddsMapping'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getOddsMapping; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.odds.getOddsMapping', input ?? {}, 'completed'); + return response; +}; + +/** Get In-Play Odds */ +export const getInPlayOdds: ApiSportsEndpoints['getInPlayOdds'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getInPlayOdds; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.odds.getInPlayOdds', input ?? {}, 'completed'); + return response; +}; + +/** Get Live Odds Bets */ +export const getLiveOddsBets: ApiSportsEndpoints['getLiveOddsBets'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getLiveOddsBets; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.odds.getLiveOddsBets', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/players.ts b/packages/api_sports/endpoints/players.ts new file mode 100644 index 000000000..1c7c040c6 --- /dev/null +++ b/packages/api_sports/endpoints/players.ts @@ -0,0 +1,113 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Players */ +export const getPlayers: ApiSportsEndpoints['getPlayers'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayers; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayers', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Profiles */ +export const getPlayersProfiles: ApiSportsEndpoints['getPlayersProfiles'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersProfiles; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersProfiles', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Seasons */ +export const getPlayersSeasons: ApiSportsEndpoints['getPlayersSeasons'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersSeasons; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersSeasons', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Squads */ +export const getPlayersSquads: ApiSportsEndpoints['getPlayersSquads'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersSquads; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersSquads', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Teams */ +export const getPlayersTeams: ApiSportsEndpoints['getPlayersTeams'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTeams; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersTeams', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Top Scorers */ +export const getPlayersTopScorers: ApiSportsEndpoints['getPlayersTopScorers'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopScorers; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersTopScorers', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Top Assists */ +export const getPlayersTopAssists: ApiSportsEndpoints['getPlayersTopAssists'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopAssists; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersTopAssists', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Top Yellow Cards */ +export const getPlayersTopYellowCards: ApiSportsEndpoints['getPlayersTopYellowCards'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopYellowCards; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersTopYellowCards', input ?? {}, 'completed'); + return response; +}; + +/** Get Players Top Red Cards */ +export const getPlayersTopRedCards: ApiSportsEndpoints['getPlayersTopRedCards'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopRedCards; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.players.getPlayersTopRedCards', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/routes.ts b/packages/api_sports/endpoints/routes.ts new file mode 100644 index 000000000..84a5b2b23 --- /dev/null +++ b/packages/api_sports/endpoints/routes.ts @@ -0,0 +1,79 @@ +import type { ApiSport } from '../client'; + +export type ApiSportsRoute = { + sport: ApiSport; + path: string; + description: string; +}; + +export const API_SPORTS_ROUTES = { + getCountries: { sport: 'football', path: '/countries', description: "Get Countries" }, + getTimezone: { sport: 'football', path: '/timezone', description: "Get Timezone" }, + getLeagues: { sport: 'football', path: '/leagues', description: "Get Leagues" }, + getLeagueSeasons: { sport: 'football', path: '/leagues/seasons', description: "Get League Seasons" }, + getTeams: { sport: 'football', path: '/teams', description: "Get Teams" }, + getTeamSeasons: { sport: 'football', path: '/teams/seasons', description: "Get Team Seasons" }, + getTeamStatistics: { sport: 'football', path: '/teams/statistics', description: "Get Team Statistics" }, + getVenues: { sport: 'football', path: '/venues', description: "Get Venues" }, + getCoaches: { sport: 'football', path: '/coachs', description: "Get Coaches" }, + getInjuries: { sport: 'football', path: '/injuries', description: "Get Injuries" }, + getSidelined: { sport: 'football', path: '/sidelined', description: "Get Sidelined" }, + getTransfers: { sport: 'football', path: '/transfers', description: "Get Transfers" }, + getTrophies: { sport: 'football', path: '/trophies', description: "Get Trophies" }, + getPredictions: { sport: 'football', path: '/predictions', description: "Get Predictions" }, + getFixtures: { sport: 'football', path: '/fixtures', description: "Get Fixtures" }, + getFixturesRounds: { sport: 'football', path: '/fixtures/rounds', description: "Get Fixtures Rounds" }, + getHeadToHeadFixtures: { sport: 'football', path: '/fixtures/headtohead', description: "Get Head-to-Head Fixtures" }, + getFixtureLineups: { sport: 'football', path: '/fixtures/lineups', description: "Get Fixture Lineups" }, + getFixtureStatistics: { sport: 'football', path: '/fixtures/statistics', description: "Get Fixture Statistics" }, + getFixturesEvents: { sport: 'football', path: '/fixtures/events', description: "Get Fixtures Events" }, + getFixturesPlayers: { sport: 'football', path: '/fixtures/players', description: "Get Fixtures Players" }, + getStandingsStages: { sport: 'nfl', path: '/standings/stages', description: "Get Standings Stages" }, + getStandingsGroups: { sport: 'nfl', path: '/standings/groups', description: "Get Standings Groups" }, + getStandingsDivisions: { sport: 'nfl', path: '/standings/divisions', description: "Get Standings Divisions" }, + getNflStandingsConferences: { sport: 'nfl', path: '/standings/conferences', description: "Get NFL Standings Conferences" }, + getPlayers: { sport: 'football', path: '/players', description: "Get Players" }, + getPlayersProfiles: { sport: 'football', path: '/players/profiles', description: "Get Players Profiles" }, + getPlayersSeasons: { sport: 'football', path: '/players/seasons', description: "Get Players Seasons" }, + getPlayersSquads: { sport: 'football', path: '/players/squads', description: "Get Players Squads" }, + getPlayersTeams: { sport: 'football', path: '/players/teams', description: "Get Players Teams" }, + getPlayersTopScorers: { sport: 'football', path: '/players/topscorers', description: "Get Players Top Scorers" }, + getPlayersTopAssists: { sport: 'football', path: '/players/topassists', description: "Get Players Top Assists" }, + getPlayersTopYellowCards: { sport: 'football', path: '/players/topyellowcards', description: "Get Players Top Yellow Cards" }, + getPlayersTopRedCards: { sport: 'football', path: '/players/topredcards', description: "Get Players Top Red Cards" }, + getOdds: { sport: 'football', path: '/odds', description: "Get Odds" }, + getOddsBets: { sport: 'football', path: '/odds/bets', description: "Get Odds Bets" }, + getOddsBookmakers: { sport: 'football', path: '/odds/bookmakers', description: "Get Odds Bookmakers" }, + getOddsMapping: { sport: 'football', path: '/odds/mapping', description: "Get Odds Mapping" }, + getInPlayOdds: { sport: 'football', path: '/odds/live', description: "Get In-Play Odds" }, + getLiveOddsBets: { sport: 'football', path: '/odds/live/bets', description: "Get Live Odds Bets" }, + getBasketballStatistics: { sport: 'basketball', path: '/statistics', description: "Get Basketball Statistics" }, + getBasketballBets: { sport: 'basketball', path: '/bets', description: "Get Basketball Bets" }, + getBasketballBookmakers: { sport: 'basketball', path: '/bookmakers', description: "Get Basketball Bookmakers" }, + getNbaGameStatistics: { sport: 'nba', path: '/games/statistics', description: "Get NBA Game Statistics" }, + getPlayerStatistics: { sport: 'nba', path: '/players/statistics', description: "Get Player Statistics" }, + getGameStatisticsByTeams: { sport: 'nba', path: '/games/statistics', description: "Get Game Statistics by Teams" }, + getGamesEvents: { sport: 'nba', path: '/games/events', description: "Get Games Events" }, + getAflSeasons: { sport: 'afl', path: '/seasons', description: "Get AFL Seasons" }, + getAflGames: { sport: 'afl', path: '/games', description: "Get AFL Games" }, + getAflGamesQuarters: { sport: 'afl', path: '/games/quarters', description: "Get AFL Games Quarters" }, + getAflGamePlayerStatistics: { sport: 'afl', path: '/games/statistics/players', description: "Get AFL Game Player Statistics" }, + getAflStandings: { sport: 'afl', path: '/standings', description: "Get AFL Standings" }, + getBaseballGamesHeadToHead: { sport: 'baseball', path: '/games/h2h', description: "Get Baseball Games Head-to-Head" }, + getFormula1Circuits: { sport: 'formula1', path: '/circuits', description: "Get Formula 1 Circuits" }, + getFormula1Competitions: { sport: 'formula1', path: '/competitions', description: "Get Formula 1 Competitions" }, + getFormula1Races: { sport: 'formula1', path: '/races', description: "Get Formula 1 Races" }, + getFormula1DriverRankings: { sport: 'formula1', path: '/rankings/drivers', description: "Get Formula 1 Driver Rankings" }, + getFormula1TeamRankings: { sport: 'formula1', path: '/rankings/teams', description: "Get Formula 1 Team Rankings" }, + getFormula1StartingGrid: { sport: 'formula1', path: '/rankings/startinggrid', description: "Get Formula 1 Starting Grid" }, + getFastestLapsRankings: { sport: 'formula1', path: '/rankings/fastestlaps', description: "Get Fastest Laps Rankings" }, + getRaceRankings: { sport: 'formula1', path: '/rankings/races', description: "Get Race Rankings" }, + getMmaCategories: { sport: 'mma', path: '/categories', description: "Get MMA Categories" }, + getMmaFighters: { sport: 'mma', path: '/fighters', description: "Get MMA Fighters" }, + getMmaFights: { sport: 'mma', path: '/fights', description: "Get MMA Fights" }, + getMmaFightResults: { sport: 'mma', path: '/fights/results', description: "Get MMA Fight Results" }, + getMmaFighterStatistics: { sport: 'mma', path: '/fights/statistics/fighters', description: "Get MMA Fighter Statistics" }, + getFightersRecords: { sport: 'mma', path: '/fighters/records', description: "Get Fighters Records" }, +} as const satisfies Record; + +export type ApiSportsRouteKey = keyof typeof API_SPORTS_ROUTES; diff --git a/packages/api_sports/endpoints/standings.ts b/packages/api_sports/endpoints/standings.ts new file mode 100644 index 000000000..19be6d91a --- /dev/null +++ b/packages/api_sports/endpoints/standings.ts @@ -0,0 +1,53 @@ +import { logEventFromContext } from 'corsair/core'; +import { makeApiSportsRequest } from '../client'; +import type { ApiSportsEndpoints } from '../index'; +import type { ApiSportsEndpointOutputs } from './types'; +import { API_SPORTS_ROUTES } from './routes'; + +/** Get Standings Stages */ +export const getStandingsStages: ApiSportsEndpoints['getStandingsStages'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getStandingsStages; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.standings.getStandingsStages', input ?? {}, 'completed'); + return response; +}; + +/** Get Standings Groups */ +export const getStandingsGroups: ApiSportsEndpoints['getStandingsGroups'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getStandingsGroups; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.standings.getStandingsGroups', input ?? {}, 'completed'); + return response; +}; + +/** Get Standings Divisions */ +export const getStandingsDivisions: ApiSportsEndpoints['getStandingsDivisions'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getStandingsDivisions; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.standings.getStandingsDivisions', input ?? {}, 'completed'); + return response; +}; + +/** Get NFL Standings Conferences */ +export const getNflStandingsConferences: ApiSportsEndpoints['getNflStandingsConferences'] = async (ctx, input) => { + const route = API_SPORTS_ROUTES.getNflStandingsConferences; + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: ctx.key, query: input }, + ); + await logEventFromContext(ctx, 'api_sports.standings.getNflStandingsConferences', input ?? {}, 'completed'); + return response; +}; diff --git a/packages/api_sports/endpoints/types.ts b/packages/api_sports/endpoints/types.ts new file mode 100644 index 000000000..913440a68 --- /dev/null +++ b/packages/api_sports/endpoints/types.ts @@ -0,0 +1,316 @@ +import { z } from 'zod'; + +/** Query params vary per sport API; callers pass documented filter fields. */ +export const ApiSportsQueryInputSchema = z + .record( + z.string(), + z.union([ + z.string(), + z.number(), + z.boolean(), + z.array(z.union([z.string(), z.number()])), + ]), + ) + .optional(); + +export type ApiSportsQueryInput = z.infer; + +export const ApiSportsResponseSchema = z + .object({ + get: z.string().optional(), + parameters: z + .union([z.record(z.string(), z.unknown()), z.array(z.unknown())]) + .optional(), + errors: z.array(z.unknown()).optional(), + results: z.number().optional(), + paging: z + .object({ + current: z.number().optional(), + total: z.number().optional(), + }) + .optional(), + response: z.unknown(), + }) + .loose(); + +export type ApiSportsResponse = z.infer; + +export type ApiSportsEndpointInputs = { + getCountries: ApiSportsQueryInput; + getTimezone: ApiSportsQueryInput; + getLeagues: ApiSportsQueryInput; + getLeagueSeasons: ApiSportsQueryInput; + getTeams: ApiSportsQueryInput; + getTeamSeasons: ApiSportsQueryInput; + getTeamStatistics: ApiSportsQueryInput; + getVenues: ApiSportsQueryInput; + getCoaches: ApiSportsQueryInput; + getInjuries: ApiSportsQueryInput; + getSidelined: ApiSportsQueryInput; + getTransfers: ApiSportsQueryInput; + getTrophies: ApiSportsQueryInput; + getPredictions: ApiSportsQueryInput; + getFixtures: ApiSportsQueryInput; + getFixturesRounds: ApiSportsQueryInput; + getHeadToHeadFixtures: ApiSportsQueryInput; + getFixtureLineups: ApiSportsQueryInput; + getFixtureStatistics: ApiSportsQueryInput; + getFixturesEvents: ApiSportsQueryInput; + getFixturesPlayers: ApiSportsQueryInput; + getStandingsStages: ApiSportsQueryInput; + getStandingsGroups: ApiSportsQueryInput; + getStandingsDivisions: ApiSportsQueryInput; + getNflStandingsConferences: ApiSportsQueryInput; + getPlayers: ApiSportsQueryInput; + getPlayersProfiles: ApiSportsQueryInput; + getPlayersSeasons: ApiSportsQueryInput; + getPlayersSquads: ApiSportsQueryInput; + getPlayersTeams: ApiSportsQueryInput; + getPlayersTopScorers: ApiSportsQueryInput; + getPlayersTopAssists: ApiSportsQueryInput; + getPlayersTopYellowCards: ApiSportsQueryInput; + getPlayersTopRedCards: ApiSportsQueryInput; + getOdds: ApiSportsQueryInput; + getOddsBets: ApiSportsQueryInput; + getOddsBookmakers: ApiSportsQueryInput; + getOddsMapping: ApiSportsQueryInput; + getInPlayOdds: ApiSportsQueryInput; + getLiveOddsBets: ApiSportsQueryInput; + getBasketballStatistics: ApiSportsQueryInput; + getBasketballBets: ApiSportsQueryInput; + getBasketballBookmakers: ApiSportsQueryInput; + getNbaGameStatistics: ApiSportsQueryInput; + getPlayerStatistics: ApiSportsQueryInput; + getGameStatisticsByTeams: ApiSportsQueryInput; + getGamesEvents: ApiSportsQueryInput; + getAflSeasons: ApiSportsQueryInput; + getAflGames: ApiSportsQueryInput; + getAflGamesQuarters: ApiSportsQueryInput; + getAflGamePlayerStatistics: ApiSportsQueryInput; + getAflStandings: ApiSportsQueryInput; + getBaseballGamesHeadToHead: ApiSportsQueryInput; + getFormula1Circuits: ApiSportsQueryInput; + getFormula1Competitions: ApiSportsQueryInput; + getFormula1Races: ApiSportsQueryInput; + getFormula1DriverRankings: ApiSportsQueryInput; + getFormula1TeamRankings: ApiSportsQueryInput; + getFormula1StartingGrid: ApiSportsQueryInput; + getFastestLapsRankings: ApiSportsQueryInput; + getRaceRankings: ApiSportsQueryInput; + getMmaCategories: ApiSportsQueryInput; + getMmaFighters: ApiSportsQueryInput; + getMmaFights: ApiSportsQueryInput; + getMmaFightResults: ApiSportsQueryInput; + getMmaFighterStatistics: ApiSportsQueryInput; + getFightersRecords: ApiSportsQueryInput; +}; + +export type ApiSportsEndpointOutputs = { + getCountries: ApiSportsResponse; + getTimezone: ApiSportsResponse; + getLeagues: ApiSportsResponse; + getLeagueSeasons: ApiSportsResponse; + getTeams: ApiSportsResponse; + getTeamSeasons: ApiSportsResponse; + getTeamStatistics: ApiSportsResponse; + getVenues: ApiSportsResponse; + getCoaches: ApiSportsResponse; + getInjuries: ApiSportsResponse; + getSidelined: ApiSportsResponse; + getTransfers: ApiSportsResponse; + getTrophies: ApiSportsResponse; + getPredictions: ApiSportsResponse; + getFixtures: ApiSportsResponse; + getFixturesRounds: ApiSportsResponse; + getHeadToHeadFixtures: ApiSportsResponse; + getFixtureLineups: ApiSportsResponse; + getFixtureStatistics: ApiSportsResponse; + getFixturesEvents: ApiSportsResponse; + getFixturesPlayers: ApiSportsResponse; + getStandingsStages: ApiSportsResponse; + getStandingsGroups: ApiSportsResponse; + getStandingsDivisions: ApiSportsResponse; + getNflStandingsConferences: ApiSportsResponse; + getPlayers: ApiSportsResponse; + getPlayersProfiles: ApiSportsResponse; + getPlayersSeasons: ApiSportsResponse; + getPlayersSquads: ApiSportsResponse; + getPlayersTeams: ApiSportsResponse; + getPlayersTopScorers: ApiSportsResponse; + getPlayersTopAssists: ApiSportsResponse; + getPlayersTopYellowCards: ApiSportsResponse; + getPlayersTopRedCards: ApiSportsResponse; + getOdds: ApiSportsResponse; + getOddsBets: ApiSportsResponse; + getOddsBookmakers: ApiSportsResponse; + getOddsMapping: ApiSportsResponse; + getInPlayOdds: ApiSportsResponse; + getLiveOddsBets: ApiSportsResponse; + getBasketballStatistics: ApiSportsResponse; + getBasketballBets: ApiSportsResponse; + getBasketballBookmakers: ApiSportsResponse; + getNbaGameStatistics: ApiSportsResponse; + getPlayerStatistics: ApiSportsResponse; + getGameStatisticsByTeams: ApiSportsResponse; + getGamesEvents: ApiSportsResponse; + getAflSeasons: ApiSportsResponse; + getAflGames: ApiSportsResponse; + getAflGamesQuarters: ApiSportsResponse; + getAflGamePlayerStatistics: ApiSportsResponse; + getAflStandings: ApiSportsResponse; + getBaseballGamesHeadToHead: ApiSportsResponse; + getFormula1Circuits: ApiSportsResponse; + getFormula1Competitions: ApiSportsResponse; + getFormula1Races: ApiSportsResponse; + getFormula1DriverRankings: ApiSportsResponse; + getFormula1TeamRankings: ApiSportsResponse; + getFormula1StartingGrid: ApiSportsResponse; + getFastestLapsRankings: ApiSportsResponse; + getRaceRankings: ApiSportsResponse; + getMmaCategories: ApiSportsResponse; + getMmaFighters: ApiSportsResponse; + getMmaFights: ApiSportsResponse; + getMmaFightResults: ApiSportsResponse; + getMmaFighterStatistics: ApiSportsResponse; + getFightersRecords: ApiSportsResponse; +}; + +export const ApiSportsEndpointInputSchemas = { + getCountries: ApiSportsQueryInputSchema, + getTimezone: ApiSportsQueryInputSchema, + getLeagues: ApiSportsQueryInputSchema, + getLeagueSeasons: ApiSportsQueryInputSchema, + getTeams: ApiSportsQueryInputSchema, + getTeamSeasons: ApiSportsQueryInputSchema, + getTeamStatistics: ApiSportsQueryInputSchema, + getVenues: ApiSportsQueryInputSchema, + getCoaches: ApiSportsQueryInputSchema, + getInjuries: ApiSportsQueryInputSchema, + getSidelined: ApiSportsQueryInputSchema, + getTransfers: ApiSportsQueryInputSchema, + getTrophies: ApiSportsQueryInputSchema, + getPredictions: ApiSportsQueryInputSchema, + getFixtures: ApiSportsQueryInputSchema, + getFixturesRounds: ApiSportsQueryInputSchema, + getHeadToHeadFixtures: ApiSportsQueryInputSchema, + getFixtureLineups: ApiSportsQueryInputSchema, + getFixtureStatistics: ApiSportsQueryInputSchema, + getFixturesEvents: ApiSportsQueryInputSchema, + getFixturesPlayers: ApiSportsQueryInputSchema, + getStandingsStages: ApiSportsQueryInputSchema, + getStandingsGroups: ApiSportsQueryInputSchema, + getStandingsDivisions: ApiSportsQueryInputSchema, + getNflStandingsConferences: ApiSportsQueryInputSchema, + getPlayers: ApiSportsQueryInputSchema, + getPlayersProfiles: ApiSportsQueryInputSchema, + getPlayersSeasons: ApiSportsQueryInputSchema, + getPlayersSquads: ApiSportsQueryInputSchema, + getPlayersTeams: ApiSportsQueryInputSchema, + getPlayersTopScorers: ApiSportsQueryInputSchema, + getPlayersTopAssists: ApiSportsQueryInputSchema, + getPlayersTopYellowCards: ApiSportsQueryInputSchema, + getPlayersTopRedCards: ApiSportsQueryInputSchema, + getOdds: ApiSportsQueryInputSchema, + getOddsBets: ApiSportsQueryInputSchema, + getOddsBookmakers: ApiSportsQueryInputSchema, + getOddsMapping: ApiSportsQueryInputSchema, + getInPlayOdds: ApiSportsQueryInputSchema, + getLiveOddsBets: ApiSportsQueryInputSchema, + getBasketballStatistics: ApiSportsQueryInputSchema, + getBasketballBets: ApiSportsQueryInputSchema, + getBasketballBookmakers: ApiSportsQueryInputSchema, + getNbaGameStatistics: ApiSportsQueryInputSchema, + getPlayerStatistics: ApiSportsQueryInputSchema, + getGameStatisticsByTeams: ApiSportsQueryInputSchema, + getGamesEvents: ApiSportsQueryInputSchema, + getAflSeasons: ApiSportsQueryInputSchema, + getAflGames: ApiSportsQueryInputSchema, + getAflGamesQuarters: ApiSportsQueryInputSchema, + getAflGamePlayerStatistics: ApiSportsQueryInputSchema, + getAflStandings: ApiSportsQueryInputSchema, + getBaseballGamesHeadToHead: ApiSportsQueryInputSchema, + getFormula1Circuits: ApiSportsQueryInputSchema, + getFormula1Competitions: ApiSportsQueryInputSchema, + getFormula1Races: ApiSportsQueryInputSchema, + getFormula1DriverRankings: ApiSportsQueryInputSchema, + getFormula1TeamRankings: ApiSportsQueryInputSchema, + getFormula1StartingGrid: ApiSportsQueryInputSchema, + getFastestLapsRankings: ApiSportsQueryInputSchema, + getRaceRankings: ApiSportsQueryInputSchema, + getMmaCategories: ApiSportsQueryInputSchema, + getMmaFighters: ApiSportsQueryInputSchema, + getMmaFights: ApiSportsQueryInputSchema, + getMmaFightResults: ApiSportsQueryInputSchema, + getMmaFighterStatistics: ApiSportsQueryInputSchema, + getFightersRecords: ApiSportsQueryInputSchema, +} as const; + +export const ApiSportsEndpointOutputSchemas = { + getCountries: ApiSportsResponseSchema, + getTimezone: ApiSportsResponseSchema, + getLeagues: ApiSportsResponseSchema, + getLeagueSeasons: ApiSportsResponseSchema, + getTeams: ApiSportsResponseSchema, + getTeamSeasons: ApiSportsResponseSchema, + getTeamStatistics: ApiSportsResponseSchema, + getVenues: ApiSportsResponseSchema, + getCoaches: ApiSportsResponseSchema, + getInjuries: ApiSportsResponseSchema, + getSidelined: ApiSportsResponseSchema, + getTransfers: ApiSportsResponseSchema, + getTrophies: ApiSportsResponseSchema, + getPredictions: ApiSportsResponseSchema, + getFixtures: ApiSportsResponseSchema, + getFixturesRounds: ApiSportsResponseSchema, + getHeadToHeadFixtures: ApiSportsResponseSchema, + getFixtureLineups: ApiSportsResponseSchema, + getFixtureStatistics: ApiSportsResponseSchema, + getFixturesEvents: ApiSportsResponseSchema, + getFixturesPlayers: ApiSportsResponseSchema, + getStandingsStages: ApiSportsResponseSchema, + getStandingsGroups: ApiSportsResponseSchema, + getStandingsDivisions: ApiSportsResponseSchema, + getNflStandingsConferences: ApiSportsResponseSchema, + getPlayers: ApiSportsResponseSchema, + getPlayersProfiles: ApiSportsResponseSchema, + getPlayersSeasons: ApiSportsResponseSchema, + getPlayersSquads: ApiSportsResponseSchema, + getPlayersTeams: ApiSportsResponseSchema, + getPlayersTopScorers: ApiSportsResponseSchema, + getPlayersTopAssists: ApiSportsResponseSchema, + getPlayersTopYellowCards: ApiSportsResponseSchema, + getPlayersTopRedCards: ApiSportsResponseSchema, + getOdds: ApiSportsResponseSchema, + getOddsBets: ApiSportsResponseSchema, + getOddsBookmakers: ApiSportsResponseSchema, + getOddsMapping: ApiSportsResponseSchema, + getInPlayOdds: ApiSportsResponseSchema, + getLiveOddsBets: ApiSportsResponseSchema, + getBasketballStatistics: ApiSportsResponseSchema, + getBasketballBets: ApiSportsResponseSchema, + getBasketballBookmakers: ApiSportsResponseSchema, + getNbaGameStatistics: ApiSportsResponseSchema, + getPlayerStatistics: ApiSportsResponseSchema, + getGameStatisticsByTeams: ApiSportsResponseSchema, + getGamesEvents: ApiSportsResponseSchema, + getAflSeasons: ApiSportsResponseSchema, + getAflGames: ApiSportsResponseSchema, + getAflGamesQuarters: ApiSportsResponseSchema, + getAflGamePlayerStatistics: ApiSportsResponseSchema, + getAflStandings: ApiSportsResponseSchema, + getBaseballGamesHeadToHead: ApiSportsResponseSchema, + getFormula1Circuits: ApiSportsResponseSchema, + getFormula1Competitions: ApiSportsResponseSchema, + getFormula1Races: ApiSportsResponseSchema, + getFormula1DriverRankings: ApiSportsResponseSchema, + getFormula1TeamRankings: ApiSportsResponseSchema, + getFormula1StartingGrid: ApiSportsResponseSchema, + getFastestLapsRankings: ApiSportsResponseSchema, + getRaceRankings: ApiSportsResponseSchema, + getMmaCategories: ApiSportsResponseSchema, + getMmaFighters: ApiSportsResponseSchema, + getMmaFights: ApiSportsResponseSchema, + getMmaFightResults: ApiSportsResponseSchema, + getMmaFighterStatistics: ApiSportsResponseSchema, + getFightersRecords: ApiSportsResponseSchema, +} as const; diff --git a/packages/api_sports/error-handlers.ts b/packages/api_sports/error-handlers.ts new file mode 100644 index 000000000..0c020b7eb --- /dev/null +++ b/packages/api_sports/error-handlers.ts @@ -0,0 +1,64 @@ +import type { CorsairErrorHandler } from 'corsair/core'; +import type { ApiSportsAPIError } from './client'; + +// CorsairErrorHandler receives a plain Error; duck-type ApiSports-specific fields +// without instanceof so handlers work across module boundaries. +function getStatus(error: Error): number | undefined { + return (error as Partial).status; +} + +function getRetryAfter(error: Error): number | undefined { + return (error as Partial).retryAfter; +} + +export const errorHandlers = { + RATE_LIMIT_ERROR: { + match: (error: Error) => { + if (getStatus(error) === 429) return true; + const msg = error.message.toLowerCase(); + return msg.includes('429') || msg.includes('rate limit'); + }, + handler: async (error: Error) => ({ + maxRetries: 3, + retryStrategy: 'exponential_backoff' as const, + headersRetryAfterMs: getRetryAfter(error), + }), + }, + AUTH_ERROR: { + match: (error: Error) => { + if (getStatus(error) === 401 || getStatus(error) === 403) return true; + const msg = error.message.toLowerCase(); + return ( + msg.includes('unauthorized') || + msg.includes('invalid api key') || + msg.includes('invalid key') || + msg.includes('401') + ); + }, + handler: async () => { + console.log('[API_SPORTS] Authentication failed — check your x-apisports-key.'); + return { maxRetries: 0 }; + }, + }, + NOT_FOUND_ERROR: { + match: (error: Error) => getStatus(error) === 404, + handler: async () => ({ maxRetries: 0 }), + }, + SERVER_ERROR: { + match: (error: Error) => { + const status = getStatus(error); + return status !== undefined && status >= 500; + }, + handler: async () => ({ + maxRetries: 2, + retryStrategy: 'exponential_backoff' as const, + }), + }, + DEFAULT: { + match: () => true, + handler: async (error: Error) => { + console.error(`[API_SPORTS] Unhandled error: ${error.message}`); + return { maxRetries: 0 }; + }, + }, +} satisfies CorsairErrorHandler; diff --git a/packages/api_sports/index.ts b/packages/api_sports/index.ts new file mode 100644 index 000000000..42b0d5650 --- /dev/null +++ b/packages/api_sports/index.ts @@ -0,0 +1,833 @@ +import type { + AuthTypes, + BindEndpoints, + CorsairEndpoint, + CorsairErrorHandler, + CorsairPlugin, + CorsairPluginContext, + KeyBuilderContext, + PickAuth, + PluginAuthConfig, + PluginPermissionsConfig, + RequiredPluginEndpointMeta, + RequiredPluginEndpointSchemas, +} from 'corsair/core'; +import { AuthMissingError } from 'corsair/core'; +import * as Core from './endpoints/core'; +import * as Fixtures from './endpoints/fixtures'; +import * as Standings from './endpoints/standings'; +import * as Players from './endpoints/players'; +import * as Odds from './endpoints/odds'; +import * as Basketball from './endpoints/basketball'; +import * as Afl from './endpoints/afl'; +import * as Baseball from './endpoints/baseball'; +import * as Formula1 from './endpoints/formula1'; +import * as Mma from './endpoints/mma'; +import type { + ApiSportsEndpointInputs, + ApiSportsEndpointOutputs, +} from './endpoints/types'; +import { + ApiSportsEndpointInputSchemas, + ApiSportsEndpointOutputSchemas, +} from './endpoints/types'; +import { errorHandlers } from './error-handlers'; +import { ApiSportsSchema } from './schema'; + +export type ApiSportsPluginOptions = { + authType?: PickAuth<'api_key'>; + key?: string; + hooks?: InternalApiSportsPlugin['hooks']; + errorHandlers?: CorsairErrorHandler; + permissions?: PluginPermissionsConfig; +}; + +export type ApiSportsContext = CorsairPluginContext< + typeof ApiSportsSchema, + ApiSportsPluginOptions +>; + +export type ApiSportsKeyBuilderContext = KeyBuilderContext; + +export type ApiSportsBoundEndpoints = BindEndpoints; + +type ApiSportsEndpoint = CorsairEndpoint< + ApiSportsContext, + ApiSportsEndpointInputs[K], + ApiSportsEndpointOutputs[K] +>; + +export type ApiSportsEndpoints = { + getCountries: ApiSportsEndpoint<'getCountries'>; + getTimezone: ApiSportsEndpoint<'getTimezone'>; + getLeagues: ApiSportsEndpoint<'getLeagues'>; + getLeagueSeasons: ApiSportsEndpoint<'getLeagueSeasons'>; + getTeams: ApiSportsEndpoint<'getTeams'>; + getTeamSeasons: ApiSportsEndpoint<'getTeamSeasons'>; + getTeamStatistics: ApiSportsEndpoint<'getTeamStatistics'>; + getVenues: ApiSportsEndpoint<'getVenues'>; + getCoaches: ApiSportsEndpoint<'getCoaches'>; + getInjuries: ApiSportsEndpoint<'getInjuries'>; + getSidelined: ApiSportsEndpoint<'getSidelined'>; + getTransfers: ApiSportsEndpoint<'getTransfers'>; + getTrophies: ApiSportsEndpoint<'getTrophies'>; + getPredictions: ApiSportsEndpoint<'getPredictions'>; + getFixtures: ApiSportsEndpoint<'getFixtures'>; + getFixturesRounds: ApiSportsEndpoint<'getFixturesRounds'>; + getHeadToHeadFixtures: ApiSportsEndpoint<'getHeadToHeadFixtures'>; + getFixtureLineups: ApiSportsEndpoint<'getFixtureLineups'>; + getFixtureStatistics: ApiSportsEndpoint<'getFixtureStatistics'>; + getFixturesEvents: ApiSportsEndpoint<'getFixturesEvents'>; + getFixturesPlayers: ApiSportsEndpoint<'getFixturesPlayers'>; + getStandingsStages: ApiSportsEndpoint<'getStandingsStages'>; + getStandingsGroups: ApiSportsEndpoint<'getStandingsGroups'>; + getStandingsDivisions: ApiSportsEndpoint<'getStandingsDivisions'>; + getNflStandingsConferences: ApiSportsEndpoint<'getNflStandingsConferences'>; + getPlayers: ApiSportsEndpoint<'getPlayers'>; + getPlayersProfiles: ApiSportsEndpoint<'getPlayersProfiles'>; + getPlayersSeasons: ApiSportsEndpoint<'getPlayersSeasons'>; + getPlayersSquads: ApiSportsEndpoint<'getPlayersSquads'>; + getPlayersTeams: ApiSportsEndpoint<'getPlayersTeams'>; + getPlayersTopScorers: ApiSportsEndpoint<'getPlayersTopScorers'>; + getPlayersTopAssists: ApiSportsEndpoint<'getPlayersTopAssists'>; + getPlayersTopYellowCards: ApiSportsEndpoint<'getPlayersTopYellowCards'>; + getPlayersTopRedCards: ApiSportsEndpoint<'getPlayersTopRedCards'>; + getOdds: ApiSportsEndpoint<'getOdds'>; + getOddsBets: ApiSportsEndpoint<'getOddsBets'>; + getOddsBookmakers: ApiSportsEndpoint<'getOddsBookmakers'>; + getOddsMapping: ApiSportsEndpoint<'getOddsMapping'>; + getInPlayOdds: ApiSportsEndpoint<'getInPlayOdds'>; + getLiveOddsBets: ApiSportsEndpoint<'getLiveOddsBets'>; + getBasketballStatistics: ApiSportsEndpoint<'getBasketballStatistics'>; + getBasketballBets: ApiSportsEndpoint<'getBasketballBets'>; + getBasketballBookmakers: ApiSportsEndpoint<'getBasketballBookmakers'>; + getNbaGameStatistics: ApiSportsEndpoint<'getNbaGameStatistics'>; + getPlayerStatistics: ApiSportsEndpoint<'getPlayerStatistics'>; + getGameStatisticsByTeams: ApiSportsEndpoint<'getGameStatisticsByTeams'>; + getGamesEvents: ApiSportsEndpoint<'getGamesEvents'>; + getAflSeasons: ApiSportsEndpoint<'getAflSeasons'>; + getAflGames: ApiSportsEndpoint<'getAflGames'>; + getAflGamesQuarters: ApiSportsEndpoint<'getAflGamesQuarters'>; + getAflGamePlayerStatistics: ApiSportsEndpoint<'getAflGamePlayerStatistics'>; + getAflStandings: ApiSportsEndpoint<'getAflStandings'>; + getBaseballGamesHeadToHead: ApiSportsEndpoint<'getBaseballGamesHeadToHead'>; + getFormula1Circuits: ApiSportsEndpoint<'getFormula1Circuits'>; + getFormula1Competitions: ApiSportsEndpoint<'getFormula1Competitions'>; + getFormula1Races: ApiSportsEndpoint<'getFormula1Races'>; + getFormula1DriverRankings: ApiSportsEndpoint<'getFormula1DriverRankings'>; + getFormula1TeamRankings: ApiSportsEndpoint<'getFormula1TeamRankings'>; + getFormula1StartingGrid: ApiSportsEndpoint<'getFormula1StartingGrid'>; + getFastestLapsRankings: ApiSportsEndpoint<'getFastestLapsRankings'>; + getRaceRankings: ApiSportsEndpoint<'getRaceRankings'>; + getMmaCategories: ApiSportsEndpoint<'getMmaCategories'>; + getMmaFighters: ApiSportsEndpoint<'getMmaFighters'>; + getMmaFights: ApiSportsEndpoint<'getMmaFights'>; + getMmaFightResults: ApiSportsEndpoint<'getMmaFightResults'>; + getMmaFighterStatistics: ApiSportsEndpoint<'getMmaFighterStatistics'>; + getFightersRecords: ApiSportsEndpoint<'getFightersRecords'>; +}; + +const apiSportsEndpointsNested = { + core: { + getCountries: Core.getCountries, + getTimezone: Core.getTimezone, + getLeagues: Core.getLeagues, + getLeagueSeasons: Core.getLeagueSeasons, + getTeams: Core.getTeams, + getTeamSeasons: Core.getTeamSeasons, + getTeamStatistics: Core.getTeamStatistics, + getVenues: Core.getVenues, + getCoaches: Core.getCoaches, + getInjuries: Core.getInjuries, + getSidelined: Core.getSidelined, + getTransfers: Core.getTransfers, + getTrophies: Core.getTrophies, + getPredictions: Core.getPredictions, + }, + fixtures: { + getFixtures: Fixtures.getFixtures, + getFixturesRounds: Fixtures.getFixturesRounds, + getHeadToHeadFixtures: Fixtures.getHeadToHeadFixtures, + getFixtureLineups: Fixtures.getFixtureLineups, + getFixtureStatistics: Fixtures.getFixtureStatistics, + getFixturesEvents: Fixtures.getFixturesEvents, + getFixturesPlayers: Fixtures.getFixturesPlayers, + }, + standings: { + getStandingsStages: Standings.getStandingsStages, + getStandingsGroups: Standings.getStandingsGroups, + getStandingsDivisions: Standings.getStandingsDivisions, + getNflStandingsConferences: Standings.getNflStandingsConferences, + }, + players: { + getPlayers: Players.getPlayers, + getPlayersProfiles: Players.getPlayersProfiles, + getPlayersSeasons: Players.getPlayersSeasons, + getPlayersSquads: Players.getPlayersSquads, + getPlayersTeams: Players.getPlayersTeams, + getPlayersTopScorers: Players.getPlayersTopScorers, + getPlayersTopAssists: Players.getPlayersTopAssists, + getPlayersTopYellowCards: Players.getPlayersTopYellowCards, + getPlayersTopRedCards: Players.getPlayersTopRedCards, + }, + odds: { + getOdds: Odds.getOdds, + getOddsBets: Odds.getOddsBets, + getOddsBookmakers: Odds.getOddsBookmakers, + getOddsMapping: Odds.getOddsMapping, + getInPlayOdds: Odds.getInPlayOdds, + getLiveOddsBets: Odds.getLiveOddsBets, + }, + basketball: { + getBasketballStatistics: Basketball.getBasketballStatistics, + getBasketballBets: Basketball.getBasketballBets, + getBasketballBookmakers: Basketball.getBasketballBookmakers, + getNbaGameStatistics: Basketball.getNbaGameStatistics, + getPlayerStatistics: Basketball.getPlayerStatistics, + getGameStatisticsByTeams: Basketball.getGameStatisticsByTeams, + getGamesEvents: Basketball.getGamesEvents, + }, + afl: { + getAflSeasons: Afl.getAflSeasons, + getAflGames: Afl.getAflGames, + getAflGamesQuarters: Afl.getAflGamesQuarters, + getAflGamePlayerStatistics: Afl.getAflGamePlayerStatistics, + getAflStandings: Afl.getAflStandings, + }, + baseball: { + getBaseballGamesHeadToHead: Baseball.getBaseballGamesHeadToHead, + }, + formula1: { + getFormula1Circuits: Formula1.getFormula1Circuits, + getFormula1Competitions: Formula1.getFormula1Competitions, + getFormula1Races: Formula1.getFormula1Races, + getFormula1DriverRankings: Formula1.getFormula1DriverRankings, + getFormula1TeamRankings: Formula1.getFormula1TeamRankings, + getFormula1StartingGrid: Formula1.getFormula1StartingGrid, + getFastestLapsRankings: Formula1.getFastestLapsRankings, + getRaceRankings: Formula1.getRaceRankings, + }, + mma: { + getMmaCategories: Mma.getMmaCategories, + getMmaFighters: Mma.getMmaFighters, + getMmaFights: Mma.getMmaFights, + getMmaFightResults: Mma.getMmaFightResults, + getMmaFighterStatistics: Mma.getMmaFighterStatistics, + getFightersRecords: Mma.getFightersRecords, + }, +} as const; + +const apiSportsWebhooksNested = {} as const; + +export const apiSportsEndpointSchemas = { + 'core.getCountries': { + input: ApiSportsEndpointInputSchemas.getCountries, + output: ApiSportsEndpointOutputSchemas.getCountries, + }, + 'core.getTimezone': { + input: ApiSportsEndpointInputSchemas.getTimezone, + output: ApiSportsEndpointOutputSchemas.getTimezone, + }, + 'core.getLeagues': { + input: ApiSportsEndpointInputSchemas.getLeagues, + output: ApiSportsEndpointOutputSchemas.getLeagues, + }, + 'core.getLeagueSeasons': { + input: ApiSportsEndpointInputSchemas.getLeagueSeasons, + output: ApiSportsEndpointOutputSchemas.getLeagueSeasons, + }, + 'core.getTeams': { + input: ApiSportsEndpointInputSchemas.getTeams, + output: ApiSportsEndpointOutputSchemas.getTeams, + }, + 'core.getTeamSeasons': { + input: ApiSportsEndpointInputSchemas.getTeamSeasons, + output: ApiSportsEndpointOutputSchemas.getTeamSeasons, + }, + 'core.getTeamStatistics': { + input: ApiSportsEndpointInputSchemas.getTeamStatistics, + output: ApiSportsEndpointOutputSchemas.getTeamStatistics, + }, + 'core.getVenues': { + input: ApiSportsEndpointInputSchemas.getVenues, + output: ApiSportsEndpointOutputSchemas.getVenues, + }, + 'core.getCoaches': { + input: ApiSportsEndpointInputSchemas.getCoaches, + output: ApiSportsEndpointOutputSchemas.getCoaches, + }, + 'core.getInjuries': { + input: ApiSportsEndpointInputSchemas.getInjuries, + output: ApiSportsEndpointOutputSchemas.getInjuries, + }, + 'core.getSidelined': { + input: ApiSportsEndpointInputSchemas.getSidelined, + output: ApiSportsEndpointOutputSchemas.getSidelined, + }, + 'core.getTransfers': { + input: ApiSportsEndpointInputSchemas.getTransfers, + output: ApiSportsEndpointOutputSchemas.getTransfers, + }, + 'core.getTrophies': { + input: ApiSportsEndpointInputSchemas.getTrophies, + output: ApiSportsEndpointOutputSchemas.getTrophies, + }, + 'core.getPredictions': { + input: ApiSportsEndpointInputSchemas.getPredictions, + output: ApiSportsEndpointOutputSchemas.getPredictions, + }, + 'fixtures.getFixtures': { + input: ApiSportsEndpointInputSchemas.getFixtures, + output: ApiSportsEndpointOutputSchemas.getFixtures, + }, + 'fixtures.getFixturesRounds': { + input: ApiSportsEndpointInputSchemas.getFixturesRounds, + output: ApiSportsEndpointOutputSchemas.getFixturesRounds, + }, + 'fixtures.getHeadToHeadFixtures': { + input: ApiSportsEndpointInputSchemas.getHeadToHeadFixtures, + output: ApiSportsEndpointOutputSchemas.getHeadToHeadFixtures, + }, + 'fixtures.getFixtureLineups': { + input: ApiSportsEndpointInputSchemas.getFixtureLineups, + output: ApiSportsEndpointOutputSchemas.getFixtureLineups, + }, + 'fixtures.getFixtureStatistics': { + input: ApiSportsEndpointInputSchemas.getFixtureStatistics, + output: ApiSportsEndpointOutputSchemas.getFixtureStatistics, + }, + 'fixtures.getFixturesEvents': { + input: ApiSportsEndpointInputSchemas.getFixturesEvents, + output: ApiSportsEndpointOutputSchemas.getFixturesEvents, + }, + 'fixtures.getFixturesPlayers': { + input: ApiSportsEndpointInputSchemas.getFixturesPlayers, + output: ApiSportsEndpointOutputSchemas.getFixturesPlayers, + }, + 'standings.getStandingsStages': { + input: ApiSportsEndpointInputSchemas.getStandingsStages, + output: ApiSportsEndpointOutputSchemas.getStandingsStages, + }, + 'standings.getStandingsGroups': { + input: ApiSportsEndpointInputSchemas.getStandingsGroups, + output: ApiSportsEndpointOutputSchemas.getStandingsGroups, + }, + 'standings.getStandingsDivisions': { + input: ApiSportsEndpointInputSchemas.getStandingsDivisions, + output: ApiSportsEndpointOutputSchemas.getStandingsDivisions, + }, + 'standings.getNflStandingsConferences': { + input: ApiSportsEndpointInputSchemas.getNflStandingsConferences, + output: ApiSportsEndpointOutputSchemas.getNflStandingsConferences, + }, + 'players.getPlayers': { + input: ApiSportsEndpointInputSchemas.getPlayers, + output: ApiSportsEndpointOutputSchemas.getPlayers, + }, + 'players.getPlayersProfiles': { + input: ApiSportsEndpointInputSchemas.getPlayersProfiles, + output: ApiSportsEndpointOutputSchemas.getPlayersProfiles, + }, + 'players.getPlayersSeasons': { + input: ApiSportsEndpointInputSchemas.getPlayersSeasons, + output: ApiSportsEndpointOutputSchemas.getPlayersSeasons, + }, + 'players.getPlayersSquads': { + input: ApiSportsEndpointInputSchemas.getPlayersSquads, + output: ApiSportsEndpointOutputSchemas.getPlayersSquads, + }, + 'players.getPlayersTeams': { + input: ApiSportsEndpointInputSchemas.getPlayersTeams, + output: ApiSportsEndpointOutputSchemas.getPlayersTeams, + }, + 'players.getPlayersTopScorers': { + input: ApiSportsEndpointInputSchemas.getPlayersTopScorers, + output: ApiSportsEndpointOutputSchemas.getPlayersTopScorers, + }, + 'players.getPlayersTopAssists': { + input: ApiSportsEndpointInputSchemas.getPlayersTopAssists, + output: ApiSportsEndpointOutputSchemas.getPlayersTopAssists, + }, + 'players.getPlayersTopYellowCards': { + input: ApiSportsEndpointInputSchemas.getPlayersTopYellowCards, + output: ApiSportsEndpointOutputSchemas.getPlayersTopYellowCards, + }, + 'players.getPlayersTopRedCards': { + input: ApiSportsEndpointInputSchemas.getPlayersTopRedCards, + output: ApiSportsEndpointOutputSchemas.getPlayersTopRedCards, + }, + 'odds.getOdds': { + input: ApiSportsEndpointInputSchemas.getOdds, + output: ApiSportsEndpointOutputSchemas.getOdds, + }, + 'odds.getOddsBets': { + input: ApiSportsEndpointInputSchemas.getOddsBets, + output: ApiSportsEndpointOutputSchemas.getOddsBets, + }, + 'odds.getOddsBookmakers': { + input: ApiSportsEndpointInputSchemas.getOddsBookmakers, + output: ApiSportsEndpointOutputSchemas.getOddsBookmakers, + }, + 'odds.getOddsMapping': { + input: ApiSportsEndpointInputSchemas.getOddsMapping, + output: ApiSportsEndpointOutputSchemas.getOddsMapping, + }, + 'odds.getInPlayOdds': { + input: ApiSportsEndpointInputSchemas.getInPlayOdds, + output: ApiSportsEndpointOutputSchemas.getInPlayOdds, + }, + 'odds.getLiveOddsBets': { + input: ApiSportsEndpointInputSchemas.getLiveOddsBets, + output: ApiSportsEndpointOutputSchemas.getLiveOddsBets, + }, + 'basketball.getBasketballStatistics': { + input: ApiSportsEndpointInputSchemas.getBasketballStatistics, + output: ApiSportsEndpointOutputSchemas.getBasketballStatistics, + }, + 'basketball.getBasketballBets': { + input: ApiSportsEndpointInputSchemas.getBasketballBets, + output: ApiSportsEndpointOutputSchemas.getBasketballBets, + }, + 'basketball.getBasketballBookmakers': { + input: ApiSportsEndpointInputSchemas.getBasketballBookmakers, + output: ApiSportsEndpointOutputSchemas.getBasketballBookmakers, + }, + 'basketball.getNbaGameStatistics': { + input: ApiSportsEndpointInputSchemas.getNbaGameStatistics, + output: ApiSportsEndpointOutputSchemas.getNbaGameStatistics, + }, + 'basketball.getPlayerStatistics': { + input: ApiSportsEndpointInputSchemas.getPlayerStatistics, + output: ApiSportsEndpointOutputSchemas.getPlayerStatistics, + }, + 'basketball.getGameStatisticsByTeams': { + input: ApiSportsEndpointInputSchemas.getGameStatisticsByTeams, + output: ApiSportsEndpointOutputSchemas.getGameStatisticsByTeams, + }, + 'basketball.getGamesEvents': { + input: ApiSportsEndpointInputSchemas.getGamesEvents, + output: ApiSportsEndpointOutputSchemas.getGamesEvents, + }, + 'afl.getAflSeasons': { + input: ApiSportsEndpointInputSchemas.getAflSeasons, + output: ApiSportsEndpointOutputSchemas.getAflSeasons, + }, + 'afl.getAflGames': { + input: ApiSportsEndpointInputSchemas.getAflGames, + output: ApiSportsEndpointOutputSchemas.getAflGames, + }, + 'afl.getAflGamesQuarters': { + input: ApiSportsEndpointInputSchemas.getAflGamesQuarters, + output: ApiSportsEndpointOutputSchemas.getAflGamesQuarters, + }, + 'afl.getAflGamePlayerStatistics': { + input: ApiSportsEndpointInputSchemas.getAflGamePlayerStatistics, + output: ApiSportsEndpointOutputSchemas.getAflGamePlayerStatistics, + }, + 'afl.getAflStandings': { + input: ApiSportsEndpointInputSchemas.getAflStandings, + output: ApiSportsEndpointOutputSchemas.getAflStandings, + }, + 'baseball.getBaseballGamesHeadToHead': { + input: ApiSportsEndpointInputSchemas.getBaseballGamesHeadToHead, + output: ApiSportsEndpointOutputSchemas.getBaseballGamesHeadToHead, + }, + 'formula1.getFormula1Circuits': { + input: ApiSportsEndpointInputSchemas.getFormula1Circuits, + output: ApiSportsEndpointOutputSchemas.getFormula1Circuits, + }, + 'formula1.getFormula1Competitions': { + input: ApiSportsEndpointInputSchemas.getFormula1Competitions, + output: ApiSportsEndpointOutputSchemas.getFormula1Competitions, + }, + 'formula1.getFormula1Races': { + input: ApiSportsEndpointInputSchemas.getFormula1Races, + output: ApiSportsEndpointOutputSchemas.getFormula1Races, + }, + 'formula1.getFormula1DriverRankings': { + input: ApiSportsEndpointInputSchemas.getFormula1DriverRankings, + output: ApiSportsEndpointOutputSchemas.getFormula1DriverRankings, + }, + 'formula1.getFormula1TeamRankings': { + input: ApiSportsEndpointInputSchemas.getFormula1TeamRankings, + output: ApiSportsEndpointOutputSchemas.getFormula1TeamRankings, + }, + 'formula1.getFormula1StartingGrid': { + input: ApiSportsEndpointInputSchemas.getFormula1StartingGrid, + output: ApiSportsEndpointOutputSchemas.getFormula1StartingGrid, + }, + 'formula1.getFastestLapsRankings': { + input: ApiSportsEndpointInputSchemas.getFastestLapsRankings, + output: ApiSportsEndpointOutputSchemas.getFastestLapsRankings, + }, + 'formula1.getRaceRankings': { + input: ApiSportsEndpointInputSchemas.getRaceRankings, + output: ApiSportsEndpointOutputSchemas.getRaceRankings, + }, + 'mma.getMmaCategories': { + input: ApiSportsEndpointInputSchemas.getMmaCategories, + output: ApiSportsEndpointOutputSchemas.getMmaCategories, + }, + 'mma.getMmaFighters': { + input: ApiSportsEndpointInputSchemas.getMmaFighters, + output: ApiSportsEndpointOutputSchemas.getMmaFighters, + }, + 'mma.getMmaFights': { + input: ApiSportsEndpointInputSchemas.getMmaFights, + output: ApiSportsEndpointOutputSchemas.getMmaFights, + }, + 'mma.getMmaFightResults': { + input: ApiSportsEndpointInputSchemas.getMmaFightResults, + output: ApiSportsEndpointOutputSchemas.getMmaFightResults, + }, + 'mma.getMmaFighterStatistics': { + input: ApiSportsEndpointInputSchemas.getMmaFighterStatistics, + output: ApiSportsEndpointOutputSchemas.getMmaFighterStatistics, + }, + 'mma.getFightersRecords': { + input: ApiSportsEndpointInputSchemas.getFightersRecords, + output: ApiSportsEndpointOutputSchemas.getFightersRecords, + }, +} satisfies RequiredPluginEndpointSchemas; + +const apiSportsEndpointMeta = { + 'core.getCountries': { + riskLevel: 'read', + description: 'Get Countries', + }, + 'core.getTimezone': { + riskLevel: 'read', + description: 'Get Timezone', + }, + 'core.getLeagues': { + riskLevel: 'read', + description: 'Get Leagues', + }, + 'core.getLeagueSeasons': { + riskLevel: 'read', + description: 'Get League Seasons', + }, + 'core.getTeams': { + riskLevel: 'read', + description: 'Get Teams', + }, + 'core.getTeamSeasons': { + riskLevel: 'read', + description: 'Get Team Seasons', + }, + 'core.getTeamStatistics': { + riskLevel: 'read', + description: 'Get Team Statistics', + }, + 'core.getVenues': { + riskLevel: 'read', + description: 'Get Venues', + }, + 'core.getCoaches': { + riskLevel: 'read', + description: 'Get Coaches', + }, + 'core.getInjuries': { + riskLevel: 'read', + description: 'Get Injuries', + }, + 'core.getSidelined': { + riskLevel: 'read', + description: 'Get Sidelined', + }, + 'core.getTransfers': { + riskLevel: 'read', + description: 'Get Transfers', + }, + 'core.getTrophies': { + riskLevel: 'read', + description: 'Get Trophies', + }, + 'core.getPredictions': { + riskLevel: 'read', + description: 'Get Predictions', + }, + 'fixtures.getFixtures': { + riskLevel: 'read', + description: 'Get Fixtures', + }, + 'fixtures.getFixturesRounds': { + riskLevel: 'read', + description: 'Get Fixtures Rounds', + }, + 'fixtures.getHeadToHeadFixtures': { + riskLevel: 'read', + description: 'Get Head-to-Head Fixtures', + }, + 'fixtures.getFixtureLineups': { + riskLevel: 'read', + description: 'Get Fixture Lineups', + }, + 'fixtures.getFixtureStatistics': { + riskLevel: 'read', + description: 'Get Fixture Statistics', + }, + 'fixtures.getFixturesEvents': { + riskLevel: 'read', + description: 'Get Fixtures Events', + }, + 'fixtures.getFixturesPlayers': { + riskLevel: 'read', + description: 'Get Fixtures Players', + }, + 'standings.getStandingsStages': { + riskLevel: 'read', + description: 'Get Standings Stages', + }, + 'standings.getStandingsGroups': { + riskLevel: 'read', + description: 'Get Standings Groups', + }, + 'standings.getStandingsDivisions': { + riskLevel: 'read', + description: 'Get Standings Divisions', + }, + 'standings.getNflStandingsConferences': { + riskLevel: 'read', + description: 'Get NFL Standings Conferences', + }, + 'players.getPlayers': { + riskLevel: 'read', + description: 'Get Players', + }, + 'players.getPlayersProfiles': { + riskLevel: 'read', + description: 'Get Players Profiles', + }, + 'players.getPlayersSeasons': { + riskLevel: 'read', + description: 'Get Players Seasons', + }, + 'players.getPlayersSquads': { + riskLevel: 'read', + description: 'Get Players Squads', + }, + 'players.getPlayersTeams': { + riskLevel: 'read', + description: 'Get Players Teams', + }, + 'players.getPlayersTopScorers': { + riskLevel: 'read', + description: 'Get Players Top Scorers', + }, + 'players.getPlayersTopAssists': { + riskLevel: 'read', + description: 'Get Players Top Assists', + }, + 'players.getPlayersTopYellowCards': { + riskLevel: 'read', + description: 'Get Players Top Yellow Cards', + }, + 'players.getPlayersTopRedCards': { + riskLevel: 'read', + description: 'Get Players Top Red Cards', + }, + 'odds.getOdds': { + riskLevel: 'read', + description: 'Get Odds', + }, + 'odds.getOddsBets': { + riskLevel: 'read', + description: 'Get Odds Bets', + }, + 'odds.getOddsBookmakers': { + riskLevel: 'read', + description: 'Get Odds Bookmakers', + }, + 'odds.getOddsMapping': { + riskLevel: 'read', + description: 'Get Odds Mapping', + }, + 'odds.getInPlayOdds': { + riskLevel: 'read', + description: 'Get In-Play Odds', + }, + 'odds.getLiveOddsBets': { + riskLevel: 'read', + description: 'Get Live Odds Bets', + }, + 'basketball.getBasketballStatistics': { + riskLevel: 'read', + description: 'Get Basketball Statistics', + }, + 'basketball.getBasketballBets': { + riskLevel: 'read', + description: 'Get Basketball Bets', + }, + 'basketball.getBasketballBookmakers': { + riskLevel: 'read', + description: 'Get Basketball Bookmakers', + }, + 'basketball.getNbaGameStatistics': { + riskLevel: 'read', + description: 'Get NBA Game Statistics', + }, + 'basketball.getPlayerStatistics': { + riskLevel: 'read', + description: 'Get Player Statistics', + }, + 'basketball.getGameStatisticsByTeams': { + riskLevel: 'read', + description: 'Get Game Statistics by Teams', + }, + 'basketball.getGamesEvents': { + riskLevel: 'read', + description: 'Get Games Events', + }, + 'afl.getAflSeasons': { + riskLevel: 'read', + description: 'Get AFL Seasons', + }, + 'afl.getAflGames': { + riskLevel: 'read', + description: 'Get AFL Games', + }, + 'afl.getAflGamesQuarters': { + riskLevel: 'read', + description: 'Get AFL Games Quarters', + }, + 'afl.getAflGamePlayerStatistics': { + riskLevel: 'read', + description: 'Get AFL Game Player Statistics', + }, + 'afl.getAflStandings': { + riskLevel: 'read', + description: 'Get AFL Standings', + }, + 'baseball.getBaseballGamesHeadToHead': { + riskLevel: 'read', + description: 'Get Baseball Games Head-to-Head', + }, + 'formula1.getFormula1Circuits': { + riskLevel: 'read', + description: 'Get Formula 1 Circuits', + }, + 'formula1.getFormula1Competitions': { + riskLevel: 'read', + description: 'Get Formula 1 Competitions', + }, + 'formula1.getFormula1Races': { + riskLevel: 'read', + description: 'Get Formula 1 Races', + }, + 'formula1.getFormula1DriverRankings': { + riskLevel: 'read', + description: 'Get Formula 1 Driver Rankings', + }, + 'formula1.getFormula1TeamRankings': { + riskLevel: 'read', + description: 'Get Formula 1 Team Rankings', + }, + 'formula1.getFormula1StartingGrid': { + riskLevel: 'read', + description: 'Get Formula 1 Starting Grid', + }, + 'formula1.getFastestLapsRankings': { + riskLevel: 'read', + description: 'Get Fastest Laps Rankings', + }, + 'formula1.getRaceRankings': { + riskLevel: 'read', + description: 'Get Race Rankings', + }, + 'mma.getMmaCategories': { + riskLevel: 'read', + description: 'Get MMA Categories', + }, + 'mma.getMmaFighters': { + riskLevel: 'read', + description: 'Get MMA Fighters', + }, + 'mma.getMmaFights': { + riskLevel: 'read', + description: 'Get MMA Fights', + }, + 'mma.getMmaFightResults': { + riskLevel: 'read', + description: 'Get MMA Fight Results', + }, + 'mma.getMmaFighterStatistics': { + riskLevel: 'read', + description: 'Get MMA Fighter Statistics', + }, + 'mma.getFightersRecords': { + riskLevel: 'read', + description: 'Get Fighters Records', + }, +} satisfies RequiredPluginEndpointMeta; + +const defaultAuthType: AuthTypes = 'api_key' as const; + +export const apiSportsAuthConfig = { + api_key: {}, +} as const satisfies PluginAuthConfig; + +export type BaseApiSportsPlugin = CorsairPlugin< + 'api_sports', + typeof ApiSportsSchema, + typeof apiSportsEndpointsNested, + typeof apiSportsWebhooksNested, + T, + typeof defaultAuthType +>; + +export type InternalApiSportsPlugin = BaseApiSportsPlugin; + +export type ExternalApiSportsPlugin = + BaseApiSportsPlugin; + +export function apiSports( + incomingOptions: ApiSportsPluginOptions & + T = {} as ApiSportsPluginOptions & T, +): ExternalApiSportsPlugin { + const options = { + ...incomingOptions, + authType: incomingOptions.authType ?? defaultAuthType, + }; + return { + id: 'api_sports', + authConfig: apiSportsAuthConfig, + schema: ApiSportsSchema, + options, + hooks: options.hooks, + webhookHooks: undefined, + endpoints: apiSportsEndpointsNested, + webhooks: apiSportsWebhooksNested, + endpointMeta: apiSportsEndpointMeta, + endpointSchemas: apiSportsEndpointSchemas, + pluginWebhookMatcher: undefined, + errorHandlers: { + ...errorHandlers, + ...options.errorHandlers, + }, + keyBuilder: async (ctx: ApiSportsKeyBuilderContext, source) => { + if (source === 'endpoint' && options.key) { + return options.key; + } + if (source === 'endpoint' && ctx.authType === 'api_key') { + const res = await ctx.keys.get_api_key(); + return res ?? ''; + } + throw new AuthMissingError('api_sports', 'api_key'); + }, + } satisfies InternalApiSportsPlugin; +} + +export type { + ApiSportsEndpointInputs, + ApiSportsEndpointOutputs, + ApiSportsQueryInput, + ApiSportsResponse, +} from './endpoints/types'; + +export { + ApiSportsEndpointInputSchemas, + ApiSportsEndpointOutputSchemas, + ApiSportsQueryInputSchema, + ApiSportsResponseSchema, +} from './endpoints/types'; diff --git a/packages/api_sports/jest.config.cjs b/packages/api_sports/jest.config.cjs new file mode 100644 index 000000000..26c3be375 --- /dev/null +++ b/packages/api_sports/jest.config.cjs @@ -0,0 +1,29 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: [''], + testMatch: ['**/*.test.ts'], + moduleFileExtensions: ['ts', 'js', 'json'], + transform: { + '^.+\\.ts$': [ + 'ts-jest', + { + useESM: true, + tsconfig: { + esModuleInterop: true, + allowSyntheticDefaultImports: true, + verbatimModuleSyntax: false, + module: 'ESNext', + moduleResolution: 'Bundler', + }, + }, + ], + }, + moduleNameMapper: { + '^corsair/http$': '/../corsair/http.ts', + '^(\\.\\.?/.*)\\.js$': '$1', + }, + extensionsToTreatAsEsm: ['.ts'], + testTimeout: 60000, + verbose: true, +}; diff --git a/packages/api_sports/package.json b/packages/api_sports/package.json new file mode 100644 index 000000000..831ac619f --- /dev/null +++ b/packages/api_sports/package.json @@ -0,0 +1,45 @@ +{ + "name": "@corsair-dev/api_sports", + "version": "0.1.0", + "description": "API-Sports plugin for Corsair", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "dev-source": "./index.ts", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "scripts": { + "build": "rm -rf dist && tsc --build --force && tsup", + "typecheck": "tsc --noEmit", + "test": "jest" + }, + "peerDependencies": { + "corsair": ">=0.1.0", + "zod": "^4.1.13" + }, + "devDependencies": { + "@types/jest": "^29.5.14", + "corsair": "workspace:*", + "dotenv": "^17.2.3", + "jest": "^29.7.0", + "ts-jest": "^29.4.9", + "tsup": "^8.0.1", + "typescript": "catalog:", + "zod": "^4.1.13" + }, + "keywords": [ + "corsair", + "api_sports", + "plugin" + ], + "author": "", + "license": "Apache-2.0", + "files": [ + "dist" + ] +} diff --git a/packages/api_sports/schema/database.ts b/packages/api_sports/schema/database.ts new file mode 100644 index 000000000..892096ace --- /dev/null +++ b/packages/api_sports/schema/database.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +export const ApiSportsQueryRecord = z.object({ + sport: z.string().optional(), + path: z.string().optional(), + queriedAt: z.coerce.date().nullable().optional(), +}); + +export type ApiSportsQueryRecord = z.infer; diff --git a/packages/api_sports/schema/index.ts b/packages/api_sports/schema/index.ts new file mode 100644 index 000000000..2ad135eee --- /dev/null +++ b/packages/api_sports/schema/index.ts @@ -0,0 +1,8 @@ +import { ApiSportsQueryRecord } from './database'; + +export const ApiSportsSchema = { + version: '1.0.0', + entities: { + queries: ApiSportsQueryRecord, + }, +} as const; diff --git a/packages/api_sports/scripts/generate-endpoints.py b/packages/api_sports/scripts/generate-endpoints.py new file mode 100644 index 000000000..53880a053 --- /dev/null +++ b/packages/api_sports/scripts/generate-endpoints.py @@ -0,0 +1,409 @@ +#!/usr/bin/env python3 +"""One-shot generator for API-Sports endpoint modules.""" + +from __future__ import annotations + +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +ENDPOINTS = ROOT / "endpoints" + +# (group, key, sport, path, description) +ROUTES: list[tuple[str, str, str, str, str]] = [ + # Football / core + ("core", "getCountries", "football", "/countries", "Get Countries"), + ("core", "getTimezone", "football", "/timezone", "Get Timezone"), + ("core", "getLeagues", "football", "/leagues", "Get Leagues"), + ("core", "getLeagueSeasons", "football", "/leagues/seasons", "Get League Seasons"), + ("core", "getTeams", "football", "/teams", "Get Teams"), + ("core", "getTeamSeasons", "football", "/teams/seasons", "Get Team Seasons"), + ("core", "getTeamStatistics", "football", "/teams/statistics", "Get Team Statistics"), + ("core", "getVenues", "football", "/venues", "Get Venues"), + ("core", "getCoaches", "football", "/coachs", "Get Coaches"), + ("core", "getInjuries", "football", "/injuries", "Get Injuries"), + ("core", "getSidelined", "football", "/sidelined", "Get Sidelined"), + ("core", "getTransfers", "football", "/transfers", "Get Transfers"), + ("core", "getTrophies", "football", "/trophies", "Get Trophies"), + ("core", "getPredictions", "football", "/predictions", "Get Predictions"), + # Fixtures + ("fixtures", "getFixtures", "football", "/fixtures", "Get Fixtures"), + ("fixtures", "getFixturesRounds", "football", "/fixtures/rounds", "Get Fixtures Rounds"), + ("fixtures", "getHeadToHeadFixtures", "football", "/fixtures/headtohead", "Get Head-to-Head Fixtures"), + ("fixtures", "getFixtureLineups", "football", "/fixtures/lineups", "Get Fixture Lineups"), + ("fixtures", "getFixtureStatistics", "football", "/fixtures/statistics", "Get Fixture Statistics"), + ("fixtures", "getFixturesEvents", "football", "/fixtures/events", "Get Fixtures Events"), + ("fixtures", "getFixturesPlayers", "football", "/fixtures/players", "Get Fixtures Players"), + # NFL standings helpers + ("standings", "getStandingsStages", "nfl", "/standings/stages", "Get Standings Stages"), + ("standings", "getStandingsGroups", "nfl", "/standings/groups", "Get Standings Groups"), + ("standings", "getStandingsDivisions", "nfl", "/standings/divisions", "Get Standings Divisions"), + ("standings", "getNflStandingsConferences", "nfl", "/standings/conferences", "Get NFL Standings Conferences"), + # Players + ("players", "getPlayers", "football", "/players", "Get Players"), + ("players", "getPlayersProfiles", "football", "/players/profiles", "Get Players Profiles"), + ("players", "getPlayersSeasons", "football", "/players/seasons", "Get Players Seasons"), + ("players", "getPlayersSquads", "football", "/players/squads", "Get Players Squads"), + ("players", "getPlayersTeams", "football", "/players/teams", "Get Players Teams"), + ("players", "getPlayersTopScorers", "football", "/players/topscorers", "Get Players Top Scorers"), + ("players", "getPlayersTopAssists", "football", "/players/topassists", "Get Players Top Assists"), + ("players", "getPlayersTopYellowCards", "football", "/players/topyellowcards", "Get Players Top Yellow Cards"), + ("players", "getPlayersTopRedCards", "football", "/players/topredcards", "Get Players Top Red Cards"), + # Odds + ("odds", "getOdds", "football", "/odds", "Get Odds"), + ("odds", "getOddsBets", "football", "/odds/bets", "Get Odds Bets"), + ("odds", "getOddsBookmakers", "football", "/odds/bookmakers", "Get Odds Bookmakers"), + ("odds", "getOddsMapping", "football", "/odds/mapping", "Get Odds Mapping"), + ("odds", "getInPlayOdds", "football", "/odds/live", "Get In-Play Odds"), + ("odds", "getLiveOddsBets", "football", "/odds/live/bets", "Get Live Odds Bets"), + # Basketball / NBA + ("basketball", "getBasketballStatistics", "basketball", "/statistics", "Get Basketball Statistics"), + ("basketball", "getBasketballBets", "basketball", "/bets", "Get Basketball Bets"), + ("basketball", "getBasketballBookmakers", "basketball", "/bookmakers", "Get Basketball Bookmakers"), + ("basketball", "getNbaGameStatistics", "nba", "/games/statistics", "Get NBA Game Statistics"), + ("basketball", "getPlayerStatistics", "nba", "/players/statistics", "Get Player Statistics"), + ("basketball", "getGameStatisticsByTeams", "nba", "/games/statistics", "Get Game Statistics by Teams"), + ("basketball", "getGamesEvents", "nba", "/games/events", "Get Games Events"), + # AFL + ("afl", "getAflSeasons", "afl", "/seasons", "Get AFL Seasons"), + ("afl", "getAflGames", "afl", "/games", "Get AFL Games"), + ("afl", "getAflGamesQuarters", "afl", "/games/quarters", "Get AFL Games Quarters"), + ("afl", "getAflGamePlayerStatistics", "afl", "/games/statistics/players", "Get AFL Game Player Statistics"), + ("afl", "getAflStandings", "afl", "/standings", "Get AFL Standings"), + # Baseball + ("baseball", "getBaseballGamesHeadToHead", "baseball", "/games/h2h", "Get Baseball Games Head-to-Head"), + # Formula 1 + ("formula1", "getFormula1Circuits", "formula1", "/circuits", "Get Formula 1 Circuits"), + ("formula1", "getFormula1Competitions", "formula1", "/competitions", "Get Formula 1 Competitions"), + ("formula1", "getFormula1Races", "formula1", "/races", "Get Formula 1 Races"), + ("formula1", "getFormula1DriverRankings", "formula1", "/rankings/drivers", "Get Formula 1 Driver Rankings"), + ("formula1", "getFormula1TeamRankings", "formula1", "/rankings/teams", "Get Formula 1 Team Rankings"), + ("formula1", "getFormula1StartingGrid", "formula1", "/rankings/startinggrid", "Get Formula 1 Starting Grid"), + ("formula1", "getFastestLapsRankings", "formula1", "/rankings/fastestlaps", "Get Fastest Laps Rankings"), + ("formula1", "getRaceRankings", "formula1", "/rankings/races", "Get Race Rankings"), + # MMA + ("mma", "getMmaCategories", "mma", "/categories", "Get MMA Categories"), + ("mma", "getMmaFighters", "mma", "/fighters", "Get MMA Fighters"), + ("mma", "getMmaFights", "mma", "/fights", "Get MMA Fights"), + ("mma", "getMmaFightResults", "mma", "/fights/results", "Get MMA Fight Results"), + ("mma", "getMmaFighterStatistics", "mma", "/fights/statistics/fighters", "Get MMA Fighter Statistics"), + ("mma", "getFightersRecords", "mma", "/fighters/records", "Get Fighters Records"), +] + +assert len(ROUTES) == 67, f"expected 67 routes, got {len(ROUTES)}" + + +def pascal(s: str) -> str: + return "".join(part.capitalize() for part in s.split("_")) + + +def write_routes_ts() -> None: + lines = [ + "import type { ApiSport } from '../client';", + "", + "export type ApiSportsRoute = {", + "\tsport: ApiSport;", + "\tpath: string;", + "\tdescription: string;", + "};", + "", + "export const API_SPORTS_ROUTES = {", + ] + for group, key, sport, path, desc in ROUTES: + lines.append(f"\t{key}: {{ sport: '{sport}', path: '{path}', description: {json.dumps(desc)} }},") + lines.append("} as const satisfies Record;") + lines.append("") + lines.append("export type ApiSportsRouteKey = keyof typeof API_SPORTS_ROUTES;") + (ENDPOINTS / "routes.ts").write_text("\n".join(lines) + "\n") + + +def write_group_file(group: str, routes: list[tuple[str, str, str, str, str]]) -> None: + lines = [ + "import { logEventFromContext } from 'corsair/core';", + "import { makeApiSportsRequest } from '../client';", + "import type { ApiSportsEndpoints } from '../index';", + "import type { ApiSportsEndpointOutputs } from './types';", + "import { API_SPORTS_ROUTES } from './routes';", + "", + ] + for _, key, _, path, desc in routes: + route = f"API_SPORTS_ROUTES.{key}" + lines.extend([ + f"/** {desc} */", + f"export const {key}: ApiSportsEndpoints['{key}'] = async (ctx, input) => {{", + f"\tconst route = {route};", + f"\tconst response = await makeApiSportsRequest(", + f"\t\troute.sport,", + f"\t\troute.path,", + f"\t\t{{ apiKey: ctx.key, query: input }},", + f"\t);", + f"\tawait logEventFromContext(ctx, 'api_sports.{group}.{key}', input ?? {{}}, 'completed');", + f"\treturn response;", + f"}};", + "", + ]) + (ENDPOINTS / f"{group}.ts").write_text("\n".join(lines)) + + +def write_types_ts() -> None: + keys = [key for _, key, _, _, _ in ROUTES] + lines = [ + "import { z } from 'zod';", + "", + "/** Query params vary per sport API; callers pass documented filter fields. */", + "export const ApiSportsQueryInputSchema = z", + "\t.record(", + "\t\tz.string(),", + "\t\tz.union([", + "\t\t\tz.string(),", + "\t\t\tz.number(),", + "\t\t\tz.boolean(),", + "\t\t\tz.array(z.union([z.string(), z.number()])),", + "\t\t]),", + "\t)", + "\t.optional();", + "", + "export type ApiSportsQueryInput = z.infer;", + "", + "export const ApiSportsResponseSchema = z", + "\t.object({", + "\t\tget: z.string().optional(),", + "\t\tparameters: z", + "\t\t\t.union([z.record(z.string(), z.unknown()), z.array(z.unknown())])", + "\t\t\t.optional(),", + "\t\terrors: z.array(z.unknown()).optional(),", + "\t\tresults: z.number().optional(),", + "\t\tpaging: z", + "\t\t\t.object({", + "\t\t\t\tcurrent: z.number().optional(),", + "\t\t\t\ttotal: z.number().optional(),", + "\t\t\t})", + "\t\t\t.optional(),", + "\t\tresponse: z.unknown(),", + "\t})", + "\t.loose();", + "", + "export type ApiSportsResponse = z.infer;", + "", + "export type ApiSportsEndpointInputs = {", + ] + for key in keys: + lines.append(f"\t{key}: ApiSportsQueryInput;") + lines.append("};") + lines.append("") + lines.append("export type ApiSportsEndpointOutputs = {") + for key in keys: + lines.append(f"\t{key}: ApiSportsResponse;") + lines.append("};") + lines.append("") + lines.append("export const ApiSportsEndpointInputSchemas = {") + for key in keys: + lines.append(f"\t{key}: ApiSportsQueryInputSchema,") + lines.append("} as const;") + lines.append("") + lines.append("export const ApiSportsEndpointOutputSchemas = {") + for key in keys: + lines.append(f"\t{key}: ApiSportsResponseSchema,") + lines.append("} as const;") + (ENDPOINTS / "types.ts").write_text("\n".join(lines) + "\n") + + +def write_index_ts() -> None: + groups: dict[str, list[str]] = {} + for group, key, *_ in ROUTES: + groups.setdefault(group, []).append(key) + + imports = [f"import * as {pascal(group)} from './endpoints/{group}';" for group in groups] + nested = [] + schema_lines = [] + meta_lines = [] + + for group, keys in groups.items(): + gp = pascal(group) + nested.append(f"\t{group}: {{") + for key in keys: + nested.append(f"\t\t{key}: {gp}.{key},") + desc = next(d for g, k, _, _, d in ROUTES if g == group and k == key).replace("'", "\\'") + schema_lines.append( + "\t'{}': {{\n\t\tinput: ApiSportsEndpointInputSchemas.{},\n\t\toutput: ApiSportsEndpointOutputSchemas.{},\n\t}},".format( + f"{group}.{key}", key, key + ) + ) + meta_lines.append( + "\t'{}': {{\n\t\t\triskLevel: 'read',\n\t\t\tdescription: '{}',\n\t\t}},".format( + f"{group}.{key}", desc + ) + ) + nested.append("\t},") + + endpoint_types = [f"\t{key}: ApiSportsEndpoint<'{key}'>;" for _, key, *_ in ROUTES] + + content = f"""import type {{ +\tAuthTypes, +\tBindEndpoints, +\tCorsairEndpoint, +\tCorsairErrorHandler, +\tCorsairPlugin, +\tCorsairPluginContext, +\tKeyBuilderContext, +\tPickAuth, +\tPluginAuthConfig, +\tPluginPermissionsConfig, +\tRequiredPluginEndpointMeta, +\tRequiredPluginEndpointSchemas, +}} from 'corsair/core'; +import {{ AuthMissingError }} from 'corsair/core'; +{chr(10).join(imports)} +import type {{ +\tApiSportsEndpointInputs, +\tApiSportsEndpointOutputs, +}} from './endpoints/types'; +import {{ +\tApiSportsEndpointInputSchemas, +\tApiSportsEndpointOutputSchemas, +}} from './endpoints/types'; +import {{ errorHandlers }} from './error-handlers'; +import {{ ApiSportsSchema }} from './schema'; + +export type ApiSportsPluginOptions = {{ +\tauthType?: PickAuth<'api_key'>; +\tkey?: string; +\thooks?: InternalApiSportsPlugin['hooks']; +\terrorHandlers?: CorsairErrorHandler; +\tpermissions?: PluginPermissionsConfig; +}}; + +export type ApiSportsContext = CorsairPluginContext< +\ttypeof ApiSportsSchema, +\tApiSportsPluginOptions +>; + +export type ApiSportsKeyBuilderContext = KeyBuilderContext; + +export type ApiSportsBoundEndpoints = BindEndpoints; + +type ApiSportsEndpoint = CorsairEndpoint< +\tApiSportsContext, +\tApiSportsEndpointInputs[K], +\tApiSportsEndpointOutputs[K] +>; + +export type ApiSportsEndpoints = {{ +{chr(10).join(endpoint_types)} +}}; + +const apiSportsEndpointsNested = {{ +{chr(10).join(nested)} +}} as const; + +const apiSportsWebhooksNested = {{}} as const; + +export const apiSportsEndpointSchemas = {{ +{chr(10).join(schema_lines)} +}} satisfies RequiredPluginEndpointSchemas; + +const apiSportsEndpointMeta = {{ +{chr(10).join(meta_lines)} +}} satisfies RequiredPluginEndpointMeta; + +const defaultAuthType: AuthTypes = 'api_key' as const; + +export const apiSportsAuthConfig = {{ +\tapi_key: {{}}, +}} as const satisfies PluginAuthConfig; + +export type BaseApiSportsPlugin = CorsairPlugin< +\t'api_sports', +\ttypeof ApiSportsSchema, +\ttypeof apiSportsEndpointsNested, +\ttypeof apiSportsWebhooksNested, +\tT, +\ttypeof defaultAuthType +>; + +export type InternalApiSportsPlugin = BaseApiSportsPlugin; + +export type ExternalApiSportsPlugin = +\tBaseApiSportsPlugin; + +export function apiSports( +\tincomingOptions: ApiSportsPluginOptions & +\t\tT = {{}} as ApiSportsPluginOptions & T, +): ExternalApiSportsPlugin {{ +\tconst options = {{ +\t\t...incomingOptions, +\t\tauthType: incomingOptions.authType ?? defaultAuthType, +\t}}; +\treturn {{ +\t\tid: 'api_sports', +\t\tauthConfig: apiSportsAuthConfig, +\t\tschema: ApiSportsSchema, +\t\toptions, +\t\thooks: options.hooks, +\t\twebhookHooks: undefined, +\t\tendpoints: apiSportsEndpointsNested, +\t\twebhooks: apiSportsWebhooksNested, +\t\tendpointMeta: apiSportsEndpointMeta, +\t\tendpointSchemas: apiSportsEndpointSchemas, +\t\tpluginWebhookMatcher: undefined, +\t\terrorHandlers: {{ +\t\t\t...errorHandlers, +\t\t\t...options.errorHandlers, +\t\t}}, +\t\tkeyBuilder: async (ctx: ApiSportsKeyBuilderContext, source) => {{ +\t\t\tif (source === 'endpoint' && options.key) {{ +\t\t\t\treturn options.key; +\t\t\t}} +\t\t\tif (source === 'endpoint' && ctx.authType === 'api_key') {{ +\t\t\t\tconst res = await ctx.keys.get_api_key(); +\t\t\t\treturn res ?? ''; +\t\t\t}} +\t\t\tthrow new AuthMissingError('api_sports', 'api_key'); +\t\t}}, +\t}} satisfies InternalApiSportsPlugin; +}} + +export type {{ +\tApiSportsEndpointInputs, +\tApiSportsEndpointOutputs, +\tApiSportsQueryInput, +\tApiSportsResponse, +}} from './endpoints/types'; + +export {{ +\tApiSportsEndpointInputSchemas, +\tApiSportsEndpointOutputSchemas, +\tApiSportsQueryInputSchema, +\tApiSportsResponseSchema, +}} from './endpoints/types'; +""" + (ROOT / "index.ts").write_text(content) + + +def write_endpoints_index() -> None: + groups = sorted({group for group, *_ in ROUTES}) + lines = [] + for group in groups: + gp = pascal(group) + lines.append(f"export * as {gp} from './{group}';") + lines.append("export * from './types';") + lines.append("export * from './routes';") + (ENDPOINTS / "index.ts").write_text("\n".join(lines) + "\n") + + +def main() -> None: + ENDPOINTS.mkdir(parents=True, exist_ok=True) + write_routes_ts() + write_types_ts() + groups: dict[str, list] = {} + for route in ROUTES: + groups.setdefault(route[0], []).append(route) + for group, routes in groups.items(): + write_group_file(group, routes) + write_endpoints_index() + write_index_ts() + print(f"Generated {len(ROUTES)} endpoints in {len(groups)} groups") + + +if __name__ == "__main__": + main() diff --git a/packages/api_sports/tsconfig.json b/packages/api_sports/tsconfig.json new file mode 100644 index 000000000..46639aa0f --- /dev/null +++ b/packages/api_sports/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["esnext"], + "types": ["node", "jest"], + "module": "ESNext", + "moduleResolution": "Bundler", + "outDir": "./dist", + "rootDir": "./", + "composite": true, + "incremental": true, + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "skipLibCheck": true + }, + "include": ["./**/*"], + "exclude": ["dist", "node_modules", "scripts"], + "references": [] +} diff --git a/packages/api_sports/tsup.config.ts b/packages/api_sports/tsup.config.ts new file mode 100644 index 000000000..3ec221e23 --- /dev/null +++ b/packages/api_sports/tsup.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + clean: false, + dts: false, + format: ['esm'], + target: 'esnext', + platform: 'node', + bundle: true, + splitting: true, + minify: true, + outDir: 'dist', + external: ['corsair', 'zod'], + entry: ['index.ts'], +}); diff --git a/packages/corsair/core/constants.ts b/packages/corsair/core/constants.ts index 9b8edbbe1..c76b776a3 100644 --- a/packages/corsair/core/constants.ts +++ b/packages/corsair/core/constants.ts @@ -17,6 +17,7 @@ export const BaseProviders = [ 'ahrefs', 'airtable', 'amplitude', + 'api_sports', 'asana', 'bitwarden', 'bluesky', @@ -87,6 +88,7 @@ export const ProviderDisplayNames = { ahrefs: 'Ahrefs', airtable: 'Airtable', amplitude: 'Amplitude', + api_sports: 'API-Sports', asana: 'Asana', bitwarden: 'Bitwarden', bluesky: 'Bluesky', @@ -164,6 +166,7 @@ export type AllProviders = | 'ahrefs' | 'airtable' | 'amplitude' + | 'api_sports' | 'asana' | 'bitwarden' | 'bluesky' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ada285871..af8ff96e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,6 +143,9 @@ importers: '@corsair-dev/agentql': specifier: workspace:* version: link:../../packages/agentql + '@corsair-dev/api_sports': + specifier: workspace:* + version: link:../../packages/api_sports '@corsair-dev/bitwarden': specifier: workspace:* version: link:../../packages/bitwarden @@ -305,7 +308,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.28.6)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.28.6))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -329,7 +332,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -353,7 +356,34 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) + tsup: + specifier: ^8.0.1 + version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) + typescript: + specifier: 'catalog:' + version: 5.9.3 + zod: + specifier: ^4.1.13 + version: 4.1.13 + + packages/api_sports: + devDependencies: + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 + corsair: + specifier: workspace:* + version: link:../corsair + dotenv: + specifier: ^17.2.3 + version: 17.4.2 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + ts-jest: + specifier: ^29.4.9 + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -399,7 +429,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -444,7 +474,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -468,7 +498,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -492,7 +522,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -516,7 +546,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -601,7 +631,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -683,7 +713,7 @@ importers: version: 19.2.7(react@19.2.7) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.28.6)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.28.6))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@24.10.1)(typescript@5.9.3) @@ -710,7 +740,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -734,7 +764,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -779,7 +809,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -803,7 +833,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -827,7 +857,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -851,7 +881,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -875,7 +905,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -899,7 +929,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -923,7 +953,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -947,7 +977,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -971,7 +1001,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -995,7 +1025,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1019,7 +1049,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1043,7 +1073,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1067,7 +1097,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1091,7 +1121,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1115,7 +1145,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1145,7 +1175,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1169,7 +1199,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1193,7 +1223,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1217,7 +1247,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1287,7 +1317,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1311,7 +1341,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1335,7 +1365,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1359,7 +1389,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1383,7 +1413,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1407,7 +1437,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1431,7 +1461,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1459,7 +1489,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1483,7 +1513,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.6 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1507,7 +1537,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.6 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1531,7 +1561,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1555,7 +1585,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1579,7 +1609,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1603,7 +1633,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1627,7 +1657,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1651,7 +1681,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1675,7 +1705,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1775,7 +1805,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1799,7 +1829,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1823,7 +1853,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1847,7 +1877,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1871,7 +1901,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1895,7 +1925,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1919,7 +1949,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1943,7 +1973,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1967,7 +1997,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -1991,7 +2021,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2015,7 +2045,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2070,7 +2100,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2094,7 +2124,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2118,7 +2148,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2142,7 +2172,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2166,7 +2196,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2190,7 +2220,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2214,7 +2244,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -2232,7 +2262,7 @@ importers: version: link:../packages/github '@next/third-parties': specifier: 15.3.2 - version: 15.3.2(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) + version: 15.3.2(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) '@phosphor-icons/react': specifier: ^2.1.10 version: 2.1.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -2253,7 +2283,7 @@ importers: version: 11.8.1(typescript@5.9.3) better-auth: specifier: ^1.5.5 - version: 1.6.15(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(better-sqlite3@12.5.0)(drizzle-kit@0.31.8)(drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@libsql/client@0.14.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/better-sqlite3@7.6.13)(@types/pg@8.15.6)(better-sqlite3@12.5.0)(bun-types@1.3.3)(gel@2.2.0)(kysely@0.28.17)(mysql2@3.15.3)(pg@8.21.0)(postgres@3.4.7)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(sqlite3@5.1.7))(mysql2@3.15.3)(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.21.0)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 1.6.15(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(better-sqlite3@12.5.0)(drizzle-kit@0.31.8)(drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@libsql/client@0.14.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/better-sqlite3@7.6.13)(@types/pg@8.15.6)(better-sqlite3@12.5.0)(bun-types@1.3.3)(gel@2.2.0)(kysely@0.28.17)(mysql2@3.15.3)(pg@8.21.0)(postgres@3.4.7)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(sqlite3@5.1.7))(mysql2@3.15.3)(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.21.0)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -2271,13 +2301,13 @@ importers: version: 0.44.7(@cloudflare/workers-types@4.20251121.0)(@libsql/client@0.14.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/better-sqlite3@7.6.13)(@types/pg@8.15.6)(better-sqlite3@12.5.0)(bun-types@1.3.3)(gel@2.2.0)(kysely@0.28.17)(mysql2@3.15.3)(pg@8.21.0)(postgres@3.4.7)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(sqlite3@5.1.7) inngest: specifier: ^3.54.0 - version: 3.54.2(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(express@5.2.1)(hono@4.12.2)(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)(zod@4.4.3) + version: 3.54.2(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(express@5.2.1)(hono@4.12.2)(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)(zod@4.4.3) next: specifier: ^15.3.2 - version: 15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next-sanity: specifier: ^11.6.13 - version: 11.6.13(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/icons@3.7.4(react@19.2.5))(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 11.6.13(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/icons@3.7.4(react@19.2.5))(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) pg: specifier: ^8.20.0 version: 8.21.0 @@ -16392,9 +16422,9 @@ snapshots: '@next/swc-win32-x64-msvc@15.5.18': optional: true - '@next/third-parties@15.3.2(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)': + '@next/third-parties@15.3.2(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)': dependencies: - next: 15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 third-party-capital: 1.0.20 @@ -19042,7 +19072,7 @@ snapshots: optionalDependencies: '@sanity/types': 6.2.0(@types/react@19.2.6) - '@sanity/visual-editing@4.0.3(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@sanity/visual-editing@4.0.3(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: '@sanity/comlink': 4.0.1 '@sanity/icons': 3.7.4(react@19.2.5) @@ -19064,7 +19094,7 @@ snapshots: xstate: 5.32.2 optionalDependencies: '@sanity/client': 7.23.0 - next: 15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) transitivePeerDependencies: - '@emotion/is-prop-valid' - '@sanity/types' @@ -20104,7 +20134,7 @@ snapshots: before-after-hook@4.0.0: {} - better-auth@1.6.15(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(better-sqlite3@12.5.0)(drizzle-kit@0.31.8)(drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@libsql/client@0.14.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/better-sqlite3@7.6.13)(@types/pg@8.15.6)(better-sqlite3@12.5.0)(bun-types@1.3.3)(gel@2.2.0)(kysely@0.28.17)(mysql2@3.15.3)(pg@8.21.0)(postgres@3.4.7)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(sqlite3@5.1.7))(mysql2@3.15.3)(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.21.0)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + better-auth@1.6.15(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(better-sqlite3@12.5.0)(drizzle-kit@0.31.8)(drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@libsql/client@0.14.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/better-sqlite3@7.6.13)(@types/pg@8.15.6)(better-sqlite3@12.5.0)(bun-types@1.3.3)(gel@2.2.0)(kysely@0.28.17)(mysql2@3.15.3)(pg@8.21.0)(postgres@3.4.7)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(sqlite3@5.1.7))(mysql2@3.15.3)(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.21.0)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@better-auth/core': 1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.1)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/drizzle-adapter': 1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.1)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@libsql/client@0.14.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/better-sqlite3@7.6.13)(@types/pg@8.15.6)(better-sqlite3@12.5.0)(bun-types@1.3.3)(gel@2.2.0)(kysely@0.28.17)(mysql2@3.15.3)(pg@8.21.0)(postgres@3.4.7)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(sqlite3@5.1.7)) @@ -20129,7 +20159,7 @@ snapshots: drizzle-kit: 0.31.8 drizzle-orm: 0.44.7(@cloudflare/workers-types@4.20251121.0)(@libsql/client@0.14.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@6.19.0(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(typescript@5.9.3))(@types/better-sqlite3@7.6.13)(@types/pg@8.15.6)(better-sqlite3@12.5.0)(bun-types@1.3.3)(gel@2.2.0)(kysely@0.28.17)(mysql2@3.15.3)(pg@8.21.0)(postgres@3.4.7)(prisma@6.19.0(magicast@0.3.5)(typescript@5.9.3))(sqlite3@5.1.7) mysql2: 3.15.3 - next: 15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) pg: 8.21.0 prisma: 6.19.0(magicast@0.3.5)(typescript@5.9.3) react: 19.2.5 @@ -22017,7 +22047,7 @@ snapshots: - encoding - supports-color - inngest@3.54.2(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(express@5.2.1)(hono@4.12.2)(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)(zod@4.4.3): + inngest@3.54.2(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(express@5.2.1)(hono@4.12.2)(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)(zod@4.4.3): dependencies: '@bufbuild/protobuf': 2.11.0 '@inngest/ai': 0.1.7 @@ -22048,7 +22078,7 @@ snapshots: optionalDependencies: express: 5.2.1 hono: 4.12.2 - next: 15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) typescript: 5.9.3 transitivePeerDependencies: - '@opentelemetry/core' @@ -23268,18 +23298,18 @@ snapshots: neo-async@2.6.2: {} - next-sanity@11.6.13(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/icons@3.7.4(react@19.2.5))(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3): + next-sanity@11.6.13(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/icons@3.7.4(react@19.2.5))(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3): dependencies: '@portabletext/react': 6.2.0(react@19.2.5) '@sanity/client': 7.23.0 '@sanity/comlink': 4.0.1 '@sanity/presentation-comlink': 2.1.0(@sanity/client@7.23.0)(@sanity/types@6.2.0(@types/react@19.2.6)) '@sanity/preview-url-secret': 3.0.0(@sanity/client@7.23.0)(@sanity/icons@3.7.4(react@19.2.5))(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0)) - '@sanity/visual-editing': 4.0.3(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@sanity/visual-editing': 4.0.3(@emotion/is-prop-valid@1.4.0)(@sanity/client@7.23.0)(@sanity/types@6.2.0(@types/react@19.2.6))(next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.7)(react@19.2.5)(sanity@4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0))(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) dequal: 2.0.3 groq: 4.22.0 history: 5.3.0 - next: 15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) sanity: 4.22.0(@emotion/is-prop-valid@1.4.0)(@portabletext/sanity-bridge@1.2.14(@types/react@19.2.6))(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.4.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -23323,7 +23353,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.5.18(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + next@15.5.18(@babel/core@7.29.7)(@opentelemetry/api@1.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@next/env': 15.5.18 '@swc/helpers': 0.5.15 @@ -23331,7 +23361,7 @@ snapshots: postcss: 8.4.31 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - styled-jsx: 5.1.6(@babel/core@7.28.6)(react@19.2.5) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.5) optionalDependencies: '@next/swc-darwin-arm64': 15.5.18 '@next/swc-darwin-x64': 15.5.18 @@ -25189,12 +25219,12 @@ snapshots: client-only: 0.0.1 react: 18.3.1 - styled-jsx@5.1.6(@babel/core@7.28.6)(react@19.2.5): + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.5): dependencies: client-only: 0.0.1 react: 19.2.5 optionalDependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.7 stylis@4.3.6: {} @@ -25421,7 +25451,7 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.28.6) jest-util: 30.4.1 - ts-jest@29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1))(typescript@5.9.3): + ts-jest@29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 From 9f4ae2754b864edb9ae366bff0a4c154bf856d2c Mon Sep 17 00:00:00 2001 From: Ayush7614 Date: Sun, 5 Jul 2026 17:42:31 +0530 Subject: [PATCH 2/9] fix(api_sports): address Greptile review on PR #359 Route getGameStatisticsByTeams to basketball /games/statistics/teams, throw AuthMissingError when API key is absent, and use console.error for auth failures. --- packages/api_sports/endpoints/routes.ts | 6 +++++- packages/api_sports/error-handlers.ts | 2 +- packages/api_sports/index.ts | 5 ++++- packages/api_sports/scripts/generate-endpoints.py | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/api_sports/endpoints/routes.ts b/packages/api_sports/endpoints/routes.ts index 84a5b2b23..0cafbdd9c 100644 --- a/packages/api_sports/endpoints/routes.ts +++ b/packages/api_sports/endpoints/routes.ts @@ -52,7 +52,11 @@ export const API_SPORTS_ROUTES = { getBasketballBookmakers: { sport: 'basketball', path: '/bookmakers', description: "Get Basketball Bookmakers" }, getNbaGameStatistics: { sport: 'nba', path: '/games/statistics', description: "Get NBA Game Statistics" }, getPlayerStatistics: { sport: 'nba', path: '/players/statistics', description: "Get Player Statistics" }, - getGameStatisticsByTeams: { sport: 'nba', path: '/games/statistics', description: "Get Game Statistics by Teams" }, + getGameStatisticsByTeams: { + sport: 'basketball', + path: '/games/statistics/teams', + description: 'Get Game Statistics by Teams', + }, getGamesEvents: { sport: 'nba', path: '/games/events', description: "Get Games Events" }, getAflSeasons: { sport: 'afl', path: '/seasons', description: "Get AFL Seasons" }, getAflGames: { sport: 'afl', path: '/games', description: "Get AFL Games" }, diff --git a/packages/api_sports/error-handlers.ts b/packages/api_sports/error-handlers.ts index 0c020b7eb..089979710 100644 --- a/packages/api_sports/error-handlers.ts +++ b/packages/api_sports/error-handlers.ts @@ -36,7 +36,7 @@ export const errorHandlers = { ); }, handler: async () => { - console.log('[API_SPORTS] Authentication failed — check your x-apisports-key.'); + console.error('[API_SPORTS] Authentication failed — check your x-apisports-key.'); return { maxRetries: 0 }; }, }, diff --git a/packages/api_sports/index.ts b/packages/api_sports/index.ts index 42b0d5650..1110b0b71 100644 --- a/packages/api_sports/index.ts +++ b/packages/api_sports/index.ts @@ -811,7 +811,10 @@ export function apiSports( } if (source === 'endpoint' && ctx.authType === 'api_key') { const res = await ctx.keys.get_api_key(); - return res ?? ''; + if (!res) { + throw new AuthMissingError('api_sports', 'api_key'); + } + return res; } throw new AuthMissingError('api_sports', 'api_key'); }, diff --git a/packages/api_sports/scripts/generate-endpoints.py b/packages/api_sports/scripts/generate-endpoints.py index 53880a053..5633adfe5 100644 --- a/packages/api_sports/scripts/generate-endpoints.py +++ b/packages/api_sports/scripts/generate-endpoints.py @@ -62,7 +62,7 @@ ("basketball", "getBasketballBookmakers", "basketball", "/bookmakers", "Get Basketball Bookmakers"), ("basketball", "getNbaGameStatistics", "nba", "/games/statistics", "Get NBA Game Statistics"), ("basketball", "getPlayerStatistics", "nba", "/players/statistics", "Get Player Statistics"), - ("basketball", "getGameStatisticsByTeams", "nba", "/games/statistics", "Get Game Statistics by Teams"), + ("basketball", "getGameStatisticsByTeams", "basketball", "/games/statistics/teams", "Get Game Statistics by Teams"), ("basketball", "getGamesEvents", "nba", "/games/events", "Get Games Events"), # AFL ("afl", "getAflSeasons", "afl", "/seasons", "Get AFL Seasons"), From 2529a7cb1856b0597e6dc43dadac3b06a2f65be1 Mon Sep 17 00:00:00 2001 From: Ayush7614 Date: Tue, 7 Jul 2026 01:25:15 +0530 Subject: [PATCH 3/9] fix: add selective DB caching for API-Sports queries Cache sport/path/query lookups via ctx.db.queries upserts following the Slack plugin pattern; remove generator script from PR. --- packages/api_sports/endpoints/afl.ts | 17 +- packages/api_sports/endpoints/baseball.ts | 5 +- packages/api_sports/endpoints/basketball.ts | 23 +- packages/api_sports/endpoints/core.ts | 44 +- packages/api_sports/endpoints/fixtures.ts | 23 +- packages/api_sports/endpoints/formula1.ts | 26 +- packages/api_sports/endpoints/mma.ts | 20 +- packages/api_sports/endpoints/odds.ts | 20 +- packages/api_sports/endpoints/players.ts | 29 +- packages/api_sports/endpoints/shared.ts | 55 +++ packages/api_sports/endpoints/standings.ts | 14 +- .../api_sports/scripts/generate-endpoints.py | 409 ------------------ 12 files changed, 199 insertions(+), 486 deletions(-) create mode 100644 packages/api_sports/endpoints/shared.ts delete mode 100644 packages/api_sports/scripts/generate-endpoints.py diff --git a/packages/api_sports/endpoints/afl.ts b/packages/api_sports/endpoints/afl.ts index 6d8231301..b737d086a 100644 --- a/packages/api_sports/endpoints/afl.ts +++ b/packages/api_sports/endpoints/afl.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get AFL Seasons */ export const getAflSeasons: ApiSportsEndpoints['getAflSeasons'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getAflSeasons; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getAflSeasons: ApiSportsEndpoints['getAflSeasons'] = async (ctx, in /** Get AFL Games */ export const getAflGames: ApiSportsEndpoints['getAflGames'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getAflGames; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getAflGames: ApiSportsEndpoints['getAflGames'] = async (ctx, input) /** Get AFL Games Quarters */ export const getAflGamesQuarters: ApiSportsEndpoints['getAflGamesQuarters'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getAflGamesQuarters; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getAflGamesQuarters: ApiSportsEndpoints['getAflGamesQuarters'] = as /** Get AFL Game Player Statistics */ export const getAflGamePlayerStatistics: ApiSportsEndpoints['getAflGamePlayerStatistics'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getAflGamePlayerStatistics; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getAflGamePlayerStatistics: ApiSportsEndpoints['getAflGamePlayerSta /** Get AFL Standings */ export const getAflStandings: ApiSportsEndpoints['getAflStandings'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getAflStandings; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/baseball.ts b/packages/api_sports/endpoints/baseball.ts index a44ae2b2d..beb3a6697 100644 --- a/packages/api_sports/endpoints/baseball.ts +++ b/packages/api_sports/endpoints/baseball.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Baseball Games Head-to-Head */ export const getBaseballGamesHeadToHead: ApiSportsEndpoints['getBaseballGamesHeadToHead'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getBaseballGamesHeadToHead; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/basketball.ts b/packages/api_sports/endpoints/basketball.ts index 946496cd6..6de7c9522 100644 --- a/packages/api_sports/endpoints/basketball.ts +++ b/packages/api_sports/endpoints/basketball.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Basketball Statistics */ export const getBasketballStatistics: ApiSportsEndpoints['getBasketballStatistics'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getBasketballStatistics; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getBasketballStatistics: ApiSportsEndpoints['getBasketballStatistic /** Get Basketball Bets */ export const getBasketballBets: ApiSportsEndpoints['getBasketballBets'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getBasketballBets; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getBasketballBets: ApiSportsEndpoints['getBasketballBets'] = async /** Get Basketball Bookmakers */ export const getBasketballBookmakers: ApiSportsEndpoints['getBasketballBookmakers'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getBasketballBookmakers; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getBasketballBookmakers: ApiSportsEndpoints['getBasketballBookmaker /** Get NBA Game Statistics */ export const getNbaGameStatistics: ApiSportsEndpoints['getNbaGameStatistics'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getNbaGameStatistics; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getNbaGameStatistics: ApiSportsEndpoints['getNbaGameStatistics'] = /** Get Player Statistics */ export const getPlayerStatistics: ApiSportsEndpoints['getPlayerStatistics'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayerStatistics; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -67,7 +72,8 @@ export const getPlayerStatistics: ApiSportsEndpoints['getPlayerStatistics'] = as /** Get Game Statistics by Teams */ export const getGameStatisticsByTeams: ApiSportsEndpoints['getGameStatisticsByTeams'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getGameStatisticsByTeams; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -79,7 +85,8 @@ export const getGameStatisticsByTeams: ApiSportsEndpoints['getGameStatisticsByTe /** Get Games Events */ export const getGamesEvents: ApiSportsEndpoints['getGamesEvents'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getGamesEvents; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/core.ts b/packages/api_sports/endpoints/core.ts index 11933ddac..336e177ce 100644 --- a/packages/api_sports/endpoints/core.ts +++ b/packages/api_sports/endpoints/core.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Countries */ export const getCountries: ApiSportsEndpoints['getCountries'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getCountries; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getCountries: ApiSportsEndpoints['getCountries'] = async (ctx, inpu /** Get Timezone */ export const getTimezone: ApiSportsEndpoints['getTimezone'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getTimezone; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getTimezone: ApiSportsEndpoints['getTimezone'] = async (ctx, input) /** Get Leagues */ export const getLeagues: ApiSportsEndpoints['getLeagues'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getLeagues; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getLeagues: ApiSportsEndpoints['getLeagues'] = async (ctx, input) = /** Get League Seasons */ export const getLeagueSeasons: ApiSportsEndpoints['getLeagueSeasons'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getLeagueSeasons; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getLeagueSeasons: ApiSportsEndpoints['getLeagueSeasons'] = async (c /** Get Teams */ export const getTeams: ApiSportsEndpoints['getTeams'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getTeams; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -67,7 +72,8 @@ export const getTeams: ApiSportsEndpoints['getTeams'] = async (ctx, input) => { /** Get Team Seasons */ export const getTeamSeasons: ApiSportsEndpoints['getTeamSeasons'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getTeamSeasons; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -79,7 +85,8 @@ export const getTeamSeasons: ApiSportsEndpoints['getTeamSeasons'] = async (ctx, /** Get Team Statistics */ export const getTeamStatistics: ApiSportsEndpoints['getTeamStatistics'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getTeamStatistics; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -91,7 +98,8 @@ export const getTeamStatistics: ApiSportsEndpoints['getTeamStatistics'] = async /** Get Venues */ export const getVenues: ApiSportsEndpoints['getVenues'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getVenues; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -103,7 +111,8 @@ export const getVenues: ApiSportsEndpoints['getVenues'] = async (ctx, input) => /** Get Coaches */ export const getCoaches: ApiSportsEndpoints['getCoaches'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getCoaches; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -115,7 +124,8 @@ export const getCoaches: ApiSportsEndpoints['getCoaches'] = async (ctx, input) = /** Get Injuries */ export const getInjuries: ApiSportsEndpoints['getInjuries'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getInjuries; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -127,7 +137,8 @@ export const getInjuries: ApiSportsEndpoints['getInjuries'] = async (ctx, input) /** Get Sidelined */ export const getSidelined: ApiSportsEndpoints['getSidelined'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getSidelined; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -139,7 +150,8 @@ export const getSidelined: ApiSportsEndpoints['getSidelined'] = async (ctx, inpu /** Get Transfers */ export const getTransfers: ApiSportsEndpoints['getTransfers'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getTransfers; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -151,7 +163,8 @@ export const getTransfers: ApiSportsEndpoints['getTransfers'] = async (ctx, inpu /** Get Trophies */ export const getTrophies: ApiSportsEndpoints['getTrophies'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getTrophies; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -163,7 +176,8 @@ export const getTrophies: ApiSportsEndpoints['getTrophies'] = async (ctx, input) /** Get Predictions */ export const getPredictions: ApiSportsEndpoints['getPredictions'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPredictions; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/fixtures.ts b/packages/api_sports/endpoints/fixtures.ts index 85d644bd7..f98737dc4 100644 --- a/packages/api_sports/endpoints/fixtures.ts +++ b/packages/api_sports/endpoints/fixtures.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Fixtures */ export const getFixtures: ApiSportsEndpoints['getFixtures'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFixtures; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getFixtures: ApiSportsEndpoints['getFixtures'] = async (ctx, input) /** Get Fixtures Rounds */ export const getFixturesRounds: ApiSportsEndpoints['getFixturesRounds'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFixturesRounds; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getFixturesRounds: ApiSportsEndpoints['getFixturesRounds'] = async /** Get Head-to-Head Fixtures */ export const getHeadToHeadFixtures: ApiSportsEndpoints['getHeadToHeadFixtures'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getHeadToHeadFixtures; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getHeadToHeadFixtures: ApiSportsEndpoints['getHeadToHeadFixtures'] /** Get Fixture Lineups */ export const getFixtureLineups: ApiSportsEndpoints['getFixtureLineups'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFixtureLineups; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getFixtureLineups: ApiSportsEndpoints['getFixtureLineups'] = async /** Get Fixture Statistics */ export const getFixtureStatistics: ApiSportsEndpoints['getFixtureStatistics'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFixtureStatistics; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -67,7 +72,8 @@ export const getFixtureStatistics: ApiSportsEndpoints['getFixtureStatistics'] = /** Get Fixtures Events */ export const getFixturesEvents: ApiSportsEndpoints['getFixturesEvents'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFixturesEvents; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -79,7 +85,8 @@ export const getFixturesEvents: ApiSportsEndpoints['getFixturesEvents'] = async /** Get Fixtures Players */ export const getFixturesPlayers: ApiSportsEndpoints['getFixturesPlayers'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFixturesPlayers; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/formula1.ts b/packages/api_sports/endpoints/formula1.ts index 996e0fe68..211a9c95f 100644 --- a/packages/api_sports/endpoints/formula1.ts +++ b/packages/api_sports/endpoints/formula1.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Formula 1 Circuits */ export const getFormula1Circuits: ApiSportsEndpoints['getFormula1Circuits'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFormula1Circuits; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getFormula1Circuits: ApiSportsEndpoints['getFormula1Circuits'] = as /** Get Formula 1 Competitions */ export const getFormula1Competitions: ApiSportsEndpoints['getFormula1Competitions'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFormula1Competitions; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getFormula1Competitions: ApiSportsEndpoints['getFormula1Competition /** Get Formula 1 Races */ export const getFormula1Races: ApiSportsEndpoints['getFormula1Races'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFormula1Races; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getFormula1Races: ApiSportsEndpoints['getFormula1Races'] = async (c /** Get Formula 1 Driver Rankings */ export const getFormula1DriverRankings: ApiSportsEndpoints['getFormula1DriverRankings'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFormula1DriverRankings; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getFormula1DriverRankings: ApiSportsEndpoints['getFormula1DriverRan /** Get Formula 1 Team Rankings */ export const getFormula1TeamRankings: ApiSportsEndpoints['getFormula1TeamRankings'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFormula1TeamRankings; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -67,7 +72,8 @@ export const getFormula1TeamRankings: ApiSportsEndpoints['getFormula1TeamRanking /** Get Formula 1 Starting Grid */ export const getFormula1StartingGrid: ApiSportsEndpoints['getFormula1StartingGrid'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFormula1StartingGrid; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -79,7 +85,8 @@ export const getFormula1StartingGrid: ApiSportsEndpoints['getFormula1StartingGri /** Get Fastest Laps Rankings */ export const getFastestLapsRankings: ApiSportsEndpoints['getFastestLapsRankings'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFastestLapsRankings; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -91,7 +98,8 @@ export const getFastestLapsRankings: ApiSportsEndpoints['getFastestLapsRankings' /** Get Race Rankings */ export const getRaceRankings: ApiSportsEndpoints['getRaceRankings'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getRaceRankings; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/mma.ts b/packages/api_sports/endpoints/mma.ts index ddf0399ff..6540a232e 100644 --- a/packages/api_sports/endpoints/mma.ts +++ b/packages/api_sports/endpoints/mma.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get MMA Categories */ export const getMmaCategories: ApiSportsEndpoints['getMmaCategories'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getMmaCategories; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getMmaCategories: ApiSportsEndpoints['getMmaCategories'] = async (c /** Get MMA Fighters */ export const getMmaFighters: ApiSportsEndpoints['getMmaFighters'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getMmaFighters; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getMmaFighters: ApiSportsEndpoints['getMmaFighters'] = async (ctx, /** Get MMA Fights */ export const getMmaFights: ApiSportsEndpoints['getMmaFights'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getMmaFights; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getMmaFights: ApiSportsEndpoints['getMmaFights'] = async (ctx, inpu /** Get MMA Fight Results */ export const getMmaFightResults: ApiSportsEndpoints['getMmaFightResults'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getMmaFightResults; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getMmaFightResults: ApiSportsEndpoints['getMmaFightResults'] = asyn /** Get MMA Fighter Statistics */ export const getMmaFighterStatistics: ApiSportsEndpoints['getMmaFighterStatistics'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getMmaFighterStatistics; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -67,7 +72,8 @@ export const getMmaFighterStatistics: ApiSportsEndpoints['getMmaFighterStatistic /** Get Fighters Records */ export const getFightersRecords: ApiSportsEndpoints['getFightersRecords'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getFightersRecords; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/odds.ts b/packages/api_sports/endpoints/odds.ts index 79544ad9d..3f8c10603 100644 --- a/packages/api_sports/endpoints/odds.ts +++ b/packages/api_sports/endpoints/odds.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Odds */ export const getOdds: ApiSportsEndpoints['getOdds'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getOdds; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getOdds: ApiSportsEndpoints['getOdds'] = async (ctx, input) => { /** Get Odds Bets */ export const getOddsBets: ApiSportsEndpoints['getOddsBets'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getOddsBets; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getOddsBets: ApiSportsEndpoints['getOddsBets'] = async (ctx, input) /** Get Odds Bookmakers */ export const getOddsBookmakers: ApiSportsEndpoints['getOddsBookmakers'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getOddsBookmakers; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getOddsBookmakers: ApiSportsEndpoints['getOddsBookmakers'] = async /** Get Odds Mapping */ export const getOddsMapping: ApiSportsEndpoints['getOddsMapping'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getOddsMapping; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getOddsMapping: ApiSportsEndpoints['getOddsMapping'] = async (ctx, /** Get In-Play Odds */ export const getInPlayOdds: ApiSportsEndpoints['getInPlayOdds'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getInPlayOdds; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -67,7 +72,8 @@ export const getInPlayOdds: ApiSportsEndpoints['getInPlayOdds'] = async (ctx, in /** Get Live Odds Bets */ export const getLiveOddsBets: ApiSportsEndpoints['getLiveOddsBets'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getLiveOddsBets; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/players.ts b/packages/api_sports/endpoints/players.ts index 1c7c040c6..e06f18a7e 100644 --- a/packages/api_sports/endpoints/players.ts +++ b/packages/api_sports/endpoints/players.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Players */ export const getPlayers: ApiSportsEndpoints['getPlayers'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayers; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getPlayers: ApiSportsEndpoints['getPlayers'] = async (ctx, input) = /** Get Players Profiles */ export const getPlayersProfiles: ApiSportsEndpoints['getPlayersProfiles'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersProfiles; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getPlayersProfiles: ApiSportsEndpoints['getPlayersProfiles'] = asyn /** Get Players Seasons */ export const getPlayersSeasons: ApiSportsEndpoints['getPlayersSeasons'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersSeasons; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getPlayersSeasons: ApiSportsEndpoints['getPlayersSeasons'] = async /** Get Players Squads */ export const getPlayersSquads: ApiSportsEndpoints['getPlayersSquads'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersSquads; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -55,7 +59,8 @@ export const getPlayersSquads: ApiSportsEndpoints['getPlayersSquads'] = async (c /** Get Players Teams */ export const getPlayersTeams: ApiSportsEndpoints['getPlayersTeams'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersTeams; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -67,7 +72,8 @@ export const getPlayersTeams: ApiSportsEndpoints['getPlayersTeams'] = async (ctx /** Get Players Top Scorers */ export const getPlayersTopScorers: ApiSportsEndpoints['getPlayersTopScorers'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersTopScorers; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -79,7 +85,8 @@ export const getPlayersTopScorers: ApiSportsEndpoints['getPlayersTopScorers'] = /** Get Players Top Assists */ export const getPlayersTopAssists: ApiSportsEndpoints['getPlayersTopAssists'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersTopAssists; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -91,7 +98,8 @@ export const getPlayersTopAssists: ApiSportsEndpoints['getPlayersTopAssists'] = /** Get Players Top Yellow Cards */ export const getPlayersTopYellowCards: ApiSportsEndpoints['getPlayersTopYellowCards'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersTopYellowCards; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -103,7 +111,8 @@ export const getPlayersTopYellowCards: ApiSportsEndpoints['getPlayersTopYellowCa /** Get Players Top Red Cards */ export const getPlayersTopRedCards: ApiSportsEndpoints['getPlayersTopRedCards'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getPlayersTopRedCards; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/endpoints/shared.ts b/packages/api_sports/endpoints/shared.ts new file mode 100644 index 000000000..43753ecf0 --- /dev/null +++ b/packages/api_sports/endpoints/shared.ts @@ -0,0 +1,55 @@ +import { makeApiSportsRequest, type ApiSport, type ApiSportsQueryValue } from '../client'; +import type { ApiSportsContext } from '../index'; + +function stableQueryKey(query: Record | undefined) { + if (!query) return ''; + return JSON.stringify( + Object.keys(query) + .sort() + .reduce>((acc, key) => { + acc[key] = query[key]; + return acc; + }, {}), + ); +} + +export function buildQueryEntityId( + sport: ApiSport, + path: string, + query: Record | undefined, +) { + return `${sport}:${path}:${stableQueryKey(query)}`; +} + +export async function cacheApiSportsQuery( + ctx: ApiSportsContext, + sport: ApiSport, + path: string, + query: Record | undefined, +) { + if (!ctx.db.queries) return; + + try { + await ctx.db.queries.upsertByEntityId(buildQueryEntityId(sport, path, query), { + sport, + path, + queriedAt: new Date(), + }); + } catch (error) { + console.warn('[api_sports] Failed to save query to database:', error); + } +} + +export async function executeApiSportsRequest( + ctx: ApiSportsContext, + sport: ApiSport, + path: string, + options: { + apiKey?: string; + query?: Record; + } = {}, +): Promise { + const response = await makeApiSportsRequest(sport, path, options); + await cacheApiSportsQuery(ctx, sport, path, options.query); + return response; +} diff --git a/packages/api_sports/endpoints/standings.ts b/packages/api_sports/endpoints/standings.ts index 19be6d91a..cc4497e1c 100644 --- a/packages/api_sports/endpoints/standings.ts +++ b/packages/api_sports/endpoints/standings.ts @@ -1,5 +1,5 @@ import { logEventFromContext } from 'corsair/core'; -import { makeApiSportsRequest } from '../client'; +import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; @@ -7,7 +7,8 @@ import { API_SPORTS_ROUTES } from './routes'; /** Get Standings Stages */ export const getStandingsStages: ApiSportsEndpoints['getStandingsStages'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getStandingsStages; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -19,7 +20,8 @@ export const getStandingsStages: ApiSportsEndpoints['getStandingsStages'] = asyn /** Get Standings Groups */ export const getStandingsGroups: ApiSportsEndpoints['getStandingsGroups'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getStandingsGroups; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -31,7 +33,8 @@ export const getStandingsGroups: ApiSportsEndpoints['getStandingsGroups'] = asyn /** Get Standings Divisions */ export const getStandingsDivisions: ApiSportsEndpoints['getStandingsDivisions'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getStandingsDivisions; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, @@ -43,7 +46,8 @@ export const getStandingsDivisions: ApiSportsEndpoints['getStandingsDivisions'] /** Get NFL Standings Conferences */ export const getNflStandingsConferences: ApiSportsEndpoints['getNflStandingsConferences'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getNflStandingsConferences; - const response = await makeApiSportsRequest( + const response = await executeApiSportsRequest( + ctx, route.sport, route.path, { apiKey: ctx.key, query: input }, diff --git a/packages/api_sports/scripts/generate-endpoints.py b/packages/api_sports/scripts/generate-endpoints.py deleted file mode 100644 index 5633adfe5..000000000 --- a/packages/api_sports/scripts/generate-endpoints.py +++ /dev/null @@ -1,409 +0,0 @@ -#!/usr/bin/env python3 -"""One-shot generator for API-Sports endpoint modules.""" - -from __future__ import annotations - -import json -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -ENDPOINTS = ROOT / "endpoints" - -# (group, key, sport, path, description) -ROUTES: list[tuple[str, str, str, str, str]] = [ - # Football / core - ("core", "getCountries", "football", "/countries", "Get Countries"), - ("core", "getTimezone", "football", "/timezone", "Get Timezone"), - ("core", "getLeagues", "football", "/leagues", "Get Leagues"), - ("core", "getLeagueSeasons", "football", "/leagues/seasons", "Get League Seasons"), - ("core", "getTeams", "football", "/teams", "Get Teams"), - ("core", "getTeamSeasons", "football", "/teams/seasons", "Get Team Seasons"), - ("core", "getTeamStatistics", "football", "/teams/statistics", "Get Team Statistics"), - ("core", "getVenues", "football", "/venues", "Get Venues"), - ("core", "getCoaches", "football", "/coachs", "Get Coaches"), - ("core", "getInjuries", "football", "/injuries", "Get Injuries"), - ("core", "getSidelined", "football", "/sidelined", "Get Sidelined"), - ("core", "getTransfers", "football", "/transfers", "Get Transfers"), - ("core", "getTrophies", "football", "/trophies", "Get Trophies"), - ("core", "getPredictions", "football", "/predictions", "Get Predictions"), - # Fixtures - ("fixtures", "getFixtures", "football", "/fixtures", "Get Fixtures"), - ("fixtures", "getFixturesRounds", "football", "/fixtures/rounds", "Get Fixtures Rounds"), - ("fixtures", "getHeadToHeadFixtures", "football", "/fixtures/headtohead", "Get Head-to-Head Fixtures"), - ("fixtures", "getFixtureLineups", "football", "/fixtures/lineups", "Get Fixture Lineups"), - ("fixtures", "getFixtureStatistics", "football", "/fixtures/statistics", "Get Fixture Statistics"), - ("fixtures", "getFixturesEvents", "football", "/fixtures/events", "Get Fixtures Events"), - ("fixtures", "getFixturesPlayers", "football", "/fixtures/players", "Get Fixtures Players"), - # NFL standings helpers - ("standings", "getStandingsStages", "nfl", "/standings/stages", "Get Standings Stages"), - ("standings", "getStandingsGroups", "nfl", "/standings/groups", "Get Standings Groups"), - ("standings", "getStandingsDivisions", "nfl", "/standings/divisions", "Get Standings Divisions"), - ("standings", "getNflStandingsConferences", "nfl", "/standings/conferences", "Get NFL Standings Conferences"), - # Players - ("players", "getPlayers", "football", "/players", "Get Players"), - ("players", "getPlayersProfiles", "football", "/players/profiles", "Get Players Profiles"), - ("players", "getPlayersSeasons", "football", "/players/seasons", "Get Players Seasons"), - ("players", "getPlayersSquads", "football", "/players/squads", "Get Players Squads"), - ("players", "getPlayersTeams", "football", "/players/teams", "Get Players Teams"), - ("players", "getPlayersTopScorers", "football", "/players/topscorers", "Get Players Top Scorers"), - ("players", "getPlayersTopAssists", "football", "/players/topassists", "Get Players Top Assists"), - ("players", "getPlayersTopYellowCards", "football", "/players/topyellowcards", "Get Players Top Yellow Cards"), - ("players", "getPlayersTopRedCards", "football", "/players/topredcards", "Get Players Top Red Cards"), - # Odds - ("odds", "getOdds", "football", "/odds", "Get Odds"), - ("odds", "getOddsBets", "football", "/odds/bets", "Get Odds Bets"), - ("odds", "getOddsBookmakers", "football", "/odds/bookmakers", "Get Odds Bookmakers"), - ("odds", "getOddsMapping", "football", "/odds/mapping", "Get Odds Mapping"), - ("odds", "getInPlayOdds", "football", "/odds/live", "Get In-Play Odds"), - ("odds", "getLiveOddsBets", "football", "/odds/live/bets", "Get Live Odds Bets"), - # Basketball / NBA - ("basketball", "getBasketballStatistics", "basketball", "/statistics", "Get Basketball Statistics"), - ("basketball", "getBasketballBets", "basketball", "/bets", "Get Basketball Bets"), - ("basketball", "getBasketballBookmakers", "basketball", "/bookmakers", "Get Basketball Bookmakers"), - ("basketball", "getNbaGameStatistics", "nba", "/games/statistics", "Get NBA Game Statistics"), - ("basketball", "getPlayerStatistics", "nba", "/players/statistics", "Get Player Statistics"), - ("basketball", "getGameStatisticsByTeams", "basketball", "/games/statistics/teams", "Get Game Statistics by Teams"), - ("basketball", "getGamesEvents", "nba", "/games/events", "Get Games Events"), - # AFL - ("afl", "getAflSeasons", "afl", "/seasons", "Get AFL Seasons"), - ("afl", "getAflGames", "afl", "/games", "Get AFL Games"), - ("afl", "getAflGamesQuarters", "afl", "/games/quarters", "Get AFL Games Quarters"), - ("afl", "getAflGamePlayerStatistics", "afl", "/games/statistics/players", "Get AFL Game Player Statistics"), - ("afl", "getAflStandings", "afl", "/standings", "Get AFL Standings"), - # Baseball - ("baseball", "getBaseballGamesHeadToHead", "baseball", "/games/h2h", "Get Baseball Games Head-to-Head"), - # Formula 1 - ("formula1", "getFormula1Circuits", "formula1", "/circuits", "Get Formula 1 Circuits"), - ("formula1", "getFormula1Competitions", "formula1", "/competitions", "Get Formula 1 Competitions"), - ("formula1", "getFormula1Races", "formula1", "/races", "Get Formula 1 Races"), - ("formula1", "getFormula1DriverRankings", "formula1", "/rankings/drivers", "Get Formula 1 Driver Rankings"), - ("formula1", "getFormula1TeamRankings", "formula1", "/rankings/teams", "Get Formula 1 Team Rankings"), - ("formula1", "getFormula1StartingGrid", "formula1", "/rankings/startinggrid", "Get Formula 1 Starting Grid"), - ("formula1", "getFastestLapsRankings", "formula1", "/rankings/fastestlaps", "Get Fastest Laps Rankings"), - ("formula1", "getRaceRankings", "formula1", "/rankings/races", "Get Race Rankings"), - # MMA - ("mma", "getMmaCategories", "mma", "/categories", "Get MMA Categories"), - ("mma", "getMmaFighters", "mma", "/fighters", "Get MMA Fighters"), - ("mma", "getMmaFights", "mma", "/fights", "Get MMA Fights"), - ("mma", "getMmaFightResults", "mma", "/fights/results", "Get MMA Fight Results"), - ("mma", "getMmaFighterStatistics", "mma", "/fights/statistics/fighters", "Get MMA Fighter Statistics"), - ("mma", "getFightersRecords", "mma", "/fighters/records", "Get Fighters Records"), -] - -assert len(ROUTES) == 67, f"expected 67 routes, got {len(ROUTES)}" - - -def pascal(s: str) -> str: - return "".join(part.capitalize() for part in s.split("_")) - - -def write_routes_ts() -> None: - lines = [ - "import type { ApiSport } from '../client';", - "", - "export type ApiSportsRoute = {", - "\tsport: ApiSport;", - "\tpath: string;", - "\tdescription: string;", - "};", - "", - "export const API_SPORTS_ROUTES = {", - ] - for group, key, sport, path, desc in ROUTES: - lines.append(f"\t{key}: {{ sport: '{sport}', path: '{path}', description: {json.dumps(desc)} }},") - lines.append("} as const satisfies Record;") - lines.append("") - lines.append("export type ApiSportsRouteKey = keyof typeof API_SPORTS_ROUTES;") - (ENDPOINTS / "routes.ts").write_text("\n".join(lines) + "\n") - - -def write_group_file(group: str, routes: list[tuple[str, str, str, str, str]]) -> None: - lines = [ - "import { logEventFromContext } from 'corsair/core';", - "import { makeApiSportsRequest } from '../client';", - "import type { ApiSportsEndpoints } from '../index';", - "import type { ApiSportsEndpointOutputs } from './types';", - "import { API_SPORTS_ROUTES } from './routes';", - "", - ] - for _, key, _, path, desc in routes: - route = f"API_SPORTS_ROUTES.{key}" - lines.extend([ - f"/** {desc} */", - f"export const {key}: ApiSportsEndpoints['{key}'] = async (ctx, input) => {{", - f"\tconst route = {route};", - f"\tconst response = await makeApiSportsRequest(", - f"\t\troute.sport,", - f"\t\troute.path,", - f"\t\t{{ apiKey: ctx.key, query: input }},", - f"\t);", - f"\tawait logEventFromContext(ctx, 'api_sports.{group}.{key}', input ?? {{}}, 'completed');", - f"\treturn response;", - f"}};", - "", - ]) - (ENDPOINTS / f"{group}.ts").write_text("\n".join(lines)) - - -def write_types_ts() -> None: - keys = [key for _, key, _, _, _ in ROUTES] - lines = [ - "import { z } from 'zod';", - "", - "/** Query params vary per sport API; callers pass documented filter fields. */", - "export const ApiSportsQueryInputSchema = z", - "\t.record(", - "\t\tz.string(),", - "\t\tz.union([", - "\t\t\tz.string(),", - "\t\t\tz.number(),", - "\t\t\tz.boolean(),", - "\t\t\tz.array(z.union([z.string(), z.number()])),", - "\t\t]),", - "\t)", - "\t.optional();", - "", - "export type ApiSportsQueryInput = z.infer;", - "", - "export const ApiSportsResponseSchema = z", - "\t.object({", - "\t\tget: z.string().optional(),", - "\t\tparameters: z", - "\t\t\t.union([z.record(z.string(), z.unknown()), z.array(z.unknown())])", - "\t\t\t.optional(),", - "\t\terrors: z.array(z.unknown()).optional(),", - "\t\tresults: z.number().optional(),", - "\t\tpaging: z", - "\t\t\t.object({", - "\t\t\t\tcurrent: z.number().optional(),", - "\t\t\t\ttotal: z.number().optional(),", - "\t\t\t})", - "\t\t\t.optional(),", - "\t\tresponse: z.unknown(),", - "\t})", - "\t.loose();", - "", - "export type ApiSportsResponse = z.infer;", - "", - "export type ApiSportsEndpointInputs = {", - ] - for key in keys: - lines.append(f"\t{key}: ApiSportsQueryInput;") - lines.append("};") - lines.append("") - lines.append("export type ApiSportsEndpointOutputs = {") - for key in keys: - lines.append(f"\t{key}: ApiSportsResponse;") - lines.append("};") - lines.append("") - lines.append("export const ApiSportsEndpointInputSchemas = {") - for key in keys: - lines.append(f"\t{key}: ApiSportsQueryInputSchema,") - lines.append("} as const;") - lines.append("") - lines.append("export const ApiSportsEndpointOutputSchemas = {") - for key in keys: - lines.append(f"\t{key}: ApiSportsResponseSchema,") - lines.append("} as const;") - (ENDPOINTS / "types.ts").write_text("\n".join(lines) + "\n") - - -def write_index_ts() -> None: - groups: dict[str, list[str]] = {} - for group, key, *_ in ROUTES: - groups.setdefault(group, []).append(key) - - imports = [f"import * as {pascal(group)} from './endpoints/{group}';" for group in groups] - nested = [] - schema_lines = [] - meta_lines = [] - - for group, keys in groups.items(): - gp = pascal(group) - nested.append(f"\t{group}: {{") - for key in keys: - nested.append(f"\t\t{key}: {gp}.{key},") - desc = next(d for g, k, _, _, d in ROUTES if g == group and k == key).replace("'", "\\'") - schema_lines.append( - "\t'{}': {{\n\t\tinput: ApiSportsEndpointInputSchemas.{},\n\t\toutput: ApiSportsEndpointOutputSchemas.{},\n\t}},".format( - f"{group}.{key}", key, key - ) - ) - meta_lines.append( - "\t'{}': {{\n\t\t\triskLevel: 'read',\n\t\t\tdescription: '{}',\n\t\t}},".format( - f"{group}.{key}", desc - ) - ) - nested.append("\t},") - - endpoint_types = [f"\t{key}: ApiSportsEndpoint<'{key}'>;" for _, key, *_ in ROUTES] - - content = f"""import type {{ -\tAuthTypes, -\tBindEndpoints, -\tCorsairEndpoint, -\tCorsairErrorHandler, -\tCorsairPlugin, -\tCorsairPluginContext, -\tKeyBuilderContext, -\tPickAuth, -\tPluginAuthConfig, -\tPluginPermissionsConfig, -\tRequiredPluginEndpointMeta, -\tRequiredPluginEndpointSchemas, -}} from 'corsair/core'; -import {{ AuthMissingError }} from 'corsair/core'; -{chr(10).join(imports)} -import type {{ -\tApiSportsEndpointInputs, -\tApiSportsEndpointOutputs, -}} from './endpoints/types'; -import {{ -\tApiSportsEndpointInputSchemas, -\tApiSportsEndpointOutputSchemas, -}} from './endpoints/types'; -import {{ errorHandlers }} from './error-handlers'; -import {{ ApiSportsSchema }} from './schema'; - -export type ApiSportsPluginOptions = {{ -\tauthType?: PickAuth<'api_key'>; -\tkey?: string; -\thooks?: InternalApiSportsPlugin['hooks']; -\terrorHandlers?: CorsairErrorHandler; -\tpermissions?: PluginPermissionsConfig; -}}; - -export type ApiSportsContext = CorsairPluginContext< -\ttypeof ApiSportsSchema, -\tApiSportsPluginOptions ->; - -export type ApiSportsKeyBuilderContext = KeyBuilderContext; - -export type ApiSportsBoundEndpoints = BindEndpoints; - -type ApiSportsEndpoint = CorsairEndpoint< -\tApiSportsContext, -\tApiSportsEndpointInputs[K], -\tApiSportsEndpointOutputs[K] ->; - -export type ApiSportsEndpoints = {{ -{chr(10).join(endpoint_types)} -}}; - -const apiSportsEndpointsNested = {{ -{chr(10).join(nested)} -}} as const; - -const apiSportsWebhooksNested = {{}} as const; - -export const apiSportsEndpointSchemas = {{ -{chr(10).join(schema_lines)} -}} satisfies RequiredPluginEndpointSchemas; - -const apiSportsEndpointMeta = {{ -{chr(10).join(meta_lines)} -}} satisfies RequiredPluginEndpointMeta; - -const defaultAuthType: AuthTypes = 'api_key' as const; - -export const apiSportsAuthConfig = {{ -\tapi_key: {{}}, -}} as const satisfies PluginAuthConfig; - -export type BaseApiSportsPlugin = CorsairPlugin< -\t'api_sports', -\ttypeof ApiSportsSchema, -\ttypeof apiSportsEndpointsNested, -\ttypeof apiSportsWebhooksNested, -\tT, -\ttypeof defaultAuthType ->; - -export type InternalApiSportsPlugin = BaseApiSportsPlugin; - -export type ExternalApiSportsPlugin = -\tBaseApiSportsPlugin; - -export function apiSports( -\tincomingOptions: ApiSportsPluginOptions & -\t\tT = {{}} as ApiSportsPluginOptions & T, -): ExternalApiSportsPlugin {{ -\tconst options = {{ -\t\t...incomingOptions, -\t\tauthType: incomingOptions.authType ?? defaultAuthType, -\t}}; -\treturn {{ -\t\tid: 'api_sports', -\t\tauthConfig: apiSportsAuthConfig, -\t\tschema: ApiSportsSchema, -\t\toptions, -\t\thooks: options.hooks, -\t\twebhookHooks: undefined, -\t\tendpoints: apiSportsEndpointsNested, -\t\twebhooks: apiSportsWebhooksNested, -\t\tendpointMeta: apiSportsEndpointMeta, -\t\tendpointSchemas: apiSportsEndpointSchemas, -\t\tpluginWebhookMatcher: undefined, -\t\terrorHandlers: {{ -\t\t\t...errorHandlers, -\t\t\t...options.errorHandlers, -\t\t}}, -\t\tkeyBuilder: async (ctx: ApiSportsKeyBuilderContext, source) => {{ -\t\t\tif (source === 'endpoint' && options.key) {{ -\t\t\t\treturn options.key; -\t\t\t}} -\t\t\tif (source === 'endpoint' && ctx.authType === 'api_key') {{ -\t\t\t\tconst res = await ctx.keys.get_api_key(); -\t\t\t\treturn res ?? ''; -\t\t\t}} -\t\t\tthrow new AuthMissingError('api_sports', 'api_key'); -\t\t}}, -\t}} satisfies InternalApiSportsPlugin; -}} - -export type {{ -\tApiSportsEndpointInputs, -\tApiSportsEndpointOutputs, -\tApiSportsQueryInput, -\tApiSportsResponse, -}} from './endpoints/types'; - -export {{ -\tApiSportsEndpointInputSchemas, -\tApiSportsEndpointOutputSchemas, -\tApiSportsQueryInputSchema, -\tApiSportsResponseSchema, -}} from './endpoints/types'; -""" - (ROOT / "index.ts").write_text(content) - - -def write_endpoints_index() -> None: - groups = sorted({group for group, *_ in ROUTES}) - lines = [] - for group in groups: - gp = pascal(group) - lines.append(f"export * as {gp} from './{group}';") - lines.append("export * from './types';") - lines.append("export * from './routes';") - (ENDPOINTS / "index.ts").write_text("\n".join(lines) + "\n") - - -def main() -> None: - ENDPOINTS.mkdir(parents=True, exist_ok=True) - write_routes_ts() - write_types_ts() - groups: dict[str, list] = {} - for route in ROUTES: - groups.setdefault(route[0], []).append(route) - for group, routes in groups.items(): - write_group_file(group, routes) - write_endpoints_index() - write_index_ts() - print(f"Generated {len(ROUTES)} endpoints in {len(groups)} groups") - - -if __name__ == "__main__": - main() From c832e7ebeac2cb52fdfb3a1eea31e184006e3bda Mon Sep 17 00:00:00 2001 From: Dhirender Choudhary Date: Tue, 4 Aug 2026 12:39:14 +0530 Subject: [PATCH 4/9] fix(api-sports): correct routes and body errors --- packages/api_sports/api.test.ts | 91 +++++- packages/api_sports/client.ts | 64 +++- packages/api_sports/endpoints/routes.ts | 382 ++++++++++++++++++++---- packages/api_sports/endpoints/types.ts | 5 +- packages/api_sports/error-handlers.ts | 6 +- 5 files changed, 475 insertions(+), 73 deletions(-) diff --git a/packages/api_sports/api.test.ts b/packages/api_sports/api.test.ts index 803aa4492..d8317a4d1 100644 --- a/packages/api_sports/api.test.ts +++ b/packages/api_sports/api.test.ts @@ -1,6 +1,11 @@ import 'dotenv/config'; -import { makeApiSportsRequest } from './client'; -import { ApiSportsEndpointOutputSchemas, ApiSportsResponseSchema, type ApiSportsResponse } from './endpoints/types'; +import { ApiSportsAPIError, makeApiSportsRequest } from './client'; +import { API_SPORTS_ROUTES } from './endpoints/routes'; +import type { ApiSportsResponse } from './endpoints/types'; +import { + ApiSportsEndpointOutputSchemas, + ApiSportsResponseSchema, +} from './endpoints/types'; const TEST_API_KEY = process.env.API_SPORTS_API_KEY; @@ -46,4 +51,86 @@ describe('API-Sports API Type Tests', () => { ApiSportsResponseSchema.parse(response); expect(response.response).toBeDefined(); }); + + it('standings stages route hits football host', async () => { + if (!TEST_API_KEY) return; + + const route = API_SPORTS_ROUTES.getStandingsStages; + expect(route.sport).toBe('football'); + + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: TEST_API_KEY, query: { league: 39, season: 2023 } }, + ); + + ApiSportsEndpointOutputSchemas.getStandingsStages.parse(response); + expect(Array.isArray(response.response) || response.response).toBeTruthy(); + }); + + it('standings groups route hits football host', async () => { + if (!TEST_API_KEY) return; + + const route = API_SPORTS_ROUTES.getStandingsGroups; + expect(route.sport).toBe('football'); + + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: TEST_API_KEY, query: { league: 39, season: 2023 } }, + ); + + ApiSportsEndpointOutputSchemas.getStandingsGroups.parse(response); + }); + + it('games events route hits nfl host', async () => { + if (!TEST_API_KEY) return; + + const route = API_SPORTS_ROUTES.getGamesEvents; + expect(route.sport).toBe('nfl'); + + const response = await makeApiSportsRequest( + route.sport, + route.path, + { apiKey: TEST_API_KEY, query: { id: 1 } }, + ); + + ApiSportsEndpointOutputSchemas.getGamesEvents.parse(response); + }); + + it('throws on API-Sports body errors', async () => { + if (!TEST_API_KEY) return; + + await expect( + makeApiSportsRequest('nba', '/games/events', { + apiKey: TEST_API_KEY, + }), + ).rejects.toBeInstanceOf(ApiSportsAPIError); + }); + + it('throws auth body errors for invalid key', async () => { + await expect( + makeApiSportsRequest('football', '/countries', { + apiKey: 'invalid', + }), + ).rejects.toThrow(/token|application key/i); + }); + + it('joins array query params with hyphens', async () => { + if (!TEST_API_KEY) return; + + // Free plan may reject ids; assert we don't get a repeated-key style failure — + // either results or a plan/parameter body error (still proves request was formed). + try { + const response = await makeApiSportsRequest( + 'football', + '/fixtures', + { apiKey: TEST_API_KEY, query: { ids: [1208002, 1208003] } }, + ); + ApiSportsResponseSchema.parse(response); + } catch (error) { + expect(error).toBeInstanceOf(ApiSportsAPIError); + expect((error as Error).message.toLowerCase()).not.toContain('endpoint'); + } + }); }); diff --git a/packages/api_sports/client.ts b/packages/api_sports/client.ts index 06bac1322..464fe756e 100644 --- a/packages/api_sports/client.ts +++ b/packages/api_sports/client.ts @@ -11,7 +11,7 @@ export class ApiSportsAPIError extends Error { constructor( message: string, public readonly code?: number, - options?: { cause?: Error }, + options?: { cause?: Error; body?: unknown }, ) { super(message, options); this.name = 'ApiSportsAPIError'; @@ -21,6 +21,8 @@ export class ApiSportsAPIError extends Error { this.statusText = options.cause.statusText; this.body = options.cause.body; this.retryAfter = options.cause.retryAfter; + } else if (options?.body !== undefined) { + this.body = options.body; } } } @@ -53,6 +55,44 @@ export type ApiSportsQueryValue = | Array | undefined; +/** API-Sports multi-id filters expect `ids=1-2-3`, not repeated keys. */ +function normalizeQuery( + query: Record, +): Record { + const out: Record = {}; + for (const [key, value] of Object.entries(query)) { + if (value === undefined) continue; + if (Array.isArray(value)) { + out[key] = value.join('-'); + } else { + out[key] = value; + } + } + return out; +} + +function formatApiSportsErrors(errors: unknown): string { + if (Array.isArray(errors)) { + return errors + .map((e) => (typeof e === 'string' ? e : JSON.stringify(e))) + .join(', '); + } + if (errors && typeof errors === 'object') { + return Object.entries(errors as Record) + .map(([k, v]) => `${k}: ${String(v)}`) + .join(', '); + } + return 'API-Sports request failed'; +} + +function hasApiSportsErrors(errors: unknown): boolean { + if (errors == null) return false; + if (Array.isArray(errors)) return errors.length > 0; + if (typeof errors === 'object') + return Object.keys(errors as object).length > 0; + return true; +} + // Catch values are untyped at runtime; narrow to ApiError/Error before rethrowing. async function handleRequestError(error: unknown): Promise { if (error instanceof ApiError) { @@ -96,12 +136,30 @@ export async function makeApiSportsRequest( const requestOptions: ApiRequestOptions = { method: 'GET', url: path, - query, + query: normalizeQuery(query), }; try { - return await request(config, requestOptions); + const response = await request(config, requestOptions); + // API-Sports returns HTTP 200 with a non-empty `errors` object/array on failures. + if ( + response && + typeof response === 'object' && + 'errors' in response && + hasApiSportsErrors((response as { errors?: unknown }).errors) + ) { + const body = response as { errors?: unknown }; + throw new ApiSportsAPIError( + formatApiSportsErrors(body.errors), + undefined, + { + body, + }, + ); + } + return response; } catch (error) { + if (error instanceof ApiSportsAPIError) throw error; return handleRequestError(error); } } diff --git a/packages/api_sports/endpoints/routes.ts b/packages/api_sports/endpoints/routes.ts index 0cafbdd9c..3d99ab5ed 100644 --- a/packages/api_sports/endpoints/routes.ts +++ b/packages/api_sports/endpoints/routes.ts @@ -7,77 +7,327 @@ export type ApiSportsRoute = { }; export const API_SPORTS_ROUTES = { - getCountries: { sport: 'football', path: '/countries', description: "Get Countries" }, - getTimezone: { sport: 'football', path: '/timezone', description: "Get Timezone" }, - getLeagues: { sport: 'football', path: '/leagues', description: "Get Leagues" }, - getLeagueSeasons: { sport: 'football', path: '/leagues/seasons', description: "Get League Seasons" }, - getTeams: { sport: 'football', path: '/teams', description: "Get Teams" }, - getTeamSeasons: { sport: 'football', path: '/teams/seasons', description: "Get Team Seasons" }, - getTeamStatistics: { sport: 'football', path: '/teams/statistics', description: "Get Team Statistics" }, - getVenues: { sport: 'football', path: '/venues', description: "Get Venues" }, - getCoaches: { sport: 'football', path: '/coachs', description: "Get Coaches" }, - getInjuries: { sport: 'football', path: '/injuries', description: "Get Injuries" }, - getSidelined: { sport: 'football', path: '/sidelined', description: "Get Sidelined" }, - getTransfers: { sport: 'football', path: '/transfers', description: "Get Transfers" }, - getTrophies: { sport: 'football', path: '/trophies', description: "Get Trophies" }, - getPredictions: { sport: 'football', path: '/predictions', description: "Get Predictions" }, - getFixtures: { sport: 'football', path: '/fixtures', description: "Get Fixtures" }, - getFixturesRounds: { sport: 'football', path: '/fixtures/rounds', description: "Get Fixtures Rounds" }, - getHeadToHeadFixtures: { sport: 'football', path: '/fixtures/headtohead', description: "Get Head-to-Head Fixtures" }, - getFixtureLineups: { sport: 'football', path: '/fixtures/lineups', description: "Get Fixture Lineups" }, - getFixtureStatistics: { sport: 'football', path: '/fixtures/statistics', description: "Get Fixture Statistics" }, - getFixturesEvents: { sport: 'football', path: '/fixtures/events', description: "Get Fixtures Events" }, - getFixturesPlayers: { sport: 'football', path: '/fixtures/players', description: "Get Fixtures Players" }, - getStandingsStages: { sport: 'nfl', path: '/standings/stages', description: "Get Standings Stages" }, - getStandingsGroups: { sport: 'nfl', path: '/standings/groups', description: "Get Standings Groups" }, - getStandingsDivisions: { sport: 'nfl', path: '/standings/divisions', description: "Get Standings Divisions" }, - getNflStandingsConferences: { sport: 'nfl', path: '/standings/conferences', description: "Get NFL Standings Conferences" }, - getPlayers: { sport: 'football', path: '/players', description: "Get Players" }, - getPlayersProfiles: { sport: 'football', path: '/players/profiles', description: "Get Players Profiles" }, - getPlayersSeasons: { sport: 'football', path: '/players/seasons', description: "Get Players Seasons" }, - getPlayersSquads: { sport: 'football', path: '/players/squads', description: "Get Players Squads" }, - getPlayersTeams: { sport: 'football', path: '/players/teams', description: "Get Players Teams" }, - getPlayersTopScorers: { sport: 'football', path: '/players/topscorers', description: "Get Players Top Scorers" }, - getPlayersTopAssists: { sport: 'football', path: '/players/topassists', description: "Get Players Top Assists" }, - getPlayersTopYellowCards: { sport: 'football', path: '/players/topyellowcards', description: "Get Players Top Yellow Cards" }, - getPlayersTopRedCards: { sport: 'football', path: '/players/topredcards', description: "Get Players Top Red Cards" }, - getOdds: { sport: 'football', path: '/odds', description: "Get Odds" }, - getOddsBets: { sport: 'football', path: '/odds/bets', description: "Get Odds Bets" }, - getOddsBookmakers: { sport: 'football', path: '/odds/bookmakers', description: "Get Odds Bookmakers" }, - getOddsMapping: { sport: 'football', path: '/odds/mapping', description: "Get Odds Mapping" }, - getInPlayOdds: { sport: 'football', path: '/odds/live', description: "Get In-Play Odds" }, - getLiveOddsBets: { sport: 'football', path: '/odds/live/bets', description: "Get Live Odds Bets" }, - getBasketballStatistics: { sport: 'basketball', path: '/statistics', description: "Get Basketball Statistics" }, - getBasketballBets: { sport: 'basketball', path: '/bets', description: "Get Basketball Bets" }, - getBasketballBookmakers: { sport: 'basketball', path: '/bookmakers', description: "Get Basketball Bookmakers" }, - getNbaGameStatistics: { sport: 'nba', path: '/games/statistics', description: "Get NBA Game Statistics" }, - getPlayerStatistics: { sport: 'nba', path: '/players/statistics', description: "Get Player Statistics" }, + getCountries: { + sport: 'football', + path: '/countries', + description: 'Get Countries', + }, + getTimezone: { + sport: 'football', + path: '/timezone', + description: 'Get Timezone', + }, + getLeagues: { + sport: 'football', + path: '/leagues', + description: 'Get Leagues', + }, + getLeagueSeasons: { + sport: 'football', + path: '/leagues/seasons', + description: 'Get League Seasons', + }, + getTeams: { sport: 'football', path: '/teams', description: 'Get Teams' }, + getTeamSeasons: { + sport: 'football', + path: '/teams/seasons', + description: 'Get Team Seasons', + }, + getTeamStatistics: { + sport: 'football', + path: '/teams/statistics', + description: 'Get Team Statistics', + }, + getVenues: { sport: 'football', path: '/venues', description: 'Get Venues' }, + getCoaches: { + sport: 'football', + path: '/coachs', + description: 'Get Coaches', + }, + getInjuries: { + sport: 'football', + path: '/injuries', + description: 'Get Injuries', + }, + getSidelined: { + sport: 'football', + path: '/sidelined', + description: 'Get Sidelined', + }, + getTransfers: { + sport: 'football', + path: '/transfers', + description: 'Get Transfers', + }, + getTrophies: { + sport: 'football', + path: '/trophies', + description: 'Get Trophies', + }, + getPredictions: { + sport: 'football', + path: '/predictions', + description: 'Get Predictions', + }, + getFixtures: { + sport: 'football', + path: '/fixtures', + description: 'Get Fixtures', + }, + getFixturesRounds: { + sport: 'football', + path: '/fixtures/rounds', + description: 'Get Fixtures Rounds', + }, + getHeadToHeadFixtures: { + sport: 'football', + path: '/fixtures/headtohead', + description: 'Get Head-to-Head Fixtures', + }, + getFixtureLineups: { + sport: 'football', + path: '/fixtures/lineups', + description: 'Get Fixture Lineups', + }, + getFixtureStatistics: { + sport: 'football', + path: '/fixtures/statistics', + description: 'Get Fixture Statistics', + }, + getFixturesEvents: { + sport: 'football', + path: '/fixtures/events', + description: 'Get Fixtures Events', + }, + getFixturesPlayers: { + sport: 'football', + path: '/fixtures/players', + description: 'Get Fixtures Players', + }, + // Football API documents /standings/stages + /standings/groups; NFL host rejects both. + getStandingsStages: { + sport: 'football', + path: '/standings/stages', + description: 'Get Standings Stages', + }, + getStandingsGroups: { + sport: 'football', + path: '/standings/groups', + description: 'Get Standings Groups', + }, + getStandingsDivisions: { + sport: 'nfl', + path: '/standings/divisions', + description: 'Get Standings Divisions', + }, + getNflStandingsConferences: { + sport: 'nfl', + path: '/standings/conferences', + description: 'Get NFL Standings Conferences', + }, + getPlayers: { + sport: 'football', + path: '/players', + description: 'Get Players', + }, + getPlayersProfiles: { + sport: 'football', + path: '/players/profiles', + description: 'Get Players Profiles', + }, + getPlayersSeasons: { + sport: 'football', + path: '/players/seasons', + description: 'Get Players Seasons', + }, + getPlayersSquads: { + sport: 'football', + path: '/players/squads', + description: 'Get Players Squads', + }, + getPlayersTeams: { + sport: 'football', + path: '/players/teams', + description: 'Get Players Teams', + }, + getPlayersTopScorers: { + sport: 'football', + path: '/players/topscorers', + description: 'Get Players Top Scorers', + }, + getPlayersTopAssists: { + sport: 'football', + path: '/players/topassists', + description: 'Get Players Top Assists', + }, + getPlayersTopYellowCards: { + sport: 'football', + path: '/players/topyellowcards', + description: 'Get Players Top Yellow Cards', + }, + getPlayersTopRedCards: { + sport: 'football', + path: '/players/topredcards', + description: 'Get Players Top Red Cards', + }, + getOdds: { sport: 'football', path: '/odds', description: 'Get Odds' }, + getOddsBets: { + sport: 'football', + path: '/odds/bets', + description: 'Get Odds Bets', + }, + getOddsBookmakers: { + sport: 'football', + path: '/odds/bookmakers', + description: 'Get Odds Bookmakers', + }, + getOddsMapping: { + sport: 'football', + path: '/odds/mapping', + description: 'Get Odds Mapping', + }, + getInPlayOdds: { + sport: 'football', + path: '/odds/live', + description: 'Get In-Play Odds', + }, + getLiveOddsBets: { + sport: 'football', + path: '/odds/live/bets', + description: 'Get Live Odds Bets', + }, + getBasketballStatistics: { + sport: 'basketball', + path: '/statistics', + description: 'Get Basketball Statistics', + }, + getBasketballBets: { + sport: 'basketball', + path: '/bets', + description: 'Get Basketball Bets', + }, + getBasketballBookmakers: { + sport: 'basketball', + path: '/bookmakers', + description: 'Get Basketball Bookmakers', + }, + getNbaGameStatistics: { + sport: 'nba', + path: '/games/statistics', + description: 'Get NBA Game Statistics', + }, + getPlayerStatistics: { + sport: 'nba', + path: '/players/statistics', + description: 'Get Player Statistics', + }, getGameStatisticsByTeams: { sport: 'basketball', path: '/games/statistics/teams', description: 'Get Game Statistics by Teams', }, - getGamesEvents: { sport: 'nba', path: '/games/events', description: "Get Games Events" }, - getAflSeasons: { sport: 'afl', path: '/seasons', description: "Get AFL Seasons" }, - getAflGames: { sport: 'afl', path: '/games', description: "Get AFL Games" }, - getAflGamesQuarters: { sport: 'afl', path: '/games/quarters', description: "Get AFL Games Quarters" }, - getAflGamePlayerStatistics: { sport: 'afl', path: '/games/statistics/players', description: "Get AFL Game Player Statistics" }, - getAflStandings: { sport: 'afl', path: '/standings', description: "Get AFL Standings" }, - getBaseballGamesHeadToHead: { sport: 'baseball', path: '/games/h2h', description: "Get Baseball Games Head-to-Head" }, - getFormula1Circuits: { sport: 'formula1', path: '/circuits', description: "Get Formula 1 Circuits" }, - getFormula1Competitions: { sport: 'formula1', path: '/competitions', description: "Get Formula 1 Competitions" }, - getFormula1Races: { sport: 'formula1', path: '/races', description: "Get Formula 1 Races" }, - getFormula1DriverRankings: { sport: 'formula1', path: '/rankings/drivers', description: "Get Formula 1 Driver Rankings" }, - getFormula1TeamRankings: { sport: 'formula1', path: '/rankings/teams', description: "Get Formula 1 Team Rankings" }, - getFormula1StartingGrid: { sport: 'formula1', path: '/rankings/startinggrid', description: "Get Formula 1 Starting Grid" }, - getFastestLapsRankings: { sport: 'formula1', path: '/rankings/fastestlaps', description: "Get Fastest Laps Rankings" }, - getRaceRankings: { sport: 'formula1', path: '/rankings/races', description: "Get Race Rankings" }, - getMmaCategories: { sport: 'mma', path: '/categories', description: "Get MMA Categories" }, - getMmaFighters: { sport: 'mma', path: '/fighters', description: "Get MMA Fighters" }, - getMmaFights: { sport: 'mma', path: '/fights', description: "Get MMA Fights" }, - getMmaFightResults: { sport: 'mma', path: '/fights/results', description: "Get MMA Fight Results" }, - getMmaFighterStatistics: { sport: 'mma', path: '/fights/statistics/fighters', description: "Get MMA Fighter Statistics" }, - getFightersRecords: { sport: 'mma', path: '/fighters/records', description: "Get Fighters Records" }, + // NBA has no /games/events; American football (nfl) does. + getGamesEvents: { + sport: 'nfl', + path: '/games/events', + description: 'Get Games Events', + }, + getAflSeasons: { + sport: 'afl', + path: '/seasons', + description: 'Get AFL Seasons', + }, + getAflGames: { sport: 'afl', path: '/games', description: 'Get AFL Games' }, + getAflGamesQuarters: { + sport: 'afl', + path: '/games/quarters', + description: 'Get AFL Games Quarters', + }, + getAflGamePlayerStatistics: { + sport: 'afl', + path: '/games/statistics/players', + description: 'Get AFL Game Player Statistics', + }, + getAflStandings: { + sport: 'afl', + path: '/standings', + description: 'Get AFL Standings', + }, + getBaseballGamesHeadToHead: { + sport: 'baseball', + path: '/games/h2h', + description: 'Get Baseball Games Head-to-Head', + }, + getFormula1Circuits: { + sport: 'formula1', + path: '/circuits', + description: 'Get Formula 1 Circuits', + }, + getFormula1Competitions: { + sport: 'formula1', + path: '/competitions', + description: 'Get Formula 1 Competitions', + }, + getFormula1Races: { + sport: 'formula1', + path: '/races', + description: 'Get Formula 1 Races', + }, + getFormula1DriverRankings: { + sport: 'formula1', + path: '/rankings/drivers', + description: 'Get Formula 1 Driver Rankings', + }, + getFormula1TeamRankings: { + sport: 'formula1', + path: '/rankings/teams', + description: 'Get Formula 1 Team Rankings', + }, + getFormula1StartingGrid: { + sport: 'formula1', + path: '/rankings/startinggrid', + description: 'Get Formula 1 Starting Grid', + }, + getFastestLapsRankings: { + sport: 'formula1', + path: '/rankings/fastestlaps', + description: 'Get Fastest Laps Rankings', + }, + getRaceRankings: { + sport: 'formula1', + path: '/rankings/races', + description: 'Get Race Rankings', + }, + getMmaCategories: { + sport: 'mma', + path: '/categories', + description: 'Get MMA Categories', + }, + getMmaFighters: { + sport: 'mma', + path: '/fighters', + description: 'Get MMA Fighters', + }, + getMmaFights: { + sport: 'mma', + path: '/fights', + description: 'Get MMA Fights', + }, + getMmaFightResults: { + sport: 'mma', + path: '/fights/results', + description: 'Get MMA Fight Results', + }, + getMmaFighterStatistics: { + sport: 'mma', + path: '/fights/statistics/fighters', + description: 'Get MMA Fighter Statistics', + }, + getFightersRecords: { + sport: 'mma', + path: '/fighters/records', + description: 'Get Fighters Records', + }, } as const satisfies Record; export type ApiSportsRouteKey = keyof typeof API_SPORTS_ROUTES; diff --git a/packages/api_sports/endpoints/types.ts b/packages/api_sports/endpoints/types.ts index 913440a68..9fe1111bc 100644 --- a/packages/api_sports/endpoints/types.ts +++ b/packages/api_sports/endpoints/types.ts @@ -21,7 +21,10 @@ export const ApiSportsResponseSchema = z parameters: z .union([z.record(z.string(), z.unknown()), z.array(z.unknown())]) .optional(), - errors: z.array(z.unknown()).optional(), + // Live API returns [] on success and `{ token|endpoint: string }` on failure. + errors: z + .union([z.array(z.unknown()), z.record(z.string(), z.unknown())]) + .optional(), results: z.number().optional(), paging: z .object({ diff --git a/packages/api_sports/error-handlers.ts b/packages/api_sports/error-handlers.ts index 089979710..098029fa5 100644 --- a/packages/api_sports/error-handlers.ts +++ b/packages/api_sports/error-handlers.ts @@ -32,11 +32,15 @@ export const errorHandlers = { msg.includes('unauthorized') || msg.includes('invalid api key') || msg.includes('invalid key') || + msg.includes('application key') || + msg.includes('token:') || msg.includes('401') ); }, handler: async () => { - console.error('[API_SPORTS] Authentication failed — check your x-apisports-key.'); + console.error( + '[API_SPORTS] Authentication failed — check your x-apisports-key.', + ); return { maxRetries: 0 }; }, }, From 2cbb7ebb617cc3d3da03b6485bd7151fcaf43dfc Mon Sep 17 00:00:00 2001 From: Dhirender Choudhary Date: Tue, 4 Aug 2026 12:46:59 +0530 Subject: [PATCH 5/9] chore(api-sports): drop out-of-scope demo and vscode edits --- .vscode/settings.json | 10 ++++++---- demo/testing/package.json | 1 - demo/testing/src/server/corsair.ts | 4 ---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8b25aa555..dd99e48f3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,12 +17,14 @@ "strings": false } }, - "editor.formatOnType": true, // required - "editor.formatOnPaste": true, // optional + "editor.formatOnType": true, + "editor.formatOnPaste": true, "editor.formatOnSave": true, - "editor.formatOnSaveMode": "file", // required to format on save + "editor.formatOnSaveMode": "file", "files.autoSave": "off", "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" - } + }, + "js/ts.experimental.useTsgo": true, + "typescript.native-preview.goMemLimit": "4GiB" } diff --git a/demo/testing/package.json b/demo/testing/package.json index cf8ba887b..3dcf0da17 100644 --- a/demo/testing/package.json +++ b/demo/testing/package.json @@ -26,7 +26,6 @@ "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.0", "@corsair-dev/agentql": "workspace:*", - "@corsair-dev/api_sports": "workspace:*", "@corsair-dev/bitwarden": "workspace:*", "@corsair-dev/cursor": "workspace:*", "@corsair-dev/firecrawl": "workspace:*", diff --git a/demo/testing/src/server/corsair.ts b/demo/testing/src/server/corsair.ts index 00105335b..3755c8b3e 100644 --- a/demo/testing/src/server/corsair.ts +++ b/demo/testing/src/server/corsair.ts @@ -3,7 +3,6 @@ import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); import { agentql } from '@corsair-dev/agentql'; -import { apiSports } from '@corsair-dev/api_sports'; import { gmail } from '@corsair-dev/gmail'; import { googlecalendar } from '@corsair-dev/googlecalendar'; import { googlesheets } from '@corsair-dev/googlesheets'; @@ -59,9 +58,6 @@ export const corsair = createCorsair({ agentql({ key: process.env.AGENTQL_API_KEY, }), - apiSports({ - key: process.env.API_SPORTS_API_KEY, - }), twilio(), vapi({ key: process.env.VAPI_API_KEY, From e3da275d6c4ad951626a51ae7d98b9055e02730f Mon Sep 17 00:00:00 2001 From: Dhirender Choudhary Date: Tue, 4 Aug 2026 12:49:38 +0530 Subject: [PATCH 6/9] fix(api-sports): sync lockfile after demo dep removal --- pnpm-lock.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75465c1c7..17f2b8c09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -165,9 +165,6 @@ importers: '@corsair-dev/agentql': specifier: workspace:* version: link:../../packages/agentql - '@corsair-dev/api_sports': - specifier: workspace:* - version: link:../../packages/api_sports '@corsair-dev/bitwarden': specifier: workspace:* version: link:../../packages/bitwarden From 5007167b5614d66df4be002a37932a13d66e9004 Mon Sep 17 00:00:00 2001 From: Dhirender Choudhary Date: Tue, 4 Aug 2026 12:53:04 +0530 Subject: [PATCH 7/9] style(api-sports): apply biome format and import order --- packages/api_sports/endpoints/afl.ts | 105 +++-- packages/api_sports/endpoints/baseball.ts | 29 +- packages/api_sports/endpoints/basketball.ts | 171 ++++---- packages/api_sports/endpoints/core.ts | 245 +++++++---- packages/api_sports/endpoints/fixtures.ts | 171 ++++---- packages/api_sports/endpoints/formula1.ts | 188 ++++---- packages/api_sports/endpoints/index.ts | 2 +- packages/api_sports/endpoints/mma.ts | 130 +++--- packages/api_sports/endpoints/odds.ts | 109 +++-- packages/api_sports/endpoints/players.ts | 205 +++++---- packages/api_sports/endpoints/shared.ts | 20 +- packages/api_sports/endpoints/standings.ts | 104 +++-- packages/api_sports/index.ts | 456 ++++++++++---------- 13 files changed, 1102 insertions(+), 833 deletions(-) diff --git a/packages/api_sports/endpoints/afl.ts b/packages/api_sports/endpoints/afl.ts index b737d086a..c0f79d8c1 100644 --- a/packages/api_sports/endpoints/afl.ts +++ b/packages/api_sports/endpoints/afl.ts @@ -1,70 +1,91 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get AFL Seasons */ -export const getAflSeasons: ApiSportsEndpoints['getAflSeasons'] = async (ctx, input) => { +export const getAflSeasons: ApiSportsEndpoints['getAflSeasons'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getAflSeasons; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getAflSeasons'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.afl.getAflSeasons', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.afl.getAflSeasons', input ?? {}, 'completed'); return response; }; /** Get AFL Games */ -export const getAflGames: ApiSportsEndpoints['getAflGames'] = async (ctx, input) => { +export const getAflGames: ApiSportsEndpoints['getAflGames'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getAflGames; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getAflGames'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.afl.getAflGames', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.afl.getAflGames', input ?? {}, 'completed'); return response; }; /** Get AFL Games Quarters */ -export const getAflGamesQuarters: ApiSportsEndpoints['getAflGamesQuarters'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getAflGamesQuarters; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.afl.getAflGamesQuarters', input ?? {}, 'completed'); - return response; -}; +export const getAflGamesQuarters: ApiSportsEndpoints['getAflGamesQuarters'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getAflGamesQuarters; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getAflGamesQuarters'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.afl.getAflGamesQuarters', + input ?? {}, + 'completed', + ); + return response; + }; /** Get AFL Game Player Statistics */ -export const getAflGamePlayerStatistics: ApiSportsEndpoints['getAflGamePlayerStatistics'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getAflGamePlayerStatistics; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.afl.getAflGamePlayerStatistics', input ?? {}, 'completed'); - return response; -}; +export const getAflGamePlayerStatistics: ApiSportsEndpoints['getAflGamePlayerStatistics'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getAflGamePlayerStatistics; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getAflGamePlayerStatistics'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.afl.getAflGamePlayerStatistics', + input ?? {}, + 'completed', + ); + return response; + }; /** Get AFL Standings */ -export const getAflStandings: ApiSportsEndpoints['getAflStandings'] = async (ctx, input) => { +export const getAflStandings: ApiSportsEndpoints['getAflStandings'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getAflStandings; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getAflStandings'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.afl.getAflStandings', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.afl.getAflStandings', input ?? {}, 'completed'); return response; }; diff --git a/packages/api_sports/endpoints/baseball.ts b/packages/api_sports/endpoints/baseball.ts index beb3a6697..d3749d678 100644 --- a/packages/api_sports/endpoints/baseball.ts +++ b/packages/api_sports/endpoints/baseball.ts @@ -1,18 +1,21 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Baseball Games Head-to-Head */ -export const getBaseballGamesHeadToHead: ApiSportsEndpoints['getBaseballGamesHeadToHead'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getBaseballGamesHeadToHead; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.baseball.getBaseballGamesHeadToHead', input ?? {}, 'completed'); - return response; -}; +export const getBaseballGamesHeadToHead: ApiSportsEndpoints['getBaseballGamesHeadToHead'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBaseballGamesHeadToHead; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getBaseballGamesHeadToHead'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.baseball.getBaseballGamesHeadToHead', + input ?? {}, + 'completed', + ); + return response; + }; diff --git a/packages/api_sports/endpoints/basketball.ts b/packages/api_sports/endpoints/basketball.ts index 6de7c9522..1fdccbc9c 100644 --- a/packages/api_sports/endpoints/basketball.ts +++ b/packages/api_sports/endpoints/basketball.ts @@ -1,96 +1,119 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Basketball Statistics */ -export const getBasketballStatistics: ApiSportsEndpoints['getBasketballStatistics'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getBasketballStatistics; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.basketball.getBasketballStatistics', input ?? {}, 'completed'); - return response; -}; +export const getBasketballStatistics: ApiSportsEndpoints['getBasketballStatistics'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBasketballStatistics; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getBasketballStatistics'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.basketball.getBasketballStatistics', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Basketball Bets */ -export const getBasketballBets: ApiSportsEndpoints['getBasketballBets'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getBasketballBets; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.basketball.getBasketballBets', input ?? {}, 'completed'); - return response; -}; +export const getBasketballBets: ApiSportsEndpoints['getBasketballBets'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBasketballBets; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getBasketballBets'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.basketball.getBasketballBets', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Basketball Bookmakers */ -export const getBasketballBookmakers: ApiSportsEndpoints['getBasketballBookmakers'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getBasketballBookmakers; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.basketball.getBasketballBookmakers', input ?? {}, 'completed'); - return response; -}; +export const getBasketballBookmakers: ApiSportsEndpoints['getBasketballBookmakers'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getBasketballBookmakers; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getBasketballBookmakers'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.basketball.getBasketballBookmakers', + input ?? {}, + 'completed', + ); + return response; + }; /** Get NBA Game Statistics */ -export const getNbaGameStatistics: ApiSportsEndpoints['getNbaGameStatistics'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getNbaGameStatistics; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.basketball.getNbaGameStatistics', input ?? {}, 'completed'); - return response; -}; +export const getNbaGameStatistics: ApiSportsEndpoints['getNbaGameStatistics'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getNbaGameStatistics; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getNbaGameStatistics'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.basketball.getNbaGameStatistics', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Player Statistics */ -export const getPlayerStatistics: ApiSportsEndpoints['getPlayerStatistics'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getPlayerStatistics; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.basketball.getPlayerStatistics', input ?? {}, 'completed'); - return response; -}; +export const getPlayerStatistics: ApiSportsEndpoints['getPlayerStatistics'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayerStatistics; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayerStatistics'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.basketball.getPlayerStatistics', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Game Statistics by Teams */ -export const getGameStatisticsByTeams: ApiSportsEndpoints['getGameStatisticsByTeams'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getGameStatisticsByTeams; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.basketball.getGameStatisticsByTeams', input ?? {}, 'completed'); - return response; -}; +export const getGameStatisticsByTeams: ApiSportsEndpoints['getGameStatisticsByTeams'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getGameStatisticsByTeams; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getGameStatisticsByTeams'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.basketball.getGameStatisticsByTeams', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Games Events */ -export const getGamesEvents: ApiSportsEndpoints['getGamesEvents'] = async (ctx, input) => { +export const getGamesEvents: ApiSportsEndpoints['getGamesEvents'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getGamesEvents; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getGamesEvents'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.basketball.getGamesEvents', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.basketball.getGamesEvents', input ?? {}, 'completed'); return response; }; diff --git a/packages/api_sports/endpoints/core.ts b/packages/api_sports/endpoints/core.ts index 336e177ce..e8c415c10 100644 --- a/packages/api_sports/endpoints/core.ts +++ b/packages/api_sports/endpoints/core.ts @@ -1,187 +1,252 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Countries */ -export const getCountries: ApiSportsEndpoints['getCountries'] = async (ctx, input) => { +export const getCountries: ApiSportsEndpoints['getCountries'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getCountries; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getCountries'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getCountries', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getCountries', input ?? {}, 'completed'); return response; }; /** Get Timezone */ -export const getTimezone: ApiSportsEndpoints['getTimezone'] = async (ctx, input) => { +export const getTimezone: ApiSportsEndpoints['getTimezone'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getTimezone; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getTimezone'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getTimezone', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getTimezone', input ?? {}, 'completed'); return response; }; /** Get Leagues */ -export const getLeagues: ApiSportsEndpoints['getLeagues'] = async (ctx, input) => { +export const getLeagues: ApiSportsEndpoints['getLeagues'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getLeagues; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getLeagues'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getLeagues', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getLeagues', input ?? {}, 'completed'); return response; }; /** Get League Seasons */ -export const getLeagueSeasons: ApiSportsEndpoints['getLeagueSeasons'] = async (ctx, input) => { +export const getLeagueSeasons: ApiSportsEndpoints['getLeagueSeasons'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getLeagueSeasons; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getLeagueSeasons'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getLeagueSeasons', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getLeagueSeasons', input ?? {}, 'completed'); return response; }; /** Get Teams */ export const getTeams: ApiSportsEndpoints['getTeams'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getTeams; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getTeams'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getTeams', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getTeams', input ?? {}, 'completed'); return response; }; /** Get Team Seasons */ -export const getTeamSeasons: ApiSportsEndpoints['getTeamSeasons'] = async (ctx, input) => { +export const getTeamSeasons: ApiSportsEndpoints['getTeamSeasons'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getTeamSeasons; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getTeamSeasons'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getTeamSeasons', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getTeamSeasons', input ?? {}, 'completed'); return response; }; /** Get Team Statistics */ -export const getTeamStatistics: ApiSportsEndpoints['getTeamStatistics'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getTeamStatistics; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.core.getTeamStatistics', input ?? {}, 'completed'); - return response; -}; +export const getTeamStatistics: ApiSportsEndpoints['getTeamStatistics'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getTeamStatistics; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getTeamStatistics'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.core.getTeamStatistics', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Venues */ -export const getVenues: ApiSportsEndpoints['getVenues'] = async (ctx, input) => { +export const getVenues: ApiSportsEndpoints['getVenues'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getVenues; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getVenues'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getVenues', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getVenues', input ?? {}, 'completed'); return response; }; /** Get Coaches */ -export const getCoaches: ApiSportsEndpoints['getCoaches'] = async (ctx, input) => { +export const getCoaches: ApiSportsEndpoints['getCoaches'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getCoaches; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getCoaches'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getCoaches', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getCoaches', input ?? {}, 'completed'); return response; }; /** Get Injuries */ -export const getInjuries: ApiSportsEndpoints['getInjuries'] = async (ctx, input) => { +export const getInjuries: ApiSportsEndpoints['getInjuries'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getInjuries; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getInjuries'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getInjuries', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getInjuries', input ?? {}, 'completed'); return response; }; /** Get Sidelined */ -export const getSidelined: ApiSportsEndpoints['getSidelined'] = async (ctx, input) => { +export const getSidelined: ApiSportsEndpoints['getSidelined'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getSidelined; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getSidelined'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getSidelined', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getSidelined', input ?? {}, 'completed'); return response; }; /** Get Transfers */ -export const getTransfers: ApiSportsEndpoints['getTransfers'] = async (ctx, input) => { +export const getTransfers: ApiSportsEndpoints['getTransfers'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getTransfers; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getTransfers'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getTransfers', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getTransfers', input ?? {}, 'completed'); return response; }; /** Get Trophies */ -export const getTrophies: ApiSportsEndpoints['getTrophies'] = async (ctx, input) => { +export const getTrophies: ApiSportsEndpoints['getTrophies'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getTrophies; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getTrophies'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getTrophies', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getTrophies', input ?? {}, 'completed'); return response; }; /** Get Predictions */ -export const getPredictions: ApiSportsEndpoints['getPredictions'] = async (ctx, input) => { +export const getPredictions: ApiSportsEndpoints['getPredictions'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getPredictions; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPredictions'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.core.getPredictions', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.core.getPredictions', input ?? {}, 'completed'); return response; }; diff --git a/packages/api_sports/endpoints/fixtures.ts b/packages/api_sports/endpoints/fixtures.ts index f98737dc4..835fbfdb5 100644 --- a/packages/api_sports/endpoints/fixtures.ts +++ b/packages/api_sports/endpoints/fixtures.ts @@ -1,96 +1,119 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Fixtures */ -export const getFixtures: ApiSportsEndpoints['getFixtures'] = async (ctx, input) => { +export const getFixtures: ApiSportsEndpoints['getFixtures'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getFixtures; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFixtures'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.fixtures.getFixtures', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.fixtures.getFixtures', input ?? {}, 'completed'); return response; }; /** Get Fixtures Rounds */ -export const getFixturesRounds: ApiSportsEndpoints['getFixturesRounds'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFixturesRounds; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.fixtures.getFixturesRounds', input ?? {}, 'completed'); - return response; -}; +export const getFixturesRounds: ApiSportsEndpoints['getFixturesRounds'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixturesRounds; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFixturesRounds'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.fixtures.getFixturesRounds', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Head-to-Head Fixtures */ -export const getHeadToHeadFixtures: ApiSportsEndpoints['getHeadToHeadFixtures'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getHeadToHeadFixtures; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.fixtures.getHeadToHeadFixtures', input ?? {}, 'completed'); - return response; -}; +export const getHeadToHeadFixtures: ApiSportsEndpoints['getHeadToHeadFixtures'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getHeadToHeadFixtures; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getHeadToHeadFixtures'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.fixtures.getHeadToHeadFixtures', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Fixture Lineups */ -export const getFixtureLineups: ApiSportsEndpoints['getFixtureLineups'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFixtureLineups; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.fixtures.getFixtureLineups', input ?? {}, 'completed'); - return response; -}; +export const getFixtureLineups: ApiSportsEndpoints['getFixtureLineups'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixtureLineups; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFixtureLineups'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.fixtures.getFixtureLineups', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Fixture Statistics */ -export const getFixtureStatistics: ApiSportsEndpoints['getFixtureStatistics'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFixtureStatistics; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.fixtures.getFixtureStatistics', input ?? {}, 'completed'); - return response; -}; +export const getFixtureStatistics: ApiSportsEndpoints['getFixtureStatistics'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixtureStatistics; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFixtureStatistics'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.fixtures.getFixtureStatistics', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Fixtures Events */ -export const getFixturesEvents: ApiSportsEndpoints['getFixturesEvents'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFixturesEvents; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.fixtures.getFixturesEvents', input ?? {}, 'completed'); - return response; -}; +export const getFixturesEvents: ApiSportsEndpoints['getFixturesEvents'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixturesEvents; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFixturesEvents'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.fixtures.getFixturesEvents', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Fixtures Players */ -export const getFixturesPlayers: ApiSportsEndpoints['getFixturesPlayers'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFixturesPlayers; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.fixtures.getFixturesPlayers', input ?? {}, 'completed'); - return response; -}; +export const getFixturesPlayers: ApiSportsEndpoints['getFixturesPlayers'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFixturesPlayers; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFixturesPlayers'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.fixtures.getFixturesPlayers', + input ?? {}, + 'completed', + ); + return response; + }; diff --git a/packages/api_sports/endpoints/formula1.ts b/packages/api_sports/endpoints/formula1.ts index 211a9c95f..b447f6b52 100644 --- a/packages/api_sports/endpoints/formula1.ts +++ b/packages/api_sports/endpoints/formula1.ts @@ -1,109 +1,137 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Formula 1 Circuits */ -export const getFormula1Circuits: ApiSportsEndpoints['getFormula1Circuits'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFormula1Circuits; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.formula1.getFormula1Circuits', input ?? {}, 'completed'); - return response; -}; +export const getFormula1Circuits: ApiSportsEndpoints['getFormula1Circuits'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1Circuits; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFormula1Circuits'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.formula1.getFormula1Circuits', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Formula 1 Competitions */ -export const getFormula1Competitions: ApiSportsEndpoints['getFormula1Competitions'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFormula1Competitions; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.formula1.getFormula1Competitions', input ?? {}, 'completed'); - return response; -}; +export const getFormula1Competitions: ApiSportsEndpoints['getFormula1Competitions'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1Competitions; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFormula1Competitions'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.formula1.getFormula1Competitions', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Formula 1 Races */ -export const getFormula1Races: ApiSportsEndpoints['getFormula1Races'] = async (ctx, input) => { +export const getFormula1Races: ApiSportsEndpoints['getFormula1Races'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getFormula1Races; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFormula1Races'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.formula1.getFormula1Races', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.formula1.getFormula1Races', input ?? {}, 'completed'); return response; }; /** Get Formula 1 Driver Rankings */ -export const getFormula1DriverRankings: ApiSportsEndpoints['getFormula1DriverRankings'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFormula1DriverRankings; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.formula1.getFormula1DriverRankings', input ?? {}, 'completed'); - return response; -}; +export const getFormula1DriverRankings: ApiSportsEndpoints['getFormula1DriverRankings'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1DriverRankings; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFormula1DriverRankings'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.formula1.getFormula1DriverRankings', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Formula 1 Team Rankings */ -export const getFormula1TeamRankings: ApiSportsEndpoints['getFormula1TeamRankings'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFormula1TeamRankings; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.formula1.getFormula1TeamRankings', input ?? {}, 'completed'); - return response; -}; +export const getFormula1TeamRankings: ApiSportsEndpoints['getFormula1TeamRankings'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1TeamRankings; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFormula1TeamRankings'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.formula1.getFormula1TeamRankings', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Formula 1 Starting Grid */ -export const getFormula1StartingGrid: ApiSportsEndpoints['getFormula1StartingGrid'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFormula1StartingGrid; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.formula1.getFormula1StartingGrid', input ?? {}, 'completed'); - return response; -}; +export const getFormula1StartingGrid: ApiSportsEndpoints['getFormula1StartingGrid'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFormula1StartingGrid; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFormula1StartingGrid'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.formula1.getFormula1StartingGrid', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Fastest Laps Rankings */ -export const getFastestLapsRankings: ApiSportsEndpoints['getFastestLapsRankings'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFastestLapsRankings; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.formula1.getFastestLapsRankings', input ?? {}, 'completed'); - return response; -}; +export const getFastestLapsRankings: ApiSportsEndpoints['getFastestLapsRankings'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFastestLapsRankings; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFastestLapsRankings'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.formula1.getFastestLapsRankings', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Race Rankings */ -export const getRaceRankings: ApiSportsEndpoints['getRaceRankings'] = async (ctx, input) => { +export const getRaceRankings: ApiSportsEndpoints['getRaceRankings'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getRaceRankings; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getRaceRankings'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.formula1.getRaceRankings', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.formula1.getRaceRankings', input ?? {}, 'completed'); return response; }; diff --git a/packages/api_sports/endpoints/index.ts b/packages/api_sports/endpoints/index.ts index 8da6cab4e..64770e6f1 100644 --- a/packages/api_sports/endpoints/index.ts +++ b/packages/api_sports/endpoints/index.ts @@ -7,6 +7,6 @@ export * as Formula1 from './formula1'; export * as Mma from './mma'; export * as Odds from './odds'; export * as Players from './players'; +export * from './routes'; export * as Standings from './standings'; export * from './types'; -export * from './routes'; diff --git a/packages/api_sports/endpoints/mma.ts b/packages/api_sports/endpoints/mma.ts index 6540a232e..2ef294a9b 100644 --- a/packages/api_sports/endpoints/mma.ts +++ b/packages/api_sports/endpoints/mma.ts @@ -1,83 +1,107 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get MMA Categories */ -export const getMmaCategories: ApiSportsEndpoints['getMmaCategories'] = async (ctx, input) => { +export const getMmaCategories: ApiSportsEndpoints['getMmaCategories'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getMmaCategories; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getMmaCategories'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.mma.getMmaCategories', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.mma.getMmaCategories', input ?? {}, 'completed'); return response; }; /** Get MMA Fighters */ -export const getMmaFighters: ApiSportsEndpoints['getMmaFighters'] = async (ctx, input) => { +export const getMmaFighters: ApiSportsEndpoints['getMmaFighters'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getMmaFighters; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getMmaFighters'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.mma.getMmaFighters', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.mma.getMmaFighters', input ?? {}, 'completed'); return response; }; /** Get MMA Fights */ -export const getMmaFights: ApiSportsEndpoints['getMmaFights'] = async (ctx, input) => { +export const getMmaFights: ApiSportsEndpoints['getMmaFights'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getMmaFights; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getMmaFights'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.mma.getMmaFights', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.mma.getMmaFights', input ?? {}, 'completed'); return response; }; /** Get MMA Fight Results */ -export const getMmaFightResults: ApiSportsEndpoints['getMmaFightResults'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getMmaFightResults; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.mma.getMmaFightResults', input ?? {}, 'completed'); - return response; -}; +export const getMmaFightResults: ApiSportsEndpoints['getMmaFightResults'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getMmaFightResults; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getMmaFightResults'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.mma.getMmaFightResults', + input ?? {}, + 'completed', + ); + return response; + }; /** Get MMA Fighter Statistics */ -export const getMmaFighterStatistics: ApiSportsEndpoints['getMmaFighterStatistics'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getMmaFighterStatistics; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.mma.getMmaFighterStatistics', input ?? {}, 'completed'); - return response; -}; +export const getMmaFighterStatistics: ApiSportsEndpoints['getMmaFighterStatistics'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getMmaFighterStatistics; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getMmaFighterStatistics'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.mma.getMmaFighterStatistics', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Fighters Records */ -export const getFightersRecords: ApiSportsEndpoints['getFightersRecords'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getFightersRecords; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.mma.getFightersRecords', input ?? {}, 'completed'); - return response; -}; +export const getFightersRecords: ApiSportsEndpoints['getFightersRecords'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getFightersRecords; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getFightersRecords'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.mma.getFightersRecords', + input ?? {}, + 'completed', + ); + return response; + }; diff --git a/packages/api_sports/endpoints/odds.ts b/packages/api_sports/endpoints/odds.ts index 3f8c10603..ca89a4bfd 100644 --- a/packages/api_sports/endpoints/odds.ts +++ b/packages/api_sports/endpoints/odds.ts @@ -1,83 +1,108 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Odds */ export const getOdds: ApiSportsEndpoints['getOdds'] = async (ctx, input) => { const route = API_SPORTS_ROUTES.getOdds; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getOdds'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.odds.getOdds', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.odds.getOdds', input ?? {}, 'completed'); return response; }; /** Get Odds Bets */ -export const getOddsBets: ApiSportsEndpoints['getOddsBets'] = async (ctx, input) => { +export const getOddsBets: ApiSportsEndpoints['getOddsBets'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getOddsBets; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getOddsBets'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.odds.getOddsBets', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.odds.getOddsBets', input ?? {}, 'completed'); return response; }; /** Get Odds Bookmakers */ -export const getOddsBookmakers: ApiSportsEndpoints['getOddsBookmakers'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getOddsBookmakers; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.odds.getOddsBookmakers', input ?? {}, 'completed'); - return response; -}; +export const getOddsBookmakers: ApiSportsEndpoints['getOddsBookmakers'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getOddsBookmakers; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getOddsBookmakers'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.odds.getOddsBookmakers', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Odds Mapping */ -export const getOddsMapping: ApiSportsEndpoints['getOddsMapping'] = async (ctx, input) => { +export const getOddsMapping: ApiSportsEndpoints['getOddsMapping'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getOddsMapping; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getOddsMapping'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.odds.getOddsMapping', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.odds.getOddsMapping', input ?? {}, 'completed'); return response; }; /** Get In-Play Odds */ -export const getInPlayOdds: ApiSportsEndpoints['getInPlayOdds'] = async (ctx, input) => { +export const getInPlayOdds: ApiSportsEndpoints['getInPlayOdds'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getInPlayOdds; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getInPlayOdds'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.odds.getInPlayOdds', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.odds.getInPlayOdds', input ?? {}, 'completed'); return response; }; /** Get Live Odds Bets */ -export const getLiveOddsBets: ApiSportsEndpoints['getLiveOddsBets'] = async (ctx, input) => { +export const getLiveOddsBets: ApiSportsEndpoints['getLiveOddsBets'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getLiveOddsBets; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getLiveOddsBets'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.odds.getLiveOddsBets', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.odds.getLiveOddsBets', input ?? {}, 'completed'); return response; }; diff --git a/packages/api_sports/endpoints/players.ts b/packages/api_sports/endpoints/players.ts index e06f18a7e..e53e53677 100644 --- a/packages/api_sports/endpoints/players.ts +++ b/packages/api_sports/endpoints/players.ts @@ -1,122 +1,155 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Players */ -export const getPlayers: ApiSportsEndpoints['getPlayers'] = async (ctx, input) => { +export const getPlayers: ApiSportsEndpoints['getPlayers'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getPlayers; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayers'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.players.getPlayers', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.players.getPlayers', input ?? {}, 'completed'); return response; }; /** Get Players Profiles */ -export const getPlayersProfiles: ApiSportsEndpoints['getPlayersProfiles'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getPlayersProfiles; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersProfiles', input ?? {}, 'completed'); - return response; -}; +export const getPlayersProfiles: ApiSportsEndpoints['getPlayersProfiles'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersProfiles; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersProfiles'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.players.getPlayersProfiles', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Players Seasons */ -export const getPlayersSeasons: ApiSportsEndpoints['getPlayersSeasons'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getPlayersSeasons; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersSeasons', input ?? {}, 'completed'); - return response; -}; +export const getPlayersSeasons: ApiSportsEndpoints['getPlayersSeasons'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersSeasons; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersSeasons'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.players.getPlayersSeasons', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Players Squads */ -export const getPlayersSquads: ApiSportsEndpoints['getPlayersSquads'] = async (ctx, input) => { +export const getPlayersSquads: ApiSportsEndpoints['getPlayersSquads'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getPlayersSquads; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersSquads'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.players.getPlayersSquads', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersSquads', input ?? {}, 'completed'); return response; }; /** Get Players Teams */ -export const getPlayersTeams: ApiSportsEndpoints['getPlayersTeams'] = async (ctx, input) => { +export const getPlayersTeams: ApiSportsEndpoints['getPlayersTeams'] = async ( + ctx, + input, +) => { const route = API_SPORTS_ROUTES.getPlayersTeams; - const response = await executeApiSportsRequest( + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersTeams'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, + 'api_sports.players.getPlayersTeams', + input ?? {}, + 'completed', ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersTeams', input ?? {}, 'completed'); return response; }; /** Get Players Top Scorers */ -export const getPlayersTopScorers: ApiSportsEndpoints['getPlayersTopScorers'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getPlayersTopScorers; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersTopScorers', input ?? {}, 'completed'); - return response; -}; +export const getPlayersTopScorers: ApiSportsEndpoints['getPlayersTopScorers'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopScorers; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersTopScorers'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.players.getPlayersTopScorers', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Players Top Assists */ -export const getPlayersTopAssists: ApiSportsEndpoints['getPlayersTopAssists'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getPlayersTopAssists; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersTopAssists', input ?? {}, 'completed'); - return response; -}; +export const getPlayersTopAssists: ApiSportsEndpoints['getPlayersTopAssists'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopAssists; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersTopAssists'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.players.getPlayersTopAssists', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Players Top Yellow Cards */ -export const getPlayersTopYellowCards: ApiSportsEndpoints['getPlayersTopYellowCards'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getPlayersTopYellowCards; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersTopYellowCards', input ?? {}, 'completed'); - return response; -}; +export const getPlayersTopYellowCards: ApiSportsEndpoints['getPlayersTopYellowCards'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopYellowCards; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersTopYellowCards'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.players.getPlayersTopYellowCards', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Players Top Red Cards */ -export const getPlayersTopRedCards: ApiSportsEndpoints['getPlayersTopRedCards'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getPlayersTopRedCards; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.players.getPlayersTopRedCards', input ?? {}, 'completed'); - return response; -}; +export const getPlayersTopRedCards: ApiSportsEndpoints['getPlayersTopRedCards'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getPlayersTopRedCards; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getPlayersTopRedCards'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.players.getPlayersTopRedCards', + input ?? {}, + 'completed', + ); + return response; + }; diff --git a/packages/api_sports/endpoints/shared.ts b/packages/api_sports/endpoints/shared.ts index 43753ecf0..f8c8cd7ba 100644 --- a/packages/api_sports/endpoints/shared.ts +++ b/packages/api_sports/endpoints/shared.ts @@ -1,7 +1,10 @@ -import { makeApiSportsRequest, type ApiSport, type ApiSportsQueryValue } from '../client'; +import type { ApiSport, ApiSportsQueryValue } from '../client'; +import { makeApiSportsRequest } from '../client'; import type { ApiSportsContext } from '../index'; -function stableQueryKey(query: Record | undefined) { +function stableQueryKey( + query: Record | undefined, +) { if (!query) return ''; return JSON.stringify( Object.keys(query) @@ -30,11 +33,14 @@ export async function cacheApiSportsQuery( if (!ctx.db.queries) return; try { - await ctx.db.queries.upsertByEntityId(buildQueryEntityId(sport, path, query), { - sport, - path, - queriedAt: new Date(), - }); + await ctx.db.queries.upsertByEntityId( + buildQueryEntityId(sport, path, query), + { + sport, + path, + queriedAt: new Date(), + }, + ); } catch (error) { console.warn('[api_sports] Failed to save query to database:', error); } diff --git a/packages/api_sports/endpoints/standings.ts b/packages/api_sports/endpoints/standings.ts index cc4497e1c..d0092e6fa 100644 --- a/packages/api_sports/endpoints/standings.ts +++ b/packages/api_sports/endpoints/standings.ts @@ -1,57 +1,69 @@ import { logEventFromContext } from 'corsair/core'; -import { executeApiSportsRequest } from './shared'; import type { ApiSportsEndpoints } from '../index'; -import type { ApiSportsEndpointOutputs } from './types'; import { API_SPORTS_ROUTES } from './routes'; +import { executeApiSportsRequest } from './shared'; +import type { ApiSportsEndpointOutputs } from './types'; /** Get Standings Stages */ -export const getStandingsStages: ApiSportsEndpoints['getStandingsStages'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getStandingsStages; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.standings.getStandingsStages', input ?? {}, 'completed'); - return response; -}; +export const getStandingsStages: ApiSportsEndpoints['getStandingsStages'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getStandingsStages; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getStandingsStages'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.standings.getStandingsStages', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Standings Groups */ -export const getStandingsGroups: ApiSportsEndpoints['getStandingsGroups'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getStandingsGroups; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.standings.getStandingsGroups', input ?? {}, 'completed'); - return response; -}; +export const getStandingsGroups: ApiSportsEndpoints['getStandingsGroups'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getStandingsGroups; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getStandingsGroups'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.standings.getStandingsGroups', + input ?? {}, + 'completed', + ); + return response; + }; /** Get Standings Divisions */ -export const getStandingsDivisions: ApiSportsEndpoints['getStandingsDivisions'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getStandingsDivisions; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.standings.getStandingsDivisions', input ?? {}, 'completed'); - return response; -}; +export const getStandingsDivisions: ApiSportsEndpoints['getStandingsDivisions'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getStandingsDivisions; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getStandingsDivisions'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.standings.getStandingsDivisions', + input ?? {}, + 'completed', + ); + return response; + }; /** Get NFL Standings Conferences */ -export const getNflStandingsConferences: ApiSportsEndpoints['getNflStandingsConferences'] = async (ctx, input) => { - const route = API_SPORTS_ROUTES.getNflStandingsConferences; - const response = await executeApiSportsRequest( - ctx, - route.sport, - route.path, - { apiKey: ctx.key, query: input }, - ); - await logEventFromContext(ctx, 'api_sports.standings.getNflStandingsConferences', input ?? {}, 'completed'); - return response; -}; +export const getNflStandingsConferences: ApiSportsEndpoints['getNflStandingsConferences'] = + async (ctx, input) => { + const route = API_SPORTS_ROUTES.getNflStandingsConferences; + const response = await executeApiSportsRequest< + ApiSportsEndpointOutputs['getNflStandingsConferences'] + >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); + await logEventFromContext( + ctx, + 'api_sports.standings.getNflStandingsConferences', + input ?? {}, + 'completed', + ); + return response; + }; diff --git a/packages/api_sports/index.ts b/packages/api_sports/index.ts index 1110b0b71..f25006933 100644 --- a/packages/api_sports/index.ts +++ b/packages/api_sports/index.ts @@ -13,16 +13,16 @@ import type { RequiredPluginEndpointSchemas, } from 'corsair/core'; import { AuthMissingError } from 'corsair/core'; -import * as Core from './endpoints/core'; -import * as Fixtures from './endpoints/fixtures'; -import * as Standings from './endpoints/standings'; -import * as Players from './endpoints/players'; -import * as Odds from './endpoints/odds'; -import * as Basketball from './endpoints/basketball'; import * as Afl from './endpoints/afl'; import * as Baseball from './endpoints/baseball'; +import * as Basketball from './endpoints/basketball'; +import * as Core from './endpoints/core'; +import * as Fixtures from './endpoints/fixtures'; import * as Formula1 from './endpoints/formula1'; import * as Mma from './endpoints/mma'; +import * as Odds from './endpoints/odds'; +import * as Players from './endpoints/players'; +import * as Standings from './endpoints/standings'; import type { ApiSportsEndpointInputs, ApiSportsEndpointOutputs, @@ -47,16 +47,20 @@ export type ApiSportsContext = CorsairPluginContext< ApiSportsPluginOptions >; -export type ApiSportsKeyBuilderContext = KeyBuilderContext; - -export type ApiSportsBoundEndpoints = BindEndpoints; +export type ApiSportsKeyBuilderContext = + KeyBuilderContext; -type ApiSportsEndpoint = CorsairEndpoint< - ApiSportsContext, - ApiSportsEndpointInputs[K], - ApiSportsEndpointOutputs[K] +export type ApiSportsBoundEndpoints = BindEndpoints< + typeof apiSportsEndpointsNested >; +type ApiSportsEndpoint = + CorsairEndpoint< + ApiSportsContext, + ApiSportsEndpointInputs[K], + ApiSportsEndpointOutputs[K] + >; + export type ApiSportsEndpoints = { getCountries: ApiSportsEndpoint<'getCountries'>; getTimezone: ApiSportsEndpoint<'getTimezone'>; @@ -492,273 +496,273 @@ export const apiSportsEndpointSchemas = { const apiSportsEndpointMeta = { 'core.getCountries': { - riskLevel: 'read', - description: 'Get Countries', - }, + riskLevel: 'read', + description: 'Get Countries', + }, 'core.getTimezone': { - riskLevel: 'read', - description: 'Get Timezone', - }, + riskLevel: 'read', + description: 'Get Timezone', + }, 'core.getLeagues': { - riskLevel: 'read', - description: 'Get Leagues', - }, + riskLevel: 'read', + description: 'Get Leagues', + }, 'core.getLeagueSeasons': { - riskLevel: 'read', - description: 'Get League Seasons', - }, + riskLevel: 'read', + description: 'Get League Seasons', + }, 'core.getTeams': { - riskLevel: 'read', - description: 'Get Teams', - }, + riskLevel: 'read', + description: 'Get Teams', + }, 'core.getTeamSeasons': { - riskLevel: 'read', - description: 'Get Team Seasons', - }, + riskLevel: 'read', + description: 'Get Team Seasons', + }, 'core.getTeamStatistics': { - riskLevel: 'read', - description: 'Get Team Statistics', - }, + riskLevel: 'read', + description: 'Get Team Statistics', + }, 'core.getVenues': { - riskLevel: 'read', - description: 'Get Venues', - }, + riskLevel: 'read', + description: 'Get Venues', + }, 'core.getCoaches': { - riskLevel: 'read', - description: 'Get Coaches', - }, + riskLevel: 'read', + description: 'Get Coaches', + }, 'core.getInjuries': { - riskLevel: 'read', - description: 'Get Injuries', - }, + riskLevel: 'read', + description: 'Get Injuries', + }, 'core.getSidelined': { - riskLevel: 'read', - description: 'Get Sidelined', - }, + riskLevel: 'read', + description: 'Get Sidelined', + }, 'core.getTransfers': { - riskLevel: 'read', - description: 'Get Transfers', - }, + riskLevel: 'read', + description: 'Get Transfers', + }, 'core.getTrophies': { - riskLevel: 'read', - description: 'Get Trophies', - }, + riskLevel: 'read', + description: 'Get Trophies', + }, 'core.getPredictions': { - riskLevel: 'read', - description: 'Get Predictions', - }, + riskLevel: 'read', + description: 'Get Predictions', + }, 'fixtures.getFixtures': { - riskLevel: 'read', - description: 'Get Fixtures', - }, + riskLevel: 'read', + description: 'Get Fixtures', + }, 'fixtures.getFixturesRounds': { - riskLevel: 'read', - description: 'Get Fixtures Rounds', - }, + riskLevel: 'read', + description: 'Get Fixtures Rounds', + }, 'fixtures.getHeadToHeadFixtures': { - riskLevel: 'read', - description: 'Get Head-to-Head Fixtures', - }, + riskLevel: 'read', + description: 'Get Head-to-Head Fixtures', + }, 'fixtures.getFixtureLineups': { - riskLevel: 'read', - description: 'Get Fixture Lineups', - }, + riskLevel: 'read', + description: 'Get Fixture Lineups', + }, 'fixtures.getFixtureStatistics': { - riskLevel: 'read', - description: 'Get Fixture Statistics', - }, + riskLevel: 'read', + description: 'Get Fixture Statistics', + }, 'fixtures.getFixturesEvents': { - riskLevel: 'read', - description: 'Get Fixtures Events', - }, + riskLevel: 'read', + description: 'Get Fixtures Events', + }, 'fixtures.getFixturesPlayers': { - riskLevel: 'read', - description: 'Get Fixtures Players', - }, + riskLevel: 'read', + description: 'Get Fixtures Players', + }, 'standings.getStandingsStages': { - riskLevel: 'read', - description: 'Get Standings Stages', - }, + riskLevel: 'read', + description: 'Get Standings Stages', + }, 'standings.getStandingsGroups': { - riskLevel: 'read', - description: 'Get Standings Groups', - }, + riskLevel: 'read', + description: 'Get Standings Groups', + }, 'standings.getStandingsDivisions': { - riskLevel: 'read', - description: 'Get Standings Divisions', - }, + riskLevel: 'read', + description: 'Get Standings Divisions', + }, 'standings.getNflStandingsConferences': { - riskLevel: 'read', - description: 'Get NFL Standings Conferences', - }, + riskLevel: 'read', + description: 'Get NFL Standings Conferences', + }, 'players.getPlayers': { - riskLevel: 'read', - description: 'Get Players', - }, + riskLevel: 'read', + description: 'Get Players', + }, 'players.getPlayersProfiles': { - riskLevel: 'read', - description: 'Get Players Profiles', - }, + riskLevel: 'read', + description: 'Get Players Profiles', + }, 'players.getPlayersSeasons': { - riskLevel: 'read', - description: 'Get Players Seasons', - }, + riskLevel: 'read', + description: 'Get Players Seasons', + }, 'players.getPlayersSquads': { - riskLevel: 'read', - description: 'Get Players Squads', - }, + riskLevel: 'read', + description: 'Get Players Squads', + }, 'players.getPlayersTeams': { - riskLevel: 'read', - description: 'Get Players Teams', - }, + riskLevel: 'read', + description: 'Get Players Teams', + }, 'players.getPlayersTopScorers': { - riskLevel: 'read', - description: 'Get Players Top Scorers', - }, + riskLevel: 'read', + description: 'Get Players Top Scorers', + }, 'players.getPlayersTopAssists': { - riskLevel: 'read', - description: 'Get Players Top Assists', - }, + riskLevel: 'read', + description: 'Get Players Top Assists', + }, 'players.getPlayersTopYellowCards': { - riskLevel: 'read', - description: 'Get Players Top Yellow Cards', - }, + riskLevel: 'read', + description: 'Get Players Top Yellow Cards', + }, 'players.getPlayersTopRedCards': { - riskLevel: 'read', - description: 'Get Players Top Red Cards', - }, + riskLevel: 'read', + description: 'Get Players Top Red Cards', + }, 'odds.getOdds': { - riskLevel: 'read', - description: 'Get Odds', - }, + riskLevel: 'read', + description: 'Get Odds', + }, 'odds.getOddsBets': { - riskLevel: 'read', - description: 'Get Odds Bets', - }, + riskLevel: 'read', + description: 'Get Odds Bets', + }, 'odds.getOddsBookmakers': { - riskLevel: 'read', - description: 'Get Odds Bookmakers', - }, + riskLevel: 'read', + description: 'Get Odds Bookmakers', + }, 'odds.getOddsMapping': { - riskLevel: 'read', - description: 'Get Odds Mapping', - }, + riskLevel: 'read', + description: 'Get Odds Mapping', + }, 'odds.getInPlayOdds': { - riskLevel: 'read', - description: 'Get In-Play Odds', - }, + riskLevel: 'read', + description: 'Get In-Play Odds', + }, 'odds.getLiveOddsBets': { - riskLevel: 'read', - description: 'Get Live Odds Bets', - }, + riskLevel: 'read', + description: 'Get Live Odds Bets', + }, 'basketball.getBasketballStatistics': { - riskLevel: 'read', - description: 'Get Basketball Statistics', - }, + riskLevel: 'read', + description: 'Get Basketball Statistics', + }, 'basketball.getBasketballBets': { - riskLevel: 'read', - description: 'Get Basketball Bets', - }, + riskLevel: 'read', + description: 'Get Basketball Bets', + }, 'basketball.getBasketballBookmakers': { - riskLevel: 'read', - description: 'Get Basketball Bookmakers', - }, + riskLevel: 'read', + description: 'Get Basketball Bookmakers', + }, 'basketball.getNbaGameStatistics': { - riskLevel: 'read', - description: 'Get NBA Game Statistics', - }, + riskLevel: 'read', + description: 'Get NBA Game Statistics', + }, 'basketball.getPlayerStatistics': { - riskLevel: 'read', - description: 'Get Player Statistics', - }, + riskLevel: 'read', + description: 'Get Player Statistics', + }, 'basketball.getGameStatisticsByTeams': { - riskLevel: 'read', - description: 'Get Game Statistics by Teams', - }, + riskLevel: 'read', + description: 'Get Game Statistics by Teams', + }, 'basketball.getGamesEvents': { - riskLevel: 'read', - description: 'Get Games Events', - }, + riskLevel: 'read', + description: 'Get Games Events', + }, 'afl.getAflSeasons': { - riskLevel: 'read', - description: 'Get AFL Seasons', - }, + riskLevel: 'read', + description: 'Get AFL Seasons', + }, 'afl.getAflGames': { - riskLevel: 'read', - description: 'Get AFL Games', - }, + riskLevel: 'read', + description: 'Get AFL Games', + }, 'afl.getAflGamesQuarters': { - riskLevel: 'read', - description: 'Get AFL Games Quarters', - }, + riskLevel: 'read', + description: 'Get AFL Games Quarters', + }, 'afl.getAflGamePlayerStatistics': { - riskLevel: 'read', - description: 'Get AFL Game Player Statistics', - }, + riskLevel: 'read', + description: 'Get AFL Game Player Statistics', + }, 'afl.getAflStandings': { - riskLevel: 'read', - description: 'Get AFL Standings', - }, + riskLevel: 'read', + description: 'Get AFL Standings', + }, 'baseball.getBaseballGamesHeadToHead': { - riskLevel: 'read', - description: 'Get Baseball Games Head-to-Head', - }, + riskLevel: 'read', + description: 'Get Baseball Games Head-to-Head', + }, 'formula1.getFormula1Circuits': { - riskLevel: 'read', - description: 'Get Formula 1 Circuits', - }, + riskLevel: 'read', + description: 'Get Formula 1 Circuits', + }, 'formula1.getFormula1Competitions': { - riskLevel: 'read', - description: 'Get Formula 1 Competitions', - }, + riskLevel: 'read', + description: 'Get Formula 1 Competitions', + }, 'formula1.getFormula1Races': { - riskLevel: 'read', - description: 'Get Formula 1 Races', - }, + riskLevel: 'read', + description: 'Get Formula 1 Races', + }, 'formula1.getFormula1DriverRankings': { - riskLevel: 'read', - description: 'Get Formula 1 Driver Rankings', - }, + riskLevel: 'read', + description: 'Get Formula 1 Driver Rankings', + }, 'formula1.getFormula1TeamRankings': { - riskLevel: 'read', - description: 'Get Formula 1 Team Rankings', - }, + riskLevel: 'read', + description: 'Get Formula 1 Team Rankings', + }, 'formula1.getFormula1StartingGrid': { - riskLevel: 'read', - description: 'Get Formula 1 Starting Grid', - }, + riskLevel: 'read', + description: 'Get Formula 1 Starting Grid', + }, 'formula1.getFastestLapsRankings': { - riskLevel: 'read', - description: 'Get Fastest Laps Rankings', - }, + riskLevel: 'read', + description: 'Get Fastest Laps Rankings', + }, 'formula1.getRaceRankings': { - riskLevel: 'read', - description: 'Get Race Rankings', - }, + riskLevel: 'read', + description: 'Get Race Rankings', + }, 'mma.getMmaCategories': { - riskLevel: 'read', - description: 'Get MMA Categories', - }, + riskLevel: 'read', + description: 'Get MMA Categories', + }, 'mma.getMmaFighters': { - riskLevel: 'read', - description: 'Get MMA Fighters', - }, + riskLevel: 'read', + description: 'Get MMA Fighters', + }, 'mma.getMmaFights': { - riskLevel: 'read', - description: 'Get MMA Fights', - }, + riskLevel: 'read', + description: 'Get MMA Fights', + }, 'mma.getMmaFightResults': { - riskLevel: 'read', - description: 'Get MMA Fight Results', - }, + riskLevel: 'read', + description: 'Get MMA Fight Results', + }, 'mma.getMmaFighterStatistics': { - riskLevel: 'read', - description: 'Get MMA Fighter Statistics', - }, + riskLevel: 'read', + description: 'Get MMA Fighter Statistics', + }, 'mma.getFightersRecords': { - riskLevel: 'read', - description: 'Get Fighters Records', - }, + riskLevel: 'read', + description: 'Get Fighters Records', + }, } satisfies RequiredPluginEndpointMeta; const defaultAuthType: AuthTypes = 'api_key' as const; @@ -767,23 +771,25 @@ export const apiSportsAuthConfig = { api_key: {}, } as const satisfies PluginAuthConfig; -export type BaseApiSportsPlugin = CorsairPlugin< - 'api_sports', - typeof ApiSportsSchema, - typeof apiSportsEndpointsNested, - typeof apiSportsWebhooksNested, - T, - typeof defaultAuthType ->; +export type BaseApiSportsPlugin = + CorsairPlugin< + 'api_sports', + typeof ApiSportsSchema, + typeof apiSportsEndpointsNested, + typeof apiSportsWebhooksNested, + T, + typeof defaultAuthType + >; -export type InternalApiSportsPlugin = BaseApiSportsPlugin; +export type InternalApiSportsPlugin = + BaseApiSportsPlugin; export type ExternalApiSportsPlugin = BaseApiSportsPlugin; export function apiSports( - incomingOptions: ApiSportsPluginOptions & - T = {} as ApiSportsPluginOptions & T, + incomingOptions: ApiSportsPluginOptions & T = {} as ApiSportsPluginOptions & + T, ): ExternalApiSportsPlugin { const options = { ...incomingOptions, From afc1edac742560c77227f82b1ef52ac12600153f Mon Sep 17 00:00:00 2001 From: Dhirender Choudhary Date: Tue, 4 Aug 2026 12:57:06 +0530 Subject: [PATCH 8/9] fix(apisports): rename package to drop underscore --- .../{api_sports => apisports}/api.test.ts | 0 packages/{api_sports => apisports}/client.ts | 0 .../endpoints/afl.ts | 10 +++---- .../endpoints/baseball.ts | 2 +- .../endpoints/basketball.ts | 14 +++++----- .../endpoints/core.ts | 28 +++++++++---------- .../endpoints/fixtures.ts | 14 +++++----- .../endpoints/formula1.ts | 16 +++++------ .../endpoints/index.ts | 0 .../endpoints/mma.ts | 12 ++++---- .../endpoints/odds.ts | 12 ++++---- .../endpoints/players.ts | 18 ++++++------ .../endpoints/routes.ts | 0 .../endpoints/shared.ts | 2 +- .../endpoints/standings.ts | 8 +++--- .../endpoints/types.ts | 0 .../error-handlers.ts | 0 packages/{api_sports => apisports}/index.ts | 10 +++---- .../{api_sports => apisports}/jest.config.cjs | 0 .../{api_sports => apisports}/package.json | 4 +-- .../schema/database.ts | 0 .../{api_sports => apisports}/schema/index.ts | 0 .../{api_sports => apisports}/tsconfig.json | 0 .../{api_sports => apisports}/tsup.config.ts | 0 packages/corsair/core/constants.ts | 6 ++-- pnpm-lock.yaml | 2 +- 26 files changed, 79 insertions(+), 79 deletions(-) rename packages/{api_sports => apisports}/api.test.ts (100%) rename packages/{api_sports => apisports}/client.ts (100%) rename packages/{api_sports => apisports}/endpoints/afl.ts (92%) rename packages/{api_sports => apisports}/endpoints/baseball.ts (93%) rename packages/{api_sports => apisports}/endpoints/basketball.ts (91%) rename packages/{api_sports => apisports}/endpoints/core.ts (92%) rename packages/{api_sports => apisports}/endpoints/fixtures.ts (91%) rename packages/{api_sports => apisports}/endpoints/formula1.ts (91%) rename packages/{api_sports => apisports}/endpoints/index.ts (100%) rename packages/{api_sports => apisports}/endpoints/mma.ts (92%) rename packages/{api_sports => apisports}/endpoints/odds.ts (92%) rename packages/{api_sports => apisports}/endpoints/players.ts (91%) rename packages/{api_sports => apisports}/endpoints/routes.ts (100%) rename packages/{api_sports => apisports}/endpoints/shared.ts (94%) rename packages/{api_sports => apisports}/endpoints/standings.ts (91%) rename packages/{api_sports => apisports}/endpoints/types.ts (100%) rename packages/{api_sports => apisports}/error-handlers.ts (100%) rename packages/{api_sports => apisports}/index.ts (99%) rename packages/{api_sports => apisports}/jest.config.cjs (100%) rename packages/{api_sports => apisports}/package.json (94%) rename packages/{api_sports => apisports}/schema/database.ts (100%) rename packages/{api_sports => apisports}/schema/index.ts (100%) rename packages/{api_sports => apisports}/tsconfig.json (100%) rename packages/{api_sports => apisports}/tsup.config.ts (100%) diff --git a/packages/api_sports/api.test.ts b/packages/apisports/api.test.ts similarity index 100% rename from packages/api_sports/api.test.ts rename to packages/apisports/api.test.ts diff --git a/packages/api_sports/client.ts b/packages/apisports/client.ts similarity index 100% rename from packages/api_sports/client.ts rename to packages/apisports/client.ts diff --git a/packages/api_sports/endpoints/afl.ts b/packages/apisports/endpoints/afl.ts similarity index 92% rename from packages/api_sports/endpoints/afl.ts rename to packages/apisports/endpoints/afl.ts index c0f79d8c1..b49ad3292 100644 --- a/packages/api_sports/endpoints/afl.ts +++ b/packages/apisports/endpoints/afl.ts @@ -15,7 +15,7 @@ export const getAflSeasons: ApiSportsEndpoints['getAflSeasons'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.afl.getAflSeasons', + 'apisports.afl.getAflSeasons', input ?? {}, 'completed', ); @@ -33,7 +33,7 @@ export const getAflGames: ApiSportsEndpoints['getAflGames'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.afl.getAflGames', + 'apisports.afl.getAflGames', input ?? {}, 'completed', ); @@ -49,7 +49,7 @@ export const getAflGamesQuarters: ApiSportsEndpoints['getAflGamesQuarters'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.afl.getAflGamesQuarters', + 'apisports.afl.getAflGamesQuarters', input ?? {}, 'completed', ); @@ -65,7 +65,7 @@ export const getAflGamePlayerStatistics: ApiSportsEndpoints['getAflGamePlayerSta >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.afl.getAflGamePlayerStatistics', + 'apisports.afl.getAflGamePlayerStatistics', input ?? {}, 'completed', ); @@ -83,7 +83,7 @@ export const getAflStandings: ApiSportsEndpoints['getAflStandings'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.afl.getAflStandings', + 'apisports.afl.getAflStandings', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/baseball.ts b/packages/apisports/endpoints/baseball.ts similarity index 93% rename from packages/api_sports/endpoints/baseball.ts rename to packages/apisports/endpoints/baseball.ts index d3749d678..a231635bd 100644 --- a/packages/api_sports/endpoints/baseball.ts +++ b/packages/apisports/endpoints/baseball.ts @@ -13,7 +13,7 @@ export const getBaseballGamesHeadToHead: ApiSportsEndpoints['getBaseballGamesHea >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.baseball.getBaseballGamesHeadToHead', + 'apisports.baseball.getBaseballGamesHeadToHead', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/basketball.ts b/packages/apisports/endpoints/basketball.ts similarity index 91% rename from packages/api_sports/endpoints/basketball.ts rename to packages/apisports/endpoints/basketball.ts index 1fdccbc9c..a62f18d19 100644 --- a/packages/api_sports/endpoints/basketball.ts +++ b/packages/apisports/endpoints/basketball.ts @@ -13,7 +13,7 @@ export const getBasketballStatistics: ApiSportsEndpoints['getBasketballStatistic >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.basketball.getBasketballStatistics', + 'apisports.basketball.getBasketballStatistics', input ?? {}, 'completed', ); @@ -29,7 +29,7 @@ export const getBasketballBets: ApiSportsEndpoints['getBasketballBets'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.basketball.getBasketballBets', + 'apisports.basketball.getBasketballBets', input ?? {}, 'completed', ); @@ -45,7 +45,7 @@ export const getBasketballBookmakers: ApiSportsEndpoints['getBasketballBookmaker >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.basketball.getBasketballBookmakers', + 'apisports.basketball.getBasketballBookmakers', input ?? {}, 'completed', ); @@ -61,7 +61,7 @@ export const getNbaGameStatistics: ApiSportsEndpoints['getNbaGameStatistics'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.basketball.getNbaGameStatistics', + 'apisports.basketball.getNbaGameStatistics', input ?? {}, 'completed', ); @@ -77,7 +77,7 @@ export const getPlayerStatistics: ApiSportsEndpoints['getPlayerStatistics'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.basketball.getPlayerStatistics', + 'apisports.basketball.getPlayerStatistics', input ?? {}, 'completed', ); @@ -93,7 +93,7 @@ export const getGameStatisticsByTeams: ApiSportsEndpoints['getGameStatisticsByTe >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.basketball.getGameStatisticsByTeams', + 'apisports.basketball.getGameStatisticsByTeams', input ?? {}, 'completed', ); @@ -111,7 +111,7 @@ export const getGamesEvents: ApiSportsEndpoints['getGamesEvents'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.basketball.getGamesEvents', + 'apisports.basketball.getGamesEvents', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/core.ts b/packages/apisports/endpoints/core.ts similarity index 92% rename from packages/api_sports/endpoints/core.ts rename to packages/apisports/endpoints/core.ts index e8c415c10..b38d6485e 100644 --- a/packages/api_sports/endpoints/core.ts +++ b/packages/apisports/endpoints/core.ts @@ -15,7 +15,7 @@ export const getCountries: ApiSportsEndpoints['getCountries'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getCountries', + 'apisports.core.getCountries', input ?? {}, 'completed', ); @@ -33,7 +33,7 @@ export const getTimezone: ApiSportsEndpoints['getTimezone'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getTimezone', + 'apisports.core.getTimezone', input ?? {}, 'completed', ); @@ -51,7 +51,7 @@ export const getLeagues: ApiSportsEndpoints['getLeagues'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getLeagues', + 'apisports.core.getLeagues', input ?? {}, 'completed', ); @@ -69,7 +69,7 @@ export const getLeagueSeasons: ApiSportsEndpoints['getLeagueSeasons'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getLeagueSeasons', + 'apisports.core.getLeagueSeasons', input ?? {}, 'completed', ); @@ -84,7 +84,7 @@ export const getTeams: ApiSportsEndpoints['getTeams'] = async (ctx, input) => { >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getTeams', + 'apisports.core.getTeams', input ?? {}, 'completed', ); @@ -102,7 +102,7 @@ export const getTeamSeasons: ApiSportsEndpoints['getTeamSeasons'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getTeamSeasons', + 'apisports.core.getTeamSeasons', input ?? {}, 'completed', ); @@ -118,7 +118,7 @@ export const getTeamStatistics: ApiSportsEndpoints['getTeamStatistics'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getTeamStatistics', + 'apisports.core.getTeamStatistics', input ?? {}, 'completed', ); @@ -136,7 +136,7 @@ export const getVenues: ApiSportsEndpoints['getVenues'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getVenues', + 'apisports.core.getVenues', input ?? {}, 'completed', ); @@ -154,7 +154,7 @@ export const getCoaches: ApiSportsEndpoints['getCoaches'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getCoaches', + 'apisports.core.getCoaches', input ?? {}, 'completed', ); @@ -172,7 +172,7 @@ export const getInjuries: ApiSportsEndpoints['getInjuries'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getInjuries', + 'apisports.core.getInjuries', input ?? {}, 'completed', ); @@ -190,7 +190,7 @@ export const getSidelined: ApiSportsEndpoints['getSidelined'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getSidelined', + 'apisports.core.getSidelined', input ?? {}, 'completed', ); @@ -208,7 +208,7 @@ export const getTransfers: ApiSportsEndpoints['getTransfers'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getTransfers', + 'apisports.core.getTransfers', input ?? {}, 'completed', ); @@ -226,7 +226,7 @@ export const getTrophies: ApiSportsEndpoints['getTrophies'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getTrophies', + 'apisports.core.getTrophies', input ?? {}, 'completed', ); @@ -244,7 +244,7 @@ export const getPredictions: ApiSportsEndpoints['getPredictions'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.core.getPredictions', + 'apisports.core.getPredictions', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/fixtures.ts b/packages/apisports/endpoints/fixtures.ts similarity index 91% rename from packages/api_sports/endpoints/fixtures.ts rename to packages/apisports/endpoints/fixtures.ts index 835fbfdb5..191d48b81 100644 --- a/packages/api_sports/endpoints/fixtures.ts +++ b/packages/apisports/endpoints/fixtures.ts @@ -15,7 +15,7 @@ export const getFixtures: ApiSportsEndpoints['getFixtures'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.fixtures.getFixtures', + 'apisports.fixtures.getFixtures', input ?? {}, 'completed', ); @@ -31,7 +31,7 @@ export const getFixturesRounds: ApiSportsEndpoints['getFixturesRounds'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.fixtures.getFixturesRounds', + 'apisports.fixtures.getFixturesRounds', input ?? {}, 'completed', ); @@ -47,7 +47,7 @@ export const getHeadToHeadFixtures: ApiSportsEndpoints['getHeadToHeadFixtures'] >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.fixtures.getHeadToHeadFixtures', + 'apisports.fixtures.getHeadToHeadFixtures', input ?? {}, 'completed', ); @@ -63,7 +63,7 @@ export const getFixtureLineups: ApiSportsEndpoints['getFixtureLineups'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.fixtures.getFixtureLineups', + 'apisports.fixtures.getFixtureLineups', input ?? {}, 'completed', ); @@ -79,7 +79,7 @@ export const getFixtureStatistics: ApiSportsEndpoints['getFixtureStatistics'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.fixtures.getFixtureStatistics', + 'apisports.fixtures.getFixtureStatistics', input ?? {}, 'completed', ); @@ -95,7 +95,7 @@ export const getFixturesEvents: ApiSportsEndpoints['getFixturesEvents'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.fixtures.getFixturesEvents', + 'apisports.fixtures.getFixturesEvents', input ?? {}, 'completed', ); @@ -111,7 +111,7 @@ export const getFixturesPlayers: ApiSportsEndpoints['getFixturesPlayers'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.fixtures.getFixturesPlayers', + 'apisports.fixtures.getFixturesPlayers', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/formula1.ts b/packages/apisports/endpoints/formula1.ts similarity index 91% rename from packages/api_sports/endpoints/formula1.ts rename to packages/apisports/endpoints/formula1.ts index b447f6b52..5d17f68d6 100644 --- a/packages/api_sports/endpoints/formula1.ts +++ b/packages/apisports/endpoints/formula1.ts @@ -13,7 +13,7 @@ export const getFormula1Circuits: ApiSportsEndpoints['getFormula1Circuits'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getFormula1Circuits', + 'apisports.formula1.getFormula1Circuits', input ?? {}, 'completed', ); @@ -29,7 +29,7 @@ export const getFormula1Competitions: ApiSportsEndpoints['getFormula1Competition >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getFormula1Competitions', + 'apisports.formula1.getFormula1Competitions', input ?? {}, 'completed', ); @@ -47,7 +47,7 @@ export const getFormula1Races: ApiSportsEndpoints['getFormula1Races'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getFormula1Races', + 'apisports.formula1.getFormula1Races', input ?? {}, 'completed', ); @@ -63,7 +63,7 @@ export const getFormula1DriverRankings: ApiSportsEndpoints['getFormula1DriverRan >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getFormula1DriverRankings', + 'apisports.formula1.getFormula1DriverRankings', input ?? {}, 'completed', ); @@ -79,7 +79,7 @@ export const getFormula1TeamRankings: ApiSportsEndpoints['getFormula1TeamRanking >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getFormula1TeamRankings', + 'apisports.formula1.getFormula1TeamRankings', input ?? {}, 'completed', ); @@ -95,7 +95,7 @@ export const getFormula1StartingGrid: ApiSportsEndpoints['getFormula1StartingGri >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getFormula1StartingGrid', + 'apisports.formula1.getFormula1StartingGrid', input ?? {}, 'completed', ); @@ -111,7 +111,7 @@ export const getFastestLapsRankings: ApiSportsEndpoints['getFastestLapsRankings' >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getFastestLapsRankings', + 'apisports.formula1.getFastestLapsRankings', input ?? {}, 'completed', ); @@ -129,7 +129,7 @@ export const getRaceRankings: ApiSportsEndpoints['getRaceRankings'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.formula1.getRaceRankings', + 'apisports.formula1.getRaceRankings', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/index.ts b/packages/apisports/endpoints/index.ts similarity index 100% rename from packages/api_sports/endpoints/index.ts rename to packages/apisports/endpoints/index.ts diff --git a/packages/api_sports/endpoints/mma.ts b/packages/apisports/endpoints/mma.ts similarity index 92% rename from packages/api_sports/endpoints/mma.ts rename to packages/apisports/endpoints/mma.ts index 2ef294a9b..ee38d866a 100644 --- a/packages/api_sports/endpoints/mma.ts +++ b/packages/apisports/endpoints/mma.ts @@ -15,7 +15,7 @@ export const getMmaCategories: ApiSportsEndpoints['getMmaCategories'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.mma.getMmaCategories', + 'apisports.mma.getMmaCategories', input ?? {}, 'completed', ); @@ -33,7 +33,7 @@ export const getMmaFighters: ApiSportsEndpoints['getMmaFighters'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.mma.getMmaFighters', + 'apisports.mma.getMmaFighters', input ?? {}, 'completed', ); @@ -51,7 +51,7 @@ export const getMmaFights: ApiSportsEndpoints['getMmaFights'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.mma.getMmaFights', + 'apisports.mma.getMmaFights', input ?? {}, 'completed', ); @@ -67,7 +67,7 @@ export const getMmaFightResults: ApiSportsEndpoints['getMmaFightResults'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.mma.getMmaFightResults', + 'apisports.mma.getMmaFightResults', input ?? {}, 'completed', ); @@ -83,7 +83,7 @@ export const getMmaFighterStatistics: ApiSportsEndpoints['getMmaFighterStatistic >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.mma.getMmaFighterStatistics', + 'apisports.mma.getMmaFighterStatistics', input ?? {}, 'completed', ); @@ -99,7 +99,7 @@ export const getFightersRecords: ApiSportsEndpoints['getFightersRecords'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.mma.getFightersRecords', + 'apisports.mma.getFightersRecords', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/odds.ts b/packages/apisports/endpoints/odds.ts similarity index 92% rename from packages/api_sports/endpoints/odds.ts rename to packages/apisports/endpoints/odds.ts index ca89a4bfd..63dbaece0 100644 --- a/packages/api_sports/endpoints/odds.ts +++ b/packages/apisports/endpoints/odds.ts @@ -12,7 +12,7 @@ export const getOdds: ApiSportsEndpoints['getOdds'] = async (ctx, input) => { >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.odds.getOdds', + 'apisports.odds.getOdds', input ?? {}, 'completed', ); @@ -30,7 +30,7 @@ export const getOddsBets: ApiSportsEndpoints['getOddsBets'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.odds.getOddsBets', + 'apisports.odds.getOddsBets', input ?? {}, 'completed', ); @@ -46,7 +46,7 @@ export const getOddsBookmakers: ApiSportsEndpoints['getOddsBookmakers'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.odds.getOddsBookmakers', + 'apisports.odds.getOddsBookmakers', input ?? {}, 'completed', ); @@ -64,7 +64,7 @@ export const getOddsMapping: ApiSportsEndpoints['getOddsMapping'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.odds.getOddsMapping', + 'apisports.odds.getOddsMapping', input ?? {}, 'completed', ); @@ -82,7 +82,7 @@ export const getInPlayOdds: ApiSportsEndpoints['getInPlayOdds'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.odds.getInPlayOdds', + 'apisports.odds.getInPlayOdds', input ?? {}, 'completed', ); @@ -100,7 +100,7 @@ export const getLiveOddsBets: ApiSportsEndpoints['getLiveOddsBets'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.odds.getLiveOddsBets', + 'apisports.odds.getLiveOddsBets', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/players.ts b/packages/apisports/endpoints/players.ts similarity index 91% rename from packages/api_sports/endpoints/players.ts rename to packages/apisports/endpoints/players.ts index e53e53677..7184d3819 100644 --- a/packages/api_sports/endpoints/players.ts +++ b/packages/apisports/endpoints/players.ts @@ -15,7 +15,7 @@ export const getPlayers: ApiSportsEndpoints['getPlayers'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayers', + 'apisports.players.getPlayers', input ?? {}, 'completed', ); @@ -31,7 +31,7 @@ export const getPlayersProfiles: ApiSportsEndpoints['getPlayersProfiles'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersProfiles', + 'apisports.players.getPlayersProfiles', input ?? {}, 'completed', ); @@ -47,7 +47,7 @@ export const getPlayersSeasons: ApiSportsEndpoints['getPlayersSeasons'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersSeasons', + 'apisports.players.getPlayersSeasons', input ?? {}, 'completed', ); @@ -65,7 +65,7 @@ export const getPlayersSquads: ApiSportsEndpoints['getPlayersSquads'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersSquads', + 'apisports.players.getPlayersSquads', input ?? {}, 'completed', ); @@ -83,7 +83,7 @@ export const getPlayersTeams: ApiSportsEndpoints['getPlayersTeams'] = async ( >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersTeams', + 'apisports.players.getPlayersTeams', input ?? {}, 'completed', ); @@ -99,7 +99,7 @@ export const getPlayersTopScorers: ApiSportsEndpoints['getPlayersTopScorers'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersTopScorers', + 'apisports.players.getPlayersTopScorers', input ?? {}, 'completed', ); @@ -115,7 +115,7 @@ export const getPlayersTopAssists: ApiSportsEndpoints['getPlayersTopAssists'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersTopAssists', + 'apisports.players.getPlayersTopAssists', input ?? {}, 'completed', ); @@ -131,7 +131,7 @@ export const getPlayersTopYellowCards: ApiSportsEndpoints['getPlayersTopYellowCa >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersTopYellowCards', + 'apisports.players.getPlayersTopYellowCards', input ?? {}, 'completed', ); @@ -147,7 +147,7 @@ export const getPlayersTopRedCards: ApiSportsEndpoints['getPlayersTopRedCards'] >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.players.getPlayersTopRedCards', + 'apisports.players.getPlayersTopRedCards', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/routes.ts b/packages/apisports/endpoints/routes.ts similarity index 100% rename from packages/api_sports/endpoints/routes.ts rename to packages/apisports/endpoints/routes.ts diff --git a/packages/api_sports/endpoints/shared.ts b/packages/apisports/endpoints/shared.ts similarity index 94% rename from packages/api_sports/endpoints/shared.ts rename to packages/apisports/endpoints/shared.ts index f8c8cd7ba..ccf55a4fb 100644 --- a/packages/api_sports/endpoints/shared.ts +++ b/packages/apisports/endpoints/shared.ts @@ -42,7 +42,7 @@ export async function cacheApiSportsQuery( }, ); } catch (error) { - console.warn('[api_sports] Failed to save query to database:', error); + console.warn('[apisports] Failed to save query to database:', error); } } diff --git a/packages/api_sports/endpoints/standings.ts b/packages/apisports/endpoints/standings.ts similarity index 91% rename from packages/api_sports/endpoints/standings.ts rename to packages/apisports/endpoints/standings.ts index d0092e6fa..779a97d50 100644 --- a/packages/api_sports/endpoints/standings.ts +++ b/packages/apisports/endpoints/standings.ts @@ -13,7 +13,7 @@ export const getStandingsStages: ApiSportsEndpoints['getStandingsStages'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.standings.getStandingsStages', + 'apisports.standings.getStandingsStages', input ?? {}, 'completed', ); @@ -29,7 +29,7 @@ export const getStandingsGroups: ApiSportsEndpoints['getStandingsGroups'] = >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.standings.getStandingsGroups', + 'apisports.standings.getStandingsGroups', input ?? {}, 'completed', ); @@ -45,7 +45,7 @@ export const getStandingsDivisions: ApiSportsEndpoints['getStandingsDivisions'] >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.standings.getStandingsDivisions', + 'apisports.standings.getStandingsDivisions', input ?? {}, 'completed', ); @@ -61,7 +61,7 @@ export const getNflStandingsConferences: ApiSportsEndpoints['getNflStandingsConf >(ctx, route.sport, route.path, { apiKey: ctx.key, query: input }); await logEventFromContext( ctx, - 'api_sports.standings.getNflStandingsConferences', + 'apisports.standings.getNflStandingsConferences', input ?? {}, 'completed', ); diff --git a/packages/api_sports/endpoints/types.ts b/packages/apisports/endpoints/types.ts similarity index 100% rename from packages/api_sports/endpoints/types.ts rename to packages/apisports/endpoints/types.ts diff --git a/packages/api_sports/error-handlers.ts b/packages/apisports/error-handlers.ts similarity index 100% rename from packages/api_sports/error-handlers.ts rename to packages/apisports/error-handlers.ts diff --git a/packages/api_sports/index.ts b/packages/apisports/index.ts similarity index 99% rename from packages/api_sports/index.ts rename to packages/apisports/index.ts index f25006933..93c5213b8 100644 --- a/packages/api_sports/index.ts +++ b/packages/apisports/index.ts @@ -773,7 +773,7 @@ export const apiSportsAuthConfig = { export type BaseApiSportsPlugin = CorsairPlugin< - 'api_sports', + 'apisports', typeof ApiSportsSchema, typeof apiSportsEndpointsNested, typeof apiSportsWebhooksNested, @@ -787,7 +787,7 @@ export type InternalApiSportsPlugin = export type ExternalApiSportsPlugin = BaseApiSportsPlugin; -export function apiSports( +export function apisports( incomingOptions: ApiSportsPluginOptions & T = {} as ApiSportsPluginOptions & T, ): ExternalApiSportsPlugin { @@ -796,7 +796,7 @@ export function apiSports( authType: incomingOptions.authType ?? defaultAuthType, }; return { - id: 'api_sports', + id: 'apisports', authConfig: apiSportsAuthConfig, schema: ApiSportsSchema, options, @@ -818,11 +818,11 @@ export function apiSports( if (source === 'endpoint' && ctx.authType === 'api_key') { const res = await ctx.keys.get_api_key(); if (!res) { - throw new AuthMissingError('api_sports', 'api_key'); + throw new AuthMissingError('apisports', 'api_key'); } return res; } - throw new AuthMissingError('api_sports', 'api_key'); + throw new AuthMissingError('apisports', 'api_key'); }, } satisfies InternalApiSportsPlugin; } diff --git a/packages/api_sports/jest.config.cjs b/packages/apisports/jest.config.cjs similarity index 100% rename from packages/api_sports/jest.config.cjs rename to packages/apisports/jest.config.cjs diff --git a/packages/api_sports/package.json b/packages/apisports/package.json similarity index 94% rename from packages/api_sports/package.json rename to packages/apisports/package.json index 831ac619f..e8ffcbd43 100644 --- a/packages/api_sports/package.json +++ b/packages/apisports/package.json @@ -1,5 +1,5 @@ { - "name": "@corsair-dev/api_sports", + "name": "@corsair-dev/apisports", "version": "0.1.0", "description": "API-Sports plugin for Corsair", "type": "module", @@ -34,7 +34,7 @@ }, "keywords": [ "corsair", - "api_sports", + "apisports", "plugin" ], "author": "", diff --git a/packages/api_sports/schema/database.ts b/packages/apisports/schema/database.ts similarity index 100% rename from packages/api_sports/schema/database.ts rename to packages/apisports/schema/database.ts diff --git a/packages/api_sports/schema/index.ts b/packages/apisports/schema/index.ts similarity index 100% rename from packages/api_sports/schema/index.ts rename to packages/apisports/schema/index.ts diff --git a/packages/api_sports/tsconfig.json b/packages/apisports/tsconfig.json similarity index 100% rename from packages/api_sports/tsconfig.json rename to packages/apisports/tsconfig.json diff --git a/packages/api_sports/tsup.config.ts b/packages/apisports/tsup.config.ts similarity index 100% rename from packages/api_sports/tsup.config.ts rename to packages/apisports/tsup.config.ts diff --git a/packages/corsair/core/constants.ts b/packages/corsair/core/constants.ts index 4d098de4f..845222984 100644 --- a/packages/corsair/core/constants.ts +++ b/packages/corsair/core/constants.ts @@ -20,7 +20,7 @@ export const BaseProviders = [ 'airtable', 'algolia', 'amplitude', - 'api_sports', + 'apisports', 'asana', 'bitwarden', 'bluesky', @@ -119,7 +119,7 @@ export const ProviderDisplayNames = { airtable: 'Airtable', algolia: 'Algolia', amplitude: 'Amplitude', - api_sports: 'API-Sports', + apisports: 'API-Sports', asana: 'Asana', bitwarden: 'Bitwarden', bluesky: 'Bluesky', @@ -225,7 +225,7 @@ export type AllProviders = | 'airtable' | 'algolia' | 'amplitude' - | 'api_sports' + | 'apisports' | 'asana' | 'bitwarden' | 'bluesky' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 17f2b8c09..827bd15dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -467,7 +467,7 @@ importers: specifier: 4.4.3 version: 4.4.3 - packages/api_sports: + packages/apisports: devDependencies: '@types/jest': specifier: ^29.5.14 From b30732f049017916cd051d853ce9df84861eff94 Mon Sep 17 00:00:00 2001 From: Dhirender Choudhary Date: Wed, 12 Aug 2026 13:57:33 +0530 Subject: [PATCH 9/9] test(apisports): unit-test query join and skip live suite --- packages/apisports/api.test.ts | 88 +++++++++++++++------------------- packages/apisports/client.ts | 2 +- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/packages/apisports/api.test.ts b/packages/apisports/api.test.ts index d8317a4d1..f473d647c 100644 --- a/packages/apisports/api.test.ts +++ b/packages/apisports/api.test.ts @@ -1,5 +1,9 @@ import 'dotenv/config'; -import { ApiSportsAPIError, makeApiSportsRequest } from './client'; +import { + ApiSportsAPIError, + makeApiSportsRequest, + normalizeQuery, +} from './client'; import { API_SPORTS_ROUTES } from './endpoints/routes'; import type { ApiSportsResponse } from './endpoints/types'; import { @@ -9,13 +13,34 @@ import { const TEST_API_KEY = process.env.API_SPORTS_API_KEY; -describe('API-Sports API Type Tests', () => { - it('football countries returns correct type', async () => { - if (!TEST_API_KEY) { - console.warn('Skipping: API_SPORTS_API_KEY not set'); - return; - } +describe('normalizeQuery', () => { + it('joins array query params with hyphens', () => { + expect(normalizeQuery({ ids: [1208002, 1208003] })).toEqual({ + ids: '1208002-1208003', + }); + expect(normalizeQuery({ ids: [1, 2], live: true })).toEqual({ + ids: '1-2', + live: true, + }); + }); +}); +describe('API-Sports auth body errors', () => { + it('throws auth body errors for invalid key', async () => { + await expect( + makeApiSportsRequest('football', '/countries', { + apiKey: 'invalid', + }), + ).rejects.toThrow(/token|application key/i); + }); +}); + +(TEST_API_KEY ? describe : describe.skip)('API-Sports API Type Tests', () => { + if (!TEST_API_KEY) { + console.warn('Skipping: API_SPORTS_API_KEY not set'); + } + + it('football countries returns correct type', async () => { const response = await makeApiSportsRequest( 'football', '/countries', @@ -27,8 +52,6 @@ describe('API-Sports API Type Tests', () => { }); it('football timezone returns correct type', async () => { - if (!TEST_API_KEY) return; - const response = await makeApiSportsRequest( 'football', '/timezone', @@ -40,8 +63,6 @@ describe('API-Sports API Type Tests', () => { }); it('nba status returns correct type', async () => { - if (!TEST_API_KEY) return; - const response = await makeApiSportsRequest( 'nba', '/status', @@ -53,8 +74,6 @@ describe('API-Sports API Type Tests', () => { }); it('standings stages route hits football host', async () => { - if (!TEST_API_KEY) return; - const route = API_SPORTS_ROUTES.getStandingsStages; expect(route.sport).toBe('football'); @@ -69,8 +88,6 @@ describe('API-Sports API Type Tests', () => { }); it('standings groups route hits football host', async () => { - if (!TEST_API_KEY) return; - const route = API_SPORTS_ROUTES.getStandingsGroups; expect(route.sport).toBe('football'); @@ -84,8 +101,6 @@ describe('API-Sports API Type Tests', () => { }); it('games events route hits nfl host', async () => { - if (!TEST_API_KEY) return; - const route = API_SPORTS_ROUTES.getGamesEvents; expect(route.sport).toBe('nfl'); @@ -99,38 +114,13 @@ describe('API-Sports API Type Tests', () => { }); it('throws on API-Sports body errors', async () => { - if (!TEST_API_KEY) return; - - await expect( - makeApiSportsRequest('nba', '/games/events', { - apiKey: TEST_API_KEY, - }), - ).rejects.toBeInstanceOf(ApiSportsAPIError); - }); - - it('throws auth body errors for invalid key', async () => { - await expect( - makeApiSportsRequest('football', '/countries', { - apiKey: 'invalid', - }), - ).rejects.toThrow(/token|application key/i); - }); + const error = await makeApiSportsRequest( + 'nba', + '/games/events', + { apiKey: TEST_API_KEY }, + ).catch((e: unknown) => e); - it('joins array query params with hyphens', async () => { - if (!TEST_API_KEY) return; - - // Free plan may reject ids; assert we don't get a repeated-key style failure — - // either results or a plan/parameter body error (still proves request was formed). - try { - const response = await makeApiSportsRequest( - 'football', - '/fixtures', - { apiKey: TEST_API_KEY, query: { ids: [1208002, 1208003] } }, - ); - ApiSportsResponseSchema.parse(response); - } catch (error) { - expect(error).toBeInstanceOf(ApiSportsAPIError); - expect((error as Error).message.toLowerCase()).not.toContain('endpoint'); - } + expect(error).toBeInstanceOf(ApiSportsAPIError); + expect((error as Error).message).toMatch(/endpoint/i); }); }); diff --git a/packages/apisports/client.ts b/packages/apisports/client.ts index 464fe756e..8fa6de705 100644 --- a/packages/apisports/client.ts +++ b/packages/apisports/client.ts @@ -56,7 +56,7 @@ export type ApiSportsQueryValue = | undefined; /** API-Sports multi-id filters expect `ids=1-2-3`, not repeated keys. */ -function normalizeQuery( +export function normalizeQuery( query: Record, ): Record { const out: Record = {};