tmdb-kit 1.0.0 → 1.1.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/dist/index.js CHANGED
@@ -1,798 +1,760 @@
1
- //#region src/errors.ts
2
- /** Base class for all SDK-originated errors. */
3
- var TMDBError = class extends Error {
4
- constructor(message, options) {
5
- super(message, options);
6
- this.name = "TMDBError";
7
- }
8
- };
9
- /** Thrown before a request is sent or when fetch itself rejects. */
10
- var TMDBRequestError = class extends TMDBError {
11
- constructor(message, options) {
12
- super(message, options);
13
- this.name = "TMDBRequestError";
14
- }
15
- };
16
- /** Thrown when TMDB returns a non-2xx response. */
17
- var TMDBResponseError = class extends TMDBError {
18
- body;
19
- headers;
20
- requestId;
21
- status;
22
- statusCode;
23
- statusMessage;
24
- statusText;
25
- url;
26
- constructor(message, options) {
27
- super(message);
28
- this.name = "TMDBResponseError";
29
- this.body = options.body;
30
- this.headers = options.headers;
31
- this.requestId = options.headers.get("x-request-id");
32
- this.status = options.status;
33
- this.statusText = options.statusText;
34
- this.url = options.url;
35
- const body = isErrorResponseBody(options.body) ? options.body : void 0;
36
- this.statusCode = body?.status_code;
37
- this.statusMessage = body?.status_message;
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
- }
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
- */
1
+ // src/errors.ts
2
+ class TMDBError extends Error {
3
+ constructor(message, options) {
4
+ super(message, options);
5
+ this.name = "TMDBError";
6
+ }
7
+ }
8
+
9
+ class TMDBRequestError extends TMDBError {
10
+ constructor(message, options) {
11
+ super(message, options);
12
+ this.name = "TMDBRequestError";
13
+ }
14
+ }
15
+
16
+ class TMDBResponseError extends TMDBError {
17
+ body;
18
+ headers;
19
+ requestId;
20
+ status;
21
+ statusCode;
22
+ statusMessage;
23
+ statusText;
24
+ url;
25
+ constructor(message, options) {
26
+ super(message);
27
+ this.name = "TMDBResponseError";
28
+ this.body = options.body;
29
+ this.headers = options.headers;
30
+ this.requestId = options.headers.get("x-request-id");
31
+ this.status = options.status;
32
+ this.statusText = options.statusText;
33
+ this.url = options.url;
34
+ const body = isErrorResponseBody(options.body) ? options.body : undefined;
35
+ this.statusCode = body?.status_code;
36
+ this.statusMessage = body?.status_message;
37
+ }
38
+ get isRateLimit() {
39
+ return this.status === 429;
40
+ }
41
+ get isNotFound() {
42
+ return this.status === 404;
43
+ }
44
+ get isUnauthorized() {
45
+ return this.status === 401;
46
+ }
47
+ get isForbidden() {
48
+ return this.status === 403;
49
+ }
50
+ get isServerError() {
51
+ return this.status >= 500 && this.status < 600;
52
+ }
53
+ }
54
+
55
+ class TMDBRateLimitError extends TMDBResponseError {
56
+ retryAfter;
57
+ constructor(message, options) {
58
+ super(message, options);
59
+ this.name = "TMDBRateLimitError";
60
+ this.retryAfter = options.retryAfter;
61
+ }
62
+ }
82
63
  function createResponseError(options) {
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);
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
- */
64
+ const body = isErrorResponseBody(options.body) ? options.body : undefined;
65
+ const message = body?.status_message ?? `${options.status} ${options.statusText}`.trim();
66
+ if (options.status === 429) {
67
+ return new TMDBRateLimitError(message, {
68
+ ...options,
69
+ retryAfter: parseRetryAfter(options.headers.get("retry-after"))
70
+ });
71
+ }
72
+ return new TMDBResponseError(message, options);
73
+ }
95
74
  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. */
75
+ if (value === null || value === undefined) {
76
+ return 1;
77
+ }
78
+ const trimmed = value.trim();
79
+ if (trimmed === "") {
80
+ return 1;
81
+ }
82
+ const seconds = Number(trimmed);
83
+ if (Number.isFinite(seconds) && seconds >= 0) {
84
+ return seconds;
85
+ }
86
+ const date = Date.parse(trimmed);
87
+ if (Number.isFinite(date)) {
88
+ const deltaMs = date - Date.now();
89
+ return Math.max(1, Math.ceil(deltaMs / 1000));
90
+ }
91
+ return 1;
92
+ }
109
93
  function isErrorResponseBody(value) {
110
- return typeof value === "object" && value !== null;
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
- */
94
+ return typeof value === "object" && value !== null;
95
+ }
96
+
97
+ // src/query.ts
98
+ var DEFAULT_API_BASE_URL = "https://api.themoviedb.org/3";
99
+ var DEFAULT_IMAGE_BASE_URL = "https://image.tmdb.org/t/p";
119
100
  function appendQuery(url, query) {
120
- for (const [key, value] of Object.entries(query)) {
121
- if (value === void 0 || value === null) continue;
122
- if (Array.isArray(value)) {
123
- url.searchParams.set(key, value.map(String).join(","));
124
- continue;
125
- }
126
- url.searchParams.set(key, String(value));
127
- }
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
- */
101
+ for (const [key, value] of Object.entries(query)) {
102
+ if (value === undefined || value === null) {
103
+ continue;
104
+ }
105
+ if (Array.isArray(value)) {
106
+ url.searchParams.set(key, value.map(String).join(","));
107
+ continue;
108
+ }
109
+ url.searchParams.set(key, String(value));
110
+ }
111
+ }
135
112
  function withLanguage(defaults, query) {
136
- const language = typeof query.language === "string" ? query.language : defaults.language;
137
- return {
138
- ...query,
139
- language
140
- };
141
- }
142
- /**
143
- * Merge language and region defaults for list endpoints.
144
- *
145
- * Combines {@link withLanguage} with region fallback from client defaults.
146
- */
113
+ const language = typeof query.language === "string" ? query.language : defaults.language;
114
+ return {
115
+ ...query,
116
+ language
117
+ };
118
+ }
147
119
  function withListDefaults(defaults, query) {
148
- const region = typeof query.region === "string" ? query.region : defaults.region;
149
- return {
150
- ...withLanguage(defaults, query),
151
- region
152
- };
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
- */
120
+ const region = typeof query.region === "string" ? query.region : defaults.region;
121
+ return {
122
+ ...withLanguage(defaults, query),
123
+ region
124
+ };
125
+ }
160
126
  function toCommaList(value) {
161
- if (value === void 0) return;
162
- return typeof value === "string" ? value : value.join(",");
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
- */
127
+ if (value === undefined) {
128
+ return;
129
+ }
130
+ return typeof value === "string" ? value : value.join(",");
131
+ }
169
132
  function toId(value, name) {
170
- if (!Number.isInteger(value) || value <= 0) throw new TMDBRequestError(`${name} must be a positive integer`);
171
- return String(value);
172
- }
173
- /**
174
- * Validate and trim a search query string.
175
- *
176
- * @throws {TMDBRequestError} If the query is empty after trimming.
177
- */
133
+ if (!Number.isInteger(value) || value <= 0) {
134
+ throw new TMDBRequestError(`${name} must be a positive integer`);
135
+ }
136
+ return String(value);
137
+ }
178
138
  function toSearchQuery(value) {
179
- const query = value.trim();
180
- if (query.length === 0) throw new TMDBRequestError("search query must not be empty");
181
- return query;
182
- }
183
- /**
184
- * Validate a trending time window value.
185
- *
186
- * @throws {TMDBRequestError} If `value` is not `"day"` or `"week"`.
187
- */
139
+ const query = value.trim();
140
+ if (query.length === 0) {
141
+ throw new TMDBRequestError("search query must not be empty");
142
+ }
143
+ return query;
144
+ }
188
145
  function toTimeWindow(value) {
189
- if (value !== "day" && value !== "week") throw new TMDBRequestError("timeWindow must be either \"day\" or \"week\"");
190
- return value;
146
+ if (value !== "day" && value !== "week") {
147
+ throw new TMDBRequestError('timeWindow must be either "day" or "week"');
148
+ }
149
+ return value;
191
150
  }
192
- /**
193
- * Build a full TMDB image URL from the path returned by API payloads.
194
- * Returns null for nullish image paths so UI code can branch naturally.
195
- */
196
151
  function buildImageUrl(path, size = "original", options = {}) {
197
- if (path === void 0 || path === null || path.trim() === "") return null;
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;
152
+ if (path === undefined || path === null || path.trim() === "") {
153
+ return null;
154
+ }
155
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_IMAGE_BASE_URL);
156
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
157
+ const url = `${baseUrl}/${size}${normalizedPath}`;
158
+ return options.transform ? options.transform(url) : url;
200
159
  }
201
- /**
202
- * Strip trailing slashes from a base URL to ensure consistent path joining.
203
- */
204
160
  function normalizeBaseUrl(baseUrl) {
205
- return baseUrl.replace(/\/+$/, "");
206
- }
207
- //#endregion
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
- */
216
- var TMDBHttpClient = class {
217
- defaults;
218
- imageTransform;
219
- #apiKey;
220
- #accessToken;
221
- #baseUrl;
222
- #fetch;
223
- #headers;
224
- constructor(options) {
225
- const accessToken = normalizeSecret("accessToken" in options ? options.accessToken : void 0);
226
- const apiKey = normalizeSecret("apiKey" in options ? options.apiKey : void 0);
227
- if (Boolean(accessToken) === Boolean(apiKey)) throw new TMDBRequestError("Provide exactly one of accessToken or apiKey");
228
- this.#accessToken = accessToken;
229
- this.#apiKey = apiKey;
230
- this.#baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://api.themoviedb.org/3");
231
- this.#fetch = options.fetch;
232
- this.#headers = options.headers;
233
- this.defaults = {
234
- imageBaseUrl: normalizeBaseUrl(options.imageBaseUrl ?? "https://image.tmdb.org/t/p"),
235
- language: options.defaultLanguage,
236
- region: options.defaultRegion
237
- };
238
- this.imageTransform = options.images?.transform;
239
- }
240
- async get(path, options = {}) {
241
- const url = this.#createUrl(path, options.query ?? {});
242
- const headers = this.#createHeaders(options.headers);
243
- const fetchImpl = this.#resolveFetch();
244
- let response;
245
- try {
246
- response = await fetchImpl(url, {
247
- headers,
248
- method: "GET",
249
- signal: options.signal
250
- });
251
- } catch (error) {
252
- throw new TMDBRequestError(`TMDB request failed: ${String(error)}`, { cause: error });
253
- }
254
- const body = await readJson(response);
255
- if (!response.ok) throw createResponseError({
256
- body,
257
- headers: response.headers,
258
- status: response.status,
259
- statusText: response.statusText,
260
- url
261
- });
262
- return body;
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
- }
270
- #createHeaders(headersInit) {
271
- const headers = new Headers(this.#headers);
272
- const requestHeaders = new Headers(headersInit);
273
- headers.set("Accept", "application/json");
274
- for (const [key, value] of requestHeaders) headers.set(key, value);
275
- if (this.#accessToken !== void 0) headers.set("Authorization", `Bearer ${this.#accessToken}`);
276
- return headers;
277
- }
278
- #createUrl(path, query) {
279
- const relativePath = path.replace(/^\/+/, "");
280
- const url = new URL(relativePath, `${this.#baseUrl}/`);
281
- appendQuery(url, {
282
- ...query,
283
- api_key: this.#apiKey
284
- });
285
- return url.toString();
286
- }
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
- */
161
+ return baseUrl.replace(/\/+$/, "");
162
+ }
163
+
164
+ // src/http.ts
165
+ class TMDBHttpClient {
166
+ defaults;
167
+ imageTransform;
168
+ #apiKey;
169
+ #accessToken;
170
+ #baseUrl;
171
+ #fetch;
172
+ #headers;
173
+ constructor(options) {
174
+ const accessToken = normalizeSecret("accessToken" in options ? options.accessToken : undefined);
175
+ const apiKey = normalizeSecret("apiKey" in options ? options.apiKey : undefined);
176
+ if (Boolean(accessToken) === Boolean(apiKey)) {
177
+ throw new TMDBRequestError("Provide exactly one of accessToken or apiKey");
178
+ }
179
+ this.#accessToken = accessToken;
180
+ this.#apiKey = apiKey;
181
+ this.#baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_API_BASE_URL);
182
+ this.#fetch = options.fetch;
183
+ this.#headers = options.headers;
184
+ this.defaults = {
185
+ imageBaseUrl: normalizeBaseUrl(options.imageBaseUrl ?? DEFAULT_IMAGE_BASE_URL),
186
+ language: options.defaultLanguage,
187
+ region: options.defaultRegion
188
+ };
189
+ this.imageTransform = options.images?.transform;
190
+ }
191
+ async get(path, options = {}) {
192
+ const url = this.#createUrl(path, options.query ?? {});
193
+ const headers = this.#createHeaders(options.headers);
194
+ const fetchImpl = this.#resolveFetch();
195
+ let response;
196
+ try {
197
+ response = await fetchImpl(url, {
198
+ headers,
199
+ method: "GET",
200
+ signal: options.signal
201
+ });
202
+ } catch (error) {
203
+ throw new TMDBRequestError(`TMDB request failed: ${String(error)}`, { cause: error });
204
+ }
205
+ const body = await readJson(response);
206
+ if (!response.ok) {
207
+ throw createResponseError({
208
+ body,
209
+ headers: response.headers,
210
+ status: response.status,
211
+ statusText: response.statusText,
212
+ url
213
+ });
214
+ }
215
+ return body;
216
+ }
217
+ #resolveFetch() {
218
+ if (this.#fetch !== undefined) {
219
+ return this.#fetch;
220
+ }
221
+ const globalFetch = globalThis.fetch;
222
+ if (typeof globalFetch !== "function") {
223
+ throw new TMDBRequestError("No fetch implementation found. Pass options.fetch in this runtime.");
224
+ }
225
+ return globalFetch.bind(globalThis);
226
+ }
227
+ #createHeaders(headersInit) {
228
+ const headers = new Headers(this.#headers);
229
+ const requestHeaders = new Headers(headersInit);
230
+ headers.set("Accept", "application/json");
231
+ for (const [key, value] of requestHeaders) {
232
+ headers.set(key, value);
233
+ }
234
+ if (this.#accessToken !== undefined) {
235
+ headers.set("Authorization", `Bearer ${this.#accessToken}`);
236
+ }
237
+ return headers;
238
+ }
239
+ #createUrl(path, query) {
240
+ const relativePath = path.replace(/^\/+/, "");
241
+ const url = new URL(relativePath, `${this.#baseUrl}/`);
242
+ appendQuery(url, {
243
+ ...query,
244
+ api_key: this.#apiKey
245
+ });
246
+ return url.toString();
247
+ }
248
+ }
295
249
  async function readJson(response) {
296
- const text = await response.text();
297
- if (text.length === 0) return;
298
- try {
299
- return JSON.parse(text);
300
- } catch {
301
- return text;
302
- }
303
- }
304
- /**
305
- * Normalize a secret value by trimming whitespace and treating empty
306
- * strings as undefined (not provided).
307
- */
250
+ const text = await response.text();
251
+ if (text.length === 0) {
252
+ return;
253
+ }
254
+ try {
255
+ return JSON.parse(text);
256
+ } catch {
257
+ return text;
258
+ }
259
+ }
308
260
  function normalizeSecret(value) {
309
- const secret = value?.trim();
310
- return secret === "" ? void 0 : secret;
311
- }
312
- //#endregion
313
- //#region src/resources/configuration.ts
314
- /**
315
- * Access TMDB configuration data (image sizes, countries, languages, etc.).
316
- *
317
- * Obtained via `client.configuration`.
318
- */
319
- var ConfigurationResource = class {
320
- #transport;
321
- constructor(transport) {
322
- this.#transport = transport;
323
- }
324
- details() {
325
- return this.#transport.get("/configuration");
326
- }
327
- countries() {
328
- return this.#transport.get("/configuration/countries");
329
- }
330
- jobs() {
331
- return this.#transport.get("/configuration/jobs");
332
- }
333
- languages() {
334
- return this.#transport.get("/configuration/languages");
335
- }
336
- primaryTranslations() {
337
- return this.#transport.get("/configuration/primary_translations");
338
- }
339
- timezones() {
340
- return this.#transport.get("/configuration/timezones");
341
- }
342
- };
343
- //#endregion
344
- //#region src/resources/genres.ts
345
- /**
346
- * Access TMDB genre lists for movies and TV shows.
347
- *
348
- * Obtained via `client.genres`.
349
- */
350
- var GenresResource = class {
351
- #transport;
352
- constructor(transport) {
353
- this.#transport = transport;
354
- }
355
- movies(options = {}) {
356
- return this.#transport.get("/genre/movie/list", { query: withLanguage(this.#transport.defaults, { language: options.language }) });
357
- }
358
- tv(options = {}) {
359
- return this.#transport.get("/genre/tv/list", { query: withLanguage(this.#transport.defaults, { language: options.language }) });
360
- }
361
- };
362
- //#endregion
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
- */
370
- var ImagesHelper = class {
371
- #transport;
372
- #transform;
373
- constructor(transport, transform) {
374
- this.#transport = transport;
375
- this.#transform = transform;
376
- }
377
- url(path, size = "original", options = {}) {
378
- return buildImageUrl(path, size, {
379
- baseUrl: this.#transport.defaults.imageBaseUrl,
380
- transform: options.transform ?? this.#transform
381
- });
382
- }
383
- };
384
- //#endregion
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
- */
391
- var MoviesResource = class {
392
- #transport;
393
- constructor(transport) {
394
- this.#transport = transport;
395
- }
396
- popular(options = {}) {
397
- return this.#transport.get("/movie/popular", { query: movieListQuery(this.#transport, options) });
398
- }
399
- topRated(options = {}) {
400
- return this.#transport.get("/movie/top_rated", { query: movieListQuery(this.#transport, options) });
401
- }
402
- nowPlaying(options = {}) {
403
- return this.#transport.get("/movie/now_playing", { query: movieListQuery(this.#transport, options) });
404
- }
405
- upcoming(options = {}) {
406
- return this.#transport.get("/movie/upcoming", { query: movieListQuery(this.#transport, options) });
407
- }
408
- details(movieId, options = {}) {
409
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}`, { query: withLanguage(this.#transport.defaults, {
410
- append_to_response: toCommaList(options.appendToResponse),
411
- language: options.language
412
- }) });
413
- }
414
- credits(movieId, options = {}) {
415
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/credits`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
416
- }
417
- images(movieId, options = {}) {
418
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/images`, { query: withLanguage(this.#transport.defaults, {
419
- include_image_language: toCommaList(options.includeImageLanguage),
420
- language: options.language
421
- }) });
422
- }
423
- recommendations(movieId, options = {}) {
424
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/recommendations`, { query: movieListQuery(this.#transport, options) });
425
- }
426
- similar(movieId, options = {}) {
427
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/similar`, { query: movieListQuery(this.#transport, options) });
428
- }
429
- videos(movieId, options = {}) {
430
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/videos`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
431
- }
432
- };
433
- /** Build query parameters for movie list endpoints. */
261
+ const secret = value?.trim();
262
+ return secret === "" ? undefined : secret;
263
+ }
264
+
265
+ // src/resources/configuration.ts
266
+ class ConfigurationResource {
267
+ #transport;
268
+ constructor(transport) {
269
+ this.#transport = transport;
270
+ }
271
+ details() {
272
+ return this.#transport.get("/configuration");
273
+ }
274
+ countries() {
275
+ return this.#transport.get("/configuration/countries");
276
+ }
277
+ jobs() {
278
+ return this.#transport.get("/configuration/jobs");
279
+ }
280
+ languages() {
281
+ return this.#transport.get("/configuration/languages");
282
+ }
283
+ primaryTranslations() {
284
+ return this.#transport.get("/configuration/primary_translations");
285
+ }
286
+ timezones() {
287
+ return this.#transport.get("/configuration/timezones");
288
+ }
289
+ }
290
+
291
+ // src/resources/genres.ts
292
+ class GenresResource {
293
+ #transport;
294
+ constructor(transport) {
295
+ this.#transport = transport;
296
+ }
297
+ movies(options = {}) {
298
+ return this.#transport.get("/genre/movie/list", {
299
+ query: withLanguage(this.#transport.defaults, {
300
+ language: options.language
301
+ })
302
+ });
303
+ }
304
+ tv(options = {}) {
305
+ return this.#transport.get("/genre/tv/list", {
306
+ query: withLanguage(this.#transport.defaults, {
307
+ language: options.language
308
+ })
309
+ });
310
+ }
311
+ }
312
+
313
+ // src/resources/images.ts
314
+ class ImagesHelper {
315
+ #transport;
316
+ #transform;
317
+ constructor(transport, transform) {
318
+ this.#transport = transport;
319
+ this.#transform = transform;
320
+ }
321
+ url(path, size = "original", options = {}) {
322
+ return buildImageUrl(path, size, {
323
+ baseUrl: this.#transport.defaults.imageBaseUrl,
324
+ transform: options.transform ?? this.#transform
325
+ });
326
+ }
327
+ }
328
+
329
+ // src/resources/movies.ts
330
+ class MoviesResource {
331
+ #transport;
332
+ constructor(transport) {
333
+ this.#transport = transport;
334
+ }
335
+ popular(options = {}) {
336
+ return this.#transport.get("/movie/popular", {
337
+ query: movieListQuery(this.#transport, options)
338
+ });
339
+ }
340
+ topRated(options = {}) {
341
+ return this.#transport.get("/movie/top_rated", {
342
+ query: movieListQuery(this.#transport, options)
343
+ });
344
+ }
345
+ nowPlaying(options = {}) {
346
+ return this.#transport.get("/movie/now_playing", {
347
+ query: movieListQuery(this.#transport, options)
348
+ });
349
+ }
350
+ upcoming(options = {}) {
351
+ return this.#transport.get("/movie/upcoming", {
352
+ query: movieListQuery(this.#transport, options)
353
+ });
354
+ }
355
+ details(movieId, options = {}) {
356
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}`, {
357
+ query: withLanguage(this.#transport.defaults, {
358
+ append_to_response: toCommaList(options.appendToResponse),
359
+ language: options.language
360
+ })
361
+ });
362
+ }
363
+ credits(movieId, options = {}) {
364
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/credits`, {
365
+ query: withLanguage(this.#transport.defaults, {
366
+ language: options.language
367
+ })
368
+ });
369
+ }
370
+ images(movieId, options = {}) {
371
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/images`, {
372
+ query: withLanguage(this.#transport.defaults, {
373
+ include_image_language: toCommaList(options.includeImageLanguage),
374
+ language: options.language
375
+ })
376
+ });
377
+ }
378
+ recommendations(movieId, options = {}) {
379
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/recommendations`, {
380
+ query: movieListQuery(this.#transport, options)
381
+ });
382
+ }
383
+ similar(movieId, options = {}) {
384
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/similar`, {
385
+ query: movieListQuery(this.#transport, options)
386
+ });
387
+ }
388
+ videos(movieId, options = {}) {
389
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/videos`, {
390
+ query: withLanguage(this.#transport.defaults, {
391
+ language: options.language
392
+ })
393
+ });
394
+ }
395
+ }
434
396
  function movieListQuery(transport, options) {
435
- return withListDefaults(transport.defaults, {
436
- language: options.language,
437
- page: options.page,
438
- region: options.region
439
- });
440
- }
441
- //#endregion
442
- //#region src/resources/people.ts
443
- /**
444
- * Access TMDB person (actor, director, etc.) endpoints.
445
- *
446
- * Obtained via `client.people`.
447
- */
448
- var PeopleResource = class {
449
- #transport;
450
- constructor(transport) {
451
- this.#transport = transport;
452
- }
453
- popular(options = {}) {
454
- return this.#transport.get("/person/popular", { query: peopleListQuery(this.#transport, options) });
455
- }
456
- details(personId, options = {}) {
457
- return this.#transport.get(`/person/${toId(personId, "personId")}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
458
- }
459
- };
460
- /** Build query parameters for person list endpoints. */
397
+ return withListDefaults(transport.defaults, {
398
+ language: options.language,
399
+ page: options.page,
400
+ region: options.region
401
+ });
402
+ }
403
+
404
+ // src/resources/people.ts
405
+ class PeopleResource {
406
+ #transport;
407
+ constructor(transport) {
408
+ this.#transport = transport;
409
+ }
410
+ popular(options = {}) {
411
+ return this.#transport.get("/person/popular", {
412
+ query: peopleListQuery(this.#transport, options)
413
+ });
414
+ }
415
+ details(personId, options = {}) {
416
+ return this.#transport.get(`/person/${toId(personId, "personId")}`, {
417
+ query: withLanguage(this.#transport.defaults, {
418
+ language: options.language
419
+ })
420
+ });
421
+ }
422
+ combinedCredits(personId, options = {}) {
423
+ return this.#transport.get(`/person/${toId(personId, "personId")}/combined_credits`, {
424
+ query: withLanguage(this.#transport.defaults, {
425
+ language: options.language
426
+ })
427
+ });
428
+ }
429
+ }
461
430
  function peopleListQuery(transport, options) {
462
- return withLanguage(transport.defaults, {
463
- language: options.language,
464
- page: options.page
465
- });
466
- }
467
- //#endregion
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
- */
474
- var SearchResource = class {
475
- #transport;
476
- constructor(transport) {
477
- this.#transport = transport;
478
- }
479
- movies(query, options = {}) {
480
- return this.#transport.get("/search/movie", { query: movieSearchQuery(this.#transport, query, options) });
481
- }
482
- tv(query, options = {}) {
483
- return this.#transport.get("/search/tv", { query: tvSearchQuery(this.#transport, query, options) });
484
- }
485
- people(query, options = {}) {
486
- return this.#transport.get("/search/person", { query: commonSearchQuery(this.#transport, query, options) });
487
- }
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
- };
497
- }
498
- };
499
- /** Build query parameters for movie search. */
431
+ return withLanguage(transport.defaults, {
432
+ language: options.language,
433
+ page: options.page
434
+ });
435
+ }
436
+
437
+ // src/resources/search.ts
438
+ class SearchResource {
439
+ #transport;
440
+ constructor(transport) {
441
+ this.#transport = transport;
442
+ }
443
+ movies(query, options = {}) {
444
+ return this.#transport.get("/search/movie", {
445
+ query: movieSearchQuery(this.#transport, query, options)
446
+ });
447
+ }
448
+ tv(query, options = {}) {
449
+ return this.#transport.get("/search/tv", {
450
+ query: tvSearchQuery(this.#transport, query, options)
451
+ });
452
+ }
453
+ people(query, options = {}) {
454
+ return this.#transport.get("/search/person", {
455
+ query: commonSearchQuery(this.#transport, query, options)
456
+ });
457
+ }
458
+ async multi(query, options = {}) {
459
+ const response = await this.#transport.get("/search/multi", {
460
+ query: commonSearchQuery(this.#transport, query, options)
461
+ });
462
+ const excluded = options.exclude;
463
+ if (excluded === undefined || excluded.length === 0) {
464
+ return response;
465
+ }
466
+ const excludedSet = new Set(excluded);
467
+ return {
468
+ ...response,
469
+ results: response.results.filter((result) => !excludedSet.has(result.media_type))
470
+ };
471
+ }
472
+ }
500
473
  function movieSearchQuery(transport, query, options) {
501
- return withListDefaults(transport.defaults, {
502
- include_adult: options.includeAdult,
503
- language: options.language,
504
- page: options.page,
505
- primary_release_year: options.primaryReleaseYear,
506
- query: toSearchQuery(query),
507
- region: options.region,
508
- year: options.year
509
- });
510
- }
511
- /** Build query parameters for TV search. */
474
+ return withListDefaults(transport.defaults, {
475
+ include_adult: options.includeAdult,
476
+ language: options.language,
477
+ page: options.page,
478
+ primary_release_year: options.primaryReleaseYear,
479
+ query: toSearchQuery(query),
480
+ region: options.region,
481
+ year: options.year
482
+ });
483
+ }
512
484
  function tvSearchQuery(transport, query, options) {
513
- return withLanguage(transport.defaults, {
514
- first_air_date_year: options.firstAirDateYear,
515
- include_adult: options.includeAdult,
516
- language: options.language,
517
- page: options.page,
518
- query: toSearchQuery(query),
519
- year: options.year
520
- });
521
- }
522
- /** Build query parameters for person and multi-search. */
485
+ return withLanguage(transport.defaults, {
486
+ first_air_date_year: options.firstAirDateYear,
487
+ include_adult: options.includeAdult,
488
+ language: options.language,
489
+ page: options.page,
490
+ query: toSearchQuery(query),
491
+ year: options.year
492
+ });
493
+ }
523
494
  function commonSearchQuery(transport, query, options) {
524
- return withLanguage(transport.defaults, {
525
- include_adult: options.includeAdult,
526
- language: options.language,
527
- page: options.page,
528
- query: toSearchQuery(query)
529
- });
530
- }
531
- //#endregion
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
- */
538
- var TrendingResource = class {
539
- #transport;
540
- constructor(transport) {
541
- this.#transport = transport;
542
- }
543
- all(timeWindow = "day", options = {}) {
544
- return this.#transport.get(`/trending/all/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
545
- }
546
- movies(timeWindow = "day", options = {}) {
547
- return this.#transport.get(`/trending/movie/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
548
- }
549
- tv(timeWindow = "day", options = {}) {
550
- return this.#transport.get(`/trending/tv/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
551
- }
552
- people(timeWindow = "day", options = {}) {
553
- return this.#transport.get(`/trending/person/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
554
- }
555
- };
556
- //#endregion
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
- */
563
- var TVResource = class {
564
- #transport;
565
- constructor(transport) {
566
- this.#transport = transport;
567
- }
568
- popular(options = {}) {
569
- return this.#transport.get("/tv/popular", { query: tvListQuery(this.#transport, options) });
570
- }
571
- topRated(options = {}) {
572
- return this.#transport.get("/tv/top_rated", { query: tvListQuery(this.#transport, options) });
573
- }
574
- airingToday(options = {}) {
575
- return this.#transport.get("/tv/airing_today", { query: tvListQuery(this.#transport, options) });
576
- }
577
- onTheAir(options = {}) {
578
- return this.#transport.get("/tv/on_the_air", { query: tvListQuery(this.#transport, options) });
579
- }
580
- details(seriesId, options = {}) {
581
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}`, { query: withLanguage(this.#transport.defaults, {
582
- append_to_response: toCommaList(options.appendToResponse),
583
- language: options.language
584
- }) });
585
- }
586
- credits(seriesId, options = {}) {
587
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/credits`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
588
- }
589
- images(seriesId, options = {}) {
590
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/images`, { query: withLanguage(this.#transport.defaults, {
591
- include_image_language: toCommaList(options.includeImageLanguage),
592
- language: options.language
593
- }) });
594
- }
595
- recommendations(seriesId, options = {}) {
596
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/recommendations`, { query: tvListQuery(this.#transport, options) });
597
- }
598
- similar(seriesId, options = {}) {
599
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/similar`, { query: tvListQuery(this.#transport, options) });
600
- }
601
- videos(seriesId, options = {}) {
602
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/videos`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
603
- }
604
- seasonDetails(seriesId, seasonNumber, options = {}) {
605
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toId(seasonNumber, "seasonNumber")}`, { query: withLanguage(this.#transport.defaults, {
606
- append_to_response: toCommaList(options.appendToResponse),
607
- language: options.language
608
- }) });
609
- }
610
- };
611
- /** Build query parameters for TV list endpoints. */
495
+ return withLanguage(transport.defaults, {
496
+ include_adult: options.includeAdult,
497
+ language: options.language,
498
+ page: options.page,
499
+ query: toSearchQuery(query)
500
+ });
501
+ }
502
+
503
+ // src/resources/trending.ts
504
+ class TrendingResource {
505
+ #transport;
506
+ constructor(transport) {
507
+ this.#transport = transport;
508
+ }
509
+ all(timeWindow = "day", options = {}) {
510
+ return this.#transport.get(`/trending/all/${toTimeWindow(timeWindow)}`, {
511
+ query: withLanguage(this.#transport.defaults, {
512
+ language: options.language,
513
+ page: options.page
514
+ })
515
+ });
516
+ }
517
+ movies(timeWindow = "day", options = {}) {
518
+ return this.#transport.get(`/trending/movie/${toTimeWindow(timeWindow)}`, {
519
+ query: withLanguage(this.#transport.defaults, {
520
+ language: options.language,
521
+ page: options.page
522
+ })
523
+ });
524
+ }
525
+ tv(timeWindow = "day", options = {}) {
526
+ return this.#transport.get(`/trending/tv/${toTimeWindow(timeWindow)}`, {
527
+ query: withLanguage(this.#transport.defaults, {
528
+ language: options.language,
529
+ page: options.page
530
+ })
531
+ });
532
+ }
533
+ people(timeWindow = "day", options = {}) {
534
+ return this.#transport.get(`/trending/person/${toTimeWindow(timeWindow)}`, {
535
+ query: withLanguage(this.#transport.defaults, {
536
+ language: options.language,
537
+ page: options.page
538
+ })
539
+ });
540
+ }
541
+ }
542
+
543
+ // src/resources/tv.ts
544
+ class TVResource {
545
+ #transport;
546
+ constructor(transport) {
547
+ this.#transport = transport;
548
+ }
549
+ popular(options = {}) {
550
+ return this.#transport.get("/tv/popular", {
551
+ query: tvListQuery(this.#transport, options)
552
+ });
553
+ }
554
+ topRated(options = {}) {
555
+ return this.#transport.get("/tv/top_rated", {
556
+ query: tvListQuery(this.#transport, options)
557
+ });
558
+ }
559
+ airingToday(options = {}) {
560
+ return this.#transport.get("/tv/airing_today", {
561
+ query: tvListQuery(this.#transport, options)
562
+ });
563
+ }
564
+ onTheAir(options = {}) {
565
+ return this.#transport.get("/tv/on_the_air", {
566
+ query: tvListQuery(this.#transport, options)
567
+ });
568
+ }
569
+ details(seriesId, options = {}) {
570
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}`, {
571
+ query: withLanguage(this.#transport.defaults, {
572
+ append_to_response: toCommaList(options.appendToResponse),
573
+ language: options.language
574
+ })
575
+ });
576
+ }
577
+ credits(seriesId, options = {}) {
578
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/credits`, {
579
+ query: withLanguage(this.#transport.defaults, {
580
+ language: options.language
581
+ })
582
+ });
583
+ }
584
+ images(seriesId, options = {}) {
585
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/images`, {
586
+ query: withLanguage(this.#transport.defaults, {
587
+ include_image_language: toCommaList(options.includeImageLanguage),
588
+ language: options.language
589
+ })
590
+ });
591
+ }
592
+ recommendations(seriesId, options = {}) {
593
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/recommendations`, {
594
+ query: tvListQuery(this.#transport, options)
595
+ });
596
+ }
597
+ similar(seriesId, options = {}) {
598
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/similar`, {
599
+ query: tvListQuery(this.#transport, options)
600
+ });
601
+ }
602
+ videos(seriesId, options = {}) {
603
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/videos`, {
604
+ query: withLanguage(this.#transport.defaults, {
605
+ language: options.language
606
+ })
607
+ });
608
+ }
609
+ seasonDetails(seriesId, seasonNumber, options = {}) {
610
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toId(seasonNumber, "seasonNumber")}`, {
611
+ query: withLanguage(this.#transport.defaults, {
612
+ append_to_response: toCommaList(options.appendToResponse),
613
+ language: options.language
614
+ })
615
+ });
616
+ }
617
+ }
612
618
  function tvListQuery(transport, options) {
613
- return withLanguage(transport.defaults, {
614
- language: options.language,
615
- page: options.page
616
- });
617
- }
618
- //#endregion
619
- //#region src/client.ts
620
- /**
621
- * Main SDK entry point.
622
- *
623
- * Resource properties are intentionally small and explicit. The SDK focuses on
624
- * common TMDB workflows first, while request<T>() keeps uncommon endpoints easy
625
- * to call without waiting for a generated surface area.
626
- */
627
- var TMDBClient = class {
628
- configuration;
629
- genres;
630
- images;
631
- movies;
632
- people;
633
- search;
634
- trending;
635
- tv;
636
- #transport;
637
- constructor(options) {
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
- */
665
- request(path, options) {
666
- return this.#transport.get(path, options);
667
- }
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
- */
619
+ return withLanguage(transport.defaults, {
620
+ language: options.language,
621
+ page: options.page
622
+ });
623
+ }
624
+
625
+ // src/client.ts
626
+ class TMDBClient {
627
+ configuration;
628
+ genres;
629
+ images;
630
+ movies;
631
+ people;
632
+ search;
633
+ trending;
634
+ tv;
635
+ #transport;
636
+ constructor(options) {
637
+ const { transport, images, ...httpOptions } = options;
638
+ const fallbackTransform = images?.transform;
639
+ const builtInClient = transport === undefined ? new TMDBHttpClient({ ...httpOptions, images }) : undefined;
640
+ this.#transport = builtInClient ?? transport;
641
+ this.configuration = new ConfigurationResource(this.#transport);
642
+ this.genres = new GenresResource(this.#transport);
643
+ this.images = new ImagesHelper(this.#transport, builtInClient ? builtInClient.imageTransform : fallbackTransform);
644
+ this.movies = new MoviesResource(this.#transport);
645
+ this.people = new PeopleResource(this.#transport);
646
+ this.search = new SearchResource(this.#transport);
647
+ this.trending = new TrendingResource(this.#transport);
648
+ this.tv = new TVResource(this.#transport);
649
+ }
650
+ request(path, options) {
651
+ return this.#transport.get(path, options);
652
+ }
653
+ }
681
654
  function createTMDB(options) {
682
- return new TMDBClient(options);
655
+ return new TMDBClient(options);
683
656
  }
684
- //#endregion
685
- //#region src/search-guards.ts
657
+ // src/search-guards.ts
686
658
  function isMovieSearchResult(result) {
687
- return isObjectWithMediaType(result, "movie");
659
+ return isObjectWithMediaType(result, "movie");
688
660
  }
689
661
  function isTVSearchResult(result) {
690
- return isObjectWithMediaType(result, "tv");
662
+ return isObjectWithMediaType(result, "tv");
691
663
  }
692
664
  function isPersonSearchResult(result) {
693
- return isObjectWithMediaType(result, "person");
665
+ return isObjectWithMediaType(result, "person");
694
666
  }
695
667
  function isMovie(result) {
696
- return isObjectWithMediaType(result, "movie");
668
+ return isObjectWithMediaType(result, "movie");
697
669
  }
698
670
  function isTV(result) {
699
- return isObjectWithMediaType(result, "tv");
671
+ return isObjectWithMediaType(result, "tv");
700
672
  }
701
673
  function isPerson(result) {
702
- return isObjectWithMediaType(result, "person");
674
+ return isObjectWithMediaType(result, "person");
703
675
  }
704
- /** Internal helper: check if a value is an object with a matching `media_type` field. */
705
676
  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"
677
+ return typeof value === "object" && value !== null && "media_type" in value && value.media_type === mediaType;
678
+ }
679
+ // src/types.ts
680
+ var KNOWN_BACKDROP_SIZES = Object.freeze([
681
+ "w300",
682
+ "w780",
683
+ "w1280",
684
+ "original"
730
685
  ]);
731
- const KNOWN_LOGO_SIZES = Object.freeze([
732
- "w45",
733
- "w92",
734
- "w154",
735
- "w185",
736
- "w300",
737
- "w500",
738
- "original"
686
+ var KNOWN_LOGO_SIZES = Object.freeze(["w45", "w92", "w154", "w185", "w300", "w500", "original"]);
687
+ var KNOWN_POSTER_SIZES = Object.freeze(["w92", "w154", "w185", "w342", "w500", "w780", "original"]);
688
+ var KNOWN_PROFILE_SIZES = Object.freeze([
689
+ "w45",
690
+ "w185",
691
+ "h632",
692
+ "original"
739
693
  ]);
740
- const KNOWN_POSTER_SIZES = Object.freeze([
741
- "w92",
742
- "w154",
743
- "w185",
744
- "w342",
745
- "w500",
746
- "w780",
747
- "original"
694
+ var KNOWN_STILL_SIZES = Object.freeze([
695
+ "w92",
696
+ "w185",
697
+ "w300",
698
+ "original"
748
699
  ]);
749
- const KNOWN_PROFILE_SIZES = Object.freeze([
750
- "w45",
751
- "w185",
752
- "h632",
753
- "original"
700
+ var KNOWN_IMAGE_SIZES = Object.freeze([
701
+ ...KNOWN_BACKDROP_SIZES,
702
+ ...KNOWN_LOGO_SIZES,
703
+ ...KNOWN_POSTER_SIZES,
704
+ ...KNOWN_PROFILE_SIZES,
705
+ ...KNOWN_STILL_SIZES
754
706
  ]);
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);
707
+ var KNOWN_BACKDROP_SET = new Set(KNOWN_BACKDROP_SIZES);
708
+ var KNOWN_LOGO_SET = new Set(KNOWN_LOGO_SIZES);
709
+ var KNOWN_POSTER_SET = new Set(KNOWN_POSTER_SIZES);
710
+ var KNOWN_PROFILE_SET = new Set(KNOWN_PROFILE_SIZES);
711
+ var KNOWN_STILL_SET = new Set(KNOWN_STILL_SIZES);
712
+ var KNOWN_IMAGE_SET = new Set(KNOWN_IMAGE_SIZES);
776
713
  function isKnownBackdropSize(value) {
777
- return KNOWN_BACKDROP_SET.has(value);
714
+ return KNOWN_BACKDROP_SET.has(value);
778
715
  }
779
716
  function isKnownLogoSize(value) {
780
- return KNOWN_LOGO_SET.has(value);
717
+ return KNOWN_LOGO_SET.has(value);
781
718
  }
782
719
  function isKnownPosterSize(value) {
783
- return KNOWN_POSTER_SET.has(value);
720
+ return KNOWN_POSTER_SET.has(value);
784
721
  }
785
722
  function isKnownProfileSize(value) {
786
- return KNOWN_PROFILE_SET.has(value);
723
+ return KNOWN_PROFILE_SET.has(value);
787
724
  }
788
725
  function isKnownStillSize(value) {
789
- return KNOWN_STILL_SET.has(value);
726
+ return KNOWN_STILL_SET.has(value);
790
727
  }
791
- /** True if `value` is in any documented size set. */
792
728
  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 };
729
+ return KNOWN_IMAGE_SET.has(value);
730
+ }
731
+ export {
732
+ KNOWN_BACKDROP_SIZES,
733
+ KNOWN_IMAGE_SIZES,
734
+ KNOWN_LOGO_SIZES,
735
+ KNOWN_POSTER_SIZES,
736
+ KNOWN_PROFILE_SIZES,
737
+ KNOWN_STILL_SIZES,
738
+ TMDBClient,
739
+ TMDBError,
740
+ TMDBRateLimitError,
741
+ TMDBRequestError,
742
+ TMDBResponseError,
743
+ buildImageUrl,
744
+ createTMDB,
745
+ isKnownBackdropSize,
746
+ isKnownImageSize,
747
+ isKnownLogoSize,
748
+ isKnownPosterSize,
749
+ isKnownProfileSize,
750
+ isKnownStillSize,
751
+ isMovie,
752
+ isMovieSearchResult,
753
+ isPerson,
754
+ isPersonSearchResult,
755
+ isTV,
756
+ isTVSearchResult
757
+ };
797
758
 
798
- //# sourceMappingURL=index.js.map
759
+ //# debugId=00B61D5405D17A8964756E2164756E21
760
+ //# sourceMappingURL=index.js.map