@zivue/zuuid 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -1
- package/README.md +291 -215
- package/dist/client.d.ts +16 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +22 -0
- package/dist/entity.d.ts.map +1 -1
- package/dist/entity.js +9 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/providers/comicvine/character.d.ts +2 -0
- package/dist/providers/comicvine/character.d.ts.map +1 -0
- package/dist/providers/comicvine/character.js +1 -0
- package/dist/providers/comicvine/constants.d.ts +8 -0
- package/dist/providers/comicvine/constants.d.ts.map +1 -0
- package/dist/providers/comicvine/constants.js +7 -0
- package/dist/providers/comicvine/index.d.ts +9 -0
- package/dist/providers/comicvine/index.d.ts.map +1 -0
- package/dist/providers/comicvine/index.js +8 -0
- package/dist/providers/comicvine/issue.d.ts +2 -0
- package/dist/providers/comicvine/issue.d.ts.map +1 -0
- package/dist/providers/comicvine/issue.js +1 -0
- package/dist/providers/comicvine/person.d.ts +2 -0
- package/dist/providers/comicvine/person.d.ts.map +1 -0
- package/dist/providers/comicvine/person.js +1 -0
- package/dist/providers/comicvine/publisher.d.ts +2 -0
- package/dist/providers/comicvine/publisher.d.ts.map +1 -0
- package/dist/providers/comicvine/publisher.js +1 -0
- package/dist/providers/comicvine/story-arc.d.ts +2 -0
- package/dist/providers/comicvine/story-arc.d.ts.map +1 -0
- package/dist/providers/comicvine/story-arc.js +1 -0
- package/dist/providers/comicvine/transform.d.ts +4 -0
- package/dist/providers/comicvine/transform.d.ts.map +1 -0
- package/dist/providers/comicvine/transform.js +63 -0
- package/dist/providers/comicvine/volume.d.ts +2 -0
- package/dist/providers/comicvine/volume.d.ts.map +1 -0
- package/dist/providers/comicvine/volume.js +1 -0
- package/dist/providers/common.d.ts +24 -0
- package/dist/providers/common.d.ts.map +1 -0
- package/dist/providers/common.js +140 -0
- package/dist/providers/gamesdb/constants.d.ts +4 -0
- package/dist/providers/gamesdb/constants.d.ts.map +1 -0
- package/dist/providers/gamesdb/constants.js +3 -0
- package/dist/providers/gamesdb/game.d.ts +7 -0
- package/dist/providers/gamesdb/game.d.ts.map +1 -0
- package/dist/providers/gamesdb/game.js +61 -0
- package/dist/providers/gamesdb/index.d.ts +4 -0
- package/dist/providers/gamesdb/index.d.ts.map +1 -0
- package/dist/providers/gamesdb/index.js +3 -0
- package/dist/providers/gamesdb/platform.d.ts +4 -0
- package/dist/providers/gamesdb/platform.d.ts.map +1 -0
- package/dist/providers/gamesdb/platform.js +23 -0
- package/dist/providers/jikan/anime.d.ts +2 -0
- package/dist/providers/jikan/anime.d.ts.map +1 -0
- package/dist/providers/jikan/anime.js +1 -0
- package/dist/providers/jikan/character.d.ts +2 -0
- package/dist/providers/jikan/character.d.ts.map +1 -0
- package/dist/providers/jikan/character.js +1 -0
- package/dist/providers/jikan/constants.d.ts +8 -0
- package/dist/providers/jikan/constants.d.ts.map +1 -0
- package/dist/providers/jikan/constants.js +7 -0
- package/dist/providers/jikan/index.d.ts +9 -0
- package/dist/providers/jikan/index.d.ts.map +1 -0
- package/dist/providers/jikan/index.js +8 -0
- package/dist/providers/jikan/magazine.d.ts +2 -0
- package/dist/providers/jikan/magazine.d.ts.map +1 -0
- package/dist/providers/jikan/magazine.js +1 -0
- package/dist/providers/jikan/manga.d.ts +2 -0
- package/dist/providers/jikan/manga.d.ts.map +1 -0
- package/dist/providers/jikan/manga.js +1 -0
- package/dist/providers/jikan/person.d.ts +2 -0
- package/dist/providers/jikan/person.d.ts.map +1 -0
- package/dist/providers/jikan/person.js +1 -0
- package/dist/providers/jikan/producer.d.ts +2 -0
- package/dist/providers/jikan/producer.d.ts.map +1 -0
- package/dist/providers/jikan/producer.js +1 -0
- package/dist/providers/jikan/transform.d.ts +8 -0
- package/dist/providers/jikan/transform.d.ts.map +1 -0
- package/dist/providers/jikan/transform.js +127 -0
- package/dist/providers/musicbrainz/artist.d.ts +4 -0
- package/dist/providers/musicbrainz/artist.d.ts.map +1 -0
- package/dist/providers/musicbrainz/artist.js +28 -0
- package/dist/providers/musicbrainz/constants.d.ts +10 -0
- package/dist/providers/musicbrainz/constants.d.ts.map +1 -0
- package/dist/providers/musicbrainz/constants.js +9 -0
- package/dist/providers/musicbrainz/helpers.d.ts +15 -0
- package/dist/providers/musicbrainz/helpers.d.ts.map +1 -0
- package/dist/providers/musicbrainz/helpers.js +71 -0
- package/dist/providers/musicbrainz/index.d.ts +8 -0
- package/dist/providers/musicbrainz/index.d.ts.map +1 -0
- package/dist/providers/musicbrainz/index.js +7 -0
- package/dist/providers/musicbrainz/label.d.ts +4 -0
- package/dist/providers/musicbrainz/label.d.ts.map +1 -0
- package/dist/providers/musicbrainz/label.js +28 -0
- package/dist/providers/musicbrainz/recording.d.ts +4 -0
- package/dist/providers/musicbrainz/recording.d.ts.map +1 -0
- package/dist/providers/musicbrainz/recording.js +41 -0
- package/dist/providers/musicbrainz/release-group.d.ts +7 -0
- package/dist/providers/musicbrainz/release-group.d.ts.map +1 -0
- package/dist/providers/musicbrainz/release-group.js +28 -0
- package/dist/providers/musicbrainz/release.d.ts +7 -0
- package/dist/providers/musicbrainz/release.d.ts.map +1 -0
- package/dist/providers/musicbrainz/release.js +50 -0
- package/dist/providers/musicbrainz/work.d.ts +4 -0
- package/dist/providers/musicbrainz/work.d.ts.map +1 -0
- package/dist/providers/musicbrainz/work.js +40 -0
- package/dist/providers/openfoodfacts/constants.d.ts +3 -0
- package/dist/providers/openfoodfacts/constants.d.ts.map +1 -0
- package/dist/providers/openfoodfacts/constants.js +2 -0
- package/dist/providers/openfoodfacts/index.d.ts +3 -0
- package/dist/providers/openfoodfacts/index.d.ts.map +1 -0
- package/dist/providers/openfoodfacts/index.js +2 -0
- package/dist/providers/openfoodfacts/product.d.ts +4 -0
- package/dist/providers/openfoodfacts/product.d.ts.map +1 -0
- package/dist/providers/openfoodfacts/product.js +29 -0
- package/dist/providers/openlibrary/author.d.ts +65 -0
- package/dist/providers/openlibrary/author.d.ts.map +1 -0
- package/dist/providers/openlibrary/author.js +228 -0
- package/dist/providers/openlibrary/book.d.ts +138 -0
- package/dist/providers/openlibrary/book.d.ts.map +1 -0
- package/dist/providers/openlibrary/book.js +536 -0
- package/dist/providers/openlibrary/client.d.ts +22 -0
- package/dist/providers/openlibrary/client.d.ts.map +1 -0
- package/dist/providers/openlibrary/client.js +61 -0
- package/dist/providers/openlibrary/constants.d.ts +4 -0
- package/dist/providers/openlibrary/constants.d.ts.map +1 -0
- package/dist/providers/openlibrary/constants.js +3 -0
- package/dist/providers/openlibrary/index.d.ts +6 -0
- package/dist/providers/openlibrary/index.d.ts.map +1 -0
- package/dist/providers/openlibrary/index.js +5 -0
- package/dist/providers/openlibrary/types.d.ts +23 -0
- package/dist/providers/openlibrary/types.d.ts.map +1 -0
- package/dist/providers/openlibrary/types.js +1 -0
- package/dist/providers/openstreetmap/constants.d.ts +6 -0
- package/dist/providers/openstreetmap/constants.d.ts.map +1 -0
- package/dist/providers/openstreetmap/constants.js +5 -0
- package/dist/providers/openstreetmap/index.d.ts +4 -0
- package/dist/providers/openstreetmap/index.d.ts.map +1 -0
- package/dist/providers/openstreetmap/index.js +3 -0
- package/dist/providers/openstreetmap/place.d.ts +4 -0
- package/dist/providers/openstreetmap/place.d.ts.map +1 -0
- package/dist/providers/openstreetmap/place.js +67 -0
- package/dist/providers/openstreetmap/venue.d.ts +2 -0
- package/dist/providers/openstreetmap/venue.d.ts.map +1 -0
- package/dist/providers/openstreetmap/venue.js +1 -0
- package/dist/providers/podcast/constants.d.ts +3 -0
- package/dist/providers/podcast/constants.d.ts.map +1 -0
- package/dist/providers/podcast/constants.js +2 -0
- package/dist/providers/podcast/index.d.ts +3 -0
- package/dist/providers/podcast/index.d.ts.map +1 -0
- package/dist/providers/podcast/index.js +2 -0
- package/dist/providers/podcast/podcast.d.ts +4 -0
- package/dist/providers/podcast/podcast.d.ts.map +1 -0
- package/dist/providers/podcast/podcast.js +30 -0
- package/dist/providers/setlistfm/artist.d.ts +2 -0
- package/dist/providers/setlistfm/artist.d.ts.map +1 -0
- package/dist/providers/setlistfm/artist.js +1 -0
- package/dist/providers/setlistfm/constants.d.ts +5 -0
- package/dist/providers/setlistfm/constants.d.ts.map +1 -0
- package/dist/providers/setlistfm/constants.js +4 -0
- package/dist/providers/setlistfm/index.d.ts +6 -0
- package/dist/providers/setlistfm/index.d.ts.map +1 -0
- package/dist/providers/setlistfm/index.js +5 -0
- package/dist/providers/setlistfm/setlist.d.ts +2 -0
- package/dist/providers/setlistfm/setlist.d.ts.map +1 -0
- package/dist/providers/setlistfm/setlist.js +1 -0
- package/dist/providers/setlistfm/transform.d.ts +7 -0
- package/dist/providers/setlistfm/transform.d.ts.map +1 -0
- package/dist/providers/setlistfm/transform.js +122 -0
- package/dist/providers/setlistfm/venue.d.ts +2 -0
- package/dist/providers/setlistfm/venue.d.ts.map +1 -0
- package/dist/providers/setlistfm/venue.js +1 -0
- package/dist/providers/ticketmaster/attraction.d.ts +2 -0
- package/dist/providers/ticketmaster/attraction.d.ts.map +1 -0
- package/dist/providers/ticketmaster/attraction.js +1 -0
- package/dist/providers/ticketmaster/constants.d.ts +5 -0
- package/dist/providers/ticketmaster/constants.d.ts.map +1 -0
- package/dist/providers/ticketmaster/constants.js +4 -0
- package/dist/providers/ticketmaster/event.d.ts +2 -0
- package/dist/providers/ticketmaster/event.d.ts.map +1 -0
- package/dist/providers/ticketmaster/event.js +1 -0
- package/dist/providers/ticketmaster/index.d.ts +6 -0
- package/dist/providers/ticketmaster/index.d.ts.map +1 -0
- package/dist/providers/ticketmaster/index.js +5 -0
- package/dist/providers/ticketmaster/transform.d.ts +7 -0
- package/dist/providers/ticketmaster/transform.d.ts.map +1 -0
- package/dist/providers/ticketmaster/transform.js +89 -0
- package/dist/providers/ticketmaster/venue.d.ts +2 -0
- package/dist/providers/ticketmaster/venue.d.ts.map +1 -0
- package/dist/providers/ticketmaster/venue.js +1 -0
- package/dist/providers/tmdb/movie.d.ts.map +1 -1
- package/dist/providers/tmdb/movie.js +9 -22
- package/dist/providers/tmdb/tv.d.ts.map +1 -1
- package/dist/providers/tmdb/tv.js +4 -2
- package/dist/providers/wger/constants.d.ts +4 -0
- package/dist/providers/wger/constants.d.ts.map +1 -0
- package/dist/providers/wger/constants.js +3 -0
- package/dist/providers/wger/equipment.d.ts +4 -0
- package/dist/providers/wger/equipment.d.ts.map +1 -0
- package/dist/providers/wger/equipment.js +22 -0
- package/dist/providers/wger/exercise.d.ts +4 -0
- package/dist/providers/wger/exercise.d.ts.map +1 -0
- package/dist/providers/wger/exercise.js +42 -0
- package/dist/providers/wger/index.d.ts +4 -0
- package/dist/providers/wger/index.d.ts.map +1 -0
- package/dist/providers/wger/index.js +3 -0
- package/package.json +201 -5
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# @zivue/zuuid
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Search, fetch, and normalize media metadata from external providers into a shared Zuuid data shape.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package is meant to be used by apps that need provider-backed lookup and transformation, but do not want provider-specific response shapes leaking through the app.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
TMDB and Open Library include live search/fetch clients. Additional providers currently expose source-record transformers: you provide the raw provider payload, and this package normalizes it into `ZuuidData`.
|
|
8
|
+
|
|
9
|
+
Storage, caching, indexing, review state, object-store keys, and persistence belong in a layer outside this package.
|
|
8
10
|
|
|
9
11
|
## Install
|
|
10
12
|
|
|
@@ -21,6 +23,9 @@ const zuuid = createZuuidClient({
|
|
|
21
23
|
providers: {
|
|
22
24
|
tmdb: {
|
|
23
25
|
bearerToken: process.env.TMDB_BEARER_TOKEN!
|
|
26
|
+
},
|
|
27
|
+
openlibrary: {
|
|
28
|
+
// Open Library does not require credentials.
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
31
|
});
|
|
@@ -29,98 +34,97 @@ const search = await zuuid.movie.tmdb?.search({ query: "Fight Club" });
|
|
|
29
34
|
const selected = search?.results[0];
|
|
30
35
|
const movie = selected ? await zuuid.movie.tmdb?.fetch({ id: selected.source.value }) : undefined;
|
|
31
36
|
|
|
32
|
-
console.log(movie?.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
## Generate A ZUUID
|
|
36
|
-
|
|
37
|
-
Zuuid generation is UUID v5:
|
|
38
|
-
|
|
39
|
-
```txt
|
|
40
|
-
uuid_v5(provider_namespace, "<normalized-category>:<external_id>")
|
|
37
|
+
console.log(movie?.primaryTitle);
|
|
38
|
+
// Fight Club
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
import { providerZuuid } from "@zivue/zuuid";
|
|
45
|
-
|
|
46
|
-
const zuuid = await providerZuuid({
|
|
47
|
-
provider: "tmdb",
|
|
48
|
-
category: "movie",
|
|
49
|
-
externalId: "550"
|
|
50
|
-
});
|
|
41
|
+
## What You Get
|
|
51
42
|
|
|
52
|
-
|
|
53
|
-
// 1706d641-d381-5618-9425-d8cd8b35f898
|
|
54
|
-
```
|
|
43
|
+
The package has two main output shapes:
|
|
55
44
|
|
|
56
|
-
|
|
45
|
+
- `SearchResponse<ZuuidSearchResult>` for search/list screens.
|
|
46
|
+
- `ZuuidData` for full fetched and transformed datasets.
|
|
57
47
|
|
|
58
|
-
|
|
48
|
+
Search is lightweight and paginated. Fetch returns the full normalized dataset for a selected provider ID.
|
|
59
49
|
|
|
60
50
|
```ts
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const dataset = createZuuidData({
|
|
64
|
-
zuuid: "1706d641-d381-5618-9425-d8cd8b35f898",
|
|
65
|
-
category: "movie",
|
|
66
|
-
primaryTitle: "Fight Club"
|
|
67
|
-
});
|
|
68
|
-
```
|
|
51
|
+
const movies = await zuuid.movie.tmdb?.search({ query: "Fight Club" });
|
|
69
52
|
|
|
70
|
-
|
|
53
|
+
console.log(movies?.pagination);
|
|
54
|
+
// { page: 1, totalPages: 10, totalResults: 190 }
|
|
71
55
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
tags: string[];
|
|
88
|
-
externalIds: ExternalId[];
|
|
89
|
-
provenance: Provenance[];
|
|
90
|
-
};
|
|
56
|
+
console.log(movies?.results[0]);
|
|
57
|
+
// {
|
|
58
|
+
// id: "1706d641-d381-5618-9425-d8cd8b35f898",
|
|
59
|
+
// zuuid: "1706d641-d381-5618-9425-d8cd8b35f898",
|
|
60
|
+
// category: "movie",
|
|
61
|
+
// title: "Fight Club",
|
|
62
|
+
// date: "1999-10-15",
|
|
63
|
+
// cover: "https://image.tmdb.org/t/p/w500/...",
|
|
64
|
+
// rating: 4.2,
|
|
65
|
+
// weight: 20.0,
|
|
66
|
+
// relationType: null,
|
|
67
|
+
// attribute: null,
|
|
68
|
+
// order: null,
|
|
69
|
+
// source: { source: "tmdb", category: "movie", value: "550" }
|
|
70
|
+
// }
|
|
91
71
|
```
|
|
92
72
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Backend-only concerns such as record versions, flags, review state, index state, and object-store metadata are intentionally not part of this package's dataset shape.
|
|
96
|
-
|
|
97
|
-
## Source Metadata
|
|
98
|
-
|
|
99
|
-
Source records are provider records before they are transformed into canonical entities. They carry the external provider key, raw JSON payload, content hash, and observation timestamps.
|
|
73
|
+
The full fetched dataset is flat and provider-normalized:
|
|
100
74
|
|
|
101
75
|
```ts
|
|
102
|
-
|
|
76
|
+
const movie = await zuuid.movie.tmdb?.fetch({ id: "550" });
|
|
103
77
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
78
|
+
console.log(movie);
|
|
79
|
+
// {
|
|
80
|
+
// zuuid,
|
|
81
|
+
// kind: "watch",
|
|
82
|
+
// category: "movie",
|
|
83
|
+
// primaryTitle: "Fight Club",
|
|
84
|
+
// primaryDate: "1999-10-15",
|
|
85
|
+
// rating,
|
|
86
|
+
// cover,
|
|
87
|
+
// aliases,
|
|
88
|
+
// descriptions,
|
|
89
|
+
// details,
|
|
90
|
+
// media,
|
|
91
|
+
// relations,
|
|
92
|
+
// recommendations,
|
|
93
|
+
// tags,
|
|
94
|
+
// externalIds,
|
|
95
|
+
// provenance
|
|
96
|
+
// }
|
|
111
97
|
```
|
|
112
98
|
|
|
113
|
-
`
|
|
99
|
+
Search results, relations, and recommendations share the same lightweight list item fields: `id`, `zuuid`, `category`, `title`, `date`, `cover`, `rating`, `weight`, `relationType`, `attribute`, and `order`.
|
|
114
100
|
|
|
115
|
-
|
|
101
|
+
Ratings are normalized to a `0-5` scale when the provider exposes a compatible numeric score. The original provider score is preserved in details as `provider_rating` for providers whose native scale differs.
|
|
116
102
|
|
|
117
|
-
|
|
103
|
+
## Supported Providers
|
|
118
104
|
|
|
119
105
|
| Provider | Category | Search | Fetch | Transform |
|
|
120
106
|
| --- | --- | --- | --- | --- |
|
|
121
107
|
| TMDB | movie | yes | yes | yes |
|
|
122
108
|
| TMDB | tv | yes | yes | yes |
|
|
123
109
|
| TMDB | person | yes | yes | yes |
|
|
110
|
+
| Open Library | book | yes | yes | yes |
|
|
111
|
+
| Open Library | author | yes | yes | yes |
|
|
112
|
+
| ComicVine | volume, issue, story_arc, character, person, publisher | no | no | yes |
|
|
113
|
+
| GamesDB | game, platform | no | no | yes |
|
|
114
|
+
| Jikan | anime, manga, producer, magazine, character, person | no | no | yes |
|
|
115
|
+
| MusicBrainz | release, release-group, recording, artist, label, work | no | no | yes |
|
|
116
|
+
| OpenFoodFacts | product | no | no | yes |
|
|
117
|
+
| OpenStreetMap | city, country, place, venue | no | no | yes |
|
|
118
|
+
| Podcast / iTunes | podcast | no | no | yes |
|
|
119
|
+
| Setlist.fm | setlist, artist, venue | no | no | yes |
|
|
120
|
+
| Ticketmaster | event, attraction, venue | no | no | yes |
|
|
121
|
+
| Wger | exercise, equipment | no | no | yes |
|
|
122
|
+
|
|
123
|
+
For transformer-only providers, "Search" and "Fetch" are marked `no` because this package does not perform those HTTP requests yet. Use your own provider client or stored payloads, wrap the payload in a `SourceRecord`, and call the category transformer.
|
|
124
|
+
|
|
125
|
+
## TMDB Credentials
|
|
126
|
+
|
|
127
|
+
`TmdbProvider` accepts either a TMDB API Read Access Token or a v3 API key:
|
|
124
128
|
|
|
125
129
|
```ts
|
|
126
130
|
import { TmdbProvider } from "@zivue/zuuid/providers/tmdb";
|
|
@@ -129,240 +133,312 @@ const tmdb = new TmdbProvider({
|
|
|
129
133
|
bearerToken: process.env.TMDB_BEARER_TOKEN!
|
|
130
134
|
});
|
|
131
135
|
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
console.log(movie?.zuuid);
|
|
137
|
-
// 1706d641-d381-5618-9425-d8cd8b35f898
|
|
136
|
+
// or
|
|
137
|
+
const tmdbWithApiKey = new TmdbProvider({
|
|
138
|
+
apiKey: process.env.TMDB_API_KEY!
|
|
139
|
+
});
|
|
138
140
|
```
|
|
139
141
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
```ts
|
|
143
|
-
import { TmdbProvider, transformTmdbMovie, transformTmdbPerson, transformTmdbTv } from "@zivue/zuuid/providers/tmdb";
|
|
142
|
+
TMDB bearer tokens usually start with `eyJ...`; v3 API keys are shorter hex-like strings.
|
|
144
143
|
|
|
145
|
-
|
|
146
|
-
const movie = source ? await transformTmdbMovie(source) : undefined;
|
|
144
|
+
## Search
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
const tv = tvSource ? await transformTmdbTv(tvSource) : undefined;
|
|
146
|
+
Use the category-first client facade when your app may have several providers:
|
|
150
147
|
|
|
151
|
-
|
|
152
|
-
const
|
|
148
|
+
```ts
|
|
149
|
+
const movies = await zuuid.movie.tmdb?.search({ query: "Fight Club" });
|
|
150
|
+
const tvShows = await zuuid.tv.tmdb?.search({ query: "Game of Thrones" });
|
|
151
|
+
const people = await zuuid.people.tmdb?.search({ query: "Brad Pitt" });
|
|
152
|
+
const books = await zuuid.read.openlibrary?.search({ query: "The Lord of the Rings" });
|
|
153
|
+
const authors = await zuuid.people.openlibrary?.search({ query: "J. K. Rowling" });
|
|
153
154
|
```
|
|
154
155
|
|
|
155
|
-
|
|
156
|
+
Provider methods are also available directly:
|
|
156
157
|
|
|
157
158
|
```ts
|
|
158
159
|
const movies = await tmdb.searchMovies({ query: "Fight Club" });
|
|
159
160
|
const tvShows = await tmdb.searchTv({ query: "Game of Thrones" });
|
|
160
161
|
const people = await tmdb.searchPeople({ query: "Brad Pitt" });
|
|
162
|
+
```
|
|
161
163
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const selectedMovie = movies.results[0];
|
|
166
|
-
console.log(selectedMovie);
|
|
167
|
-
// {
|
|
168
|
-
// id: "1706d641-d381-5618-9425-d8cd8b35f898",
|
|
169
|
-
// zuuid: "1706d641-d381-5618-9425-d8cd8b35f898",
|
|
170
|
-
// category: "movie",
|
|
171
|
-
// title: "Fight Club",
|
|
172
|
-
// date: "1999-10-15",
|
|
173
|
-
// cover: "https://image.tmdb.org/t/p/w500/...",
|
|
174
|
-
// rating: 8.4,
|
|
175
|
-
// weight: 20.0,
|
|
176
|
-
// relationType: null,
|
|
177
|
-
// attribute: null,
|
|
178
|
-
// order: null,
|
|
179
|
-
// source: { source: "tmdb", category: "movie", value: "550" }
|
|
180
|
-
// }
|
|
164
|
+
```ts
|
|
165
|
+
import { OpenLibraryProvider } from "@zivue/zuuid/providers/openlibrary";
|
|
181
166
|
|
|
182
|
-
const
|
|
167
|
+
const openlibrary = new OpenLibraryProvider();
|
|
168
|
+
const books = await openlibrary.searchBooks({ query: "The Lord of the Rings" });
|
|
169
|
+
const authors = await openlibrary.searchAuthors({ query: "J. K. Rowling" });
|
|
183
170
|
```
|
|
184
171
|
|
|
185
|
-
|
|
172
|
+
Search options include pagination and common TMDB filters:
|
|
186
173
|
|
|
187
174
|
```ts
|
|
188
|
-
const
|
|
175
|
+
const movies = await tmdb.searchMovies({
|
|
176
|
+
query: "Fight Club",
|
|
177
|
+
page: 2,
|
|
178
|
+
includeAdult: false,
|
|
179
|
+
primaryReleaseYear: 1999
|
|
180
|
+
});
|
|
189
181
|
```
|
|
190
182
|
|
|
191
|
-
|
|
183
|
+
If you need the raw TMDB search payload wrapped as source records:
|
|
192
184
|
|
|
193
185
|
```ts
|
|
194
|
-
|
|
195
|
-
import { transformTmdbTv } from "@zivue/zuuid/providers/tmdb/tv";
|
|
196
|
-
import { transformTmdbPerson } from "@zivue/zuuid/providers/tmdb/person";
|
|
186
|
+
const rawMovies = await tmdb.searchMovieSourceRecords({ query: "Fight Club" });
|
|
197
187
|
```
|
|
198
188
|
|
|
199
|
-
|
|
189
|
+
## Fetch
|
|
200
190
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
For applications with multiple providers, use `createZuuidClient` to wire provider config once:
|
|
191
|
+
Fetch returns transformed `ZuuidData`:
|
|
204
192
|
|
|
205
193
|
```ts
|
|
206
|
-
import { createZuuidClient } from "@zivue/zuuid";
|
|
207
|
-
|
|
208
|
-
const zuuid = createZuuidClient({
|
|
209
|
-
providers: {
|
|
210
|
-
tmdb: {
|
|
211
|
-
bearerToken: process.env.TMDB_BEARER_TOKEN!
|
|
212
|
-
}
|
|
213
|
-
// Future movie providers can sit beside tmdb, e.g. omdb.
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
|
|
217
194
|
const movie = await zuuid.movie.tmdb?.fetch({ id: 550 });
|
|
218
195
|
const tv = await zuuid.tv.tmdb?.fetch({ id: 1399 });
|
|
219
196
|
const person = await zuuid.people.tmdb?.fetch({ id: 287 });
|
|
197
|
+
const book = await zuuid.read.openlibrary?.fetch({ id: "OL82563W" });
|
|
198
|
+
const author = await zuuid.people.openlibrary?.fetch({ id: "OL23919A" });
|
|
220
199
|
```
|
|
221
200
|
|
|
222
|
-
|
|
201
|
+
Direct provider methods are equivalent:
|
|
223
202
|
|
|
224
203
|
```ts
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
204
|
+
const movie = await tmdb.fetchMovie({ id: 550 });
|
|
205
|
+
const tv = await tmdb.fetchTv({ id: 1399 });
|
|
206
|
+
const person = await tmdb.fetchPerson({ id: 287 });
|
|
228
207
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
zuuid.people.tmdb?.search({ query: "Brad Pitt" });
|
|
232
|
-
// later: zuuid.movie.omdb?.fetch(...)
|
|
208
|
+
const book = await openlibrary.fetchBook({ id: "OL82563W" });
|
|
209
|
+
const author = await openlibrary.fetchAuthor({ id: "OL23919A" });
|
|
233
210
|
```
|
|
234
211
|
|
|
235
|
-
|
|
212
|
+
## Raw Source Records And Transform
|
|
236
213
|
|
|
237
|
-
|
|
214
|
+
For debugging, caching in your own layer, or custom transform timing, split fetch from transform:
|
|
238
215
|
|
|
239
|
-
|
|
216
|
+
```ts
|
|
217
|
+
import { transformTmdbMovie } from "@zivue/zuuid/providers/tmdb";
|
|
240
218
|
|
|
241
|
-
|
|
219
|
+
const source = await tmdb.fetchMovieSourceRecord({ id: 550 });
|
|
220
|
+
const movie = source ? await transformTmdbMovie(source, tmdb.transformOptions()) : undefined;
|
|
221
|
+
```
|
|
242
222
|
|
|
243
|
-
|
|
244
|
-
- `entity.ts`: flat Zuuid data types and category helpers
|
|
245
|
-
- `client.ts`: stateless package instantiator for configured providers
|
|
246
|
-
- `providers/<provider>/index.ts`: provider module barrel
|
|
247
|
-
- `providers/<provider>/client.ts`: shared provider client/config
|
|
248
|
-
- `providers/<provider>/<category>.ts`: category-specific fetch and transform helpers
|
|
249
|
-
- `providers/tmdb/movie.ts`: TMDB movie fetch and transform helpers
|
|
250
|
-
- `providers/tmdb/tv.ts`: TMDB TV fetch and transform helpers
|
|
251
|
-
- `providers/tmdb/person.ts`: TMDB person fetch and transform helpers
|
|
252
|
-
- `source.ts`: source records, external IDs, and provenance
|
|
253
|
-
- `hash.ts`: stable payload hashing
|
|
254
|
-
- `uuid.ts`: UUID parsing/normalization and UUID v5 internals
|
|
255
|
-
- `types.ts`: shared JSON value types
|
|
256
|
-
- `index.ts`: public barrel exports
|
|
223
|
+
The source record contains the raw payload:
|
|
257
224
|
|
|
258
|
-
|
|
225
|
+
```ts
|
|
226
|
+
console.log(source?.payload);
|
|
227
|
+
```
|
|
259
228
|
|
|
260
|
-
|
|
229
|
+
The transform result is normalized `ZuuidData`:
|
|
261
230
|
|
|
262
|
-
|
|
231
|
+
```ts
|
|
232
|
+
console.log(movie?.primaryTitle);
|
|
233
|
+
console.log(movie?.externalIds);
|
|
234
|
+
console.log(movie?.provenance);
|
|
235
|
+
```
|
|
263
236
|
|
|
264
|
-
|
|
237
|
+
For transformer-only providers:
|
|
265
238
|
|
|
266
|
-
|
|
239
|
+
```ts
|
|
240
|
+
import { createSourceRecord, transformGamesDbGame } from "@zivue/zuuid";
|
|
267
241
|
|
|
268
|
-
|
|
242
|
+
const source = await createSourceRecord({
|
|
243
|
+
source: { provider: "gamesdb", category: "game", externalId: "17444" },
|
|
244
|
+
payload: rawGamesDbPayload
|
|
245
|
+
});
|
|
269
246
|
|
|
270
|
-
|
|
247
|
+
const game = await transformGamesDbGame(source);
|
|
248
|
+
```
|
|
271
249
|
|
|
272
|
-
|
|
250
|
+
Category-specific imports are available:
|
|
273
251
|
|
|
274
|
-
|
|
252
|
+
```ts
|
|
253
|
+
import { transformTmdbMovie } from "@zivue/zuuid/providers/tmdb/movie";
|
|
254
|
+
import { transformTmdbTv } from "@zivue/zuuid/providers/tmdb/tv";
|
|
255
|
+
import { transformTmdbPerson } from "@zivue/zuuid/providers/tmdb/person";
|
|
256
|
+
import { transformOpenLibraryBook } from "@zivue/zuuid/providers/openlibrary/book";
|
|
257
|
+
import { transformOpenLibraryAuthor } from "@zivue/zuuid/providers/openlibrary/author";
|
|
258
|
+
import { transformMusicBrainzReleaseGroup } from "@zivue/zuuid/providers/musicbrainz/release-group";
|
|
259
|
+
import { transformComicVineIssue } from "@zivue/zuuid/providers/comicvine/issue";
|
|
260
|
+
import { transformJikanProducer } from "@zivue/zuuid/providers/jikan/producer";
|
|
261
|
+
import { transformOpenStreetMapVenue } from "@zivue/zuuid/providers/openstreetmap/venue";
|
|
262
|
+
import { transformWgerEquipment } from "@zivue/zuuid/providers/wger/equipment";
|
|
263
|
+
```
|
|
275
264
|
|
|
276
|
-
|
|
265
|
+
## Data Model
|
|
277
266
|
|
|
278
|
-
|
|
267
|
+
`ZuuidData` is the full normalized dataset:
|
|
279
268
|
|
|
280
|
-
|
|
269
|
+
```ts
|
|
270
|
+
type ZuuidData = {
|
|
271
|
+
zuuid: string;
|
|
272
|
+
kind: EntityKind;
|
|
273
|
+
category: string;
|
|
274
|
+
primaryTitle: string;
|
|
275
|
+
primaryDate?: string;
|
|
276
|
+
rating?: number;
|
|
277
|
+
cover?: string;
|
|
278
|
+
aliases: Alias[];
|
|
279
|
+
descriptions: Description[];
|
|
280
|
+
details: Detail[];
|
|
281
|
+
media: MediaAsset[];
|
|
282
|
+
relations: EntityRelation[];
|
|
283
|
+
recommendations: RecommendationEdge[];
|
|
284
|
+
tags: string[];
|
|
285
|
+
externalIds: ExternalId[];
|
|
286
|
+
provenance: Provenance[];
|
|
287
|
+
};
|
|
288
|
+
```
|
|
281
289
|
|
|
282
|
-
|
|
290
|
+
`Detail.value` can be any JSON value, so details can hold strings, numbers, booleans, arrays, or structured objects without duplicating `value` and `data` fields.
|
|
283
291
|
|
|
284
|
-
|
|
292
|
+
## ZUUIDs
|
|
285
293
|
|
|
286
|
-
|
|
294
|
+
Every fetched dataset and unified search result includes a `zuuid`. This is a deterministic UUID v5 generated from the provider namespace, category, and external ID. It gives your app a stable cross-provider identifier while the provider's own ID remains available in `source` or `externalIds`.
|
|
287
295
|
|
|
288
|
-
|
|
296
|
+
```ts
|
|
297
|
+
import { providerZuuid } from "@zivue/zuuid";
|
|
289
298
|
|
|
290
|
-
|
|
299
|
+
const zuuid = await providerZuuid({
|
|
300
|
+
provider: "tmdb",
|
|
301
|
+
category: "movie",
|
|
302
|
+
externalId: "550"
|
|
303
|
+
});
|
|
304
|
+
```
|
|
291
305
|
|
|
292
|
-
|
|
306
|
+
Most applications do not need to call `providerZuuid` directly; search and fetch do it internally.
|
|
293
307
|
|
|
294
|
-
|
|
308
|
+
## Client Design
|
|
295
309
|
|
|
296
|
-
|
|
310
|
+
The client is stateless. It does not cache, persist, schedule, read environment variables, or write files. It only closes over provider configuration and exposes category/provider methods:
|
|
297
311
|
|
|
298
|
-
|
|
312
|
+
```ts
|
|
313
|
+
zuuid.movie.tmdb?.search({ query: "Fight Club" });
|
|
314
|
+
zuuid.movie.tmdb?.fetch({ id: 550 });
|
|
299
315
|
|
|
300
|
-
|
|
316
|
+
zuuid.tv.tmdb?.search({ query: "Game of Thrones" });
|
|
317
|
+
zuuid.tv.tmdb?.fetch({ id: 1399 });
|
|
301
318
|
|
|
302
|
-
|
|
319
|
+
zuuid.people.tmdb?.search({ query: "Brad Pitt" });
|
|
320
|
+
zuuid.people.tmdb?.fetch({ id: 287 });
|
|
321
|
+
zuuid.people.openlibrary?.search({ query: "J. K. Rowling" });
|
|
322
|
+
zuuid.people.openlibrary?.fetch({ id: "OL23919A" });
|
|
303
323
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
npm test
|
|
324
|
+
zuuid.read.openlibrary?.search({ query: "The Lord of the Rings" });
|
|
325
|
+
zuuid.read.openlibrary?.fetch({ id: "OL82563W" });
|
|
307
326
|
```
|
|
308
327
|
|
|
309
|
-
##
|
|
328
|
+
## Example Scripts
|
|
310
329
|
|
|
311
|
-
|
|
330
|
+
The examples read `.env` from the repo root:
|
|
312
331
|
|
|
313
332
|
```sh
|
|
314
|
-
TMDB_BEARER_TOKEN=...
|
|
333
|
+
TMDB_BEARER_TOKEN=...
|
|
334
|
+
# or
|
|
335
|
+
TMDB_READ_ACCESS_TOKEN=...
|
|
336
|
+
# or
|
|
337
|
+
TMDB_API_KEY=...
|
|
315
338
|
```
|
|
316
339
|
|
|
317
|
-
|
|
340
|
+
Search a provider and print unified search results:
|
|
318
341
|
|
|
319
342
|
```sh
|
|
320
|
-
|
|
343
|
+
npm run example:search -- movie "Fight Club"
|
|
344
|
+
npm run example:search -- tv "Game of Thrones"
|
|
345
|
+
npm run example:search -- people "Brad Pitt"
|
|
346
|
+
npm run example:search -- book "The Lord of the Rings"
|
|
347
|
+
npm run example:search -- author "J. K. Rowling"
|
|
321
348
|
```
|
|
322
349
|
|
|
323
|
-
Fetch and transform
|
|
350
|
+
Fetch and transform a selected provider ID:
|
|
324
351
|
|
|
325
352
|
```sh
|
|
326
|
-
|
|
353
|
+
npm run example:fetch -- movie 550
|
|
354
|
+
npm run example:fetch -- tv 1399
|
|
355
|
+
npm run example:fetch -- people 287
|
|
356
|
+
npm run example:fetch -- book OL82563W
|
|
357
|
+
npm run example:fetch -- author OL23919A
|
|
327
358
|
```
|
|
328
359
|
|
|
329
|
-
Fetch
|
|
360
|
+
Fetch fixture-backed transformer examples:
|
|
330
361
|
|
|
331
362
|
```sh
|
|
332
|
-
|
|
363
|
+
npm run example:fetch -- gamesdb:game 17444
|
|
364
|
+
npm run example:fetch -- gamesdb:platform 6
|
|
365
|
+
npm run example:fetch -- musicbrainz:release-group aaa50249-1e6b-3910-b830-7e2fb622a8c4
|
|
366
|
+
npm run example:fetch -- musicbrainz:recording 0b5d8c0f-4975-4e44-9e67-0a5f1b5939f6
|
|
367
|
+
npm run example:fetch -- comicvine:issue 101
|
|
368
|
+
npm run example:fetch -- comicvine:story_arc 201
|
|
369
|
+
npm run example:fetch -- jikan:producer 14
|
|
370
|
+
npm run example:fetch -- jikan:magazine 1
|
|
371
|
+
npm run example:fetch -- openfoodfacts:product 3017620422003
|
|
372
|
+
npm run example:fetch -- openstreetmap:venue W123456
|
|
373
|
+
npm run example:fetch -- wger:equipment 7
|
|
333
374
|
```
|
|
334
375
|
|
|
335
|
-
|
|
376
|
+
`example:fetch` writes both raw and transformed JSON:
|
|
336
377
|
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
npm run example:tmdb-search -- people "Brad Pitt"
|
|
378
|
+
```text
|
|
379
|
+
data/<provider>/<category>/<id>.raw.json
|
|
380
|
+
data/<provider>/<category>/<id>.zuuid.json
|
|
341
381
|
```
|
|
342
382
|
|
|
343
|
-
|
|
383
|
+
`example:search` writes raw and transformed search JSON:
|
|
344
384
|
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
TMDB_READ_ACCESS_TOKEN=...
|
|
349
|
-
# or
|
|
350
|
-
TMDB_API_KEY=...
|
|
385
|
+
```text
|
|
386
|
+
data/<provider>/search/<category>/<query>.raw-search.json
|
|
387
|
+
data/<provider>/search/<category>/<query>.zuuid-search.json
|
|
351
388
|
```
|
|
352
389
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
390
|
+
## API Reference
|
|
391
|
+
|
|
392
|
+
Core exports:
|
|
393
|
+
|
|
394
|
+
- `createZuuidClient(config)`
|
|
395
|
+
- `providerZuuid(input)`
|
|
396
|
+
- `providerNamespace(provider)`
|
|
397
|
+
- `categoryFor(value)`
|
|
398
|
+
- `kindForCategory(category)`
|
|
399
|
+
- `createSourceRecord(input)`
|
|
400
|
+
- `attachSourceMetadata(dataset, sourceRecord, confidence?)`
|
|
401
|
+
|
|
402
|
+
Provider exports:
|
|
403
|
+
|
|
404
|
+
- `TmdbProvider`
|
|
405
|
+
- `OpenLibraryProvider`
|
|
406
|
+
- `transformTmdbMovie(sourceRecord, options?)`
|
|
407
|
+
- `transformTmdbTv(sourceRecord, options?)`
|
|
408
|
+
- `transformTmdbPerson(sourceRecord, options?)`
|
|
409
|
+
- `transformOpenLibraryBook(sourceRecord, options?)`
|
|
410
|
+
- `transformOpenLibraryAuthor(sourceRecord, options?)`
|
|
411
|
+
- `transformComicVine(sourceRecord)`
|
|
412
|
+
- `transformGamesDbGame(sourceRecord, options?)`
|
|
413
|
+
- `transformGamesDbPlatform(sourceRecord)`
|
|
414
|
+
- `transformJikan(sourceRecord)`
|
|
415
|
+
- `transformMusicBrainzRelease(sourceRecord, options?)`
|
|
416
|
+
- `transformMusicBrainzReleaseGroup(sourceRecord, options?)`
|
|
417
|
+
- `transformMusicBrainzRecording(sourceRecord)`
|
|
418
|
+
- `transformMusicBrainzArtist(sourceRecord)`
|
|
419
|
+
- `transformMusicBrainzLabel(sourceRecord)`
|
|
420
|
+
- `transformMusicBrainzWork(sourceRecord)`
|
|
421
|
+
- `transformOpenFoodFactsProduct(sourceRecord)`
|
|
422
|
+
- `transformOpenStreetMapPlace(sourceRecord)`
|
|
423
|
+
- `transformPodcast(sourceRecord)`
|
|
424
|
+
- `transformSetlistFm(sourceRecord)`
|
|
425
|
+
- `transformTicketmaster(sourceRecord)`
|
|
426
|
+
- `transformWgerExercise(sourceRecord)`
|
|
427
|
+
- `transformWgerEquipment(sourceRecord)`
|
|
428
|
+
- `searchTmdbMovies(provider, input, options?)`
|
|
429
|
+
- `searchTmdbTv(provider, input, options?)`
|
|
430
|
+
- `searchTmdbPeople(provider, input, options?)`
|
|
431
|
+
- `searchOpenLibraryBooks(provider, input, options?)`
|
|
432
|
+
- `searchOpenLibraryAuthors(provider, input, options?)`
|
|
356
433
|
|
|
357
|
-
|
|
434
|
+
## Development
|
|
358
435
|
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
data/tmdb/tv/1399.zuuid.json
|
|
364
|
-
data/tmdb/people/287.raw.json
|
|
365
|
-
data/tmdb/people/287.zuuid.json
|
|
366
|
-
data/tmdb/search/movie/fight-club.zuuid-search.json
|
|
367
|
-
data/tmdb/search/movie/fight-club.raw-search.json
|
|
436
|
+
```sh
|
|
437
|
+
npm install
|
|
438
|
+
npm test
|
|
439
|
+
npm pack --dry-run
|
|
368
440
|
```
|
|
441
|
+
|
|
442
|
+
## Package Boundary
|
|
443
|
+
|
|
444
|
+
This package intentionally does not include storage, caching, object-store metadata, record versions, review state, index state, or backend flags. Those concerns should live in the consuming application or service.
|