tmdb-kit 0.1.0-beta.3 → 1.0.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/LICENSE +21 -0
- package/README.md +216 -12
- package/dist/index.cjs +375 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +236 -11
- package/dist/index.d.ts +236 -11
- package/dist/index.js +357 -24
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -36,13 +36,86 @@ var TMDBResponseError = class extends TMDBError {
|
|
|
36
36
|
this.statusCode = body?.status_code;
|
|
37
37
|
this.statusMessage = body?.status_message;
|
|
38
38
|
}
|
|
39
|
+
/** True when TMDB has asked the caller to back off (HTTP 429). */
|
|
40
|
+
get isRateLimit() {
|
|
41
|
+
return this.status === 429;
|
|
42
|
+
}
|
|
43
|
+
/** True when the resource was not found (HTTP 404). */
|
|
44
|
+
get isNotFound() {
|
|
45
|
+
return this.status === 404;
|
|
46
|
+
}
|
|
47
|
+
/** True when the request was rejected as unauthenticated (HTTP 401). */
|
|
48
|
+
get isUnauthorized() {
|
|
49
|
+
return this.status === 401;
|
|
50
|
+
}
|
|
51
|
+
/** True when the request was rejected as forbidden (HTTP 403). */
|
|
52
|
+
get isForbidden() {
|
|
53
|
+
return this.status === 403;
|
|
54
|
+
}
|
|
55
|
+
/** True when the upstream returned a 5xx server error. */
|
|
56
|
+
get isServerError() {
|
|
57
|
+
return this.status >= 500 && this.status < 600;
|
|
58
|
+
}
|
|
39
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* Thrown when TMDB returns HTTP 429.
|
|
62
|
+
*
|
|
63
|
+
* The SDK does NOT retry automatically — that decision is left to the
|
|
64
|
+
* caller, since retry policies vary widely. Inspect `retryAfter` to
|
|
65
|
+
* implement your own backoff.
|
|
66
|
+
*/
|
|
67
|
+
var TMDBRateLimitError = class extends TMDBResponseError {
|
|
68
|
+
retryAfter;
|
|
69
|
+
constructor(message, options) {
|
|
70
|
+
super(message, options);
|
|
71
|
+
this.name = "TMDBRateLimitError";
|
|
72
|
+
this.retryAfter = options.retryAfter;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Create the appropriate error instance for a non-2xx TMDB response.
|
|
77
|
+
*
|
|
78
|
+
* Returns a {@link TMDBRateLimitError} when the status is 429, otherwise
|
|
79
|
+
* a generic {@link TMDBResponseError}. The error message is extracted from
|
|
80
|
+
* the TMDB `status_message` field when available.
|
|
81
|
+
*/
|
|
40
82
|
function createResponseError(options) {
|
|
41
|
-
|
|
83
|
+
const message = (isErrorResponseBody(options.body) ? options.body : void 0)?.status_message ?? `${options.status} ${options.statusText}`.trim();
|
|
84
|
+
if (options.status === 429) return new TMDBRateLimitError(message, {
|
|
85
|
+
...options,
|
|
86
|
+
retryAfter: parseRetryAfter(options.headers.get("retry-after"))
|
|
87
|
+
});
|
|
88
|
+
return new TMDBResponseError(message, options);
|
|
42
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Parse the `Retry-After` header into seconds. Accepts both delta-seconds
|
|
92
|
+
* (e.g. "5") and HTTP-date forms (e.g. "Wed, 21 Oct 2026 07:28:00 GMT").
|
|
93
|
+
* Falls back to 1 second when the header is missing or unparseable.
|
|
94
|
+
*/
|
|
95
|
+
function parseRetryAfter(value) {
|
|
96
|
+
if (value === null || value === void 0) return 1;
|
|
97
|
+
const trimmed = value.trim();
|
|
98
|
+
if (trimmed === "") return 1;
|
|
99
|
+
const seconds = Number(trimmed);
|
|
100
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds;
|
|
101
|
+
const date = Date.parse(trimmed);
|
|
102
|
+
if (Number.isFinite(date)) {
|
|
103
|
+
const deltaMs = date - Date.now();
|
|
104
|
+
return Math.max(1, Math.ceil(deltaMs / 1e3));
|
|
105
|
+
}
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
108
|
+
/** Check if a value has the shape of a TMDB error response body. */
|
|
43
109
|
function isErrorResponseBody(value) {
|
|
44
110
|
return typeof value === "object" && value !== null;
|
|
45
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Append query parameters to a URL object.
|
|
114
|
+
*
|
|
115
|
+
* - `undefined` and `null` values are skipped.
|
|
116
|
+
* - Arrays are joined with commas (TMDB convention).
|
|
117
|
+
* - All values are converted to strings.
|
|
118
|
+
*/
|
|
46
119
|
function appendQuery(url, query) {
|
|
47
120
|
for (const [key, value] of Object.entries(query)) {
|
|
48
121
|
if (value === void 0 || value === null) continue;
|
|
@@ -53,6 +126,12 @@ function appendQuery(url, query) {
|
|
|
53
126
|
url.searchParams.set(key, String(value));
|
|
54
127
|
}
|
|
55
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Merge a language query parameter with client defaults.
|
|
131
|
+
*
|
|
132
|
+
* If `query.language` is set it takes precedence; otherwise the client's
|
|
133
|
+
* default language is used.
|
|
134
|
+
*/
|
|
56
135
|
function withLanguage(defaults, query) {
|
|
57
136
|
const language = typeof query.language === "string" ? query.language : defaults.language;
|
|
58
137
|
return {
|
|
@@ -60,6 +139,11 @@ function withLanguage(defaults, query) {
|
|
|
60
139
|
language
|
|
61
140
|
};
|
|
62
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Merge language and region defaults for list endpoints.
|
|
144
|
+
*
|
|
145
|
+
* Combines {@link withLanguage} with region fallback from client defaults.
|
|
146
|
+
*/
|
|
63
147
|
function withListDefaults(defaults, query) {
|
|
64
148
|
const region = typeof query.region === "string" ? query.region : defaults.region;
|
|
65
149
|
return {
|
|
@@ -67,19 +151,40 @@ function withListDefaults(defaults, query) {
|
|
|
67
151
|
region
|
|
68
152
|
};
|
|
69
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Convert a string or string array to a comma-separated list.
|
|
156
|
+
*
|
|
157
|
+
* Returns `undefined` if the input is `undefined` (skips the parameter).
|
|
158
|
+
* TMDB uses comma-separated values for multi-value query parameters.
|
|
159
|
+
*/
|
|
70
160
|
function toCommaList(value) {
|
|
71
161
|
if (value === void 0) return;
|
|
72
162
|
return typeof value === "string" ? value : value.join(",");
|
|
73
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Validate and convert a numeric ID to a string for use in URL paths.
|
|
166
|
+
*
|
|
167
|
+
* @throws {TMDBRequestError} If `value` is not a positive integer.
|
|
168
|
+
*/
|
|
74
169
|
function toId(value, name) {
|
|
75
170
|
if (!Number.isInteger(value) || value <= 0) throw new TMDBRequestError(`${name} must be a positive integer`);
|
|
76
171
|
return String(value);
|
|
77
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Validate and trim a search query string.
|
|
175
|
+
*
|
|
176
|
+
* @throws {TMDBRequestError} If the query is empty after trimming.
|
|
177
|
+
*/
|
|
78
178
|
function toSearchQuery(value) {
|
|
79
179
|
const query = value.trim();
|
|
80
180
|
if (query.length === 0) throw new TMDBRequestError("search query must not be empty");
|
|
81
181
|
return query;
|
|
82
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Validate a trending time window value.
|
|
185
|
+
*
|
|
186
|
+
* @throws {TMDBRequestError} If `value` is not `"day"` or `"week"`.
|
|
187
|
+
*/
|
|
83
188
|
function toTimeWindow(value) {
|
|
84
189
|
if (value !== "day" && value !== "week") throw new TMDBRequestError("timeWindow must be either \"day\" or \"week\"");
|
|
85
190
|
return value;
|
|
@@ -90,15 +195,27 @@ function toTimeWindow(value) {
|
|
|
90
195
|
*/
|
|
91
196
|
function buildImageUrl(path, size = "original", options = {}) {
|
|
92
197
|
if (path === void 0 || path === null || path.trim() === "") return null;
|
|
93
|
-
|
|
198
|
+
const url = `${normalizeBaseUrl(options.baseUrl ?? "https://image.tmdb.org/t/p")}/${size}${path.startsWith("/") ? path : `/${path}`}`;
|
|
199
|
+
return options.transform ? options.transform(url) : url;
|
|
94
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Strip trailing slashes from a base URL to ensure consistent path joining.
|
|
203
|
+
*/
|
|
95
204
|
function normalizeBaseUrl(baseUrl) {
|
|
96
205
|
return baseUrl.replace(/\/+$/, "");
|
|
97
206
|
}
|
|
98
207
|
//#endregion
|
|
99
208
|
//#region src/http.ts
|
|
209
|
+
/**
|
|
210
|
+
* Built-in HTTP transport that uses the Fetch API.
|
|
211
|
+
*
|
|
212
|
+
* Handles authentication (API key or access token), URL construction,
|
|
213
|
+
* request headers, and response parsing. Use the factory function
|
|
214
|
+
* {@link createTMDB} instead of instantiating this directly.
|
|
215
|
+
*/
|
|
100
216
|
var TMDBHttpClient = class {
|
|
101
217
|
defaults;
|
|
218
|
+
imageTransform;
|
|
102
219
|
#apiKey;
|
|
103
220
|
#accessToken;
|
|
104
221
|
#baseUrl;
|
|
@@ -108,25 +225,25 @@ var TMDBHttpClient = class {
|
|
|
108
225
|
const accessToken = normalizeSecret("accessToken" in options ? options.accessToken : void 0);
|
|
109
226
|
const apiKey = normalizeSecret("apiKey" in options ? options.apiKey : void 0);
|
|
110
227
|
if (Boolean(accessToken) === Boolean(apiKey)) throw new TMDBRequestError("Provide exactly one of accessToken or apiKey");
|
|
111
|
-
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
112
|
-
if (typeof fetchImpl !== "function") throw new TMDBRequestError("No fetch implementation found. Pass options.fetch in this runtime.");
|
|
113
228
|
this.#accessToken = accessToken;
|
|
114
229
|
this.#apiKey = apiKey;
|
|
115
230
|
this.#baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://api.themoviedb.org/3");
|
|
116
|
-
this.#fetch =
|
|
231
|
+
this.#fetch = options.fetch;
|
|
117
232
|
this.#headers = options.headers;
|
|
118
233
|
this.defaults = {
|
|
119
234
|
imageBaseUrl: normalizeBaseUrl(options.imageBaseUrl ?? "https://image.tmdb.org/t/p"),
|
|
120
235
|
language: options.defaultLanguage,
|
|
121
236
|
region: options.defaultRegion
|
|
122
237
|
};
|
|
238
|
+
this.imageTransform = options.images?.transform;
|
|
123
239
|
}
|
|
124
240
|
async get(path, options = {}) {
|
|
125
241
|
const url = this.#createUrl(path, options.query ?? {});
|
|
126
242
|
const headers = this.#createHeaders(options.headers);
|
|
243
|
+
const fetchImpl = this.#resolveFetch();
|
|
127
244
|
let response;
|
|
128
245
|
try {
|
|
129
|
-
response = await
|
|
246
|
+
response = await fetchImpl(url, {
|
|
130
247
|
headers,
|
|
131
248
|
method: "GET",
|
|
132
249
|
signal: options.signal
|
|
@@ -144,6 +261,12 @@ var TMDBHttpClient = class {
|
|
|
144
261
|
});
|
|
145
262
|
return body;
|
|
146
263
|
}
|
|
264
|
+
#resolveFetch() {
|
|
265
|
+
if (this.#fetch !== void 0) return this.#fetch;
|
|
266
|
+
const globalFetch = globalThis.fetch;
|
|
267
|
+
if (typeof globalFetch !== "function") throw new TMDBRequestError("No fetch implementation found. Pass options.fetch in this runtime.");
|
|
268
|
+
return globalFetch.bind(globalThis);
|
|
269
|
+
}
|
|
147
270
|
#createHeaders(headersInit) {
|
|
148
271
|
const headers = new Headers(this.#headers);
|
|
149
272
|
const requestHeaders = new Headers(headersInit);
|
|
@@ -162,6 +285,13 @@ var TMDBHttpClient = class {
|
|
|
162
285
|
return url.toString();
|
|
163
286
|
}
|
|
164
287
|
};
|
|
288
|
+
/**
|
|
289
|
+
* Read and parse a JSON response body.
|
|
290
|
+
*
|
|
291
|
+
* Returns `undefined` for empty responses. If the body is not valid JSON,
|
|
292
|
+
* the raw text string is returned as-is (TMDB occasionally returns plain
|
|
293
|
+
* text for certain error conditions).
|
|
294
|
+
*/
|
|
165
295
|
async function readJson(response) {
|
|
166
296
|
const text = await response.text();
|
|
167
297
|
if (text.length === 0) return;
|
|
@@ -171,12 +301,21 @@ async function readJson(response) {
|
|
|
171
301
|
return text;
|
|
172
302
|
}
|
|
173
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Normalize a secret value by trimming whitespace and treating empty
|
|
306
|
+
* strings as undefined (not provided).
|
|
307
|
+
*/
|
|
174
308
|
function normalizeSecret(value) {
|
|
175
309
|
const secret = value?.trim();
|
|
176
310
|
return secret === "" ? void 0 : secret;
|
|
177
311
|
}
|
|
178
312
|
//#endregion
|
|
179
313
|
//#region src/resources/configuration.ts
|
|
314
|
+
/**
|
|
315
|
+
* Access TMDB configuration data (image sizes, countries, languages, etc.).
|
|
316
|
+
*
|
|
317
|
+
* Obtained via `client.configuration`.
|
|
318
|
+
*/
|
|
180
319
|
var ConfigurationResource = class {
|
|
181
320
|
#transport;
|
|
182
321
|
constructor(transport) {
|
|
@@ -203,6 +342,11 @@ var ConfigurationResource = class {
|
|
|
203
342
|
};
|
|
204
343
|
//#endregion
|
|
205
344
|
//#region src/resources/genres.ts
|
|
345
|
+
/**
|
|
346
|
+
* Access TMDB genre lists for movies and TV shows.
|
|
347
|
+
*
|
|
348
|
+
* Obtained via `client.genres`.
|
|
349
|
+
*/
|
|
206
350
|
var GenresResource = class {
|
|
207
351
|
#transport;
|
|
208
352
|
constructor(transport) {
|
|
@@ -217,17 +361,33 @@ var GenresResource = class {
|
|
|
217
361
|
};
|
|
218
362
|
//#endregion
|
|
219
363
|
//#region src/resources/images.ts
|
|
364
|
+
/**
|
|
365
|
+
* Helper for constructing TMDB image URLs from API path values.
|
|
366
|
+
*
|
|
367
|
+
* Obtained via `client.images`. Supports optional URL transforms for
|
|
368
|
+
* routing image requests through a CDN or proxy.
|
|
369
|
+
*/
|
|
220
370
|
var ImagesHelper = class {
|
|
221
371
|
#transport;
|
|
222
|
-
|
|
372
|
+
#transform;
|
|
373
|
+
constructor(transport, transform) {
|
|
223
374
|
this.#transport = transport;
|
|
375
|
+
this.#transform = transform;
|
|
224
376
|
}
|
|
225
|
-
url(path, size = "original") {
|
|
226
|
-
return buildImageUrl(path, size, {
|
|
377
|
+
url(path, size = "original", options = {}) {
|
|
378
|
+
return buildImageUrl(path, size, {
|
|
379
|
+
baseUrl: this.#transport.defaults.imageBaseUrl,
|
|
380
|
+
transform: options.transform ?? this.#transform
|
|
381
|
+
});
|
|
227
382
|
}
|
|
228
383
|
};
|
|
229
384
|
//#endregion
|
|
230
385
|
//#region src/resources/movies.ts
|
|
386
|
+
/**
|
|
387
|
+
* Access TMDB movie endpoints (popular, top-rated, details, credits, etc.).
|
|
388
|
+
*
|
|
389
|
+
* Obtained via `client.movies`.
|
|
390
|
+
*/
|
|
231
391
|
var MoviesResource = class {
|
|
232
392
|
#transport;
|
|
233
393
|
constructor(transport) {
|
|
@@ -270,6 +430,7 @@ var MoviesResource = class {
|
|
|
270
430
|
return this.#transport.get(`/movie/${toId(movieId, "movieId")}/videos`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
|
|
271
431
|
}
|
|
272
432
|
};
|
|
433
|
+
/** Build query parameters for movie list endpoints. */
|
|
273
434
|
function movieListQuery(transport, options) {
|
|
274
435
|
return withListDefaults(transport.defaults, {
|
|
275
436
|
language: options.language,
|
|
@@ -279,6 +440,11 @@ function movieListQuery(transport, options) {
|
|
|
279
440
|
}
|
|
280
441
|
//#endregion
|
|
281
442
|
//#region src/resources/people.ts
|
|
443
|
+
/**
|
|
444
|
+
* Access TMDB person (actor, director, etc.) endpoints.
|
|
445
|
+
*
|
|
446
|
+
* Obtained via `client.people`.
|
|
447
|
+
*/
|
|
282
448
|
var PeopleResource = class {
|
|
283
449
|
#transport;
|
|
284
450
|
constructor(transport) {
|
|
@@ -291,6 +457,7 @@ var PeopleResource = class {
|
|
|
291
457
|
return this.#transport.get(`/person/${toId(personId, "personId")}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
|
|
292
458
|
}
|
|
293
459
|
};
|
|
460
|
+
/** Build query parameters for person list endpoints. */
|
|
294
461
|
function peopleListQuery(transport, options) {
|
|
295
462
|
return withLanguage(transport.defaults, {
|
|
296
463
|
language: options.language,
|
|
@@ -299,6 +466,11 @@ function peopleListQuery(transport, options) {
|
|
|
299
466
|
}
|
|
300
467
|
//#endregion
|
|
301
468
|
//#region src/resources/search.ts
|
|
469
|
+
/**
|
|
470
|
+
* Search TMDB for movies, TV shows, people, or all media types.
|
|
471
|
+
*
|
|
472
|
+
* Obtained via `client.search`.
|
|
473
|
+
*/
|
|
302
474
|
var SearchResource = class {
|
|
303
475
|
#transport;
|
|
304
476
|
constructor(transport) {
|
|
@@ -313,10 +485,18 @@ var SearchResource = class {
|
|
|
313
485
|
people(query, options = {}) {
|
|
314
486
|
return this.#transport.get("/search/person", { query: commonSearchQuery(this.#transport, query, options) });
|
|
315
487
|
}
|
|
316
|
-
multi(query, options = {}) {
|
|
317
|
-
|
|
488
|
+
async multi(query, options = {}) {
|
|
489
|
+
const response = await this.#transport.get("/search/multi", { query: commonSearchQuery(this.#transport, query, options) });
|
|
490
|
+
const excluded = options.exclude;
|
|
491
|
+
if (excluded === void 0 || excluded.length === 0) return response;
|
|
492
|
+
const excludedSet = new Set(excluded);
|
|
493
|
+
return {
|
|
494
|
+
...response,
|
|
495
|
+
results: response.results.filter((result) => !excludedSet.has(result.media_type))
|
|
496
|
+
};
|
|
318
497
|
}
|
|
319
498
|
};
|
|
499
|
+
/** Build query parameters for movie search. */
|
|
320
500
|
function movieSearchQuery(transport, query, options) {
|
|
321
501
|
return withListDefaults(transport.defaults, {
|
|
322
502
|
include_adult: options.includeAdult,
|
|
@@ -328,6 +508,7 @@ function movieSearchQuery(transport, query, options) {
|
|
|
328
508
|
year: options.year
|
|
329
509
|
});
|
|
330
510
|
}
|
|
511
|
+
/** Build query parameters for TV search. */
|
|
331
512
|
function tvSearchQuery(transport, query, options) {
|
|
332
513
|
return withLanguage(transport.defaults, {
|
|
333
514
|
first_air_date_year: options.firstAirDateYear,
|
|
@@ -338,6 +519,7 @@ function tvSearchQuery(transport, query, options) {
|
|
|
338
519
|
year: options.year
|
|
339
520
|
});
|
|
340
521
|
}
|
|
522
|
+
/** Build query parameters for person and multi-search. */
|
|
341
523
|
function commonSearchQuery(transport, query, options) {
|
|
342
524
|
return withLanguage(transport.defaults, {
|
|
343
525
|
include_adult: options.includeAdult,
|
|
@@ -348,6 +530,11 @@ function commonSearchQuery(transport, query, options) {
|
|
|
348
530
|
}
|
|
349
531
|
//#endregion
|
|
350
532
|
//#region src/resources/trending.ts
|
|
533
|
+
/**
|
|
534
|
+
* Access TMDB trending content (movies, TV, people) for day/week windows.
|
|
535
|
+
*
|
|
536
|
+
* Obtained via `client.trending`.
|
|
537
|
+
*/
|
|
351
538
|
var TrendingResource = class {
|
|
352
539
|
#transport;
|
|
353
540
|
constructor(transport) {
|
|
@@ -368,6 +555,11 @@ var TrendingResource = class {
|
|
|
368
555
|
};
|
|
369
556
|
//#endregion
|
|
370
557
|
//#region src/resources/tv.ts
|
|
558
|
+
/**
|
|
559
|
+
* Access TMDB TV show endpoints (popular, top-rated, details, seasons, etc.).
|
|
560
|
+
*
|
|
561
|
+
* Obtained via `client.tv`.
|
|
562
|
+
*/
|
|
371
563
|
var TVResource = class {
|
|
372
564
|
#transport;
|
|
373
565
|
constructor(transport) {
|
|
@@ -416,6 +608,7 @@ var TVResource = class {
|
|
|
416
608
|
}) });
|
|
417
609
|
}
|
|
418
610
|
};
|
|
611
|
+
/** Build query parameters for TV list endpoints. */
|
|
419
612
|
function tvListQuery(transport, options) {
|
|
420
613
|
return withLanguage(transport.defaults, {
|
|
421
614
|
language: options.language,
|
|
@@ -440,26 +633,166 @@ var TMDBClient = class {
|
|
|
440
633
|
search;
|
|
441
634
|
trending;
|
|
442
635
|
tv;
|
|
443
|
-
#
|
|
636
|
+
#transport;
|
|
444
637
|
constructor(options) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
this
|
|
452
|
-
this.
|
|
453
|
-
this.
|
|
454
|
-
|
|
638
|
+
const { transport, images, ...httpOptions } = options;
|
|
639
|
+
const fallbackTransform = images?.transform;
|
|
640
|
+
const builtInClient = transport === void 0 ? new TMDBHttpClient({
|
|
641
|
+
...httpOptions,
|
|
642
|
+
images
|
|
643
|
+
}) : void 0;
|
|
644
|
+
this.#transport = builtInClient ?? transport;
|
|
645
|
+
this.configuration = new ConfigurationResource(this.#transport);
|
|
646
|
+
this.genres = new GenresResource(this.#transport);
|
|
647
|
+
this.images = new ImagesHelper(this.#transport, builtInClient ? builtInClient.imageTransform : fallbackTransform);
|
|
648
|
+
this.movies = new MoviesResource(this.#transport);
|
|
649
|
+
this.people = new PeopleResource(this.#transport);
|
|
650
|
+
this.search = new SearchResource(this.#transport);
|
|
651
|
+
this.trending = new TrendingResource(this.#transport);
|
|
652
|
+
this.tv = new TVResource(this.#transport);
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Make a raw GET request to any TMDB endpoint.
|
|
656
|
+
*
|
|
657
|
+
* This is an escape hatch for endpoints not covered by the typed resource
|
|
658
|
+
* helpers. The `path` should be relative to the API base URL (e.g.
|
|
659
|
+
* `/movie/{id}/credits`). Response is parsed as JSON and cast to `T`.
|
|
660
|
+
*
|
|
661
|
+
* @param path - API path relative to the base URL (e.g. `/movie/123`)
|
|
662
|
+
* @param options - Optional request-level overrides (headers, query, signal)
|
|
663
|
+
* @returns Parsed JSON response typed as `T`
|
|
664
|
+
*/
|
|
455
665
|
request(path, options) {
|
|
456
|
-
return this.#
|
|
666
|
+
return this.#transport.get(path, options);
|
|
457
667
|
}
|
|
458
668
|
};
|
|
669
|
+
/**
|
|
670
|
+
* Create a new {@link TMDBClient} instance.
|
|
671
|
+
*
|
|
672
|
+
* @example
|
|
673
|
+
* ```ts
|
|
674
|
+
* const tmdb = createTMDB({ accessToken: 'YOUR_TOKEN' })
|
|
675
|
+
* const { results } = await tmdb.search.movies('Inception')
|
|
676
|
+
* ```
|
|
677
|
+
*
|
|
678
|
+
* @param options - Authentication and configuration options
|
|
679
|
+
* @returns A configured TMDBClient ready to make API calls
|
|
680
|
+
*/
|
|
459
681
|
function createTMDB(options) {
|
|
460
682
|
return new TMDBClient(options);
|
|
461
683
|
}
|
|
462
684
|
//#endregion
|
|
463
|
-
|
|
685
|
+
//#region src/search-guards.ts
|
|
686
|
+
function isMovieSearchResult(result) {
|
|
687
|
+
return isObjectWithMediaType(result, "movie");
|
|
688
|
+
}
|
|
689
|
+
function isTVSearchResult(result) {
|
|
690
|
+
return isObjectWithMediaType(result, "tv");
|
|
691
|
+
}
|
|
692
|
+
function isPersonSearchResult(result) {
|
|
693
|
+
return isObjectWithMediaType(result, "person");
|
|
694
|
+
}
|
|
695
|
+
function isMovie(result) {
|
|
696
|
+
return isObjectWithMediaType(result, "movie");
|
|
697
|
+
}
|
|
698
|
+
function isTV(result) {
|
|
699
|
+
return isObjectWithMediaType(result, "tv");
|
|
700
|
+
}
|
|
701
|
+
function isPerson(result) {
|
|
702
|
+
return isObjectWithMediaType(result, "person");
|
|
703
|
+
}
|
|
704
|
+
/** Internal helper: check if a value is an object with a matching `media_type` field. */
|
|
705
|
+
function isObjectWithMediaType(value, mediaType) {
|
|
706
|
+
return typeof value === "object" && value !== null && "media_type" in value && value.media_type === mediaType;
|
|
707
|
+
}
|
|
708
|
+
//#endregion
|
|
709
|
+
//#region src/types.ts
|
|
710
|
+
/**
|
|
711
|
+
* Public set of image sizes TMDB currently documents. The SDK does not
|
|
712
|
+
* pin to a static copy of the TMDB docs — TMDB has added new sizes in
|
|
713
|
+
* the past (e.g. `h632` for profile) without notice — but exposing the
|
|
714
|
+
* canonical list lets callers:
|
|
715
|
+
*
|
|
716
|
+
* - iterate over the set to build a size picker
|
|
717
|
+
* - validate user-supplied sizes with `isKnownBackdropSize(...)` etc.
|
|
718
|
+
* - type a variable as a "known" size without giving up the
|
|
719
|
+
* `(string & {})` escape hatch for forward-compatibility
|
|
720
|
+
*
|
|
721
|
+
* If TMDB publishes a new size, the SDK will still accept it at runtime
|
|
722
|
+
* (every helper is `(string & {})` permissive), but you will need to
|
|
723
|
+
* add the literal to these constants to get autocomplete on it.
|
|
724
|
+
*/
|
|
725
|
+
const KNOWN_BACKDROP_SIZES = Object.freeze([
|
|
726
|
+
"w300",
|
|
727
|
+
"w780",
|
|
728
|
+
"w1280",
|
|
729
|
+
"original"
|
|
730
|
+
]);
|
|
731
|
+
const KNOWN_LOGO_SIZES = Object.freeze([
|
|
732
|
+
"w45",
|
|
733
|
+
"w92",
|
|
734
|
+
"w154",
|
|
735
|
+
"w185",
|
|
736
|
+
"w300",
|
|
737
|
+
"w500",
|
|
738
|
+
"original"
|
|
739
|
+
]);
|
|
740
|
+
const KNOWN_POSTER_SIZES = Object.freeze([
|
|
741
|
+
"w92",
|
|
742
|
+
"w154",
|
|
743
|
+
"w185",
|
|
744
|
+
"w342",
|
|
745
|
+
"w500",
|
|
746
|
+
"w780",
|
|
747
|
+
"original"
|
|
748
|
+
]);
|
|
749
|
+
const KNOWN_PROFILE_SIZES = Object.freeze([
|
|
750
|
+
"w45",
|
|
751
|
+
"w185",
|
|
752
|
+
"h632",
|
|
753
|
+
"original"
|
|
754
|
+
]);
|
|
755
|
+
const KNOWN_STILL_SIZES = Object.freeze([
|
|
756
|
+
"w92",
|
|
757
|
+
"w185",
|
|
758
|
+
"w300",
|
|
759
|
+
"original"
|
|
760
|
+
]);
|
|
761
|
+
/** Union of every documented image size. */
|
|
762
|
+
const KNOWN_IMAGE_SIZES = Object.freeze([
|
|
763
|
+
...KNOWN_BACKDROP_SIZES,
|
|
764
|
+
...KNOWN_LOGO_SIZES,
|
|
765
|
+
...KNOWN_POSTER_SIZES,
|
|
766
|
+
...KNOWN_PROFILE_SIZES,
|
|
767
|
+
...KNOWN_STILL_SIZES
|
|
768
|
+
]);
|
|
769
|
+
/** O(1) membership check backed by a Set. */
|
|
770
|
+
const KNOWN_BACKDROP_SET = new Set(KNOWN_BACKDROP_SIZES);
|
|
771
|
+
const KNOWN_LOGO_SET = new Set(KNOWN_LOGO_SIZES);
|
|
772
|
+
const KNOWN_POSTER_SET = new Set(KNOWN_POSTER_SIZES);
|
|
773
|
+
const KNOWN_PROFILE_SET = new Set(KNOWN_PROFILE_SIZES);
|
|
774
|
+
const KNOWN_STILL_SET = new Set(KNOWN_STILL_SIZES);
|
|
775
|
+
const KNOWN_IMAGE_SET = new Set(KNOWN_IMAGE_SIZES);
|
|
776
|
+
function isKnownBackdropSize(value) {
|
|
777
|
+
return KNOWN_BACKDROP_SET.has(value);
|
|
778
|
+
}
|
|
779
|
+
function isKnownLogoSize(value) {
|
|
780
|
+
return KNOWN_LOGO_SET.has(value);
|
|
781
|
+
}
|
|
782
|
+
function isKnownPosterSize(value) {
|
|
783
|
+
return KNOWN_POSTER_SET.has(value);
|
|
784
|
+
}
|
|
785
|
+
function isKnownProfileSize(value) {
|
|
786
|
+
return KNOWN_PROFILE_SET.has(value);
|
|
787
|
+
}
|
|
788
|
+
function isKnownStillSize(value) {
|
|
789
|
+
return KNOWN_STILL_SET.has(value);
|
|
790
|
+
}
|
|
791
|
+
/** True if `value` is in any documented size set. */
|
|
792
|
+
function isKnownImageSize(value) {
|
|
793
|
+
return KNOWN_IMAGE_SET.has(value);
|
|
794
|
+
}
|
|
795
|
+
//#endregion
|
|
796
|
+
export { KNOWN_BACKDROP_SIZES, KNOWN_IMAGE_SIZES, KNOWN_LOGO_SIZES, KNOWN_POSTER_SIZES, KNOWN_PROFILE_SIZES, KNOWN_STILL_SIZES, TMDBClient, TMDBError, TMDBRateLimitError, TMDBRequestError, TMDBResponseError, buildImageUrl, createTMDB, isKnownBackdropSize, isKnownImageSize, isKnownLogoSize, isKnownPosterSize, isKnownProfileSize, isKnownStillSize, isMovie, isMovieSearchResult, isPerson, isPersonSearchResult, isTV, isTVSearchResult };
|
|
464
797
|
|
|
465
798
|
//# sourceMappingURL=index.js.map
|