fansunited-data-layer
v0.11.2
Published
A TypeScript library for fetching and transforming sports data from multiple API providers. Returns clean, canonical types that are provider-agnostic.
Keywords
Readme
fansunited-data-layer
A TypeScript library for fetching and transforming sports data from multiple API providers. Returns clean, canonical types that are provider-agnostic.
Installation
npm install fansunited-data-layerQuick Start
import { setConfig, getFootballMatch } from "fansunited-data-layer";
// Configure the library (once at app startup)
setConfig({
sportal365Sports: {
username: "your-username",
password: "your-password",
projectId: "your-project-id",
},
});
// Fetch a match
const match = await getFootballMatch("7576255");
console.log(match.competitorOne.name); // "Manchester United"
console.log(match.score?.competitorOne); // "2"API Reference
Configuration
setConfig(config)
Initialize the library with your API credentials.
Sportal365 Sports API:
setConfig({
defaultSportsProvider: "sportal365Sports",
sportal365Sports: {
username: string; // API username
password: string; // API password
projectId: string; // Your project ID
languageCode?: string; // Default language (default: 'en')
oddClient?: string; // Odd client identifier for odds
timeout?: number; // Request timeout in ms
}
});Fans United Sports API:
setConfig({
defaultSportsProvider: "fansUnitedSportsApi",
fansUnited: {
apiKey: string; // Your Fans United API key
clientId: string; // Your Fans United client ID
}
});The domain is hardcoded to https://football.fansunitedapi.com and timeout defaults to 30 seconds.
Fans United Football API
The library also supports the Fans United Football API as an alternative data provider. Use the same functions as above, but configure with Fans United credentials:
setConfig({
defaultSportsProvider: "fansUnitedSportsApi",
fansUnited: {
apiKey: "your-api-key",
clientId: "your-client-id",
},
});
// Now all football functions will use Fans United API
const match = await getFootballMatch("match-id");
const matches = await getFansUnitedFootballMatches({
teams: ["team-id"],
dateFrom: "2024-01-01",
dateTo: "2024-12-31",
});Available Fans United endpoints:
getFansUnitedFootballMatches(options)- Get multiple matches with filteringgetFansUnitedFootballCompetition(competitionId)- Get competition detailsgetFansUnitedFootballCompetitions(options)- Get list of competitionsgetFansUnitedFootballTeam(teamId)- Get team detailsgetFansUnitedFootballPlayer(playerId)- Get player details
All responses are transformed to the same canonical FUSports types for consistency.
Football Endpoints
getFootballMatch(matchId, options?)
Get a single match by ID, UUID, or slug.
const match = await getFootballMatch("7576255");
// With optional data
const match = await getFootballMatch("7576255", {
optionalData: ["MAIN_EVENTS", "LINEUP_STATUS", "REFEREES"],
});Options:
optionalData- Array of:'MAIN_EVENTS','LINEUP_STATUS','REFEREES','PENALTY_SHOOTOUT_EVENTS'languageCode- Override default language
getFootballMatchEvents(matchId, options?)
Get all events for a match (goals, cards, substitutions).
const events = await getFootballMatchEvents("7576255");
events.forEach((e) => console.log(`${e.minute}' - ${e.type}`));getFootballMatchLineups(matchId, options?)
Get match lineups with formations and player details.
const lineups = await getFootballMatchLineups("7576255");
console.log(lineups.competitorOne.formation); // "4-3-3"
console.log(lineups.competitorOne.starters); // Player[]getFootballMatchStatistics(matchId, options?)
Get match statistics (possession, shots, corners, etc.).
const stats = await getFootballMatchStatistics("7576255");
stats.competitorOne.statistics.forEach((s) => {
console.log(`${s.label}: ${s.value}${s.unit || ""}`);
});getFootballMatchOdds(matchId, options?)
Get betting odds from various operators.
const odds = await getFootballMatchOdds("7576255", {
oddType: "PREMATCH",
marketTypes: ["1X2", "OVER_UNDER"],
});getFootballMatchCommentary(matchId, options?)
Get live text commentary for a match.
const commentary = await getFootballMatchCommentary("7576255");
commentary.forEach((c) => {
console.log(`${c.minute}' - ${c.text}`);
});getFootballTeam(teamId, options?)
Get team details.
const team = await getFootballTeam("1234");
console.log(team.name);
console.log(team.assets?.logo);searchFootball(query, options?)
Search for football entities (teams, players, tournaments).
const results = await searchFootball("Manchester United", {
entityTypes: ["TEAM", "TOURNAMENT"],
languageCode: "en",
});
results.forEach((result) => {
console.log(`${result.entityType}: ${result.name}`);
});Options:
entityTypes- Array of:'TEAM','PLAYER','TOURNAMENT'languageCode- Override default language
search(query, options?)
Cross-sport search for entities across all sports.
const results = await search("Ronaldo", {
sports: ["FOOTBALL", "BASKETBALL"],
entityTypes: ["PLAYER"],
});Options:
sports- Array of sport types to search inentityTypes- Array of entity types to search forlanguageCode- Override default language
React Providers (Client Components)
For React Server Components (RSC) compatibility, client-side exports are available from a separate entry point:
"use client";
import { CompetitionProvider, useCompetition } from "fansunited-data-layer/client";
function MatchList() {
const { matches, getUpcomingMatches } = useCompetition();
const upcoming = getUpcomingMatches();
return (
<ul>
{upcoming.map((match) => (
<li key={match.id}>{match.competitorOne.name} vs {match.competitorTwo.name}</li>
))}
</ul>
);
}
// Wrap your app with the provider
function App() {
return (
<CompetitionProvider
competitionId="123"
matches={matches}
standings={standings}
>
<MatchList />
</CompetitionProvider>
);
}Available client exports:
CompetitionProvider/useCompetition- Competition data and helper functionsTeamProvider/useTeam- Team data, form stats, and match helpersMatchProvider/useMatch- Match data with lineups, events, statistics, odds, and commentaryFansUnitedConfigProvider/useFansUnitedConfig- SDK configuration and authentication
Match Provider
The MatchProvider offers comprehensive match data management with built-in helper hooks:
"use client";
import { MatchProvider, useMatch } from "fansunited-data-layer/client";
function MatchDetails() {
const {
match,
lineups,
events,
statistics,
odds,
commentary,
// Helper hooks
getScore,
getHomeTeam,
getAwayTeam,
isLive,
getGoals,
getCards,
// ... and many more
} = useMatch();
return (
<div>
<h1>{getHomeTeam().name} vs {getAwayTeam().name}</h1>
<p>Score: {getScore().home} - {getScore().away}</p>
{isLive() && <span>LIVE</span>}
</div>
);
}
function App() {
return (
<MatchProvider
match={matchData}
lineups={lineupsData}
events={eventsData}
statistics={statisticsData}
odds={oddsData}
commentary={commentaryData}
standings={standingsData}
headToHead={h2hData}
>
<MatchDetails />
</MatchProvider>
);
}Note: Server-safe functions (setConfig, getFootballMatch, etc.) should be imported from the main entry point 'fansunited-data-layer', not from '/client'.
Statistical Utilities
The library includes powerful statistical calculation functions for match and team analysis:
import {
calculateH2HStats,
getTeamGoalStats,
calculateStreak,
getTeamOverUnderStats,
getTeamsCommonOpponents,
} from "fansunited-data-layer";
// Head-to-head analysis
const h2hStats = calculateH2HStats(matches, "team-1-id", "team-2-id");
console.log(h2hStats.team1Wins, h2hStats.draws, h2hStats.team2Wins);
// Goal statistics
const goalStats = getTeamGoalStats(matches, "team-id");
console.log(goalStats.scored, goalStats.conceded, goalStats.avgScored);
// Streak analysis
const streak = calculateStreak(matches, "team-id");
console.log(streak.type, streak.count); // e.g., "WIN", 5
// Over/Under statistics
const overUnder = getTeamOverUnderStats(matches, "team-id", 2.5);
console.log(overUnder.over, overUnder.under, overUnder.overPercentage);Canonical Types
All responses are transformed to provider-agnostic canonical types prefixed with FUSports:
Match Types:
FUSportsMatch- Full match data with scores, status, timing, and competitorsFUSportsMatchEvent- Goals, cards, substitutions, and other match eventsFUSportsMatchLineups- Team lineups with formations and player detailsFUSportsMatchStatistics- Match statistics (possession, shots, passes, etc.)FUSportsMatchOdds- Betting odds from various operatorsFUSportsCommentaryItem- Live text commentary entriesFUSportsMatchScore- Score information including halftime, fulltime, and penaltiesFUSportsMatchStatus- Match status (not started, live, finished, etc.)
Competitor Types:
FUSportsCompetitor- Team/competitor data (discriminated union: team, player, or pair)FUSportsTeamCompetitor- Team-specific competitor dataFUSportsPlayerCompetitor- Player-specific competitor dataFUSportsPairCompetitor- Pair competitor data (for doubles sports)
Competition & Standing Types:
FUSportsCompetition- Tournament/league dataFUSportsStandings- League standings with team rankingsFUSportsStandingEntry- Individual team standing entry
Player & Squad Types:
FUSportsMember- Team member/player data (for squads, lineups, events)FUSportsSquadMember- Squad member with statisticsFUSportsLineupMember- Lineup player with position and formation dataFUSportsPlayerSeasonStatistics- Player season statisticsFUSportsPlayerMatchStats- Player match statistics (goals, assists, shots, etc.)
Search Types:
FUSportsTournamentSearchResult- Tournament search resultFUSportsTeamSearchResult- Team search resultFUSportsPlayerSearchResult- Player search result
TypeScript
Full TypeScript support with exported types:
import type {
FUSportsMatch,
FUSportsMatchEvent,
FUSportsCompetitor,
FUSportsMatchLineups,
FUSportsMatchStatistics,
} from "fansunited-data-layer";Features
- ✅ Multi-provider support - Sportal365 Sports API and Fans United Football API
- ✅ Canonical types - Provider-agnostic data structures for consistency
- ✅ TypeScript first - Full type safety with comprehensive type definitions
- ✅ React Server Components - Separate client/server entry points for RSC compatibility
- ✅ React Providers - Context providers for Competition, Team, and Match data
- ✅ Statistical utilities - Built-in functions for H2H, streaks, goals, and more
- ✅ Search functionality - Football-specific and cross-sport search
- ✅ Next.js optimized - Support for ISR and on-demand revalidation
- ✅ HMR-safe configuration - Config persists across hot module reloads
Configuration Persistence
The library automatically persists configuration across hot module replacement (HMR) in development environments like Next.js. You only need to call setConfig() once at app startup, and it will remain available even during development reloads.
License
MIT
