fansunited-data-layer 0.14.1 → 0.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/lib/api/fansunited/http.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,kEAAkE;IAClE,MAAM,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACjC;;;;;;;;;;OAUG;IACH,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAwFrE"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/lib/api/fansunited/http.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,kEAAkE;IAClE,MAAM,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACjC;;;;;;;;;;OAUG;IACH,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CA8ErE"}
@@ -31,11 +31,6 @@ function createHttpClient(domain) {
31
31
  }
32
32
  }
33
33
  }
34
- const timeout = 3e4;
35
- const debugUrl = new URL(url.toString());
36
- debugUrl.searchParams.delete("key");
37
- debugUrl.searchParams.delete("client_id");
38
- console.log("🔗 FansUnited API URL:", debugUrl.toString());
39
34
  const response = await fetch(url.toString(), {
40
35
  method: "GET",
41
36
  headers: {
@@ -44,7 +39,6 @@ function createHttpClient(domain) {
44
39
  // Merge custom headers (they can override defaults)
45
40
  ...options.headers
46
41
  },
47
- signal: AbortSignal.timeout(timeout),
48
42
  // Next.js cache options for ISR/on-demand revalidation
49
43
  ...options.next && { next: options.next }
50
44
  });
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sources":["../../../src/lib/api/fansunited/http.ts"],"sourcesContent":["/**\n * HTTP client for Fans United APIs\n */\n\nimport { getConfig, type DataLayerConfig } from \"../../config\";\n\n/**\n * Next.js cache options for ISR/on-demand revalidation\n */\nexport interface NextCacheOptions {\n revalidate?: number | false;\n tags?: string[];\n}\n\nexport interface RequestOptions {\n /** API path (e.g., '/v1/competitions') */\n path: string;\n /** Query parameters */\n params?: Record<string, string | string[] | undefined>;\n /** Custom headers to include in the request */\n headers?: Record<string, string>;\n /** Next.js cache options for ISR/on-demand revalidation */\n next?: NextCacheOptions;\n /** Optional data layer config (uses singleton if not provided) */\n config?: DataLayerConfig;\n}\n\nexport interface FansUnitedHttpClient {\n /**\n * Make a GET request to a Fans United API\n *\n * Handles:\n * - API key and client ID authentication via query params\n * - Timeout\n * - Error handling\n *\n * @param options - Request options\n * @returns Parsed JSON response\n */\n get<T>(options: RequestOptions): Promise<T>;\n}\n\n/**\n * Create an HTTP client for a specific Fans United API domain\n *\n * @param domain - The base URL for the API (e.g., 'https://football.fansunitedapi.com')\n * @returns HTTP client configured for the specified domain\n *\n * @example\n * ```typescript\n * import { createHttpClient } from '../http';\n * import { FANSUNITED_FOOTBALL_DOMAIN } from '../constants';\n *\n * const footballHttp = createHttpClient(FANSUNITED_FOOTBALL_DOMAIN);\n * const data = await footballHttp.get({ path: '/v1/competitions' });\n * ```\n */\nexport function createHttpClient(domain: string): FansUnitedHttpClient {\n const baseUrl = domain.replace(/\\/$/, \"\");\n\n function buildUrl(path: string): string {\n return `${baseUrl}${path}`;\n }\n\n return {\n async get<T>(options: RequestOptions): Promise<T> {\n const finalConfig = options.config || getConfig();\n const { fansUnited } = finalConfig;\n\n if (!fansUnited) {\n throw new Error(\n \"Fans United configuration is missing. \" +\n \"Add 'fansUnited' with 'apiKey' and 'clientId' to your config.\"\n );\n }\n\n if (!fansUnited.apiKey || !fansUnited.clientId) {\n throw new Error(\"Fans United configuration requires both 'apiKey' and 'clientId'\");\n }\n\n const url = new URL(buildUrl(options.path));\n\n // Add authentication query parameters\n url.searchParams.set(\"key\", fansUnited.apiKey);\n url.searchParams.set(\"client_id\", fansUnited.clientId);\n\n // Add additional query parameters\n if (options.params) {\n for (const [key, value] of Object.entries(options.params)) {\n if (value === undefined) continue;\n\n if (Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(key, value.join(\",\"));\n }\n } else {\n url.searchParams.set(key, value);\n }\n }\n }\n\n // Default timeout: 30 seconds\n const timeout = 30000;\n\n // Debug: Log the actual URL being called (without sensitive params)\n const debugUrl = new URL(url.toString());\n debugUrl.searchParams.delete(\"key\");\n debugUrl.searchParams.delete(\"client_id\");\n console.log(\"🔗 FansUnited API URL:\", debugUrl.toString());\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n // Merge custom headers (they can override defaults)\n ...options.headers,\n },\n signal: AbortSignal.timeout(timeout),\n // Next.js cache options for ISR/on-demand revalidation\n ...(options.next && { next: options.next }),\n });\n\n if (!response.ok) {\n // Try to get error details from response body\n let errorMessage = `Fans United API error: ${response.status} ${response.statusText}`;\n try {\n const errorBody = await response.text();\n if (errorBody) {\n errorMessage += ` - ${errorBody}`;\n }\n } catch (error) {\n // Log if we can't read the error body, but continue\n console.error(\"[Fans United HTTP] Failed to read error response body:\", {\n error: error instanceof Error ? error.message : String(error),\n status: response.status,\n statusText: response.statusText,\n });\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n },\n };\n}\n"],"names":[],"mappings":";AAyDO,SAAS,iBAAiB,QAAsC;AACnE,QAAM,UAAU,OAAO,QAAQ,OAAO,EAAE;AAExC,WAAS,SAAS,MAAsB;AACpC,WAAO,GAAG,OAAO,GAAG,IAAI;AAAA,EAC5B;AAEA,SAAO;AAAA,IACH,MAAM,IAAO,SAAqC;AAC9C,YAAM,cAAc,QAAQ,UAAU,UAAA;AACtC,YAAM,EAAE,eAAe;AAEvB,UAAI,CAAC,YAAY;AACb,cAAM,IAAI;AAAA,UACN;AAAA,QAAA;AAAA,MAGR;AAEA,UAAI,CAAC,WAAW,UAAU,CAAC,WAAW,UAAU;AAC5C,cAAM,IAAI,MAAM,iEAAiE;AAAA,MACrF;AAEA,YAAM,MAAM,IAAI,IAAI,SAAS,QAAQ,IAAI,CAAC;AAG1C,UAAI,aAAa,IAAI,OAAO,WAAW,MAAM;AAC7C,UAAI,aAAa,IAAI,aAAa,WAAW,QAAQ;AAGrD,UAAI,QAAQ,QAAQ;AAChB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AACvD,cAAI,UAAU,OAAW;AAEzB,cAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,gBAAI,MAAM,SAAS,GAAG;AAClB,kBAAI,aAAa,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,YAC7C;AAAA,UACJ,OAAO;AACH,gBAAI,aAAa,IAAI,KAAK,KAAK;AAAA,UACnC;AAAA,QACJ;AAAA,MACJ;AAGA,YAAM,UAAU;AAGhB,YAAM,WAAW,IAAI,IAAI,IAAI,UAAU;AACvC,eAAS,aAAa,OAAO,KAAK;AAClC,eAAS,aAAa,OAAO,WAAW;AACxC,cAAQ,IAAI,0BAA0B,SAAS,SAAA,CAAU;AAEzD,YAAM,WAAW,MAAM,MAAM,IAAI,YAAY;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS;AAAA,UACL,QAAQ;AAAA,UACR,gBAAgB;AAAA;AAAA,UAEhB,GAAG,QAAQ;AAAA,QAAA;AAAA,QAEf,QAAQ,YAAY,QAAQ,OAAO;AAAA;AAAA,QAEnC,GAAI,QAAQ,QAAQ,EAAE,MAAM,QAAQ,KAAA;AAAA,MAAK,CAC5C;AAED,UAAI,CAAC,SAAS,IAAI;AAEd,YAAI,eAAe,0BAA0B,SAAS,MAAM,IAAI,SAAS,UAAU;AACnF,YAAI;AACA,gBAAM,YAAY,MAAM,SAAS,KAAA;AACjC,cAAI,WAAW;AACX,4BAAgB,MAAM,SAAS;AAAA,UACnC;AAAA,QACJ,SAAS,OAAO;AAEZ,kBAAQ,MAAM,0DAA0D;AAAA,YACpE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC5D,QAAQ,SAAS;AAAA,YACjB,YAAY,SAAS;AAAA,UAAA,CACxB;AAAA,QACL;AACA,cAAM,IAAI,MAAM,YAAY;AAAA,MAChC;AAEA,aAAO,SAAS,KAAA;AAAA,IACpB;AAAA,EAAA;AAER;"}
1
+ {"version":3,"file":"http.js","sources":["../../../src/lib/api/fansunited/http.ts"],"sourcesContent":["/**\n * HTTP client for Fans United APIs\n */\n\nimport { getConfig, type DataLayerConfig } from \"../../config\";\n\n/**\n * Next.js cache options for ISR/on-demand revalidation\n */\nexport interface NextCacheOptions {\n revalidate?: number | false;\n tags?: string[];\n}\n\nexport interface RequestOptions {\n /** API path (e.g., '/v1/competitions') */\n path: string;\n /** Query parameters */\n params?: Record<string, string | string[] | undefined>;\n /** Custom headers to include in the request */\n headers?: Record<string, string>;\n /** Next.js cache options for ISR/on-demand revalidation */\n next?: NextCacheOptions;\n /** Optional data layer config (uses singleton if not provided) */\n config?: DataLayerConfig;\n}\n\nexport interface FansUnitedHttpClient {\n /**\n * Make a GET request to a Fans United API\n *\n * Handles:\n * - API key and client ID authentication via query params\n * - Timeout\n * - Error handling\n *\n * @param options - Request options\n * @returns Parsed JSON response\n */\n get<T>(options: RequestOptions): Promise<T>;\n}\n\n/**\n * Create an HTTP client for a specific Fans United API domain\n *\n * @param domain - The base URL for the API (e.g., 'https://football.fansunitedapi.com')\n * @returns HTTP client configured for the specified domain\n *\n * @example\n * ```typescript\n * import { createHttpClient } from '../http';\n * import { FANSUNITED_FOOTBALL_DOMAIN } from '../constants';\n *\n * const footballHttp = createHttpClient(FANSUNITED_FOOTBALL_DOMAIN);\n * const data = await footballHttp.get({ path: '/v1/competitions' });\n * ```\n */\nexport function createHttpClient(domain: string): FansUnitedHttpClient {\n const baseUrl = domain.replace(/\\/$/, \"\");\n\n function buildUrl(path: string): string {\n return `${baseUrl}${path}`;\n }\n\n return {\n async get<T>(options: RequestOptions): Promise<T> {\n const finalConfig = options.config || getConfig();\n const { fansUnited } = finalConfig;\n\n if (!fansUnited) {\n throw new Error(\n \"Fans United configuration is missing. \" +\n \"Add 'fansUnited' with 'apiKey' and 'clientId' to your config.\"\n );\n }\n\n if (!fansUnited.apiKey || !fansUnited.clientId) {\n throw new Error(\"Fans United configuration requires both 'apiKey' and 'clientId'\");\n }\n\n const url = new URL(buildUrl(options.path));\n\n // Add authentication query parameters\n url.searchParams.set(\"key\", fansUnited.apiKey);\n url.searchParams.set(\"client_id\", fansUnited.clientId);\n\n // Add additional query parameters\n if (options.params) {\n for (const [key, value] of Object.entries(options.params)) {\n if (value === undefined) continue;\n\n if (Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(key, value.join(\",\"));\n }\n } else {\n url.searchParams.set(key, value);\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n // Merge custom headers (they can override defaults)\n ...options.headers,\n },\n // Next.js cache options for ISR/on-demand revalidation\n ...(options.next && { next: options.next }),\n });\n\n if (!response.ok) {\n // Try to get error details from response body\n let errorMessage = `Fans United API error: ${response.status} ${response.statusText}`;\n try {\n const errorBody = await response.text();\n if (errorBody) {\n errorMessage += ` - ${errorBody}`;\n }\n } catch (error) {\n // Log if we can't read the error body, but continue\n console.error(\"[Fans United HTTP] Failed to read error response body:\", {\n error: error instanceof Error ? error.message : String(error),\n status: response.status,\n statusText: response.statusText,\n });\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n },\n };\n}\n"],"names":[],"mappings":";AAyDO,SAAS,iBAAiB,QAAsC;AACnE,QAAM,UAAU,OAAO,QAAQ,OAAO,EAAE;AAExC,WAAS,SAAS,MAAsB;AACpC,WAAO,GAAG,OAAO,GAAG,IAAI;AAAA,EAC5B;AAEA,SAAO;AAAA,IACH,MAAM,IAAO,SAAqC;AAC9C,YAAM,cAAc,QAAQ,UAAU,UAAA;AACtC,YAAM,EAAE,eAAe;AAEvB,UAAI,CAAC,YAAY;AACb,cAAM,IAAI;AAAA,UACN;AAAA,QAAA;AAAA,MAGR;AAEA,UAAI,CAAC,WAAW,UAAU,CAAC,WAAW,UAAU;AAC5C,cAAM,IAAI,MAAM,iEAAiE;AAAA,MACrF;AAEA,YAAM,MAAM,IAAI,IAAI,SAAS,QAAQ,IAAI,CAAC;AAG1C,UAAI,aAAa,IAAI,OAAO,WAAW,MAAM;AAC7C,UAAI,aAAa,IAAI,aAAa,WAAW,QAAQ;AAGrD,UAAI,QAAQ,QAAQ;AAChB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AACvD,cAAI,UAAU,OAAW;AAEzB,cAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,gBAAI,MAAM,SAAS,GAAG;AAClB,kBAAI,aAAa,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,YAC7C;AAAA,UACJ,OAAO;AACH,gBAAI,aAAa,IAAI,KAAK,KAAK;AAAA,UACnC;AAAA,QACJ;AAAA,MACJ;AAEA,YAAM,WAAW,MAAM,MAAM,IAAI,YAAY;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS;AAAA,UACL,QAAQ;AAAA,UACR,gBAAgB;AAAA;AAAA,UAEhB,GAAG,QAAQ;AAAA,QAAA;AAAA;AAAA,QAGf,GAAI,QAAQ,QAAQ,EAAE,MAAM,QAAQ,KAAA;AAAA,MAAK,CAC5C;AAED,UAAI,CAAC,SAAS,IAAI;AAEd,YAAI,eAAe,0BAA0B,SAAS,MAAM,IAAI,SAAS,UAAU;AACnF,YAAI;AACA,gBAAM,YAAY,MAAM,SAAS,KAAA;AACjC,cAAI,WAAW;AACX,4BAAgB,MAAM,SAAS;AAAA,UACnC;AAAA,QACJ,SAAS,OAAO;AAEZ,kBAAQ,MAAM,0DAA0D;AAAA,YACpE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC5D,QAAQ,SAAS;AAAA,YACjB,YAAY,SAAS;AAAA,UAAA,CACxB;AAAA,QACL;AACA,cAAM,IAAI,MAAM,YAAY;AAAA,MAChC;AAEA,aAAO,SAAS,KAAA;AAAA,IACpB;AAAA,EAAA;AAER;"}
@@ -1,18 +1,18 @@
1
1
  function getMarketTypeEnum(marketType) {
2
2
  const marketTypeMap = {
3
- "1x2": "1X2",
4
- "12": "12",
5
- OVER_UNDER: "OVER_UNDER",
3
+ "1x2": "FT_1X2",
4
+ "12": "FT_1X2",
5
+ OVER_UNDER: "OVER_GOALS_2_5",
6
6
  DOUBLE_CHANCE: "DOUBLE_CHANCE",
7
- BOTH_TO_SCORE: "BOTH_TO_SCORE",
7
+ BOTH_TO_SCORE: "BOTH_TEAMS_SCORE",
8
8
  DRAW_NO_BET: "DRAW_NO_BET",
9
9
  FIRST_TEAM_TO_SCORE: "FIRST_TEAM_TO_SCORE",
10
10
  CORRECT_SCORE: "CORRECT_SCORE",
11
11
  FIRST_HALF_GOALS: "FIRST_HALF_GOALS",
12
- FIRST_PLAYER_TO_SCORE: "FIRST_PLAYER_TO_SCORE",
13
- PLAYER_TO_SCORE_DURING_GAME: "PLAYER_TO_SCORE_DURING_GAME",
14
- PLAYER_TO_RECEIVE_CARD: "PLAYER_TO_RECEIVE_CARD",
15
- FIRST_HALF_AND_FINAL_RESULT: "FIRST_HALF_AND_FINAL_RESULT"
12
+ FIRST_PLAYER_TO_SCORE: "PLAYER_SCORE_FIRST_GOAL",
13
+ PLAYER_TO_SCORE_DURING_GAME: "PLAYER_SCORE",
14
+ PLAYER_TO_RECEIVE_CARD: "PLAYER_YELLOW_CARD",
15
+ FIRST_HALF_AND_FINAL_RESULT: "HT_FT"
16
16
  };
17
17
  return marketTypeMap[marketType] || marketType.toUpperCase();
18
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"matches.js","sources":["../../../../src/lib/api/fansunited-sdk/odds/matches.ts"],"sourcesContent":["/**\n * SDK-based odds operations for matches\n *\n * These functions use the FansUnited SDK's odds namespace to fetch betting odds\n * for matches and transform them to canonical types.\n */\n\nimport type FansUnitedSDKModel from \"fansunited-sdk-esm/Core/Global/Models/FansUnitedSDKModel\";\nimport type { FUSportsBatchMatchOdds, FUSportsBettingOperatorOdds } from \"../../../types/canonical\";\nimport type { MarketType } from \"../../sportal365-sports/football/matches/types\";\n\n/**\n * Options for fetching batch match odds\n */\nexport interface GetBatchMatchOddsOptions {\n /** Market types to include (e.g., ['1x2', 'OVER_UNDER']) */\n marketTypes?: MarketType[];\n /** Filter odds by specific bookmaker/operator IDs */\n bookmakerIds?: string[];\n /** Type of odds: PRE_EVENT, LIVE, or ALL (default: ALL) */\n oddType?: \"PRE_EVENT\" | \"LIVE\" | \"ALL\";\n /** Scope type for odds (default: ORDINARY_TIME) */\n scopeType?: \"ORDINARY_TIME\" | \"FULL_TIME\";\n /** Format of odds (default: DECIMAL) */\n oddFormat?: \"FRACTIONAL\" | \"DECIMAL\" | \"MONEYLINE\";\n}\n\n/**\n * Map SDK market type string to SDK enum\n */\nfunction getMarketTypeEnum(marketType: MarketType): string {\n // Map our canonical market types to SDK market type strings\n const marketTypeMap: Record<MarketType, string> = {\n \"1x2\": \"1X2\",\n \"12\": \"12\",\n OVER_UNDER: \"OVER_UNDER\",\n DOUBLE_CHANCE: \"DOUBLE_CHANCE\",\n BOTH_TO_SCORE: \"BOTH_TO_SCORE\",\n DRAW_NO_BET: \"DRAW_NO_BET\",\n FIRST_TEAM_TO_SCORE: \"FIRST_TEAM_TO_SCORE\",\n CORRECT_SCORE: \"CORRECT_SCORE\",\n FIRST_HALF_GOALS: \"FIRST_HALF_GOALS\",\n FIRST_PLAYER_TO_SCORE: \"FIRST_PLAYER_TO_SCORE\",\n PLAYER_TO_SCORE_DURING_GAME: \"PLAYER_TO_SCORE_DURING_GAME\",\n PLAYER_TO_RECEIVE_CARD: \"PLAYER_TO_RECEIVE_CARD\",\n FIRST_HALF_AND_FINAL_RESULT: \"FIRST_HALF_AND_FINAL_RESULT\",\n };\n\n return marketTypeMap[marketType] || marketType.toUpperCase();\n}\n\n/**\n * Transform SDK odds response to canonical format\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction transformSDKOdds(sdkOddsMap: Map<string, any[]>, bookmakerIds?: string[]): FUSportsBatchMatchOdds {\n const result: FUSportsBatchMatchOdds = new Map();\n\n sdkOddsMap.forEach((matchOdds, matchId) => {\n if (!matchOdds || matchOdds.length === 0) {\n return;\n }\n\n // Filter by bookmaker IDs if provided\n const filteredOdds = bookmakerIds\n ? matchOdds.filter((odd) => odd.bookmaker && bookmakerIds.includes(odd.bookmaker.id))\n : matchOdds;\n\n // Transform to canonical format\n const operators: FUSportsBettingOperatorOdds[] = filteredOdds\n .filter((odd) => odd.bookmaker && odd.markets && odd.markets.length > 0)\n .map((odd) => {\n const bookmaker = odd.bookmaker;\n const firstAsset = bookmaker.assets?.[0];\n\n // Get background color from branding or assets\n const backgroundColor = bookmaker.branding?.backgroundColor || firstAsset?.backgroundColor;\n\n // Get text color from branding, or calculate based on background\n const textColor =\n bookmaker.branding?.textColor || (isDarkColor(backgroundColor) ? \"#FFFFFF\" : \"#000000\");\n\n // Prefer transparent background URL, fallback to regular logo\n const logo = firstAsset?.transparentBackgroundUrl || firstAsset?.logo;\n\n // Get operator URL: prefer eventUrls, fallback to links homepage\n /* eslint-disable @typescript-eslint/no-explicit-any */\n const operatorUrl =\n bookmaker.eventUrls?.find((u: any) => u.appType === \"desktop\")?.url ||\n bookmaker.links?.find((l: any) => l.appType === \"desktop\")?.homepageUrl ||\n bookmaker.url ||\n \"\";\n /* eslint-enable @typescript-eslint/no-explicit-any */\n\n return {\n operator: {\n id: bookmaker.id,\n name: bookmaker.name,\n url: operatorUrl,\n branding: {\n backgroundColor,\n textColor,\n logo,\n },\n },\n type: odd.type,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n markets: odd.markets.map((market: any) => ({\n type: {\n id: market.type.id,\n code: market.type.code,\n name: market.type.name,\n },\n period: {\n id: market.scope.id,\n type: market.scope.type,\n name: market.scope.name,\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n selections: market.selections.map((selection: any) => {\n // Get the desktop URL from selection.urls array\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const selectionUrl = selection.urls?.find((u: any) => u.appType === \"desktop\")?.url;\n\n // Map movement to canonical format\n let movement: \"UP\" | \"DOWN\" | \"NONE\" = \"NONE\";\n if (selection.movement === \"UP\") movement = \"UP\";\n else if (selection.movement === \"DOWN\") movement = \"DOWN\";\n\n return {\n id: selection.id,\n name: selection.name,\n code: selection.code,\n value: selection.value,\n odds: selection.odds,\n oddsOld: selection.oddsOld,\n movement,\n url: selectionUrl,\n providerSelectionId: selection.providerInfo?.selectionId,\n };\n }),\n })),\n };\n });\n\n result.set(matchId, operators);\n });\n\n return result;\n}\n\n/**\n * Determine if a color is dark based on luminance\n */\nfunction isDarkColor(hexColor?: string): boolean {\n if (!hexColor) return true;\n\n const hex = hexColor.replace(\"#\", \"\");\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n\n // Calculate relative luminance (ITU-R BT.709)\n const luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;\n\n return luminance < 0.5;\n}\n\n/**\n * Get betting odds for multiple matches in a single API call\n *\n * Fetches odds for multiple matches using the SDK's batch odds endpoint.\n * This is more efficient than making individual calls for each match.\n *\n * @param sdk - The FansUnited SDK instance\n * @param matchIds - Array of match IDs to fetch odds for\n * @param options - Optional parameters for filtering odds\n * @returns Map of match IDs to their betting odds in canonical format\n *\n * @example\n * ```typescript\n * import { useFansUnitedSDK } from 'fansunited-data-layer/client';\n * import { getBatchMatchOdds } from 'fansunited-data-layer/client';\n *\n * function MyComponent() {\n * const sdk = useFansUnitedSDK();\n *\n * const fetchOdds = async () => {\n * if (!sdk) return;\n * const oddsMap = await getBatchMatchOdds(sdk, ['match1', 'match2', 'match3'], {\n * marketTypes: ['1x2', 'OVER_UNDER'],\n * oddType: 'PRE_EVENT'\n * });\n * console.log(oddsMap); // Map<matchId, operators[]>\n * };\n * }\n * ```\n */\nexport async function getBatchMatchOdds(\n sdk: FansUnitedSDKModel,\n matchIds: string[],\n options?: GetBatchMatchOddsOptions\n): Promise<FUSportsBatchMatchOdds> {\n if (!matchIds || matchIds.length === 0) {\n return new Map();\n }\n\n // Build filters for SDK call\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const filters: any = {\n oddType: options?.oddType || \"ALL\",\n scopeType: options?.scopeType || \"ORDINARY_TIME\",\n oddFormat: options?.oddFormat || \"DECIMAL\",\n };\n\n // Add market types if provided\n if (options?.marketTypes && options.marketTypes.length > 0) {\n filters.marketTypes = options.marketTypes.map((market) => getMarketTypeEnum(market));\n }\n\n // Call SDK odds.getByMatchIds()\n const sdkResponse = await sdk.odds.getByMatchIds(matchIds, filters);\n\n // Transform to canonical format\n return transformSDKOdds(sdkResponse, options?.bookmakerIds);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"matches.js","sources":["../../../../src/lib/api/fansunited-sdk/odds/matches.ts"],"sourcesContent":["/**\n * SDK-based odds operations for matches\n *\n * These functions use the FansUnited SDK's odds namespace to fetch betting odds\n * for matches and transform them to canonical types.\n */\n\nimport type FansUnitedSDKModel from \"fansunited-sdk-esm/Core/Global/Models/FansUnitedSDKModel\";\nimport type { FUSportsBatchMatchOdds, FUSportsBettingOperatorOdds } from \"../../../types/canonical\";\nimport type { MarketType } from \"../../sportal365-sports/football/matches/types\";\n\n/**\n * Options for fetching batch match odds\n */\nexport interface GetBatchMatchOddsOptions {\n /** Market types to include (e.g., ['1x2', 'OVER_UNDER']) */\n marketTypes?: MarketType[];\n /** Filter odds by specific bookmaker/operator IDs */\n bookmakerIds?: string[];\n /** Type of odds: PRE_EVENT, LIVE, or ALL (default: ALL) */\n oddType?: \"PRE_EVENT\" | \"LIVE\" | \"ALL\";\n /** Scope type for odds (default: ORDINARY_TIME) */\n scopeType?: \"ORDINARY_TIME\" | \"FULL_TIME\";\n /** Format of odds (default: DECIMAL) */\n oddFormat?: \"FRACTIONAL\" | \"DECIMAL\" | \"MONEYLINE\";\n}\n\n/**\n * Map SDK market type string to SDK enum\n */\nfunction getMarketTypeEnum(marketType: MarketType): string {\n // Map our canonical market types to SDK MatchOddsMarketEnum values\n const marketTypeMap: Record<MarketType, string> = {\n \"1x2\": \"FT_1X2\",\n \"12\": \"FT_1X2\",\n OVER_UNDER: \"OVER_GOALS_2_5\",\n DOUBLE_CHANCE: \"DOUBLE_CHANCE\",\n BOTH_TO_SCORE: \"BOTH_TEAMS_SCORE\",\n DRAW_NO_BET: \"DRAW_NO_BET\",\n FIRST_TEAM_TO_SCORE: \"FIRST_TEAM_TO_SCORE\",\n CORRECT_SCORE: \"CORRECT_SCORE\",\n FIRST_HALF_GOALS: \"FIRST_HALF_GOALS\",\n FIRST_PLAYER_TO_SCORE: \"PLAYER_SCORE_FIRST_GOAL\",\n PLAYER_TO_SCORE_DURING_GAME: \"PLAYER_SCORE\",\n PLAYER_TO_RECEIVE_CARD: \"PLAYER_YELLOW_CARD\",\n FIRST_HALF_AND_FINAL_RESULT: \"HT_FT\",\n };\n\n return marketTypeMap[marketType] || marketType.toUpperCase();\n}\n\n/**\n * Transform SDK odds response to canonical format\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction transformSDKOdds(sdkOddsMap: Map<string, any[]>, bookmakerIds?: string[]): FUSportsBatchMatchOdds {\n const result: FUSportsBatchMatchOdds = new Map();\n\n sdkOddsMap.forEach((matchOdds, matchId) => {\n if (!matchOdds || matchOdds.length === 0) {\n return;\n }\n\n // Filter by bookmaker IDs if provided\n const filteredOdds = bookmakerIds\n ? matchOdds.filter((odd) => odd.bookmaker && bookmakerIds.includes(odd.bookmaker.id))\n : matchOdds;\n\n // Transform to canonical format\n const operators: FUSportsBettingOperatorOdds[] = filteredOdds\n .filter((odd) => odd.bookmaker && odd.markets && odd.markets.length > 0)\n .map((odd) => {\n const bookmaker = odd.bookmaker;\n const firstAsset = bookmaker.assets?.[0];\n\n // Get background color from branding or assets\n const backgroundColor = bookmaker.branding?.backgroundColor || firstAsset?.backgroundColor;\n\n // Get text color from branding, or calculate based on background\n const textColor =\n bookmaker.branding?.textColor || (isDarkColor(backgroundColor) ? \"#FFFFFF\" : \"#000000\");\n\n // Prefer transparent background URL, fallback to regular logo\n const logo = firstAsset?.transparentBackgroundUrl || firstAsset?.logo;\n\n // Get operator URL: prefer eventUrls, fallback to links homepage\n /* eslint-disable @typescript-eslint/no-explicit-any */\n const operatorUrl =\n bookmaker.eventUrls?.find((u: any) => u.appType === \"desktop\")?.url ||\n bookmaker.links?.find((l: any) => l.appType === \"desktop\")?.homepageUrl ||\n bookmaker.url ||\n \"\";\n /* eslint-enable @typescript-eslint/no-explicit-any */\n\n return {\n operator: {\n id: bookmaker.id,\n name: bookmaker.name,\n url: operatorUrl,\n branding: {\n backgroundColor,\n textColor,\n logo,\n },\n },\n type: odd.type,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n markets: odd.markets.map((market: any) => ({\n type: {\n id: market.type.id,\n code: market.type.code,\n name: market.type.name,\n },\n period: {\n id: market.scope.id,\n type: market.scope.type,\n name: market.scope.name,\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n selections: market.selections.map((selection: any) => {\n // Get the desktop URL from selection.urls array\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const selectionUrl = selection.urls?.find((u: any) => u.appType === \"desktop\")?.url;\n\n // Map movement to canonical format\n let movement: \"UP\" | \"DOWN\" | \"NONE\" = \"NONE\";\n if (selection.movement === \"UP\") movement = \"UP\";\n else if (selection.movement === \"DOWN\") movement = \"DOWN\";\n\n return {\n id: selection.id,\n name: selection.name,\n code: selection.code,\n value: selection.value,\n odds: selection.odds,\n oddsOld: selection.oddsOld,\n movement,\n url: selectionUrl,\n providerSelectionId: selection.providerInfo?.selectionId,\n };\n }),\n })),\n };\n });\n\n result.set(matchId, operators);\n });\n\n return result;\n}\n\n/**\n * Determine if a color is dark based on luminance\n */\nfunction isDarkColor(hexColor?: string): boolean {\n if (!hexColor) return true;\n\n const hex = hexColor.replace(\"#\", \"\");\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n\n // Calculate relative luminance (ITU-R BT.709)\n const luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;\n\n return luminance < 0.5;\n}\n\n/**\n * Get betting odds for multiple matches in a single API call\n *\n * Fetches odds for multiple matches using the SDK's batch odds endpoint.\n * This is more efficient than making individual calls for each match.\n *\n * @param sdk - The FansUnited SDK instance\n * @param matchIds - Array of match IDs to fetch odds for\n * @param options - Optional parameters for filtering odds\n * @returns Map of match IDs to their betting odds in canonical format\n *\n * @example\n * ```typescript\n * import { useFansUnitedSDK } from 'fansunited-data-layer/client';\n * import { getBatchMatchOdds } from 'fansunited-data-layer/client';\n *\n * function MyComponent() {\n * const sdk = useFansUnitedSDK();\n *\n * const fetchOdds = async () => {\n * if (!sdk) return;\n * const oddsMap = await getBatchMatchOdds(sdk, ['match1', 'match2', 'match3'], {\n * marketTypes: ['1x2', 'OVER_UNDER'],\n * oddType: 'PRE_EVENT'\n * });\n * console.log(oddsMap); // Map<matchId, operators[]>\n * };\n * }\n * ```\n */\nexport async function getBatchMatchOdds(\n sdk: FansUnitedSDKModel,\n matchIds: string[],\n options?: GetBatchMatchOddsOptions\n): Promise<FUSportsBatchMatchOdds> {\n if (!matchIds || matchIds.length === 0) {\n return new Map();\n }\n\n // Build filters for SDK call\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const filters: any = {\n oddType: options?.oddType || \"ALL\",\n scopeType: options?.scopeType || \"ORDINARY_TIME\",\n oddFormat: options?.oddFormat || \"DECIMAL\",\n };\n\n // Add market types if provided\n if (options?.marketTypes && options.marketTypes.length > 0) {\n filters.marketTypes = options.marketTypes.map((market) => getMarketTypeEnum(market));\n }\n\n // Call SDK odds.getByMatchIds()\n const sdkResponse = await sdk.odds.getByMatchIds(matchIds, filters);\n\n // Transform to canonical format\n return transformSDKOdds(sdkResponse, options?.bookmakerIds);\n}\n"],"names":[],"mappings":"AA8BA,SAAS,kBAAkB,YAAgC;AAEvD,QAAM,gBAA4C;AAAA,IAC9C,OAAO;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,qBAAqB;AAAA,IACrB,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,6BAA6B;AAAA,IAC7B,wBAAwB;AAAA,IACxB,6BAA6B;AAAA,EAAA;AAGjC,SAAO,cAAc,UAAU,KAAK,WAAW,YAAA;AACnD;AAMA,SAAS,iBAAiB,YAAgC,cAAiD;AACvG,QAAM,6BAAqC,IAAA;AAE3C,aAAW,QAAQ,CAAC,WAAW,YAAY;AACvC,QAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACtC;AAAA,IACJ;AAGA,UAAM,eAAe,eACf,UAAU,OAAO,CAAC,QAAQ,IAAI,aAAa,aAAa,SAAS,IAAI,UAAU,EAAE,CAAC,IAClF;AAGN,UAAM,YAA2C,aAC5C,OAAO,CAAC,QAAQ,IAAI,aAAa,IAAI,WAAW,IAAI,QAAQ,SAAS,CAAC,EACtE,IAAI,CAAC,QAAQ;AACV,YAAM,YAAY,IAAI;AACtB,YAAM,aAAa,UAAU,SAAS,CAAC;AAGvC,YAAM,kBAAkB,UAAU,UAAU,mBAAmB,YAAY;AAG3E,YAAM,YACF,UAAU,UAAU,cAAc,YAAY,eAAe,IAAI,YAAY;AAGjF,YAAM,OAAO,YAAY,4BAA4B,YAAY;AAIjE,YAAM,cACF,UAAU,WAAW,KAAK,CAAC,MAAW,EAAE,YAAY,SAAS,GAAG,OAChE,UAAU,OAAO,KAAK,CAAC,MAAW,EAAE,YAAY,SAAS,GAAG,eAC5D,UAAU,OACV;AAGJ,aAAO;AAAA,QACH,UAAU;AAAA,UACN,IAAI,UAAU;AAAA,UACd,MAAM,UAAU;AAAA,UAChB,KAAK;AAAA,UACL,UAAU;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QACJ;AAAA,QAEJ,MAAM,IAAI;AAAA;AAAA,QAEV,SAAS,IAAI,QAAQ,IAAI,CAAC,YAAiB;AAAA,UACvC,MAAM;AAAA,YACF,IAAI,OAAO,KAAK;AAAA,YAChB,MAAM,OAAO,KAAK;AAAA,YAClB,MAAM,OAAO,KAAK;AAAA,UAAA;AAAA,UAEtB,QAAQ;AAAA,YACJ,IAAI,OAAO,MAAM;AAAA,YACjB,MAAM,OAAO,MAAM;AAAA,YACnB,MAAM,OAAO,MAAM;AAAA,UAAA;AAAA;AAAA,UAGvB,YAAY,OAAO,WAAW,IAAI,CAAC,cAAmB;AAGlD,kBAAM,eAAe,UAAU,MAAM,KAAK,CAAC,MAAW,EAAE,YAAY,SAAS,GAAG;AAGhF,gBAAI,WAAmC;AACvC,gBAAI,UAAU,aAAa,KAAM,YAAW;AAAA,qBACnC,UAAU,aAAa,OAAQ,YAAW;AAEnD,mBAAO;AAAA,cACH,IAAI,UAAU;AAAA,cACd,MAAM,UAAU;AAAA,cAChB,MAAM,UAAU;AAAA,cAChB,OAAO,UAAU;AAAA,cACjB,MAAM,UAAU;AAAA,cAChB,SAAS,UAAU;AAAA,cACnB;AAAA,cACA,KAAK;AAAA,cACL,qBAAqB,UAAU,cAAc;AAAA,YAAA;AAAA,UAErD,CAAC;AAAA,QAAA,EACH;AAAA,MAAA;AAAA,IAEV,CAAC;AAEL,WAAO,IAAI,SAAS,SAAS;AAAA,EACjC,CAAC;AAED,SAAO;AACX;AAKA,SAAS,YAAY,UAA4B;AAC7C,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,MAAM,SAAS,QAAQ,KAAK,EAAE;AACpC,QAAM,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC,GAAG,EAAE;AAC1C,QAAM,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC,GAAG,EAAE;AAC1C,QAAM,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC,GAAG,EAAE;AAG1C,QAAM,aAAa,SAAS,IAAI,SAAS,IAAI,SAAS,KAAK;AAE3D,SAAO,YAAY;AACvB;AAgCA,eAAsB,kBAClB,KACA,UACA,SAC+B;AAC/B,MAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AACpC,+BAAW,IAAA;AAAA,EACf;AAIA,QAAM,UAAe;AAAA,IACjB,SAAS,SAAS,WAAW;AAAA,IAC7B,WAAW,SAAS,aAAa;AAAA,IACjC,WAAW,SAAS,aAAa;AAAA,EAAA;AAIrC,MAAI,SAAS,eAAe,QAAQ,YAAY,SAAS,GAAG;AACxD,YAAQ,cAAc,QAAQ,YAAY,IAAI,CAAC,WAAW,kBAAkB,MAAM,CAAC;AAAA,EACvF;AAGA,QAAM,cAAc,MAAM,IAAI,KAAK,cAAc,UAAU,OAAO;AAGlE,SAAO,iBAAiB,aAAa,SAAS,YAAY;AAC9D;"}
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/lib/api/sportal365-sports/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/D;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,kEAAkE;IAClE,MAAM,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACjC;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CA+DrE"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/lib/api/sportal365-sports/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/D;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,kEAAkE;IAClE,MAAM,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACjC;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CA8DrE"}
@@ -41,7 +41,6 @@ function createHttpClient(domain) {
41
41
  // Merge custom headers (they can override defaults)
42
42
  ...options.headers
43
43
  },
44
- signal: sportal365Sports.timeout ? AbortSignal.timeout(sportal365Sports.timeout) : void 0,
45
44
  // Next.js cache options for ISR/on-demand revalidation
46
45
  ...options.next && { next: options.next }
47
46
  });
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sources":["../../../src/lib/api/sportal365-sports/http.ts"],"sourcesContent":["/**\n * Sportal365 Sports API - HTTP client factory\n * Creates sport-specific HTTP clients for Sportal365 APIs\n */\n\nimport { getConfig, type DataLayerConfig } from \"../../config\";\n\n/**\n * Next.js cache options for fetch requests\n * @see https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnext\n */\nexport interface NextCacheOptions {\n /** Time in seconds to cache the response. Set to 0 to disable caching. */\n revalidate?: number | false;\n /** Cache tags for on-demand revalidation with revalidateTag() */\n tags?: string[];\n}\n\nexport interface RequestOptions {\n /** API path (e.g., '/v2/matches/123') */\n path: string;\n /** Query parameters */\n params?: Record<string, string | string[] | undefined>;\n /** Custom headers to include in the request */\n headers?: Record<string, string>;\n /** Next.js cache options for ISR/on-demand revalidation */\n next?: NextCacheOptions;\n /** Optional data layer config (uses singleton if not provided) */\n config?: DataLayerConfig;\n}\n\nexport interface Sportal365HttpClient {\n /**\n * Make a GET request to the Sportal365 Sports API\n *\n * Handles:\n * - Authentication (Basic Auth)\n * - Project ID header\n * - Timeout\n * - Error handling\n *\n * @param options - Request options\n * @returns Parsed JSON response\n */\n get<T>(options: RequestOptions): Promise<T>;\n}\n\n/**\n * Create an HTTP client for a specific Sportal365 API domain\n *\n * @param domain - The base URL for the API (e.g., 'https://football.api.sportal365.com')\n * @returns HTTP client configured for the specified domain\n *\n * @example\n * ```typescript\n * import { createHttpClient } from '../http';\n * import { SPORTAL365_FOOTBALL_DOMAIN } from '../constants';\n *\n * const footballHttp = createHttpClient(SPORTAL365_FOOTBALL_DOMAIN);\n * const data = await footballHttp.get({ path: '/v2/matches/123' });\n * ```\n */\nexport function createHttpClient(domain: string): Sportal365HttpClient {\n const baseUrl = domain.replace(/\\/$/, \"\");\n\n function getAuthHeader(config: DataLayerConfig): string {\n const { sportal365Sports } = config;\n if (!sportal365Sports) {\n throw new Error(\"Sportal365 Sports API configuration is missing\");\n }\n const credentials = `${sportal365Sports.username}:${sportal365Sports.password}`;\n return `Basic ${btoa(credentials)}`;\n }\n\n function buildUrl(path: string): string {\n return `${baseUrl}${path}`;\n }\n\n return {\n async get<T>(options: RequestOptions): Promise<T> {\n const finalConfig = options.config || getConfig();\n const { sportal365Sports } = finalConfig;\n\n if (!sportal365Sports) {\n throw new Error(\"Sportal365 Sports API configuration is missing\");\n }\n\n const url = new URL(buildUrl(options.path));\n\n // Add query parameters\n if (options.params) {\n for (const [key, value] of Object.entries(options.params)) {\n if (value === undefined) continue;\n\n if (Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(key, value.join(\",\"));\n }\n } else {\n url.searchParams.set(key, value);\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n Authorization: getAuthHeader(finalConfig),\n \"Content-Type\": \"application/json\",\n \"X-Project\": sportal365Sports.projectId,\n // Merge custom headers (they can override defaults)\n ...options.headers,\n },\n signal: sportal365Sports.timeout ? AbortSignal.timeout(sportal365Sports.timeout) : undefined,\n // Next.js cache options for ISR/on-demand revalidation\n ...(options.next && { next: options.next }),\n });\n\n if (!response.ok) {\n throw new Error(`Sportal365 API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json();\n },\n };\n}\n"],"names":[],"mappings":";AA8DO,SAAS,iBAAiB,QAAsC;AACnE,QAAM,UAAU,OAAO,QAAQ,OAAO,EAAE;AAExC,WAAS,cAAc,QAAiC;AACpD,UAAM,EAAE,qBAAqB;AAC7B,QAAI,CAAC,kBAAkB;AACnB,YAAM,IAAI,MAAM,gDAAgD;AAAA,IACpE;AACA,UAAM,cAAc,GAAG,iBAAiB,QAAQ,IAAI,iBAAiB,QAAQ;AAC7E,WAAO,SAAS,KAAK,WAAW,CAAC;AAAA,EACrC;AAEA,WAAS,SAAS,MAAsB;AACpC,WAAO,GAAG,OAAO,GAAG,IAAI;AAAA,EAC5B;AAEA,SAAO;AAAA,IACH,MAAM,IAAO,SAAqC;AAC9C,YAAM,cAAc,QAAQ,UAAU,UAAA;AACtC,YAAM,EAAE,qBAAqB;AAE7B,UAAI,CAAC,kBAAkB;AACnB,cAAM,IAAI,MAAM,gDAAgD;AAAA,MACpE;AAEA,YAAM,MAAM,IAAI,IAAI,SAAS,QAAQ,IAAI,CAAC;AAG1C,UAAI,QAAQ,QAAQ;AAChB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AACvD,cAAI,UAAU,OAAW;AAEzB,cAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,gBAAI,MAAM,SAAS,GAAG;AAClB,kBAAI,aAAa,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,YAC7C;AAAA,UACJ,OAAO;AACH,gBAAI,aAAa,IAAI,KAAK,KAAK;AAAA,UACnC;AAAA,QACJ;AAAA,MACJ;AAEA,YAAM,WAAW,MAAM,MAAM,IAAI,YAAY;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS;AAAA,UACL,eAAe,cAAc,WAAW;AAAA,UACxC,gBAAgB;AAAA,UAChB,aAAa,iBAAiB;AAAA;AAAA,UAE9B,GAAG,QAAQ;AAAA,QAAA;AAAA,QAEf,QAAQ,iBAAiB,UAAU,YAAY,QAAQ,iBAAiB,OAAO,IAAI;AAAA;AAAA,QAEnF,GAAI,QAAQ,QAAQ,EAAE,MAAM,QAAQ,KAAA;AAAA,MAAK,CAC5C;AAED,UAAI,CAAC,SAAS,IAAI;AACd,cAAM,IAAI,MAAM,yBAAyB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,MACrF;AAEA,aAAO,SAAS,KAAA;AAAA,IACpB;AAAA,EAAA;AAER;"}
1
+ {"version":3,"file":"http.js","sources":["../../../src/lib/api/sportal365-sports/http.ts"],"sourcesContent":["/**\n * Sportal365 Sports API - HTTP client factory\n * Creates sport-specific HTTP clients for Sportal365 APIs\n */\n\nimport { getConfig, type DataLayerConfig } from \"../../config\";\n\n/**\n * Next.js cache options for fetch requests\n * @see https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnext\n */\nexport interface NextCacheOptions {\n /** Time in seconds to cache the response. Set to 0 to disable caching. */\n revalidate?: number | false;\n /** Cache tags for on-demand revalidation with revalidateTag() */\n tags?: string[];\n}\n\nexport interface RequestOptions {\n /** API path (e.g., '/v2/matches/123') */\n path: string;\n /** Query parameters */\n params?: Record<string, string | string[] | undefined>;\n /** Custom headers to include in the request */\n headers?: Record<string, string>;\n /** Next.js cache options for ISR/on-demand revalidation */\n next?: NextCacheOptions;\n /** Optional data layer config (uses singleton if not provided) */\n config?: DataLayerConfig;\n}\n\nexport interface Sportal365HttpClient {\n /**\n * Make a GET request to the Sportal365 Sports API\n *\n * Handles:\n * - Authentication (Basic Auth)\n * - Project ID header\n * - Timeout\n * - Error handling\n *\n * @param options - Request options\n * @returns Parsed JSON response\n */\n get<T>(options: RequestOptions): Promise<T>;\n}\n\n/**\n * Create an HTTP client for a specific Sportal365 API domain\n *\n * @param domain - The base URL for the API (e.g., 'https://football.api.sportal365.com')\n * @returns HTTP client configured for the specified domain\n *\n * @example\n * ```typescript\n * import { createHttpClient } from '../http';\n * import { SPORTAL365_FOOTBALL_DOMAIN } from '../constants';\n *\n * const footballHttp = createHttpClient(SPORTAL365_FOOTBALL_DOMAIN);\n * const data = await footballHttp.get({ path: '/v2/matches/123' });\n * ```\n */\nexport function createHttpClient(domain: string): Sportal365HttpClient {\n const baseUrl = domain.replace(/\\/$/, \"\");\n\n function getAuthHeader(config: DataLayerConfig): string {\n const { sportal365Sports } = config;\n if (!sportal365Sports) {\n throw new Error(\"Sportal365 Sports API configuration is missing\");\n }\n const credentials = `${sportal365Sports.username}:${sportal365Sports.password}`;\n return `Basic ${btoa(credentials)}`;\n }\n\n function buildUrl(path: string): string {\n return `${baseUrl}${path}`;\n }\n\n return {\n async get<T>(options: RequestOptions): Promise<T> {\n const finalConfig = options.config || getConfig();\n const { sportal365Sports } = finalConfig;\n\n if (!sportal365Sports) {\n throw new Error(\"Sportal365 Sports API configuration is missing\");\n }\n\n const url = new URL(buildUrl(options.path));\n\n // Add query parameters\n if (options.params) {\n for (const [key, value] of Object.entries(options.params)) {\n if (value === undefined) continue;\n\n if (Array.isArray(value)) {\n if (value.length > 0) {\n url.searchParams.set(key, value.join(\",\"));\n }\n } else {\n url.searchParams.set(key, value);\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n Authorization: getAuthHeader(finalConfig),\n \"Content-Type\": \"application/json\",\n \"X-Project\": sportal365Sports.projectId,\n // Merge custom headers (they can override defaults)\n ...options.headers,\n },\n // Next.js cache options for ISR/on-demand revalidation\n ...(options.next && { next: options.next }),\n });\n\n if (!response.ok) {\n throw new Error(`Sportal365 API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json();\n },\n };\n}\n"],"names":[],"mappings":";AA8DO,SAAS,iBAAiB,QAAsC;AACnE,QAAM,UAAU,OAAO,QAAQ,OAAO,EAAE;AAExC,WAAS,cAAc,QAAiC;AACpD,UAAM,EAAE,qBAAqB;AAC7B,QAAI,CAAC,kBAAkB;AACnB,YAAM,IAAI,MAAM,gDAAgD;AAAA,IACpE;AACA,UAAM,cAAc,GAAG,iBAAiB,QAAQ,IAAI,iBAAiB,QAAQ;AAC7E,WAAO,SAAS,KAAK,WAAW,CAAC;AAAA,EACrC;AAEA,WAAS,SAAS,MAAsB;AACpC,WAAO,GAAG,OAAO,GAAG,IAAI;AAAA,EAC5B;AAEA,SAAO;AAAA,IACH,MAAM,IAAO,SAAqC;AAC9C,YAAM,cAAc,QAAQ,UAAU,UAAA;AACtC,YAAM,EAAE,qBAAqB;AAE7B,UAAI,CAAC,kBAAkB;AACnB,cAAM,IAAI,MAAM,gDAAgD;AAAA,MACpE;AAEA,YAAM,MAAM,IAAI,IAAI,SAAS,QAAQ,IAAI,CAAC;AAG1C,UAAI,QAAQ,QAAQ;AAChB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AACvD,cAAI,UAAU,OAAW;AAEzB,cAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,gBAAI,MAAM,SAAS,GAAG;AAClB,kBAAI,aAAa,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,YAC7C;AAAA,UACJ,OAAO;AACH,gBAAI,aAAa,IAAI,KAAK,KAAK;AAAA,UACnC;AAAA,QACJ;AAAA,MACJ;AAEA,YAAM,WAAW,MAAM,MAAM,IAAI,YAAY;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS;AAAA,UACL,eAAe,cAAc,WAAW;AAAA,UACxC,gBAAgB;AAAA,UAChB,aAAa,iBAAiB;AAAA;AAAA,UAE9B,GAAG,QAAQ;AAAA,QAAA;AAAA;AAAA,QAGf,GAAI,QAAQ,QAAQ,EAAE,MAAM,QAAQ,KAAA;AAAA,MAAK,CAC5C;AAED,UAAI,CAAC,SAAS,IAAI;AACd,cAAM,IAAI,MAAM,yBAAyB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,MACrF;AAEA,aAAO,SAAS,KAAA;AAAA,IACpB;AAAA,EAAA;AAER;"}
package/config/types.d.ts CHANGED
@@ -9,7 +9,6 @@ export interface Sportal365SportsConfig {
9
9
  languageCode?: string;
10
10
  /** Odd client identifier for fetching odds (e.g., 'sportal_web') */
11
11
  oddClient?: string;
12
- timeout?: number;
13
12
  }
14
13
  export interface PayloadConfig {
15
14
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/config/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC5B,kDAAkD;IAClD,qBAAqB,EAAE,kBAAkB,GAAG,qBAAqB,CAAC;IAElE,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAE1C,gCAAgC;IAChC,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;;OAIG;IACH,UAAU,CAAC,EAAE;QACT,iDAAiD;QACjD,MAAM,EAAE,MAAM,CAAC;QACf,mDAAmD;QACnD,QAAQ,EAAE,MAAM,CAAC;QACjB,+EAA+E;QAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACL"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/config/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC1B,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC5B,kDAAkD;IAClD,qBAAqB,EAAE,kBAAkB,GAAG,qBAAqB,CAAC;IAElE,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAE1C,gCAAgC;IAChC,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;;OAIG;IACH,UAAU,CAAC,EAAE;QACT,iDAAiD;QACjD,MAAM,EAAE,MAAM,CAAC;QACf,mDAAmD;QACnD,QAAQ,EAAE,MAAM,CAAC;QACjB,+EAA+E;QAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACL"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "description": "A TypeScript library for fetching and transforming sports data from multiple API providers. Returns clean, canonical types that are provider-agnostic.",
5
5
  "homepage": "https://fansunited.com/",
6
6
  "private": false,
7
- "version": "0.14.1",
7
+ "version": "0.14.3",
8
8
  "type": "module",
9
9
  "sideEffects": false,
10
10
  "module": "./fansunited-data-layer.js",