fansunited-data-layer 0.15.3 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/api/fansunited/index.d.ts +2 -0
- package/api/fansunited/index.d.ts.map +1 -1
- package/api/fansunited/search/__tests__/locale-agnostic-cache.test.d.ts +2 -0
- package/api/fansunited/search/__tests__/locale-agnostic-cache.test.d.ts.map +1 -0
- package/api/fansunited/search/index.d.ts.map +1 -1
- package/api/fansunited/search/index.js +41 -25
- package/api/fansunited/search/index.js.map +1 -1
- package/api/fansunited/search/transformer.js +3 -2
- package/api/fansunited/search/transformer.js.map +1 -1
- package/api/fansunited/sports/competition/__tests__/exports.test.d.ts +2 -0
- package/api/fansunited/sports/competition/__tests__/exports.test.d.ts.map +1 -0
- package/api/fansunited/sports/competition/__tests__/hydrated.test.d.ts +2 -0
- package/api/fansunited/sports/competition/__tests__/hydrated.test.d.ts.map +1 -0
- package/api/fansunited/sports/competition/__tests__/index.test.d.ts +2 -0
- package/api/fansunited/sports/competition/__tests__/index.test.d.ts.map +1 -0
- package/api/fansunited/sports/competition/hydrated.d.ts +45 -0
- package/api/fansunited/sports/competition/hydrated.d.ts.map +1 -0
- package/api/fansunited/sports/competition/hydrated.js +26 -0
- package/api/fansunited/sports/competition/hydrated.js.map +1 -0
- package/api/fansunited/sports/competition/index.d.ts +19 -0
- package/api/fansunited/sports/competition/index.d.ts.map +1 -0
- package/api/fansunited/sports/competition/index.js +27 -0
- package/api/fansunited/sports/competition/index.js.map +1 -0
- package/api/fansunited/sports/competition/transformer.d.ts +8 -0
- package/api/fansunited/sports/competition/transformer.d.ts.map +1 -0
- package/api/fansunited/sports/competition/transformer.js +52 -0
- package/api/fansunited/sports/competition/transformer.js.map +1 -0
- package/api/fansunited/sports/competition/types.d.ts +57 -0
- package/api/fansunited/sports/competition/types.d.ts.map +1 -0
- package/api/fansunited/sports/constants.d.ts +5 -0
- package/api/fansunited/sports/constants.d.ts.map +1 -0
- package/api/fansunited/sports/constants.js +5 -0
- package/api/fansunited/sports/constants.js.map +1 -0
- package/api/fansunited/sports/http.d.ts +8 -0
- package/api/fansunited/sports/http.d.ts.map +1 -0
- package/api/fansunited/sports/http.js +7 -0
- package/api/fansunited/sports/http.js.map +1 -0
- package/api/fansunited/sports/index.d.ts +15 -0
- package/api/fansunited/sports/index.d.ts.map +1 -0
- package/api/fansunited/sports/livescore/__tests__/hydrated.test.d.ts +2 -0
- package/api/fansunited/sports/livescore/__tests__/hydrated.test.d.ts.map +1 -0
- package/api/fansunited/sports/livescore/hydrated.d.ts +48 -0
- package/api/fansunited/sports/livescore/hydrated.d.ts.map +1 -0
- package/api/fansunited/sports/livescore/hydrated.js +34 -0
- package/api/fansunited/sports/livescore/hydrated.js.map +1 -0
- package/api/fansunited/sports/livescore/index.d.ts +27 -0
- package/api/fansunited/sports/livescore/index.d.ts.map +1 -0
- package/api/fansunited/sports/livescore/index.js +36 -0
- package/api/fansunited/sports/livescore/index.js.map +1 -0
- package/api/fansunited/sports/livescore/transformer.d.ts +8 -0
- package/api/fansunited/sports/livescore/transformer.d.ts.map +1 -0
- package/api/fansunited/sports/livescore/transformer.js +44 -0
- package/api/fansunited/sports/livescore/transformer.js.map +1 -0
- package/api/fansunited/sports/livescore/types.d.ts +58 -0
- package/api/fansunited/sports/livescore/types.d.ts.map +1 -0
- package/cache/__tests__/redis-integration.test.d.ts +14 -0
- package/cache/__tests__/redis-integration.test.d.ts.map +1 -0
- package/cache/__tests__/redis-l2-store.d.ts +52 -0
- package/cache/__tests__/redis-l2-store.d.ts.map +1 -0
- package/cache/__tests__/test-l2-store.d.ts +18 -0
- package/cache/__tests__/test-l2-store.d.ts.map +1 -0
- package/cache/cache-manager.d.ts +117 -12
- package/cache/cache-manager.d.ts.map +1 -1
- package/cache/cache-manager.js +23 -14
- package/cache/cache-manager.js.map +1 -1
- package/cache/cleanup.d.ts +1 -1
- package/cache/cleanup.d.ts.map +1 -1
- package/cache/index.d.ts +3 -2
- package/cache/index.d.ts.map +1 -1
- package/cache/sqlite-store.d.ts +4 -4
- package/cache/sqlite-store.d.ts.map +1 -1
- package/cache/types.d.ts +9 -1
- package/cache/types.d.ts.map +1 -1
- package/cache/types.js +5 -0
- package/cache/types.js.map +1 -0
- package/fansunited-data-layer.js +13 -1
- package/fansunited-data-layer.js.map +1 -1
- package/index.d.ts +5 -5
- package/index.d.ts.map +1 -1
- package/package.json +2 -1
- package/types/canonical/index.d.ts +2 -0
- package/types/canonical/index.d.ts.map +1 -1
- package/types/canonical/sports-competition.types.d.ts +100 -0
- package/types/canonical/sports-competition.types.d.ts.map +1 -0
- package/types/canonical/sports-livescore.types.d.ts +84 -0
- package/types/canonical/sports-livescore.types.d.ts.map +1 -0
package/README.md
CHANGED
|
@@ -28,6 +28,47 @@ console.log(match.competitorOne.name); // "Manchester United"
|
|
|
28
28
|
console.log(match.score?.competitorOne); // "2"
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Caching & Hydration (new in v0.17)
|
|
32
|
+
|
|
33
|
+
The library ships a shared, SWR-backed cache for Sports API responses and a
|
|
34
|
+
`…Hydrated` family of functions that resolve every entity ID in a response
|
|
35
|
+
to its human-readable form (team names, logos, competition titles) in one
|
|
36
|
+
call.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { getFansUnitedSportsCompetitionHydrated } from "fansunited-data-layer";
|
|
40
|
+
|
|
41
|
+
const board = await getFansUnitedSportsCompetitionHydrated("fb:c:1", {
|
|
42
|
+
locale: "EN",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
for (const stage of board.season.stages) {
|
|
46
|
+
for (const group of stage.groups ?? []) {
|
|
47
|
+
for (const entry of group.standings) {
|
|
48
|
+
const team = board.entities.get(entry.competitorId);
|
|
49
|
+
console.log(`${entry.rank}. ${team?.name ?? entry.competitorId}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Cache topology:**
|
|
56
|
+
|
|
57
|
+
- **L1** (in-process LRU, 50 MB) is always on.
|
|
58
|
+
- **L2** is opt-in via `initL2(store)` — typically Redis in a multi-instance
|
|
59
|
+
deployment so one warm cache serves every server. The adapter ships in
|
|
60
|
+
the consumer (browser bundles stay free of Node-only deps).
|
|
61
|
+
- **Stale-while-revalidate** TTLs per entity type — users almost never wait.
|
|
62
|
+
- **`fudl:`** prefix on every key so a shared Redis instance can be
|
|
63
|
+
inspected / cleared safely via `SCAN fudl:*`.
|
|
64
|
+
|
|
65
|
+
**For everything else** — the hydrated livescore variant, locale handling,
|
|
66
|
+
Redis wiring, TTL tuning, adding a new hydrated endpoint, troubleshooting —
|
|
67
|
+
read [`src/lib/cache/README.md`](src/lib/cache/README.md).
|
|
68
|
+
|
|
69
|
+
For the copy-paste template when adding a new hydrated Sports API endpoint,
|
|
70
|
+
read [`src/lib/api/fansunited/sports/README.md`](src/lib/api/fansunited/sports/README.md).
|
|
71
|
+
|
|
31
72
|
## API Reference
|
|
32
73
|
|
|
33
74
|
### Configuration
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
export { getFansUnitedFootballCompetitions, getFansUnitedFootballCompetition, getFansUnitedFootballTeam, getFansUnitedFootballTeams, getFansUnitedFootballPlayer, getFansUnitedFootballPlayers, getFansUnitedFootballMatch, getFansUnitedFootballMatches, getFansUnitedFootballTeamNextMatch, getFansUnitedFootballTeamPreviousMatch, getFansUnitedFootballPlayerNextMatch, getFansUnitedFootballPlayerPreviousMatch, getFansUnitedFootballSearch, } from "./football";
|
|
8
8
|
export type { GetFootballCompetitionsOptions, GetFootballCompetitionOptions, GetFootballTeamOptions, GetFootballTeamsOptions, GetFootballPlayerOptions, GetFootballPlayersOptions, GetFootballMatchOptions, GetFootballMatchesOptions, GetFootballSearchOptions, SearchEntityType, FansUnitedFootballSearchResult, } from "./football";
|
|
9
9
|
export { getFansUnitedSearchEntities, getFansUnitedEntityById, getFansUnitedEntitiesByIds, getFansUnitedCompetitions, getFansUnitedTeamsByCountry, getFansUnitedTeamsByCompetition, getFansUnitedCountries, getFansUnitedVenues, } from "./search";
|
|
10
|
+
export { getFansUnitedSportsCompetition, getFansUnitedSportsCompetitionHydrated, getFansUnitedSportsLivescore, getFansUnitedSportsLivescoreHydrated, } from "./sports";
|
|
11
|
+
export type { GetSportsCompetitionOptions, GetSportsCompetitionHydratedOptions, GetSportsLivescoreOptions, GetSportsLivescoreHydratedOptions, FUSportsCompetitionHydrated, FUSportsLivescoreHydrated, } from "./sports";
|
|
10
12
|
export type { SearchMode, EntityContentType, EntitySearchOptions, GetEntityByIdOptions, GetEntitiesByIdsOptions, GetCompetitionsOptions, GetTeamsByCountryOptions, GetTeamsByCompetitionOptions, GetCountriesOptions, GetVenuesOptions, RawSearchEntity, SearchEntityResult, SearchEntitySummary, EntitySearchResponse, PaginationMeta, PaginatedResult, } from "./search";
|
|
11
13
|
export type { NextCacheOptions } from "./http";
|
|
12
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/api/fansunited/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACH,iCAAiC,EACjC,gCAAgC,EAChC,yBAAyB,EACzB,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC5B,0BAA0B,EAC1B,4BAA4B,EAC5B,kCAAkC,EAClC,sCAAsC,EACtC,oCAAoC,EACpC,wCAAwC,EACxC,2BAA2B,GAC9B,MAAM,YAAY,CAAC;AAEpB,YAAY,EACR,8BAA8B,EAC9B,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,gBAAgB,EAChB,8BAA8B,GACjC,MAAM,YAAY,CAAC;AAGpB,OAAO,EACH,2BAA2B,EAC3B,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,EACzB,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,EACtB,mBAAmB,GACtB,MAAM,UAAU,CAAC;AAElB,YAAY,EACR,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,eAAe,GAClB,MAAM,UAAU,CAAC;AAGlB,YAAY,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/api/fansunited/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACH,iCAAiC,EACjC,gCAAgC,EAChC,yBAAyB,EACzB,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC5B,0BAA0B,EAC1B,4BAA4B,EAC5B,kCAAkC,EAClC,sCAAsC,EACtC,oCAAoC,EACpC,wCAAwC,EACxC,2BAA2B,GAC9B,MAAM,YAAY,CAAC;AAEpB,YAAY,EACR,8BAA8B,EAC9B,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,gBAAgB,EAChB,8BAA8B,GACjC,MAAM,YAAY,CAAC;AAGpB,OAAO,EACH,2BAA2B,EAC3B,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,EACzB,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,EACtB,mBAAmB,GACtB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACH,8BAA8B,EAC9B,sCAAsC,EACtC,4BAA4B,EAC5B,oCAAoC,GACvC,MAAM,UAAU,CAAC;AAClB,YAAY,EACR,2BAA2B,EAC3B,mCAAmC,EACnC,yBAAyB,EACzB,iCAAiC,EACjC,2BAA2B,EAC3B,yBAAyB,GAC5B,MAAM,UAAU,CAAC;AAElB,YAAY,EACR,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,eAAe,GAClB,MAAM,UAAU,CAAC;AAGlB,YAAY,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locale-agnostic-cache.test.d.ts","sourceRoot":"","sources":["../../../../../src/lib/api/fansunited/search/__tests__/locale-agnostic-cache.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/fansunited/search/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,OAAO,KAAK,EACR,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,gBAAgB,EAGhB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACtB,MAAM,SAAS,CAAC;AAGjB,OAAO,KAAK,EACR,0BAA0B,EAC1B,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACvB,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/fansunited/search/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,OAAO,KAAK,EACR,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,gBAAgB,EAGhB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACtB,MAAM,SAAS,CAAC;AAGjB,OAAO,KAAK,EACR,0BAA0B,EAC1B,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACvB,MAAM,qCAAqC,CAAC;AAqM7C;;;GAGG;AACH,wBAAsB,2BAA2B,CAC7C,OAAO,GAAE,mBAAwB,EACjC,MAAM,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAA;CAAE,GAChD,OAAO,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAqC/C;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CACzC,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,oBAAoB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAuB7B;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC5C,GAAG,EAAE,MAAM,EAAE,EACb,OAAO,CAAC,EAAE,uBAAuB,GAClC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAgC/B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC3C,OAAO,GAAE,sBAA2B,GACrC,OAAO,CAAC,eAAe,CAAC,0BAA0B,CAAC,CAAC,CA2BtD;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC7C,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,wBAA6B,GACvC,OAAO,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CA6B/C;AAED;;;GAGG;AACH,wBAAsB,+BAA+B,CACjD,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,4BAAiC,GAC3C,OAAO,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CA6B/C;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CACxC,OAAO,GAAE,mBAAwB,GAClC,OAAO,CAAC,eAAe,CAAC,sBAAsB,CAAC,CAAC,CA0BlD;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACrC,OAAO,GAAE,gBAAqB,GAC/B,OAAO,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC,CA2BhD;AAGD,YAAY,EACR,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,mBAAmB,GACtB,MAAM,SAAS,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { searchHttp } from "./http.js";
|
|
2
2
|
import { isConfigured, getConfig } from "../../../config/index.js";
|
|
3
3
|
import { transformCompetitionSummary, transformCountrySummary, transformEntity, transformEntitySummary, transformTeamSummary, transformVenueSummary } from "./transformer.js";
|
|
4
|
+
import { CACHE_KEY_PREFIX } from "../../../cache/types.js";
|
|
4
5
|
import { cached, cachedBatch } from "../../../cache/cache-manager.js";
|
|
5
6
|
import { memoryStore } from "../../../cache/memory-store.js";
|
|
6
7
|
function hashParams(params) {
|
|
@@ -14,7 +15,7 @@ function hashParams(params) {
|
|
|
14
15
|
function cacheIndividualEntities(entities) {
|
|
15
16
|
for (const entity of entities) {
|
|
16
17
|
if (entity.id) {
|
|
17
|
-
memoryStore.set(
|
|
18
|
+
memoryStore.set(`${CACHE_KEY_PREFIX}entity:${entity.id}`, entity);
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
}
|
|
@@ -35,28 +36,45 @@ function collectMissingIds(entities) {
|
|
|
35
36
|
const related = raw.related;
|
|
36
37
|
if (related) {
|
|
37
38
|
for (const r of related) {
|
|
38
|
-
if (!memoryStore.get(
|
|
39
|
+
if (!memoryStore.get(`${CACHE_KEY_PREFIX}entity:${r.related_id}`)) {
|
|
39
40
|
missingIds.add(r.related_id);
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
const countryId = raw.country_id;
|
|
44
|
-
if (countryId && !memoryStore.get(
|
|
45
|
+
if (countryId && !memoryStore.get(`${CACHE_KEY_PREFIX}entity:${countryId}`)) {
|
|
45
46
|
missingIds.add(countryId);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
return missingIds;
|
|
49
50
|
}
|
|
51
|
+
const SEARCH_API_MAX_LIMIT = 100;
|
|
52
|
+
async function fetchEntitiesByIds(ids, fetchOptions) {
|
|
53
|
+
if (ids.length === 0) return [];
|
|
54
|
+
const chunks = [];
|
|
55
|
+
for (let i = 0; i < ids.length; i += SEARCH_API_MAX_LIMIT) {
|
|
56
|
+
chunks.push(ids.slice(i, i + SEARCH_API_MAX_LIMIT));
|
|
57
|
+
}
|
|
58
|
+
const responses = await Promise.all(
|
|
59
|
+
chunks.map(
|
|
60
|
+
(chunk) => searchHttp.get({
|
|
61
|
+
path: "/v1/entities/search",
|
|
62
|
+
params: {
|
|
63
|
+
ids: chunk,
|
|
64
|
+
limit: String(chunk.length)
|
|
65
|
+
},
|
|
66
|
+
next: fetchOptions?.next,
|
|
67
|
+
config: fetchOptions?.config
|
|
68
|
+
})
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
return responses.flatMap((r) => r.data);
|
|
72
|
+
}
|
|
50
73
|
async function batchFetchAndCache(ids, fetchOptions) {
|
|
51
74
|
if (ids.size === 0) return [];
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
next: fetchOptions?.next,
|
|
56
|
-
config: fetchOptions?.config
|
|
57
|
-
});
|
|
58
|
-
cacheIndividualEntities(response.data);
|
|
59
|
-
return response.data;
|
|
75
|
+
const data = await fetchEntitiesByIds(Array.from(ids), fetchOptions);
|
|
76
|
+
cacheIndividualEntities(data);
|
|
77
|
+
return data;
|
|
60
78
|
}
|
|
61
79
|
async function prefetchRelatedEntities(entities, fetchOptions) {
|
|
62
80
|
const pass1Ids = collectMissingIds(entities);
|
|
@@ -75,13 +93,13 @@ async function prefetchCountries(entities, fetchOptions) {
|
|
|
75
93
|
for (const entity of entities) {
|
|
76
94
|
const raw = entity;
|
|
77
95
|
const countryId = raw.country_id;
|
|
78
|
-
if (countryId && !memoryStore.get(
|
|
96
|
+
if (countryId && !memoryStore.get(`${CACHE_KEY_PREFIX}entity:${countryId}`)) {
|
|
79
97
|
missingIds.add(countryId);
|
|
80
98
|
}
|
|
81
99
|
const related = raw.related;
|
|
82
100
|
if (related) {
|
|
83
101
|
for (const r of related) {
|
|
84
|
-
if (r.relationship === "COUNTRY" && !memoryStore.get(
|
|
102
|
+
if (r.relationship === "COUNTRY" && !memoryStore.get(`${CACHE_KEY_PREFIX}entity:${r.related_id}`)) {
|
|
85
103
|
missingIds.add(r.related_id);
|
|
86
104
|
}
|
|
87
105
|
}
|
|
@@ -106,7 +124,7 @@ async function getFansUnitedSearchEntities(options = {}, config) {
|
|
|
106
124
|
relationship: options.relationship,
|
|
107
125
|
value: options.value
|
|
108
126
|
};
|
|
109
|
-
const cacheKey =
|
|
127
|
+
const cacheKey = `${CACHE_KEY_PREFIX}search:entities:${hashParams(params)}`;
|
|
110
128
|
const result = await cached(
|
|
111
129
|
cacheKey,
|
|
112
130
|
"search",
|
|
@@ -126,7 +144,7 @@ async function getFansUnitedSearchEntities(options = {}, config) {
|
|
|
126
144
|
}
|
|
127
145
|
async function getFansUnitedEntityById(id, options) {
|
|
128
146
|
const lang = resolveLanguage(options);
|
|
129
|
-
const cacheKey =
|
|
147
|
+
const cacheKey = `${CACHE_KEY_PREFIX}entity:${id}`;
|
|
130
148
|
const raw = await cached(cacheKey, "search", async () => {
|
|
131
149
|
const response = await searchHttp.get({
|
|
132
150
|
path: "/v1/entities/search",
|
|
@@ -149,19 +167,17 @@ async function getFansUnitedEntitiesByIds(ids, options) {
|
|
|
149
167
|
ids,
|
|
150
168
|
"search",
|
|
151
169
|
async (missingIds) => {
|
|
152
|
-
const
|
|
153
|
-
path: "/v1/entities/search",
|
|
154
|
-
params: { ids: missingIds },
|
|
170
|
+
const fetched = await fetchEntitiesByIds(missingIds, {
|
|
155
171
|
next: options?.next,
|
|
156
172
|
config: options?.config
|
|
157
173
|
});
|
|
158
174
|
const map = /* @__PURE__ */ new Map();
|
|
159
|
-
for (const entity of
|
|
175
|
+
for (const entity of fetched) {
|
|
160
176
|
map.set(entity.id, entity);
|
|
161
177
|
}
|
|
162
178
|
return map;
|
|
163
179
|
},
|
|
164
|
-
(id) =>
|
|
180
|
+
(id) => `${CACHE_KEY_PREFIX}entity:${id}`
|
|
165
181
|
);
|
|
166
182
|
const rawEntities = ids.map((id) => resultsMap.get(id)).filter((e) => e !== void 0);
|
|
167
183
|
await prefetchRelatedEntities(rawEntities, { next: options?.next, config: options?.config });
|
|
@@ -176,7 +192,7 @@ async function getFansUnitedCompetitions(options = {}) {
|
|
|
176
192
|
page: options.page?.toString(),
|
|
177
193
|
sport: options.sport
|
|
178
194
|
};
|
|
179
|
-
const cacheKey =
|
|
195
|
+
const cacheKey = `${CACHE_KEY_PREFIX}competitions:${hashParams(params)}`;
|
|
180
196
|
const result = await cached(
|
|
181
197
|
cacheKey,
|
|
182
198
|
"competitions",
|
|
@@ -203,7 +219,7 @@ async function getFansUnitedTeamsByCountry(countryId, options = {}) {
|
|
|
203
219
|
page: options.page?.toString(),
|
|
204
220
|
sport: options.sport
|
|
205
221
|
};
|
|
206
|
-
const cacheKey =
|
|
222
|
+
const cacheKey = `${CACHE_KEY_PREFIX}teams:country:${countryId}:${hashParams(params)}`;
|
|
207
223
|
const result = await cached(
|
|
208
224
|
cacheKey,
|
|
209
225
|
"teams",
|
|
@@ -230,7 +246,7 @@ async function getFansUnitedTeamsByCompetition(competitionId, options = {}) {
|
|
|
230
246
|
page: options.page?.toString(),
|
|
231
247
|
sport: options.sport
|
|
232
248
|
};
|
|
233
|
-
const cacheKey =
|
|
249
|
+
const cacheKey = `${CACHE_KEY_PREFIX}teams:competition:${competitionId}:${hashParams(params)}`;
|
|
234
250
|
const result = await cached(
|
|
235
251
|
cacheKey,
|
|
236
252
|
"teams",
|
|
@@ -255,7 +271,7 @@ async function getFansUnitedCountries(options = {}) {
|
|
|
255
271
|
page: options.page?.toString(),
|
|
256
272
|
sport: options.sport
|
|
257
273
|
};
|
|
258
|
-
const cacheKey =
|
|
274
|
+
const cacheKey = `${CACHE_KEY_PREFIX}countries:${hashParams(params)}`;
|
|
259
275
|
const result = await cached(
|
|
260
276
|
cacheKey,
|
|
261
277
|
"countries",
|
|
@@ -279,7 +295,7 @@ async function getFansUnitedVenues(options = {}) {
|
|
|
279
295
|
page: options.page?.toString(),
|
|
280
296
|
sport: options.sport
|
|
281
297
|
};
|
|
282
|
-
const cacheKey =
|
|
298
|
+
const cacheKey = `${CACHE_KEY_PREFIX}venues:${hashParams(params)}`;
|
|
283
299
|
const result = await cached(
|
|
284
300
|
cacheKey,
|
|
285
301
|
"venues",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/lib/api/fansunited/search/index.ts"],"sourcesContent":["/**\n * Fans United Search API - Public functions with caching\n */\n\nimport { searchHttp } from \"./http\";\nimport { cached, cachedBatch, memoryStore } from \"../../../cache\";\nimport { getConfig, isConfigured } from \"../../../config\";\nimport {\n transformEntity,\n transformEntitySummary,\n transformCompetitionSummary,\n transformTeamSummary,\n transformCountrySummary,\n transformVenueSummary,\n} from \"./transformer\";\nimport type { RawCompetition, RawTeam, RawCountry, RawVenue, RawSearchEntityBase, RawRelated } from \"./raw-types\";\nimport type {\n EntitySearchOptions,\n GetEntityByIdOptions,\n GetEntitiesByIdsOptions,\n GetCompetitionsOptions,\n GetTeamsByCountryOptions,\n GetTeamsByCompetitionOptions,\n GetCountriesOptions,\n GetVenuesOptions,\n RawSearchEntity,\n EntitySearchResponse,\n PaginatedResult,\n SearchEntityResult,\n SearchEntitySummary,\n} from \"./types\";\nimport type { NextCacheOptions } from \"../http\";\nimport type { DataLayerConfig } from \"../../../config\";\nimport type {\n FUSportsCompetitionSummary,\n FUSportsTeamSummary,\n FUSportsCountrySummary,\n FUSportsVenueSummary,\n} from \"../../../types/canonical/base.types\";\n\nfunction hashParams(params: Record<string, string | string[] | undefined>): string {\n const sorted = Object.entries(params)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${Array.isArray(v) ? v.join(\",\") : v}`)\n .join(\"&\");\n // Simple hash — sufficient for cache key uniqueness\n let hash = 0;\n for (let i = 0; i < sorted.length; i++) {\n hash = ((hash << 5) - hash + sorted.charCodeAt(i)) | 0;\n }\n return hash.toString(36);\n}\n\n/** Cache individual entities from a search response for later ID lookups */\nfunction cacheIndividualEntities(entities: RawSearchEntity[]): void {\n for (const entity of entities) {\n if (entity.id) {\n memoryStore.set(`entity:${entity.id}`, entity);\n }\n }\n}\n\n/**\n * Resolve the language for transformation.\n * Priority: options.lang → config.fansUnited.lang → \"EN\"\n */\nfunction resolveLanguage(options?: { lang?: string }): string {\n if (options?.lang) return options.lang;\n if (isConfigured()) {\n const config = getConfig();\n if (config.fansUnited && \"lang\" in config.fansUnited && config.fansUnited.lang) {\n return config.fansUnited.lang;\n }\n }\n return \"EN\";\n}\n\n/**\n * Collect missing related entity IDs (and country_id fields) from raw entities.\n */\nfunction collectMissingIds(entities: RawSearchEntity[]): Set<string> {\n const missingIds = new Set<string>();\n\n for (const entity of entities) {\n const raw = entity as Record<string, unknown>;\n\n // Collect related IDs\n const related = raw.related as RawRelated[] | undefined;\n if (related) {\n for (const r of related) {\n if (!memoryStore.get(`entity:${r.related_id}`)) {\n missingIds.add(r.related_id);\n }\n }\n }\n\n // Collect country_id\n const countryId = raw.country_id as string | undefined;\n if (countryId && !memoryStore.get(`entity:${countryId}`)) {\n missingIds.add(countryId);\n }\n }\n\n return missingIds;\n}\n\n/**\n * Batch-fetch entity IDs from the search API and cache the results.\n * Returns the fetched raw entities.\n */\nasync function batchFetchAndCache(\n ids: Set<string>,\n fetchOptions?: { next?: NextCacheOptions; config?: DataLayerConfig }\n): Promise<RawSearchEntity[]> {\n if (ids.size === 0) return [];\n\n const response = await searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params: { ids: Array.from(ids) },\n next: fetchOptions?.next,\n config: fetchOptions?.config,\n });\n cacheIndividualEntities(response.data);\n return response.data;\n}\n\n/**\n * Collect all related entity IDs (and country_id fields) from raw entities\n * that are not already in cache, then batch-fetch them.\n * Does a two-pass fetch: after the first fetch, checks the newly fetched\n * entities for their own dependencies (e.g. country_ids) and fetches those too.\n */\nasync function prefetchRelatedEntities(\n entities: RawSearchEntity[],\n fetchOptions?: { next?: NextCacheOptions; config?: DataLayerConfig }\n): Promise<void> {\n // Pass 1: fetch related entities and country_ids from top-level entities\n const pass1Ids = collectMissingIds(entities);\n if (pass1Ids.size === 0) return;\n\n try {\n const fetched = await batchFetchAndCache(pass1Ids, fetchOptions);\n\n // Pass 2: fetch dependencies of the newly fetched entities\n // (e.g. country_ids of related competitions/teams)\n const pass2Ids = collectMissingIds(fetched);\n if (pass2Ids.size > 0) {\n await batchFetchAndCache(pass2Ids, fetchOptions);\n }\n } catch {\n // Prefetch is best-effort — if it fails, the transformer\n // will produce partial results for uncached related entities\n }\n}\n\n/**\n * Lightweight prefetch — only country_ids (single pass).\n * Used by list/search functions that return summary types.\n */\nasync function prefetchCountries(\n entities: RawSearchEntity[],\n fetchOptions?: { next?: NextCacheOptions; config?: DataLayerConfig }\n): Promise<void> {\n const missingIds = new Set<string>();\n\n for (const entity of entities) {\n const raw = entity as Record<string, unknown>;\n\n const countryId = raw.country_id as string | undefined;\n if (countryId && !memoryStore.get(`entity:${countryId}`)) {\n missingIds.add(countryId);\n }\n\n // Also check related array for COUNTRY entries\n const related = raw.related as RawRelated[] | undefined;\n if (related) {\n for (const r of related) {\n if (r.relationship === \"COUNTRY\" && !memoryStore.get(`entity:${r.related_id}`)) {\n missingIds.add(r.related_id);\n }\n }\n }\n }\n\n if (missingIds.size === 0) return;\n\n try {\n await batchFetchAndCache(missingIds, fetchOptions);\n } catch {\n // Best-effort — summary transforms will produce partial country data\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Search entities across all content types.\n * Returns transformed canonical types.\n */\nexport async function getFansUnitedSearchEntities(\n options: EntitySearchOptions = {},\n config?: { next?: EntitySearchOptions[\"next\"] }\n): Promise<PaginatedResult<SearchEntitySummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | string[] | undefined> = {\n query: options.query,\n content_type: options.contentType,\n ids: options.ids,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n mode: options.mode,\n sport: options.sport,\n relationship: options.relationship,\n value: options.value,\n };\n\n const cacheKey = `search:entities:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"search\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next || config?.next,\n config: options.config,\n })\n );\n\n // Side-cache individual entities (raw)\n cacheIndividualEntities(result.data);\n\n // Pre-fetch only countries (lightweight, single pass)\n await prefetchCountries(result.data, { next: options.next || config?.next, config: options.config });\n\n // Transform each raw entity to its summary type (no related, no providerRef)\n const transformed = result.data.map((e) =>\n transformEntitySummary(e as RawSearchEntityBase & Record<string, unknown>, lang)\n );\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get a single entity by ID.\n * Returns transformed canonical type.\n */\nexport async function getFansUnitedEntityById(\n id: string,\n options?: GetEntityByIdOptions\n): Promise<SearchEntityResult> {\n const lang = resolveLanguage(options);\n const cacheKey = `entity:${id}`;\n\n const raw = await cached<RawSearchEntity>(cacheKey, \"search\", async () => {\n const response = await searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params: { ids: [id] },\n next: options?.next,\n config: options?.config,\n });\n\n if (!response.data || response.data.length === 0) {\n throw new Error(`Entity not found: ${id}`);\n }\n\n return response.data[0];\n });\n\n // Pre-fetch related entities for this single entity\n await prefetchRelatedEntities([raw], { next: options?.next, config: options?.config });\n\n return transformEntity(raw as RawSearchEntityBase & Record<string, unknown>, lang);\n}\n\n/**\n * Get multiple entities by IDs — smart batch caching.\n * Only fetches uncached IDs from the API.\n * Returns transformed canonical types.\n */\nexport async function getFansUnitedEntitiesByIds(\n ids: string[],\n options?: GetEntitiesByIdsOptions\n): Promise<SearchEntityResult[]> {\n if (ids.length === 0) return [];\n\n const lang = resolveLanguage(options);\n\n const resultsMap = await cachedBatch<RawSearchEntity>(\n ids,\n \"search\",\n async (missingIds) => {\n const response = await searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params: { ids: missingIds },\n next: options?.next,\n config: options?.config,\n });\n\n const map = new Map<string, RawSearchEntity>();\n for (const entity of response.data) {\n map.set(entity.id, entity);\n }\n return map;\n },\n (id) => `entity:${id}`\n );\n\n // Collect raw entities in order\n const rawEntities = ids\n .map((id) => resultsMap.get(id))\n .filter((e): e is RawSearchEntity => e !== undefined);\n\n // Pre-fetch related entities\n await prefetchRelatedEntities(rawEntities, { next: options?.next, config: options?.config });\n\n return rawEntities.map((e) => transformEntity(e as RawSearchEntityBase & Record<string, unknown>, lang));\n}\n\n/**\n * Get competitions with optional filtering.\n * Returns transformed FUSportsCompetition objects.\n */\nexport async function getFansUnitedCompetitions(\n options: GetCompetitionsOptions = {}\n): Promise<PaginatedResult<FUSportsCompetitionSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"competition\",\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `competitions:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"competitions\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformCompetitionSummary(e as unknown as RawCompetition, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get teams filtered by country.\n * Returns transformed FUSportsTeamCompetitor objects.\n */\nexport async function getFansUnitedTeamsByCountry(\n countryId: string,\n options: GetTeamsByCountryOptions = {}\n): Promise<PaginatedResult<FUSportsTeamSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"team\",\n relationship: \"COUNTRY\",\n value: countryId,\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `teams:country:${countryId}:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"teams\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformTeamSummary(e as unknown as RawTeam, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get teams filtered by competition.\n * Returns transformed FUSportsTeamCompetitor objects.\n */\nexport async function getFansUnitedTeamsByCompetition(\n competitionId: string,\n options: GetTeamsByCompetitionOptions = {}\n): Promise<PaginatedResult<FUSportsTeamSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"team\",\n relationship: \"COMPETITION\",\n value: competitionId,\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `teams:competition:${competitionId}:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"teams\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformTeamSummary(e as unknown as RawTeam, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get countries with optional filtering.\n * Returns transformed FUSportsCountry objects.\n */\nexport async function getFansUnitedCountries(\n options: GetCountriesOptions = {}\n): Promise<PaginatedResult<FUSportsCountrySummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"country\",\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `countries:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"countries\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n\n const transformed = result.data.map((e) => transformCountrySummary(e as unknown as RawCountry, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get venues with optional filtering.\n * Returns transformed FUSportsVenue objects.\n */\nexport async function getFansUnitedVenues(\n options: GetVenuesOptions = {}\n): Promise<PaginatedResult<FUSportsVenueSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"venue\",\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `venues:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"venues\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformVenueSummary(e as unknown as RawVenue, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n// Re-export types\nexport type {\n SearchMode,\n EntityContentType,\n EntitySearchOptions,\n GetEntityByIdOptions,\n GetEntitiesByIdsOptions,\n GetCompetitionsOptions,\n GetTeamsByCountryOptions,\n GetTeamsByCompetitionOptions,\n GetCountriesOptions,\n GetVenuesOptions,\n RawSearchEntity,\n EntitySearchResponse,\n PaginationMeta,\n PaginatedResult,\n SearchEntityResult,\n SearchEntitySummary,\n} from \"./types\";\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/lib/api/fansunited/search/index.ts"],"sourcesContent":["/**\n * Fans United Search API - Public functions with caching\n */\n\nimport { searchHttp } from \"./http\";\nimport { cached, cachedBatch, memoryStore, CACHE_KEY_PREFIX } from \"../../../cache\";\nimport { getConfig, isConfigured } from \"../../../config\";\nimport {\n transformEntity,\n transformEntitySummary,\n transformCompetitionSummary,\n transformTeamSummary,\n transformCountrySummary,\n transformVenueSummary,\n} from \"./transformer\";\nimport type { RawCompetition, RawTeam, RawCountry, RawVenue, RawSearchEntityBase, RawRelated } from \"./raw-types\";\nimport type {\n EntitySearchOptions,\n GetEntityByIdOptions,\n GetEntitiesByIdsOptions,\n GetCompetitionsOptions,\n GetTeamsByCountryOptions,\n GetTeamsByCompetitionOptions,\n GetCountriesOptions,\n GetVenuesOptions,\n RawSearchEntity,\n EntitySearchResponse,\n PaginatedResult,\n SearchEntityResult,\n SearchEntitySummary,\n} from \"./types\";\nimport type { NextCacheOptions } from \"../http\";\nimport type { DataLayerConfig } from \"../../../config\";\nimport type {\n FUSportsCompetitionSummary,\n FUSportsTeamSummary,\n FUSportsCountrySummary,\n FUSportsVenueSummary,\n} from \"../../../types/canonical/base.types\";\n\nfunction hashParams(params: Record<string, string | string[] | undefined>): string {\n const sorted = Object.entries(params)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${Array.isArray(v) ? v.join(\",\") : v}`)\n .join(\"&\");\n // Simple hash — sufficient for cache key uniqueness\n let hash = 0;\n for (let i = 0; i < sorted.length; i++) {\n hash = ((hash << 5) - hash + sorted.charCodeAt(i)) | 0;\n }\n return hash.toString(36);\n}\n\n/** Cache individual entities from a search response for later ID lookups */\nfunction cacheIndividualEntities(entities: RawSearchEntity[]): void {\n for (const entity of entities) {\n if (entity.id) {\n memoryStore.set(`${CACHE_KEY_PREFIX}entity:${entity.id}`, entity);\n }\n }\n}\n\n/**\n * Resolve the language for transformation.\n * Priority: options.lang → config.fansUnited.lang → \"EN\"\n */\nfunction resolveLanguage(options?: { lang?: string }): string {\n if (options?.lang) return options.lang;\n if (isConfigured()) {\n const config = getConfig();\n if (config.fansUnited && \"lang\" in config.fansUnited && config.fansUnited.lang) {\n return config.fansUnited.lang;\n }\n }\n return \"EN\";\n}\n\n/**\n * Collect missing related entity IDs (and country_id fields) from raw entities.\n */\nfunction collectMissingIds(entities: RawSearchEntity[]): Set<string> {\n const missingIds = new Set<string>();\n\n for (const entity of entities) {\n const raw = entity as Record<string, unknown>;\n\n // Collect related IDs\n const related = raw.related as RawRelated[] | undefined;\n if (related) {\n for (const r of related) {\n if (!memoryStore.get(`${CACHE_KEY_PREFIX}entity:${r.related_id}`)) {\n missingIds.add(r.related_id);\n }\n }\n }\n\n // Collect country_id\n const countryId = raw.country_id as string | undefined;\n if (countryId && !memoryStore.get(`${CACHE_KEY_PREFIX}entity:${countryId}`)) {\n missingIds.add(countryId);\n }\n }\n\n return missingIds;\n}\n\n/**\n * Search API `limit` parameter caps at 100 (and defaults to 10 if unset).\n * Passing more than 100 IDs in one request would silently drop everything\n * beyond the page limit — so we chunk and fan-out in parallel.\n */\nconst SEARCH_API_MAX_LIMIT = 100;\n\n/**\n * Fetch raw entities by ID, working around the Search API's pagination cap.\n *\n * - Always passes `limit` equal to the chunk size, so the API never silently\n * trims the response to its default page size (10).\n * - Splits requests of >100 IDs into parallel chunks of ≤100.\n */\nasync function fetchEntitiesByIds(\n ids: string[],\n fetchOptions?: { next?: NextCacheOptions; config?: DataLayerConfig }\n): Promise<RawSearchEntity[]> {\n if (ids.length === 0) return [];\n\n const chunks: string[][] = [];\n for (let i = 0; i < ids.length; i += SEARCH_API_MAX_LIMIT) {\n chunks.push(ids.slice(i, i + SEARCH_API_MAX_LIMIT));\n }\n\n const responses = await Promise.all(\n chunks.map((chunk) =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params: {\n ids: chunk,\n limit: String(chunk.length),\n },\n next: fetchOptions?.next,\n config: fetchOptions?.config,\n })\n )\n );\n\n return responses.flatMap((r) => r.data);\n}\n\n/**\n * Batch-fetch entity IDs from the search API and cache the results.\n * Returns the fetched raw entities.\n */\nasync function batchFetchAndCache(\n ids: Set<string>,\n fetchOptions?: { next?: NextCacheOptions; config?: DataLayerConfig }\n): Promise<RawSearchEntity[]> {\n if (ids.size === 0) return [];\n\n const data = await fetchEntitiesByIds(Array.from(ids), fetchOptions);\n cacheIndividualEntities(data);\n return data;\n}\n\n/**\n * Collect all related entity IDs (and country_id fields) from raw entities\n * that are not already in cache, then batch-fetch them.\n * Does a two-pass fetch: after the first fetch, checks the newly fetched\n * entities for their own dependencies (e.g. country_ids) and fetches those too.\n */\nasync function prefetchRelatedEntities(\n entities: RawSearchEntity[],\n fetchOptions?: { next?: NextCacheOptions; config?: DataLayerConfig }\n): Promise<void> {\n // Pass 1: fetch related entities and country_ids from top-level entities\n const pass1Ids = collectMissingIds(entities);\n if (pass1Ids.size === 0) return;\n\n try {\n const fetched = await batchFetchAndCache(pass1Ids, fetchOptions);\n\n // Pass 2: fetch dependencies of the newly fetched entities\n // (e.g. country_ids of related competitions/teams)\n const pass2Ids = collectMissingIds(fetched);\n if (pass2Ids.size > 0) {\n await batchFetchAndCache(pass2Ids, fetchOptions);\n }\n } catch {\n // Prefetch is best-effort — if it fails, the transformer\n // will produce partial results for uncached related entities\n }\n}\n\n/**\n * Lightweight prefetch — only country_ids (single pass).\n * Used by list/search functions that return summary types.\n */\nasync function prefetchCountries(\n entities: RawSearchEntity[],\n fetchOptions?: { next?: NextCacheOptions; config?: DataLayerConfig }\n): Promise<void> {\n const missingIds = new Set<string>();\n\n for (const entity of entities) {\n const raw = entity as Record<string, unknown>;\n\n const countryId = raw.country_id as string | undefined;\n if (countryId && !memoryStore.get(`${CACHE_KEY_PREFIX}entity:${countryId}`)) {\n missingIds.add(countryId);\n }\n\n // Also check related array for COUNTRY entries\n const related = raw.related as RawRelated[] | undefined;\n if (related) {\n for (const r of related) {\n if (r.relationship === \"COUNTRY\" && !memoryStore.get(`${CACHE_KEY_PREFIX}entity:${r.related_id}`)) {\n missingIds.add(r.related_id);\n }\n }\n }\n }\n\n if (missingIds.size === 0) return;\n\n try {\n await batchFetchAndCache(missingIds, fetchOptions);\n } catch {\n // Best-effort — summary transforms will produce partial country data\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Search entities across all content types.\n * Returns transformed canonical types.\n */\nexport async function getFansUnitedSearchEntities(\n options: EntitySearchOptions = {},\n config?: { next?: EntitySearchOptions[\"next\"] }\n): Promise<PaginatedResult<SearchEntitySummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | string[] | undefined> = {\n query: options.query,\n content_type: options.contentType,\n ids: options.ids,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n mode: options.mode,\n sport: options.sport,\n relationship: options.relationship,\n value: options.value,\n };\n\n const cacheKey = `${CACHE_KEY_PREFIX}search:entities:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"search\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next || config?.next,\n config: options.config,\n })\n );\n\n // Side-cache individual entities (raw)\n cacheIndividualEntities(result.data);\n\n // Pre-fetch only countries (lightweight, single pass)\n await prefetchCountries(result.data, { next: options.next || config?.next, config: options.config });\n\n // Transform each raw entity to its summary type (no related, no providerRef)\n const transformed = result.data.map((e) =>\n transformEntitySummary(e as RawSearchEntityBase & Record<string, unknown>, lang)\n );\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get a single entity by ID.\n * Returns transformed canonical type.\n */\nexport async function getFansUnitedEntityById(\n id: string,\n options?: GetEntityByIdOptions\n): Promise<SearchEntityResult> {\n const lang = resolveLanguage(options);\n const cacheKey = `${CACHE_KEY_PREFIX}entity:${id}`;\n\n const raw = await cached<RawSearchEntity>(cacheKey, \"search\", async () => {\n const response = await searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params: { ids: [id] },\n next: options?.next,\n config: options?.config,\n });\n\n if (!response.data || response.data.length === 0) {\n throw new Error(`Entity not found: ${id}`);\n }\n\n return response.data[0];\n });\n\n // Pre-fetch related entities for this single entity\n await prefetchRelatedEntities([raw], { next: options?.next, config: options?.config });\n\n return transformEntity(raw as RawSearchEntityBase & Record<string, unknown>, lang);\n}\n\n/**\n * Get multiple entities by IDs — smart batch caching.\n * Only fetches uncached IDs from the API.\n * Returns transformed canonical types.\n */\nexport async function getFansUnitedEntitiesByIds(\n ids: string[],\n options?: GetEntitiesByIdsOptions\n): Promise<SearchEntityResult[]> {\n if (ids.length === 0) return [];\n\n const lang = resolveLanguage(options);\n\n const resultsMap = await cachedBatch<RawSearchEntity>(\n ids,\n \"search\",\n async (missingIds) => {\n const fetched = await fetchEntitiesByIds(missingIds, {\n next: options?.next,\n config: options?.config,\n });\n\n const map = new Map<string, RawSearchEntity>();\n for (const entity of fetched) {\n map.set(entity.id, entity);\n }\n return map;\n },\n (id) => `${CACHE_KEY_PREFIX}entity:${id}`\n );\n\n // Collect raw entities in order\n const rawEntities = ids\n .map((id) => resultsMap.get(id))\n .filter((e): e is RawSearchEntity => e !== undefined);\n\n // Pre-fetch related entities\n await prefetchRelatedEntities(rawEntities, { next: options?.next, config: options?.config });\n\n return rawEntities.map((e) => transformEntity(e as RawSearchEntityBase & Record<string, unknown>, lang));\n}\n\n/**\n * Get competitions with optional filtering.\n * Returns transformed FUSportsCompetition objects.\n */\nexport async function getFansUnitedCompetitions(\n options: GetCompetitionsOptions = {}\n): Promise<PaginatedResult<FUSportsCompetitionSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"competition\",\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `${CACHE_KEY_PREFIX}competitions:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"competitions\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformCompetitionSummary(e as unknown as RawCompetition, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get teams filtered by country.\n * Returns transformed FUSportsTeamCompetitor objects.\n */\nexport async function getFansUnitedTeamsByCountry(\n countryId: string,\n options: GetTeamsByCountryOptions = {}\n): Promise<PaginatedResult<FUSportsTeamSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"team\",\n relationship: \"COUNTRY\",\n value: countryId,\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `${CACHE_KEY_PREFIX}teams:country:${countryId}:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"teams\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformTeamSummary(e as unknown as RawTeam, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get teams filtered by competition.\n * Returns transformed FUSportsTeamCompetitor objects.\n */\nexport async function getFansUnitedTeamsByCompetition(\n competitionId: string,\n options: GetTeamsByCompetitionOptions = {}\n): Promise<PaginatedResult<FUSportsTeamSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"team\",\n relationship: \"COMPETITION\",\n value: competitionId,\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `${CACHE_KEY_PREFIX}teams:competition:${competitionId}:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"teams\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformTeamSummary(e as unknown as RawTeam, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get countries with optional filtering.\n * Returns transformed FUSportsCountry objects.\n */\nexport async function getFansUnitedCountries(\n options: GetCountriesOptions = {}\n): Promise<PaginatedResult<FUSportsCountrySummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"country\",\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `${CACHE_KEY_PREFIX}countries:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"countries\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n\n const transformed = result.data.map((e) => transformCountrySummary(e as unknown as RawCountry, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n/**\n * Get venues with optional filtering.\n * Returns transformed FUSportsVenue objects.\n */\nexport async function getFansUnitedVenues(\n options: GetVenuesOptions = {}\n): Promise<PaginatedResult<FUSportsVenueSummary>> {\n const lang = resolveLanguage(options);\n const params: Record<string, string | undefined> = {\n content_type: \"venue\",\n query: options.query,\n limit: options.limit?.toString(),\n page: options.page?.toString(),\n sport: options.sport,\n };\n\n const cacheKey = `${CACHE_KEY_PREFIX}venues:${hashParams(params)}`;\n\n const result = await cached<EntitySearchResponse>(cacheKey, \"venues\", () =>\n searchHttp.get<EntitySearchResponse>({\n path: \"/v1/entities/search\",\n params,\n next: options.next,\n config: options.config,\n })\n );\n\n cacheIndividualEntities(result.data);\n await prefetchCountries(result.data, { next: options.next, config: options.config });\n\n const transformed = result.data.map((e) => transformVenueSummary(e as unknown as RawVenue, lang));\n\n return { data: transformed, pagination: result.meta.pagination };\n}\n\n// Re-export types\nexport type {\n SearchMode,\n EntityContentType,\n EntitySearchOptions,\n GetEntityByIdOptions,\n GetEntitiesByIdsOptions,\n GetCompetitionsOptions,\n GetTeamsByCountryOptions,\n GetTeamsByCompetitionOptions,\n GetCountriesOptions,\n GetVenuesOptions,\n RawSearchEntity,\n EntitySearchResponse,\n PaginationMeta,\n PaginatedResult,\n SearchEntityResult,\n SearchEntitySummary,\n} from \"./types\";\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { memoryStore } from "../../../cache/memory-store.js";
|
|
2
|
+
import { CACHE_KEY_PREFIX } from "../../../cache/types.js";
|
|
2
3
|
function resolveTranslation(translations, lang, fallbackName, fallbackShortName) {
|
|
3
4
|
const upperLang = lang.toUpperCase();
|
|
4
5
|
const target = translations.find((t) => t.language.toUpperCase() === upperLang);
|
|
@@ -50,7 +51,7 @@ function getRelatedIds(related, relationship) {
|
|
|
50
51
|
function resolveCountry(countryId, related, lang) {
|
|
51
52
|
const id = countryId || getRelatedIds(related, "COUNTRY")[0];
|
|
52
53
|
if (!id) return void 0;
|
|
53
|
-
const cachedEntry = memoryStore.get(id) ?? memoryStore.get(
|
|
54
|
+
const cachedEntry = memoryStore.get(id) ?? memoryStore.get(`${CACHE_KEY_PREFIX}entity:${id}`);
|
|
54
55
|
if (cachedEntry?.data) {
|
|
55
56
|
const raw = cachedEntry.data;
|
|
56
57
|
return transformCountrySummary(raw, lang);
|
|
@@ -153,7 +154,7 @@ function transformCoachSummary(raw, lang) {
|
|
|
153
154
|
};
|
|
154
155
|
}
|
|
155
156
|
function hydrateRelatedEntity(id, relationship, lang) {
|
|
156
|
-
const entry = memoryStore.get(id) ?? memoryStore.get(
|
|
157
|
+
const entry = memoryStore.get(id) ?? memoryStore.get(`${CACHE_KEY_PREFIX}entity:${id}`);
|
|
157
158
|
if (!entry?.data) return void 0;
|
|
158
159
|
const raw = entry.data;
|
|
159
160
|
switch (relationship) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.js","sources":["../../../../src/lib/api/fansunited/search/transformer.ts"],"sourcesContent":["/**\n * Raw → Canonical transformer for Search API entities.\n *\n * Resolves translations to a target language (with EN fallback),\n * maps raw snake_case fields to canonical camelCase types,\n * and hydrates related entries (country + related) one level deep from cache.\n */\n\nimport { memoryStore } from \"../../../cache\";\nimport type {\n FUSportsCompetition,\n FUSportsTeamCompetitor,\n FUSportsPlayerCompetitor,\n FUSportsCountry,\n FUSportsVenue,\n FUSportsCoach,\n FUSportsRelated,\n FUBranding,\n FUSportsCompetitionSummary,\n FUSportsTeamSummary,\n FUSportsPlayerSummary,\n FUSportsCountrySummary,\n FUSportsVenueSummary,\n FUSportsCoachSummary,\n} from \"../../../types/canonical/base.types\";\nimport type { SearchEntityResult, SearchEntitySummary } from \"./types\";\nimport type {\n RawTranslation,\n RawAsset,\n RawRelated,\n RawProviderRef,\n RawBranding,\n RawTeamBranding,\n RawSearchEntityBase,\n RawCompetition,\n RawTeam,\n RawAthlete,\n RawCountry,\n RawVenue,\n RawCoach,\n} from \"./raw-types\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve name/shortName in target language.\n * Fallback order: target lang → EN → raw name.\n */\nexport function resolveTranslation(\n translations: RawTranslation[],\n lang: string,\n fallbackName: string,\n fallbackShortName?: string | null\n): { name: string; shortName?: string } {\n const upperLang = lang.toUpperCase();\n\n const target = translations.find((t) => t.language.toUpperCase() === upperLang);\n if (target) {\n return {\n name: target.name,\n shortName: target.short_name ?? fallbackShortName ?? undefined,\n };\n }\n\n // Fallback to EN\n if (upperLang !== \"EN\") {\n const en = translations.find((t) => t.language.toUpperCase() === \"EN\");\n if (en) {\n return {\n name: en.name,\n shortName: en.short_name ?? fallbackShortName ?? undefined,\n };\n }\n }\n\n return {\n name: fallbackName,\n shortName: fallbackShortName ?? undefined,\n };\n}\n\n/**\n * Map [{key: \"LOGO\", value: \"url\"}] → { logo: \"url\" }\n */\nexport function resolveAssets(assets: RawAsset[]): Record<string, string> {\n const result: Record<string, string> = {};\n for (const asset of assets) {\n result[asset.key.toLowerCase()] = asset.value;\n }\n return result;\n}\n\n/**\n * Map raw branding snake_case → canonical FUBranding camelCase.\n */\nexport function resolveBranding(raw: RawBranding | RawTeamBranding | undefined | null): FUBranding | undefined {\n if (!raw) return undefined;\n\n const branding: FUBranding = {};\n if (raw.primary_color) branding.primaryColor = raw.primary_color;\n if (raw.secondary_color) branding.secondaryColor = raw.secondary_color;\n if (raw.text_color) branding.textColor = raw.text_color;\n if (raw.background_color) branding.backgroundColor = raw.background_color;\n if (raw.background_gradient_from_color) branding.backgroundGradientFromColor = raw.background_gradient_from_color;\n if (raw.background_gradient_to_color) branding.backgroundGradientToColor = raw.background_gradient_to_color;\n if (raw.background_image) branding.backgroundImage = raw.background_image;\n\n return Object.keys(branding).length > 0 ? branding : undefined;\n}\n\n/** Map raw provider_ref → canonical providerRef */\nexport function resolveProviderRef(refs: RawProviderRef[]): { provider: string; id: string }[] {\n return refs.map((r) => ({ provider: r.provider, id: r.id }));\n}\n\n/** Extract related IDs by relationship type */\nexport function getRelatedIds(related: RawRelated[], relationship: string): string[] {\n return related.filter((r) => r.relationship === relationship).map((r) => r.related_id);\n}\n\n/**\n * Resolve a country from cache (one level deep).\n * Returns FUSportsCountry with name in target lang if cached, or { id } if not.\n */\nexport function resolveCountry(\n countryId: string | null | undefined,\n related: RawRelated[],\n lang: string\n): FUSportsCountry | undefined {\n // Determine the country ID — from direct field or related array\n const id = countryId || getRelatedIds(related, \"COUNTRY\")[0];\n if (!id) return undefined;\n\n // Try cache lookup\n const cachedEntry = memoryStore.get<RawCountry>(id) ?? memoryStore.get<RawCountry>(`entity:${id}`);\n\n if (cachedEntry?.data) {\n const raw = cachedEntry.data;\n return transformCountrySummary(raw, lang);\n }\n\n // Not in cache — return partial\n return { id, name: id };\n}\n\n// ---------------------------------------------------------------------------\n// Summary transforms — used for list/search views AND one-level-deep related\n// entity hydration. These do NOT populate `related` or `providerRef`.\n// ---------------------------------------------------------------------------\n\nexport function transformCountrySummary(raw: RawCountry, lang: string): FUSportsCountrySummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n\n return {\n id: raw.id,\n name,\n ...(raw.country_code ? { code: raw.country_code } : {}),\n ...(assets.flag ? { flag: assets.flag } : {}),\n ...(shortName ? { shortName } : {}),\n };\n}\n\nexport function transformCompetitionSummary(raw: RawCompetition, lang: string): FUSportsCompetitionSummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.branding);\n const country = resolveCountry(null, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.format ? { type: raw.format as FUSportsCompetition[\"type\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n };\n}\n\nexport function transformTeamSummary(raw: RawTeam, lang: string): FUSportsTeamSummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.three_letter_code ? { threeLetterCode: raw.three_letter_code } : {}),\n ...(raw.full_name ? { fullName: raw.full_name } : {}),\n ...(raw.nickname ? { nickname: raw.nickname } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsTeamCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n };\n}\n\nexport function transformAthleteSummary(raw: RawAthlete, lang: string): FUSportsPlayerSummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n type: \"player\",\n ...(shortName ? { shortName } : {}),\n ...(raw.position ? { position: raw.position } : {}),\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(raw.shirt_number != null ? { shirtNumber: raw.shirt_number } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsPlayerCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo || assets.headshot\n ? { assets: { ...(assets.logo ? { logo: assets.logo } : {}), ...(assets.headshot ? { photo: assets.headshot } : {}) } }\n : {}),\n ...(branding ? { metadata: { branding } } : {}),\n };\n}\n\nexport function transformVenueSummary(raw: RawVenue, lang: string): FUSportsVenueSummary {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n const hasProfile = raw.capacity != null || raw.latitude != null || raw.longitude != null;\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(country ? { country } : {}),\n ...(hasProfile\n ? {\n profile: {\n ...(raw.capacity != null ? { capacity: raw.capacity } : {}),\n ...(raw.latitude != null ? { latitude: raw.latitude } : {}),\n ...(raw.longitude != null ? { longitude: raw.longitude } : {}),\n },\n }\n : {}),\n };\n}\n\nexport function transformCoachSummary(raw: RawCoach, lang: string): FUSportsCoachSummary {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(country ? { country } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Related entity resolution (one level deep from cache)\n// ---------------------------------------------------------------------------\n\n/**\n * Look up a cached raw entity and determine its type for shallow transformation.\n */\nfunction hydrateRelatedEntity(\n id: string,\n relationship: string,\n lang: string\n): FUSportsCompetition | FUSportsTeamCompetitor | FUSportsPlayerCompetitor | FUSportsCountry | undefined {\n const entry = memoryStore.get<RawSearchEntityBase & Record<string, unknown>>(id)\n ?? memoryStore.get<RawSearchEntityBase & Record<string, unknown>>(`entity:${id}`);\n\n if (!entry?.data) return undefined;\n\n const raw = entry.data;\n switch (relationship) {\n case \"COMPETITION\":\n return transformCompetitionSummary(raw as unknown as RawCompetition, lang);\n case \"TEAM\":\n return transformTeamSummary(raw as unknown as RawTeam, lang);\n case \"ATHLETE\":\n return transformAthleteSummary(raw as unknown as RawAthlete, lang);\n case \"COUNTRY\":\n return transformCountrySummary(raw as unknown as RawCountry, lang);\n default:\n return undefined;\n }\n}\n\n/**\n * Resolve all related entries from cache, grouped by relationship type.\n * Returns undefined if there are no related entries.\n */\nexport function resolveRelated(related: RawRelated[], lang: string): FUSportsRelated | undefined {\n if (!related || related.length === 0) return undefined;\n\n const result: FUSportsRelated = {};\n\n for (const entry of related) {\n const hydrated = hydrateRelatedEntity(entry.related_id, entry.relationship, lang);\n // Skip entries not in cache — the prefetch step in index.ts should have\n // fetched them. If still missing, the entity was not found by the API.\n if (!hydrated) continue;\n\n switch (entry.relationship) {\n case \"COMPETITION\":\n (result.competitions ??= []).push(hydrated as FUSportsCompetition);\n break;\n case \"TEAM\":\n (result.teams ??= []).push(hydrated as FUSportsTeamCompetitor);\n break;\n case \"ATHLETE\":\n (result.athletes ??= []).push(hydrated as FUSportsPlayerCompetitor);\n break;\n case \"COUNTRY\":\n (result.countries ??= []).push(hydrated as FUSportsCountry);\n break;\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Entity transformers\n// ---------------------------------------------------------------------------\n\nexport function transformCompetition(raw: RawCompetition, lang: string): FUSportsCompetition {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.branding);\n const country = resolveCountry(null, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.format ? { type: raw.format as FUSportsCompetition[\"type\"] } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsCompetition[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformTeam(raw: RawTeam, lang: string): FUSportsTeamCompetitor {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.three_letter_code ? { threeLetterCode: raw.three_letter_code } : {}),\n ...(raw.full_name ? { fullName: raw.full_name } : {}),\n ...(raw.nickname ? { nickname: raw.nickname } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsTeamCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformAthlete(raw: RawAthlete, lang: string): FUSportsPlayerCompetitor {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n type: \"player\",\n ...(shortName ? { shortName } : {}),\n ...(raw.position ? { position: raw.position } : {}),\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(raw.shirt_number != null ? { shirtNumber: raw.shirt_number } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsPlayerCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo || assets.headshot\n ? { assets: { ...(assets.logo ? { logo: assets.logo } : {}), ...(assets.headshot ? { photo: assets.headshot } : {}) } }\n : {}),\n ...(branding ? { metadata: { branding } } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformCountry(raw: RawCountry, lang: string): FUSportsCountry {\n const summary = transformCountrySummary(raw, lang);\n return {\n ...summary,\n sport: raw.sport,\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n };\n}\n\nexport function transformVenue(raw: RawVenue, lang: string): FUSportsVenue {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n const hasProfile = raw.capacity != null || raw.latitude != null || raw.longitude != null;\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(country ? { country } : {}),\n ...(hasProfile\n ? {\n profile: {\n ...(raw.capacity != null ? { capacity: raw.capacity } : {}),\n ...(raw.latitude != null ? { latitude: raw.latitude } : {}),\n ...(raw.longitude != null ? { longitude: raw.longitude } : {}),\n },\n }\n : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformCoach(raw: RawCoach, lang: string): FUSportsCoach {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(country ? { country } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Main dispatcher\n// ---------------------------------------------------------------------------\n\n/**\n * Determine entity type from raw data and call the appropriate transformer.\n * The raw API uses `content_type` for competitions and `type` / general context for others.\n */\nexport function transformEntity(raw: RawSearchEntityBase & Record<string, unknown>, lang: string): SearchEntityResult {\n // Determine entity type from raw fields\n const contentType = (raw.content_type as string)?.toUpperCase?.();\n const type = (raw.type as string)?.toUpperCase?.();\n const entityType = (raw.entityType as string)?.toLowerCase?.();\n\n if (contentType === \"COMPETITION\" || entityType === \"competition\") {\n return { ...transformCompetition(raw as unknown as RawCompetition, lang), entityType: \"competition\" };\n }\n\n if (entityType === \"country\" || raw.country_code !== undefined) {\n return { ...transformCountry(raw as RawCountry, lang), entityType: \"country\" };\n }\n\n if (entityType === \"venue\" || (raw.capacity !== undefined && !entityType)) {\n return { ...transformVenue(raw as RawVenue, lang), entityType: \"venue\" };\n }\n\n if (entityType === \"coach\" || (type === \"COACH\")) {\n return { ...transformCoach(raw as RawCoach, lang), entityType: \"coach\" };\n }\n\n if (entityType === \"athlete\" || type === \"PLAYER\" || raw.position !== undefined || raw.shirt_number !== undefined) {\n return { ...transformAthlete(raw as RawAthlete, lang), entityType: \"athlete\" };\n }\n\n // Default to team\n if (entityType === \"team\" || type === \"TEAM\" || raw.three_letter_code !== undefined) {\n return { ...transformTeam(raw as RawTeam, lang), entityType: \"team\" };\n }\n\n // Fallback: treat as team (most common entity type)\n return { ...transformTeam(raw as RawTeam, lang), entityType: \"team\" };\n}\n\n/**\n * Summary dispatcher — like transformEntity but calls summary transforms.\n * Returns lightweight types without `related` or `providerRef`.\n */\nexport function transformEntitySummary(raw: RawSearchEntityBase & Record<string, unknown>, lang: string): SearchEntitySummary {\n const contentType = (raw.content_type as string)?.toUpperCase?.();\n const type = (raw.type as string)?.toUpperCase?.();\n const entityType = (raw.entityType as string)?.toLowerCase?.();\n\n if (contentType === \"COMPETITION\" || entityType === \"competition\") {\n return { ...transformCompetitionSummary(raw as unknown as RawCompetition, lang), entityType: \"competition\" };\n }\n\n if (entityType === \"country\" || raw.country_code !== undefined) {\n return { ...transformCountrySummary(raw as RawCountry, lang), entityType: \"country\" };\n }\n\n if (entityType === \"venue\" || (raw.capacity !== undefined && !entityType)) {\n return { ...transformVenueSummary(raw as RawVenue, lang), entityType: \"venue\" };\n }\n\n if (entityType === \"coach\" || (type === \"COACH\")) {\n return { ...transformCoachSummary(raw as RawCoach, lang), entityType: \"coach\" };\n }\n\n if (entityType === \"athlete\" || type === \"PLAYER\" || raw.position !== undefined || raw.shirt_number !== undefined) {\n return { ...transformAthleteSummary(raw as RawAthlete, lang), entityType: \"athlete\" };\n }\n\n if (entityType === \"team\" || type === \"TEAM\" || raw.three_letter_code !== undefined) {\n return { ...transformTeamSummary(raw as RawTeam, lang), entityType: \"team\" };\n }\n\n return { ...transformTeamSummary(raw as RawTeam, lang), entityType: \"team\" };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transformer.js","sources":["../../../../src/lib/api/fansunited/search/transformer.ts"],"sourcesContent":["/**\n * Raw → Canonical transformer for Search API entities.\n *\n * Resolves translations to a target language (with EN fallback),\n * maps raw snake_case fields to canonical camelCase types,\n * and hydrates related entries (country + related) one level deep from cache.\n */\n\nimport { memoryStore, CACHE_KEY_PREFIX } from \"../../../cache\";\nimport type {\n FUSportsCompetition,\n FUSportsTeamCompetitor,\n FUSportsPlayerCompetitor,\n FUSportsCountry,\n FUSportsVenue,\n FUSportsCoach,\n FUSportsRelated,\n FUBranding,\n FUSportsCompetitionSummary,\n FUSportsTeamSummary,\n FUSportsPlayerSummary,\n FUSportsCountrySummary,\n FUSportsVenueSummary,\n FUSportsCoachSummary,\n} from \"../../../types/canonical/base.types\";\nimport type { SearchEntityResult, SearchEntitySummary } from \"./types\";\nimport type {\n RawTranslation,\n RawAsset,\n RawRelated,\n RawProviderRef,\n RawBranding,\n RawTeamBranding,\n RawSearchEntityBase,\n RawCompetition,\n RawTeam,\n RawAthlete,\n RawCountry,\n RawVenue,\n RawCoach,\n} from \"./raw-types\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve name/shortName in target language.\n * Fallback order: target lang → EN → raw name.\n */\nexport function resolveTranslation(\n translations: RawTranslation[],\n lang: string,\n fallbackName: string,\n fallbackShortName?: string | null\n): { name: string; shortName?: string } {\n const upperLang = lang.toUpperCase();\n\n const target = translations.find((t) => t.language.toUpperCase() === upperLang);\n if (target) {\n return {\n name: target.name,\n shortName: target.short_name ?? fallbackShortName ?? undefined,\n };\n }\n\n // Fallback to EN\n if (upperLang !== \"EN\") {\n const en = translations.find((t) => t.language.toUpperCase() === \"EN\");\n if (en) {\n return {\n name: en.name,\n shortName: en.short_name ?? fallbackShortName ?? undefined,\n };\n }\n }\n\n return {\n name: fallbackName,\n shortName: fallbackShortName ?? undefined,\n };\n}\n\n/**\n * Map [{key: \"LOGO\", value: \"url\"}] → { logo: \"url\" }\n */\nexport function resolveAssets(assets: RawAsset[]): Record<string, string> {\n const result: Record<string, string> = {};\n for (const asset of assets) {\n result[asset.key.toLowerCase()] = asset.value;\n }\n return result;\n}\n\n/**\n * Map raw branding snake_case → canonical FUBranding camelCase.\n */\nexport function resolveBranding(raw: RawBranding | RawTeamBranding | undefined | null): FUBranding | undefined {\n if (!raw) return undefined;\n\n const branding: FUBranding = {};\n if (raw.primary_color) branding.primaryColor = raw.primary_color;\n if (raw.secondary_color) branding.secondaryColor = raw.secondary_color;\n if (raw.text_color) branding.textColor = raw.text_color;\n if (raw.background_color) branding.backgroundColor = raw.background_color;\n if (raw.background_gradient_from_color) branding.backgroundGradientFromColor = raw.background_gradient_from_color;\n if (raw.background_gradient_to_color) branding.backgroundGradientToColor = raw.background_gradient_to_color;\n if (raw.background_image) branding.backgroundImage = raw.background_image;\n\n return Object.keys(branding).length > 0 ? branding : undefined;\n}\n\n/** Map raw provider_ref → canonical providerRef */\nexport function resolveProviderRef(refs: RawProviderRef[]): { provider: string; id: string }[] {\n return refs.map((r) => ({ provider: r.provider, id: r.id }));\n}\n\n/** Extract related IDs by relationship type */\nexport function getRelatedIds(related: RawRelated[], relationship: string): string[] {\n return related.filter((r) => r.relationship === relationship).map((r) => r.related_id);\n}\n\n/**\n * Resolve a country from cache (one level deep).\n * Returns FUSportsCountry with name in target lang if cached, or { id } if not.\n */\nexport function resolveCountry(\n countryId: string | null | undefined,\n related: RawRelated[],\n lang: string\n): FUSportsCountry | undefined {\n // Determine the country ID — from direct field or related array\n const id = countryId || getRelatedIds(related, \"COUNTRY\")[0];\n if (!id) return undefined;\n\n // Try cache lookup\n const cachedEntry = memoryStore.get<RawCountry>(id) ?? memoryStore.get<RawCountry>(`${CACHE_KEY_PREFIX}entity:${id}`);\n\n if (cachedEntry?.data) {\n const raw = cachedEntry.data;\n return transformCountrySummary(raw, lang);\n }\n\n // Not in cache — return partial\n return { id, name: id };\n}\n\n// ---------------------------------------------------------------------------\n// Summary transforms — used for list/search views AND one-level-deep related\n// entity hydration. These do NOT populate `related` or `providerRef`.\n// ---------------------------------------------------------------------------\n\nexport function transformCountrySummary(raw: RawCountry, lang: string): FUSportsCountrySummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n\n return {\n id: raw.id,\n name,\n ...(raw.country_code ? { code: raw.country_code } : {}),\n ...(assets.flag ? { flag: assets.flag } : {}),\n ...(shortName ? { shortName } : {}),\n };\n}\n\nexport function transformCompetitionSummary(raw: RawCompetition, lang: string): FUSportsCompetitionSummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.branding);\n const country = resolveCountry(null, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.format ? { type: raw.format as FUSportsCompetition[\"type\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n };\n}\n\nexport function transformTeamSummary(raw: RawTeam, lang: string): FUSportsTeamSummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.three_letter_code ? { threeLetterCode: raw.three_letter_code } : {}),\n ...(raw.full_name ? { fullName: raw.full_name } : {}),\n ...(raw.nickname ? { nickname: raw.nickname } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsTeamCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n };\n}\n\nexport function transformAthleteSummary(raw: RawAthlete, lang: string): FUSportsPlayerSummary {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n type: \"player\",\n ...(shortName ? { shortName } : {}),\n ...(raw.position ? { position: raw.position } : {}),\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(raw.shirt_number != null ? { shirtNumber: raw.shirt_number } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsPlayerCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo || assets.headshot\n ? { assets: { ...(assets.logo ? { logo: assets.logo } : {}), ...(assets.headshot ? { photo: assets.headshot } : {}) } }\n : {}),\n ...(branding ? { metadata: { branding } } : {}),\n };\n}\n\nexport function transformVenueSummary(raw: RawVenue, lang: string): FUSportsVenueSummary {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n const hasProfile = raw.capacity != null || raw.latitude != null || raw.longitude != null;\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(country ? { country } : {}),\n ...(hasProfile\n ? {\n profile: {\n ...(raw.capacity != null ? { capacity: raw.capacity } : {}),\n ...(raw.latitude != null ? { latitude: raw.latitude } : {}),\n ...(raw.longitude != null ? { longitude: raw.longitude } : {}),\n },\n }\n : {}),\n };\n}\n\nexport function transformCoachSummary(raw: RawCoach, lang: string): FUSportsCoachSummary {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(country ? { country } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Related entity resolution (one level deep from cache)\n// ---------------------------------------------------------------------------\n\n/**\n * Look up a cached raw entity and determine its type for shallow transformation.\n */\nfunction hydrateRelatedEntity(\n id: string,\n relationship: string,\n lang: string\n): FUSportsCompetition | FUSportsTeamCompetitor | FUSportsPlayerCompetitor | FUSportsCountry | undefined {\n const entry = memoryStore.get<RawSearchEntityBase & Record<string, unknown>>(id)\n ?? memoryStore.get<RawSearchEntityBase & Record<string, unknown>>(`${CACHE_KEY_PREFIX}entity:${id}`);\n\n if (!entry?.data) return undefined;\n\n const raw = entry.data;\n switch (relationship) {\n case \"COMPETITION\":\n return transformCompetitionSummary(raw as unknown as RawCompetition, lang);\n case \"TEAM\":\n return transformTeamSummary(raw as unknown as RawTeam, lang);\n case \"ATHLETE\":\n return transformAthleteSummary(raw as unknown as RawAthlete, lang);\n case \"COUNTRY\":\n return transformCountrySummary(raw as unknown as RawCountry, lang);\n default:\n return undefined;\n }\n}\n\n/**\n * Resolve all related entries from cache, grouped by relationship type.\n * Returns undefined if there are no related entries.\n */\nexport function resolveRelated(related: RawRelated[], lang: string): FUSportsRelated | undefined {\n if (!related || related.length === 0) return undefined;\n\n const result: FUSportsRelated = {};\n\n for (const entry of related) {\n const hydrated = hydrateRelatedEntity(entry.related_id, entry.relationship, lang);\n // Skip entries not in cache — the prefetch step in index.ts should have\n // fetched them. If still missing, the entity was not found by the API.\n if (!hydrated) continue;\n\n switch (entry.relationship) {\n case \"COMPETITION\":\n (result.competitions ??= []).push(hydrated as FUSportsCompetition);\n break;\n case \"TEAM\":\n (result.teams ??= []).push(hydrated as FUSportsTeamCompetitor);\n break;\n case \"ATHLETE\":\n (result.athletes ??= []).push(hydrated as FUSportsPlayerCompetitor);\n break;\n case \"COUNTRY\":\n (result.countries ??= []).push(hydrated as FUSportsCountry);\n break;\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Entity transformers\n// ---------------------------------------------------------------------------\n\nexport function transformCompetition(raw: RawCompetition, lang: string): FUSportsCompetition {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.branding);\n const country = resolveCountry(null, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.format ? { type: raw.format as FUSportsCompetition[\"type\"] } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsCompetition[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformTeam(raw: RawTeam, lang: string): FUSportsTeamCompetitor {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(shortName ? { shortName } : {}),\n ...(raw.three_letter_code ? { threeLetterCode: raw.three_letter_code } : {}),\n ...(raw.full_name ? { fullName: raw.full_name } : {}),\n ...(raw.nickname ? { nickname: raw.nickname } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsTeamCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo ? { assets: { logo: assets.logo } } : {}),\n ...(branding ? { metadata: { branding } } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformAthlete(raw: RawAthlete, lang: string): FUSportsPlayerCompetitor {\n const { name, shortName } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const assets = resolveAssets(raw.assets ?? []);\n const branding = resolveBranding(raw.metadata?.branding);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n type: \"player\",\n ...(shortName ? { shortName } : {}),\n ...(raw.position ? { position: raw.position } : {}),\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(raw.shirt_number != null ? { shirtNumber: raw.shirt_number } : {}),\n ...(raw.gender ? { gender: raw.gender as FUSportsPlayerCompetitor[\"gender\"] } : {}),\n ...(country ? { country } : {}),\n ...(assets.logo || assets.headshot\n ? { assets: { ...(assets.logo ? { logo: assets.logo } : {}), ...(assets.headshot ? { photo: assets.headshot } : {}) } }\n : {}),\n ...(branding ? { metadata: { branding } } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformCountry(raw: RawCountry, lang: string): FUSportsCountry {\n const summary = transformCountrySummary(raw, lang);\n return {\n ...summary,\n sport: raw.sport,\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n };\n}\n\nexport function transformVenue(raw: RawVenue, lang: string): FUSportsVenue {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n const hasProfile = raw.capacity != null || raw.latitude != null || raw.longitude != null;\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(country ? { country } : {}),\n ...(hasProfile\n ? {\n profile: {\n ...(raw.capacity != null ? { capacity: raw.capacity } : {}),\n ...(raw.latitude != null ? { latitude: raw.latitude } : {}),\n ...(raw.longitude != null ? { longitude: raw.longitude } : {}),\n },\n }\n : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\nexport function transformCoach(raw: RawCoach, lang: string): FUSportsCoach {\n const { name } = resolveTranslation(raw.translations ?? [], lang, raw.name, raw.short_name);\n const country = resolveCountry(raw.country_id, raw.related ?? [], lang);\n const related = resolveRelated(raw.related ?? [], lang);\n\n return {\n id: raw.id,\n name,\n sport: raw.sport,\n ...(raw.birth_date ? { birthdate: raw.birth_date } : {}),\n ...(country ? { country } : {}),\n ...(raw.provider_ref?.length ? { providerRef: resolveProviderRef(raw.provider_ref) } : {}),\n ...(related ? { related } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Main dispatcher\n// ---------------------------------------------------------------------------\n\n/**\n * Determine entity type from raw data and call the appropriate transformer.\n * The raw API uses `content_type` for competitions and `type` / general context for others.\n */\nexport function transformEntity(raw: RawSearchEntityBase & Record<string, unknown>, lang: string): SearchEntityResult {\n // Determine entity type from raw fields\n const contentType = (raw.content_type as string)?.toUpperCase?.();\n const type = (raw.type as string)?.toUpperCase?.();\n const entityType = (raw.entityType as string)?.toLowerCase?.();\n\n if (contentType === \"COMPETITION\" || entityType === \"competition\") {\n return { ...transformCompetition(raw as unknown as RawCompetition, lang), entityType: \"competition\" };\n }\n\n if (entityType === \"country\" || raw.country_code !== undefined) {\n return { ...transformCountry(raw as RawCountry, lang), entityType: \"country\" };\n }\n\n if (entityType === \"venue\" || (raw.capacity !== undefined && !entityType)) {\n return { ...transformVenue(raw as RawVenue, lang), entityType: \"venue\" };\n }\n\n if (entityType === \"coach\" || (type === \"COACH\")) {\n return { ...transformCoach(raw as RawCoach, lang), entityType: \"coach\" };\n }\n\n if (entityType === \"athlete\" || type === \"PLAYER\" || raw.position !== undefined || raw.shirt_number !== undefined) {\n return { ...transformAthlete(raw as RawAthlete, lang), entityType: \"athlete\" };\n }\n\n // Default to team\n if (entityType === \"team\" || type === \"TEAM\" || raw.three_letter_code !== undefined) {\n return { ...transformTeam(raw as RawTeam, lang), entityType: \"team\" };\n }\n\n // Fallback: treat as team (most common entity type)\n return { ...transformTeam(raw as RawTeam, lang), entityType: \"team\" };\n}\n\n/**\n * Summary dispatcher — like transformEntity but calls summary transforms.\n * Returns lightweight types without `related` or `providerRef`.\n */\nexport function transformEntitySummary(raw: RawSearchEntityBase & Record<string, unknown>, lang: string): SearchEntitySummary {\n const contentType = (raw.content_type as string)?.toUpperCase?.();\n const type = (raw.type as string)?.toUpperCase?.();\n const entityType = (raw.entityType as string)?.toLowerCase?.();\n\n if (contentType === \"COMPETITION\" || entityType === \"competition\") {\n return { ...transformCompetitionSummary(raw as unknown as RawCompetition, lang), entityType: \"competition\" };\n }\n\n if (entityType === \"country\" || raw.country_code !== undefined) {\n return { ...transformCountrySummary(raw as RawCountry, lang), entityType: \"country\" };\n }\n\n if (entityType === \"venue\" || (raw.capacity !== undefined && !entityType)) {\n return { ...transformVenueSummary(raw as RawVenue, lang), entityType: \"venue\" };\n }\n\n if (entityType === \"coach\" || (type === \"COACH\")) {\n return { ...transformCoachSummary(raw as RawCoach, lang), entityType: \"coach\" };\n }\n\n if (entityType === \"athlete\" || type === \"PLAYER\" || raw.position !== undefined || raw.shirt_number !== undefined) {\n return { ...transformAthleteSummary(raw as RawAthlete, lang), entityType: \"athlete\" };\n }\n\n if (entityType === \"team\" || type === \"TEAM\" || raw.three_letter_code !== undefined) {\n return { ...transformTeamSummary(raw as RawTeam, lang), entityType: \"team\" };\n }\n\n return { ...transformTeamSummary(raw as RawTeam, lang), entityType: \"team\" };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports.test.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/api/fansunited/sports/competition/__tests__/exports.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydrated.test.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/api/fansunited/sports/competition/__tests__/hydrated.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/api/fansunited/sports/competition/__tests__/index.test.ts"],"names":[],"mappings":""}
|