tmdb-kit 1.0.0 → 1.2.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.
Files changed (45) hide show
  1. package/README.md +455 -196
  2. package/dist/cli.js +3823 -0
  3. package/dist/client.d.cts +71 -0
  4. package/dist/client.d.ts +71 -0
  5. package/dist/errors.d.cts +86 -0
  6. package/dist/errors.d.ts +86 -0
  7. package/dist/helpers/cache.d.cts +28 -0
  8. package/dist/helpers/cache.d.ts +28 -0
  9. package/dist/helpers/pagination.d.cts +35 -0
  10. package/dist/helpers/pagination.d.ts +35 -0
  11. package/dist/helpers/retry.d.cts +47 -0
  12. package/dist/helpers/retry.d.ts +47 -0
  13. package/dist/helpers/timeout.d.cts +20 -0
  14. package/dist/helpers/timeout.d.ts +20 -0
  15. package/dist/http.d.cts +80 -0
  16. package/dist/http.d.ts +80 -0
  17. package/dist/index.cjs +1115 -768
  18. package/dist/index.cjs.map +27 -1
  19. package/dist/index.d.cts +13 -783
  20. package/dist/index.d.ts +13 -783
  21. package/dist/index.js +1074 -744
  22. package/dist/index.js.map +27 -1
  23. package/dist/query.d.cts +91 -0
  24. package/dist/query.d.ts +91 -0
  25. package/dist/resources/configuration.d.cts +17 -0
  26. package/dist/resources/configuration.d.ts +17 -0
  27. package/dist/resources/genres.d.cts +13 -0
  28. package/dist/resources/genres.d.ts +13 -0
  29. package/dist/resources/images.d.cts +17 -0
  30. package/dist/resources/images.d.ts +17 -0
  31. package/dist/resources/movies.d.cts +21 -0
  32. package/dist/resources/movies.d.ts +21 -0
  33. package/dist/resources/people.d.cts +14 -0
  34. package/dist/resources/people.d.ts +14 -0
  35. package/dist/resources/search.d.cts +15 -0
  36. package/dist/resources/search.d.ts +15 -0
  37. package/dist/resources/trending.d.cts +23 -0
  38. package/dist/resources/trending.d.ts +23 -0
  39. package/dist/resources/tv.d.cts +30 -0
  40. package/dist/resources/tv.d.ts +30 -0
  41. package/dist/search-guards.d.cts +32 -0
  42. package/dist/search-guards.d.ts +32 -0
  43. package/dist/types.d.cts +550 -0
  44. package/dist/types.d.ts +550 -0
  45. package/package.json +26 -19
package/dist/index.cjs CHANGED
@@ -1,823 +1,1170 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region src/errors.ts
3
- /** Base class for all SDK-originated errors. */
4
- var TMDBError = class extends Error {
5
- constructor(message, options) {
6
- super(message, options);
7
- this.name = "TMDBError";
8
- }
9
- };
10
- /** Thrown before a request is sent or when fetch itself rejects. */
11
- var TMDBRequestError = class extends TMDBError {
12
- constructor(message, options) {
13
- super(message, options);
14
- this.name = "TMDBRequestError";
15
- }
16
- };
17
- /** Thrown when TMDB returns a non-2xx response. */
18
- var TMDBResponseError = class extends TMDBError {
19
- body;
20
- headers;
21
- requestId;
22
- status;
23
- statusCode;
24
- statusMessage;
25
- statusText;
26
- url;
27
- constructor(message, options) {
28
- super(message);
29
- this.name = "TMDBResponseError";
30
- this.body = options.body;
31
- this.headers = options.headers;
32
- this.requestId = options.headers.get("x-request-id");
33
- this.status = options.status;
34
- this.statusText = options.statusText;
35
- this.url = options.url;
36
- const body = isErrorResponseBody(options.body) ? options.body : void 0;
37
- this.statusCode = body?.status_code;
38
- this.statusMessage = body?.status_message;
39
- }
40
- /** True when TMDB has asked the caller to back off (HTTP 429). */
41
- get isRateLimit() {
42
- return this.status === 429;
43
- }
44
- /** True when the resource was not found (HTTP 404). */
45
- get isNotFound() {
46
- return this.status === 404;
47
- }
48
- /** True when the request was rejected as unauthenticated (HTTP 401). */
49
- get isUnauthorized() {
50
- return this.status === 401;
51
- }
52
- /** True when the request was rejected as forbidden (HTTP 403). */
53
- get isForbidden() {
54
- return this.status === 403;
55
- }
56
- /** True when the upstream returned a 5xx server error. */
57
- get isServerError() {
58
- return this.status >= 500 && this.status < 600;
59
- }
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
60
23
  };
61
- /**
62
- * Thrown when TMDB returns HTTP 429.
63
- *
64
- * The SDK does NOT retry automatically — that decision is left to the
65
- * caller, since retry policies vary widely. Inspect `retryAfter` to
66
- * implement your own backoff.
67
- */
68
- var TMDBRateLimitError = class extends TMDBResponseError {
69
- retryAfter;
70
- constructor(message, options) {
71
- super(message, options);
72
- this.name = "TMDBRateLimitError";
73
- this.retryAfter = options.retryAfter;
74
- }
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
75
37
  };
76
- /**
77
- * Create the appropriate error instance for a non-2xx TMDB response.
78
- *
79
- * Returns a {@link TMDBRateLimitError} when the status is 429, otherwise
80
- * a generic {@link TMDBResponseError}. The error message is extracted from
81
- * the TMDB `status_message` field when available.
82
- */
38
+
39
+ // src/index.ts
40
+ var exports_src = {};
41
+ __export(exports_src, {
42
+ KNOWN_BACKDROP_SIZES: () => KNOWN_BACKDROP_SIZES,
43
+ KNOWN_IMAGE_SIZES: () => KNOWN_IMAGE_SIZES,
44
+ KNOWN_LOGO_SIZES: () => KNOWN_LOGO_SIZES,
45
+ KNOWN_POSTER_SIZES: () => KNOWN_POSTER_SIZES,
46
+ KNOWN_PROFILE_SIZES: () => KNOWN_PROFILE_SIZES,
47
+ KNOWN_STILL_SIZES: () => KNOWN_STILL_SIZES,
48
+ TMDBClient: () => TMDBClient,
49
+ TMDBError: () => TMDBError,
50
+ TMDBHttpClient: () => TMDBHttpClient,
51
+ TMDBRateLimitError: () => TMDBRateLimitError,
52
+ TMDBRequestError: () => TMDBRequestError,
53
+ TMDBResponseError: () => TMDBResponseError,
54
+ TMDBTimeoutError: () => TMDBTimeoutError,
55
+ buildImageUrl: () => buildImageUrl,
56
+ createTMDB: () => createTMDB,
57
+ isKnownBackdropSize: () => isKnownBackdropSize,
58
+ isKnownImageSize: () => isKnownImageSize,
59
+ isKnownLogoSize: () => isKnownLogoSize,
60
+ isKnownPosterSize: () => isKnownPosterSize,
61
+ isKnownProfileSize: () => isKnownProfileSize,
62
+ isKnownStillSize: () => isKnownStillSize,
63
+ isMovie: () => isMovie,
64
+ isMovieSearchResult: () => isMovieSearchResult,
65
+ isPerson: () => isPerson,
66
+ isPersonSearchResult: () => isPersonSearchResult,
67
+ isTV: () => isTV,
68
+ isTVSearchResult: () => isTVSearchResult,
69
+ paginate: () => paginate,
70
+ paginateItems: () => paginateItems,
71
+ retry: () => retry,
72
+ withMemoryCache: () => withMemoryCache,
73
+ withRetry: () => withRetry,
74
+ withTimeout: () => withTimeout
75
+ });
76
+ module.exports = __toCommonJS(exports_src);
77
+
78
+ // src/errors.ts
79
+ class TMDBError extends Error {
80
+ constructor(message, options) {
81
+ super(message, options);
82
+ this.name = "TMDBError";
83
+ }
84
+ }
85
+
86
+ class TMDBRequestError extends TMDBError {
87
+ constructor(message, options) {
88
+ super(message, options);
89
+ this.name = "TMDBRequestError";
90
+ }
91
+ }
92
+
93
+ class TMDBTimeoutError extends TMDBError {
94
+ timeoutMs;
95
+ constructor(timeoutMs, message = `TMDB request timed out after ${timeoutMs}ms`) {
96
+ super(message);
97
+ this.name = "TMDBTimeoutError";
98
+ this.timeoutMs = timeoutMs;
99
+ }
100
+ }
101
+
102
+ class TMDBResponseError extends TMDBError {
103
+ body;
104
+ headers;
105
+ requestId;
106
+ status;
107
+ statusCode;
108
+ statusMessage;
109
+ statusText;
110
+ url;
111
+ constructor(message, options) {
112
+ super(message);
113
+ this.name = "TMDBResponseError";
114
+ this.body = options.body;
115
+ this.headers = options.headers;
116
+ this.requestId = options.headers.get("x-request-id");
117
+ this.status = options.status;
118
+ this.statusText = options.statusText;
119
+ this.url = options.url;
120
+ const body = isErrorResponseBody(options.body) ? options.body : undefined;
121
+ this.statusCode = body?.status_code;
122
+ this.statusMessage = body?.status_message;
123
+ }
124
+ get isRateLimit() {
125
+ return this.status === 429;
126
+ }
127
+ get isNotFound() {
128
+ return this.status === 404;
129
+ }
130
+ get isUnauthorized() {
131
+ return this.status === 401;
132
+ }
133
+ get isForbidden() {
134
+ return this.status === 403;
135
+ }
136
+ get isServerError() {
137
+ return this.status >= 500 && this.status < 600;
138
+ }
139
+ }
140
+
141
+ class TMDBRateLimitError extends TMDBResponseError {
142
+ retryAfter;
143
+ constructor(message, options) {
144
+ super(message, options);
145
+ this.name = "TMDBRateLimitError";
146
+ this.retryAfter = options.retryAfter;
147
+ }
148
+ }
83
149
  function createResponseError(options) {
84
- const message = (isErrorResponseBody(options.body) ? options.body : void 0)?.status_message ?? `${options.status} ${options.statusText}`.trim();
85
- if (options.status === 429) return new TMDBRateLimitError(message, {
86
- ...options,
87
- retryAfter: parseRetryAfter(options.headers.get("retry-after"))
88
- });
89
- return new TMDBResponseError(message, options);
90
- }
91
- /**
92
- * Parse the `Retry-After` header into seconds. Accepts both delta-seconds
93
- * (e.g. "5") and HTTP-date forms (e.g. "Wed, 21 Oct 2026 07:28:00 GMT").
94
- * Falls back to 1 second when the header is missing or unparseable.
95
- */
150
+ const body = isErrorResponseBody(options.body) ? options.body : undefined;
151
+ const message = body?.status_message ?? `${options.status} ${options.statusText}`.trim();
152
+ if (options.status === 429) {
153
+ return new TMDBRateLimitError(message, {
154
+ ...options,
155
+ retryAfter: parseRetryAfter(options.headers.get("retry-after"))
156
+ });
157
+ }
158
+ return new TMDBResponseError(message, options);
159
+ }
96
160
  function parseRetryAfter(value) {
97
- if (value === null || value === void 0) return 1;
98
- const trimmed = value.trim();
99
- if (trimmed === "") return 1;
100
- const seconds = Number(trimmed);
101
- if (Number.isFinite(seconds) && seconds >= 0) return seconds;
102
- const date = Date.parse(trimmed);
103
- if (Number.isFinite(date)) {
104
- const deltaMs = date - Date.now();
105
- return Math.max(1, Math.ceil(deltaMs / 1e3));
106
- }
107
- return 1;
108
- }
109
- /** Check if a value has the shape of a TMDB error response body. */
161
+ if (value === null || value === undefined) {
162
+ return 1;
163
+ }
164
+ const trimmed = value.trim();
165
+ if (trimmed === "") {
166
+ return 1;
167
+ }
168
+ const seconds = Number(trimmed);
169
+ if (Number.isFinite(seconds) && seconds >= 0) {
170
+ return seconds;
171
+ }
172
+ const date = Date.parse(trimmed);
173
+ if (Number.isFinite(date)) {
174
+ const deltaMs = date - Date.now();
175
+ return Math.max(1, Math.ceil(deltaMs / 1000));
176
+ }
177
+ return 1;
178
+ }
110
179
  function isErrorResponseBody(value) {
111
- return typeof value === "object" && value !== null;
112
- }
113
- /**
114
- * Append query parameters to a URL object.
115
- *
116
- * - `undefined` and `null` values are skipped.
117
- * - Arrays are joined with commas (TMDB convention).
118
- * - All values are converted to strings.
119
- */
180
+ return typeof value === "object" && value !== null;
181
+ }
182
+
183
+ // src/query.ts
184
+ var DEFAULT_API_BASE_URL = "https://api.themoviedb.org/3";
185
+ var DEFAULT_IMAGE_BASE_URL = "https://image.tmdb.org/t/p";
120
186
  function appendQuery(url, query) {
121
- for (const [key, value] of Object.entries(query)) {
122
- if (value === void 0 || value === null) continue;
123
- if (Array.isArray(value)) {
124
- url.searchParams.set(key, value.map(String).join(","));
125
- continue;
126
- }
127
- url.searchParams.set(key, String(value));
128
- }
129
- }
130
- /**
131
- * Merge a language query parameter with client defaults.
132
- *
133
- * If `query.language` is set it takes precedence; otherwise the client's
134
- * default language is used.
135
- */
187
+ for (const [key, value] of Object.entries(query)) {
188
+ if (value === undefined || value === null) {
189
+ continue;
190
+ }
191
+ if (Array.isArray(value)) {
192
+ url.searchParams.set(key, value.map(String).join(","));
193
+ continue;
194
+ }
195
+ url.searchParams.set(key, String(value));
196
+ }
197
+ }
136
198
  function withLanguage(defaults, query) {
137
- const language = typeof query.language === "string" ? query.language : defaults.language;
138
- return {
139
- ...query,
140
- language
141
- };
142
- }
143
- /**
144
- * Merge language and region defaults for list endpoints.
145
- *
146
- * Combines {@link withLanguage} with region fallback from client defaults.
147
- */
199
+ const language = typeof query.language === "string" ? query.language : defaults.language;
200
+ return {
201
+ ...query,
202
+ language
203
+ };
204
+ }
148
205
  function withListDefaults(defaults, query) {
149
- const region = typeof query.region === "string" ? query.region : defaults.region;
150
- return {
151
- ...withLanguage(defaults, query),
152
- region
153
- };
154
- }
155
- /**
156
- * Convert a string or string array to a comma-separated list.
157
- *
158
- * Returns `undefined` if the input is `undefined` (skips the parameter).
159
- * TMDB uses comma-separated values for multi-value query parameters.
160
- */
206
+ const region = typeof query.region === "string" ? query.region : defaults.region;
207
+ return {
208
+ ...withLanguage(defaults, query),
209
+ region
210
+ };
211
+ }
161
212
  function toCommaList(value) {
162
- if (value === void 0) return;
163
- return typeof value === "string" ? value : value.join(",");
164
- }
165
- /**
166
- * Validate and convert a numeric ID to a string for use in URL paths.
167
- *
168
- * @throws {TMDBRequestError} If `value` is not a positive integer.
169
- */
213
+ if (value === undefined) {
214
+ return;
215
+ }
216
+ return typeof value === "string" ? value : value.join(",");
217
+ }
170
218
  function toId(value, name) {
171
- if (!Number.isInteger(value) || value <= 0) throw new TMDBRequestError(`${name} must be a positive integer`);
172
- return String(value);
173
- }
174
- /**
175
- * Validate and trim a search query string.
176
- *
177
- * @throws {TMDBRequestError} If the query is empty after trimming.
178
- */
219
+ if (!Number.isInteger(value) || value <= 0) {
220
+ throw new TMDBRequestError(`${name} must be a positive integer`);
221
+ }
222
+ return String(value);
223
+ }
224
+ function toSeasonNumber(value) {
225
+ if (!Number.isInteger(value) || value < 0) {
226
+ throw new TMDBRequestError("seasonNumber must be a non-negative integer");
227
+ }
228
+ return String(value);
229
+ }
230
+ function toGroupId(value) {
231
+ const groupId = value.trim();
232
+ if (!/^[A-Za-z0-9_-]+$/.test(groupId)) {
233
+ throw new TMDBRequestError("groupId must be a non-empty identifier");
234
+ }
235
+ return groupId;
236
+ }
179
237
  function toSearchQuery(value) {
180
- const query = value.trim();
181
- if (query.length === 0) throw new TMDBRequestError("search query must not be empty");
182
- return query;
183
- }
184
- /**
185
- * Validate a trending time window value.
186
- *
187
- * @throws {TMDBRequestError} If `value` is not `"day"` or `"week"`.
188
- */
238
+ const query = value.trim();
239
+ if (query.length === 0) {
240
+ throw new TMDBRequestError("search query must not be empty");
241
+ }
242
+ return query;
243
+ }
189
244
  function toTimeWindow(value) {
190
- if (value !== "day" && value !== "week") throw new TMDBRequestError("timeWindow must be either \"day\" or \"week\"");
191
- return value;
245
+ if (value !== "day" && value !== "week") {
246
+ throw new TMDBRequestError('timeWindow must be either "day" or "week"');
247
+ }
248
+ return value;
192
249
  }
193
- /**
194
- * Build a full TMDB image URL from the path returned by API payloads.
195
- * Returns null for nullish image paths so UI code can branch naturally.
196
- */
197
250
  function buildImageUrl(path, size = "original", options = {}) {
198
- if (path === void 0 || path === null || path.trim() === "") return null;
199
- const url = `${normalizeBaseUrl(options.baseUrl ?? "https://image.tmdb.org/t/p")}/${size}${path.startsWith("/") ? path : `/${path}`}`;
200
- return options.transform ? options.transform(url) : url;
251
+ if (path === undefined || path === null || path.trim() === "") {
252
+ return null;
253
+ }
254
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_IMAGE_BASE_URL);
255
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
256
+ const url = `${baseUrl}/${size}${normalizedPath}`;
257
+ return options.transform ? options.transform(url) : url;
201
258
  }
202
- /**
203
- * Strip trailing slashes from a base URL to ensure consistent path joining.
204
- */
205
259
  function normalizeBaseUrl(baseUrl) {
206
- return baseUrl.replace(/\/+$/, "");
207
- }
208
- //#endregion
209
- //#region src/http.ts
210
- /**
211
- * Built-in HTTP transport that uses the Fetch API.
212
- *
213
- * Handles authentication (API key or access token), URL construction,
214
- * request headers, and response parsing. Use the factory function
215
- * {@link createTMDB} instead of instantiating this directly.
216
- */
217
- var TMDBHttpClient = class {
218
- defaults;
219
- imageTransform;
220
- #apiKey;
221
- #accessToken;
222
- #baseUrl;
223
- #fetch;
224
- #headers;
225
- constructor(options) {
226
- const accessToken = normalizeSecret("accessToken" in options ? options.accessToken : void 0);
227
- const apiKey = normalizeSecret("apiKey" in options ? options.apiKey : void 0);
228
- if (Boolean(accessToken) === Boolean(apiKey)) throw new TMDBRequestError("Provide exactly one of accessToken or apiKey");
229
- this.#accessToken = accessToken;
230
- this.#apiKey = apiKey;
231
- this.#baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://api.themoviedb.org/3");
232
- this.#fetch = options.fetch;
233
- this.#headers = options.headers;
234
- this.defaults = {
235
- imageBaseUrl: normalizeBaseUrl(options.imageBaseUrl ?? "https://image.tmdb.org/t/p"),
236
- language: options.defaultLanguage,
237
- region: options.defaultRegion
238
- };
239
- this.imageTransform = options.images?.transform;
240
- }
241
- async get(path, options = {}) {
242
- const url = this.#createUrl(path, options.query ?? {});
243
- const headers = this.#createHeaders(options.headers);
244
- const fetchImpl = this.#resolveFetch();
245
- let response;
246
- try {
247
- response = await fetchImpl(url, {
248
- headers,
249
- method: "GET",
250
- signal: options.signal
251
- });
252
- } catch (error) {
253
- throw new TMDBRequestError(`TMDB request failed: ${String(error)}`, { cause: error });
254
- }
255
- const body = await readJson(response);
256
- if (!response.ok) throw createResponseError({
257
- body,
258
- headers: response.headers,
259
- status: response.status,
260
- statusText: response.statusText,
261
- url
262
- });
263
- return body;
264
- }
265
- #resolveFetch() {
266
- if (this.#fetch !== void 0) return this.#fetch;
267
- const globalFetch = globalThis.fetch;
268
- if (typeof globalFetch !== "function") throw new TMDBRequestError("No fetch implementation found. Pass options.fetch in this runtime.");
269
- return globalFetch.bind(globalThis);
270
- }
271
- #createHeaders(headersInit) {
272
- const headers = new Headers(this.#headers);
273
- const requestHeaders = new Headers(headersInit);
274
- headers.set("Accept", "application/json");
275
- for (const [key, value] of requestHeaders) headers.set(key, value);
276
- if (this.#accessToken !== void 0) headers.set("Authorization", `Bearer ${this.#accessToken}`);
277
- return headers;
278
- }
279
- #createUrl(path, query) {
280
- const relativePath = path.replace(/^\/+/, "");
281
- const url = new URL(relativePath, `${this.#baseUrl}/`);
282
- appendQuery(url, {
283
- ...query,
284
- api_key: this.#apiKey
285
- });
286
- return url.toString();
287
- }
288
- };
289
- /**
290
- * Read and parse a JSON response body.
291
- *
292
- * Returns `undefined` for empty responses. If the body is not valid JSON,
293
- * the raw text string is returned as-is (TMDB occasionally returns plain
294
- * text for certain error conditions).
295
- */
260
+ return baseUrl.replace(/\/+$/, "");
261
+ }
262
+
263
+ // src/http.ts
264
+ class TMDBHttpClient {
265
+ defaults;
266
+ imageTransform;
267
+ #apiKey;
268
+ #accessToken;
269
+ #baseUrl;
270
+ #fetch;
271
+ #headers;
272
+ constructor(options) {
273
+ const accessToken = normalizeSecret("accessToken" in options ? options.accessToken : undefined);
274
+ const apiKey = normalizeSecret("apiKey" in options ? options.apiKey : undefined);
275
+ if (Boolean(accessToken) === Boolean(apiKey)) {
276
+ throw new TMDBRequestError("Provide exactly one of accessToken or apiKey");
277
+ }
278
+ this.#accessToken = accessToken;
279
+ this.#apiKey = apiKey;
280
+ this.#baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_API_BASE_URL);
281
+ this.#fetch = options.fetch;
282
+ this.#headers = options.headers;
283
+ this.defaults = {
284
+ imageBaseUrl: normalizeBaseUrl(options.imageBaseUrl ?? DEFAULT_IMAGE_BASE_URL),
285
+ language: options.defaultLanguage,
286
+ region: options.defaultRegion
287
+ };
288
+ this.imageTransform = options.images?.transform;
289
+ }
290
+ async get(path, options = {}) {
291
+ const url = this.#createUrl(path, options.query ?? {});
292
+ const headers = this.#createHeaders(options.headers);
293
+ const fetchImpl = this.#resolveFetch();
294
+ let response;
295
+ try {
296
+ response = await fetchImpl(url, {
297
+ headers,
298
+ method: "GET",
299
+ signal: options.signal
300
+ });
301
+ } catch (error) {
302
+ throw new TMDBRequestError(`TMDB request failed: ${String(error)}`, { cause: error });
303
+ }
304
+ const body = await readJson(response);
305
+ if (!response.ok) {
306
+ throw createResponseError({
307
+ body,
308
+ headers: response.headers,
309
+ status: response.status,
310
+ statusText: response.statusText,
311
+ url
312
+ });
313
+ }
314
+ return body;
315
+ }
316
+ #resolveFetch() {
317
+ if (this.#fetch !== undefined) {
318
+ return this.#fetch;
319
+ }
320
+ const globalFetch = globalThis.fetch;
321
+ if (typeof globalFetch !== "function") {
322
+ throw new TMDBRequestError("No fetch implementation found. Pass options.fetch in this runtime.");
323
+ }
324
+ return globalFetch.bind(globalThis);
325
+ }
326
+ #createHeaders(headersInit) {
327
+ const headers = new Headers(this.#headers);
328
+ const requestHeaders = new Headers(headersInit);
329
+ headers.set("Accept", "application/json");
330
+ for (const [key, value] of requestHeaders) {
331
+ headers.set(key, value);
332
+ }
333
+ if (this.#accessToken !== undefined) {
334
+ headers.set("Authorization", `Bearer ${this.#accessToken}`);
335
+ }
336
+ return headers;
337
+ }
338
+ #createUrl(path, query) {
339
+ const relativePath = path.replace(/^\/+/, "");
340
+ const url = new URL(relativePath, `${this.#baseUrl}/`);
341
+ appendQuery(url, {
342
+ ...query,
343
+ api_key: this.#apiKey
344
+ });
345
+ return url.toString();
346
+ }
347
+ }
296
348
  async function readJson(response) {
297
- const text = await response.text();
298
- if (text.length === 0) return;
299
- try {
300
- return JSON.parse(text);
301
- } catch {
302
- return text;
303
- }
304
- }
305
- /**
306
- * Normalize a secret value by trimming whitespace and treating empty
307
- * strings as undefined (not provided).
308
- */
349
+ const text = await response.text();
350
+ if (text.length === 0) {
351
+ return;
352
+ }
353
+ try {
354
+ return JSON.parse(text);
355
+ } catch {
356
+ return text;
357
+ }
358
+ }
309
359
  function normalizeSecret(value) {
310
- const secret = value?.trim();
311
- return secret === "" ? void 0 : secret;
312
- }
313
- //#endregion
314
- //#region src/resources/configuration.ts
315
- /**
316
- * Access TMDB configuration data (image sizes, countries, languages, etc.).
317
- *
318
- * Obtained via `client.configuration`.
319
- */
320
- var ConfigurationResource = class {
321
- #transport;
322
- constructor(transport) {
323
- this.#transport = transport;
324
- }
325
- details() {
326
- return this.#transport.get("/configuration");
327
- }
328
- countries() {
329
- return this.#transport.get("/configuration/countries");
330
- }
331
- jobs() {
332
- return this.#transport.get("/configuration/jobs");
333
- }
334
- languages() {
335
- return this.#transport.get("/configuration/languages");
336
- }
337
- primaryTranslations() {
338
- return this.#transport.get("/configuration/primary_translations");
339
- }
340
- timezones() {
341
- return this.#transport.get("/configuration/timezones");
342
- }
343
- };
344
- //#endregion
345
- //#region src/resources/genres.ts
346
- /**
347
- * Access TMDB genre lists for movies and TV shows.
348
- *
349
- * Obtained via `client.genres`.
350
- */
351
- var GenresResource = class {
352
- #transport;
353
- constructor(transport) {
354
- this.#transport = transport;
355
- }
356
- movies(options = {}) {
357
- return this.#transport.get("/genre/movie/list", { query: withLanguage(this.#transport.defaults, { language: options.language }) });
358
- }
359
- tv(options = {}) {
360
- return this.#transport.get("/genre/tv/list", { query: withLanguage(this.#transport.defaults, { language: options.language }) });
361
- }
362
- };
363
- //#endregion
364
- //#region src/resources/images.ts
365
- /**
366
- * Helper for constructing TMDB image URLs from API path values.
367
- *
368
- * Obtained via `client.images`. Supports optional URL transforms for
369
- * routing image requests through a CDN or proxy.
370
- */
371
- var ImagesHelper = class {
372
- #transport;
373
- #transform;
374
- constructor(transport, transform) {
375
- this.#transport = transport;
376
- this.#transform = transform;
377
- }
378
- url(path, size = "original", options = {}) {
379
- return buildImageUrl(path, size, {
380
- baseUrl: this.#transport.defaults.imageBaseUrl,
381
- transform: options.transform ?? this.#transform
382
- });
383
- }
384
- };
385
- //#endregion
386
- //#region src/resources/movies.ts
387
- /**
388
- * Access TMDB movie endpoints (popular, top-rated, details, credits, etc.).
389
- *
390
- * Obtained via `client.movies`.
391
- */
392
- var MoviesResource = class {
393
- #transport;
394
- constructor(transport) {
395
- this.#transport = transport;
396
- }
397
- popular(options = {}) {
398
- return this.#transport.get("/movie/popular", { query: movieListQuery(this.#transport, options) });
399
- }
400
- topRated(options = {}) {
401
- return this.#transport.get("/movie/top_rated", { query: movieListQuery(this.#transport, options) });
402
- }
403
- nowPlaying(options = {}) {
404
- return this.#transport.get("/movie/now_playing", { query: movieListQuery(this.#transport, options) });
405
- }
406
- upcoming(options = {}) {
407
- return this.#transport.get("/movie/upcoming", { query: movieListQuery(this.#transport, options) });
408
- }
409
- details(movieId, options = {}) {
410
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}`, { query: withLanguage(this.#transport.defaults, {
411
- append_to_response: toCommaList(options.appendToResponse),
412
- language: options.language
413
- }) });
414
- }
415
- credits(movieId, options = {}) {
416
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/credits`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
417
- }
418
- images(movieId, options = {}) {
419
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/images`, { query: withLanguage(this.#transport.defaults, {
420
- include_image_language: toCommaList(options.includeImageLanguage),
421
- language: options.language
422
- }) });
423
- }
424
- recommendations(movieId, options = {}) {
425
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/recommendations`, { query: movieListQuery(this.#transport, options) });
426
- }
427
- similar(movieId, options = {}) {
428
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/similar`, { query: movieListQuery(this.#transport, options) });
429
- }
430
- videos(movieId, options = {}) {
431
- return this.#transport.get(`/movie/${toId(movieId, "movieId")}/videos`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
432
- }
433
- };
434
- /** Build query parameters for movie list endpoints. */
360
+ const secret = value?.trim();
361
+ return secret === "" ? undefined : secret;
362
+ }
363
+
364
+ // src/resources/configuration.ts
365
+ class ConfigurationResource {
366
+ #transport;
367
+ constructor(transport) {
368
+ this.#transport = transport;
369
+ }
370
+ details(options = {}) {
371
+ return this.#transport.get("/configuration", { signal: options.signal });
372
+ }
373
+ countries(options = {}) {
374
+ return this.#transport.get("/configuration/countries", { signal: options.signal });
375
+ }
376
+ jobs(options = {}) {
377
+ return this.#transport.get("/configuration/jobs", { signal: options.signal });
378
+ }
379
+ languages(options = {}) {
380
+ return this.#transport.get("/configuration/languages", { signal: options.signal });
381
+ }
382
+ primaryTranslations(options = {}) {
383
+ return this.#transport.get("/configuration/primary_translations", {
384
+ signal: options.signal
385
+ });
386
+ }
387
+ timezones(options = {}) {
388
+ return this.#transport.get("/configuration/timezones", { signal: options.signal });
389
+ }
390
+ }
391
+
392
+ // src/resources/genres.ts
393
+ class GenresResource {
394
+ #transport;
395
+ constructor(transport) {
396
+ this.#transport = transport;
397
+ }
398
+ movies(options = {}) {
399
+ return this.#transport.get("/genre/movie/list", {
400
+ query: withLanguage(this.#transport.defaults, {
401
+ language: options.language
402
+ }),
403
+ signal: options.signal
404
+ });
405
+ }
406
+ tv(options = {}) {
407
+ return this.#transport.get("/genre/tv/list", {
408
+ query: withLanguage(this.#transport.defaults, {
409
+ language: options.language
410
+ }),
411
+ signal: options.signal
412
+ });
413
+ }
414
+ }
415
+
416
+ // src/resources/images.ts
417
+ class ImagesHelper {
418
+ #transport;
419
+ #transform;
420
+ constructor(transport, transform) {
421
+ this.#transport = transport;
422
+ this.#transform = transform;
423
+ }
424
+ url(path, size = "original", options = {}) {
425
+ return buildImageUrl(path, size, {
426
+ baseUrl: this.#transport.defaults.imageBaseUrl,
427
+ transform: options.transform ?? this.#transform
428
+ });
429
+ }
430
+ }
431
+
432
+ // src/resources/movies.ts
433
+ class MoviesResource {
434
+ #transport;
435
+ constructor(transport) {
436
+ this.#transport = transport;
437
+ }
438
+ popular(options = {}) {
439
+ return this.#transport.get("/movie/popular", {
440
+ query: movieListQuery(this.#transport, options),
441
+ signal: options.signal
442
+ });
443
+ }
444
+ topRated(options = {}) {
445
+ return this.#transport.get("/movie/top_rated", {
446
+ query: movieListQuery(this.#transport, options),
447
+ signal: options.signal
448
+ });
449
+ }
450
+ nowPlaying(options = {}) {
451
+ return this.#transport.get("/movie/now_playing", {
452
+ query: movieListQuery(this.#transport, options),
453
+ signal: options.signal
454
+ });
455
+ }
456
+ upcoming(options = {}) {
457
+ return this.#transport.get("/movie/upcoming", {
458
+ query: movieListQuery(this.#transport, options),
459
+ signal: options.signal
460
+ });
461
+ }
462
+ details(movieId, options = {}) {
463
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}`, {
464
+ query: withLanguage(this.#transport.defaults, {
465
+ append_to_response: toCommaList(options.appendToResponse),
466
+ language: options.language
467
+ }),
468
+ signal: options.signal
469
+ });
470
+ }
471
+ credits(movieId, options = {}) {
472
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/credits`, {
473
+ query: withLanguage(this.#transport.defaults, {
474
+ language: options.language
475
+ }),
476
+ signal: options.signal
477
+ });
478
+ }
479
+ images(movieId, options = {}) {
480
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/images`, {
481
+ query: withLanguage(this.#transport.defaults, {
482
+ include_image_language: toCommaList(options.includeImageLanguage),
483
+ language: options.language
484
+ }),
485
+ signal: options.signal
486
+ });
487
+ }
488
+ recommendations(movieId, options = {}) {
489
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/recommendations`, {
490
+ query: movieListQuery(this.#transport, options),
491
+ signal: options.signal
492
+ });
493
+ }
494
+ similar(movieId, options = {}) {
495
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/similar`, {
496
+ query: movieListQuery(this.#transport, options),
497
+ signal: options.signal
498
+ });
499
+ }
500
+ videos(movieId, options = {}) {
501
+ return this.#transport.get(`/movie/${toId(movieId, "movieId")}/videos`, {
502
+ query: withLanguage(this.#transport.defaults, {
503
+ language: options.language
504
+ }),
505
+ signal: options.signal
506
+ });
507
+ }
508
+ }
435
509
  function movieListQuery(transport, options) {
436
- return withListDefaults(transport.defaults, {
437
- language: options.language,
438
- page: options.page,
439
- region: options.region
440
- });
441
- }
442
- //#endregion
443
- //#region src/resources/people.ts
444
- /**
445
- * Access TMDB person (actor, director, etc.) endpoints.
446
- *
447
- * Obtained via `client.people`.
448
- */
449
- var PeopleResource = class {
450
- #transport;
451
- constructor(transport) {
452
- this.#transport = transport;
453
- }
454
- popular(options = {}) {
455
- return this.#transport.get("/person/popular", { query: peopleListQuery(this.#transport, options) });
456
- }
457
- details(personId, options = {}) {
458
- return this.#transport.get(`/person/${toId(personId, "personId")}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
459
- }
460
- };
461
- /** Build query parameters for person list endpoints. */
510
+ return withListDefaults(transport.defaults, {
511
+ language: options.language,
512
+ page: options.page,
513
+ region: options.region
514
+ });
515
+ }
516
+
517
+ // src/resources/people.ts
518
+ class PeopleResource {
519
+ #transport;
520
+ constructor(transport) {
521
+ this.#transport = transport;
522
+ }
523
+ popular(options = {}) {
524
+ return this.#transport.get("/person/popular", {
525
+ query: peopleListQuery(this.#transport, options),
526
+ signal: options.signal
527
+ });
528
+ }
529
+ details(personId, options = {}) {
530
+ return this.#transport.get(`/person/${toId(personId, "personId")}`, {
531
+ query: withLanguage(this.#transport.defaults, {
532
+ language: options.language
533
+ }),
534
+ signal: options.signal
535
+ });
536
+ }
537
+ combinedCredits(personId, options = {}) {
538
+ return this.#transport.get(`/person/${toId(personId, "personId")}/combined_credits`, {
539
+ query: withLanguage(this.#transport.defaults, {
540
+ language: options.language
541
+ }),
542
+ signal: options.signal
543
+ });
544
+ }
545
+ }
462
546
  function peopleListQuery(transport, options) {
463
- return withLanguage(transport.defaults, {
464
- language: options.language,
465
- page: options.page
466
- });
467
- }
468
- //#endregion
469
- //#region src/resources/search.ts
470
- /**
471
- * Search TMDB for movies, TV shows, people, or all media types.
472
- *
473
- * Obtained via `client.search`.
474
- */
475
- var SearchResource = class {
476
- #transport;
477
- constructor(transport) {
478
- this.#transport = transport;
479
- }
480
- movies(query, options = {}) {
481
- return this.#transport.get("/search/movie", { query: movieSearchQuery(this.#transport, query, options) });
482
- }
483
- tv(query, options = {}) {
484
- return this.#transport.get("/search/tv", { query: tvSearchQuery(this.#transport, query, options) });
485
- }
486
- people(query, options = {}) {
487
- return this.#transport.get("/search/person", { query: commonSearchQuery(this.#transport, query, options) });
488
- }
489
- async multi(query, options = {}) {
490
- const response = await this.#transport.get("/search/multi", { query: commonSearchQuery(this.#transport, query, options) });
491
- const excluded = options.exclude;
492
- if (excluded === void 0 || excluded.length === 0) return response;
493
- const excludedSet = new Set(excluded);
494
- return {
495
- ...response,
496
- results: response.results.filter((result) => !excludedSet.has(result.media_type))
497
- };
498
- }
499
- };
500
- /** Build query parameters for movie search. */
547
+ return withLanguage(transport.defaults, {
548
+ language: options.language,
549
+ page: options.page
550
+ });
551
+ }
552
+
553
+ // src/resources/search.ts
554
+ class SearchResource {
555
+ #transport;
556
+ constructor(transport) {
557
+ this.#transport = transport;
558
+ }
559
+ movies(query, options = {}) {
560
+ return this.#transport.get("/search/movie", {
561
+ query: movieSearchQuery(this.#transport, query, options),
562
+ signal: options.signal
563
+ });
564
+ }
565
+ tv(query, options = {}) {
566
+ return this.#transport.get("/search/tv", {
567
+ query: tvSearchQuery(this.#transport, query, options),
568
+ signal: options.signal
569
+ });
570
+ }
571
+ people(query, options = {}) {
572
+ return this.#transport.get("/search/person", {
573
+ query: commonSearchQuery(this.#transport, query, options),
574
+ signal: options.signal
575
+ });
576
+ }
577
+ async multi(query, options = {}) {
578
+ const response = await this.#transport.get("/search/multi", {
579
+ query: commonSearchQuery(this.#transport, query, options),
580
+ signal: options.signal
581
+ });
582
+ const excluded = options.exclude;
583
+ if (excluded === undefined || excluded.length === 0) {
584
+ return response;
585
+ }
586
+ const excludedSet = new Set(excluded);
587
+ return {
588
+ ...response,
589
+ results: response.results.filter((result) => !excludedSet.has(result.media_type))
590
+ };
591
+ }
592
+ }
501
593
  function movieSearchQuery(transport, query, options) {
502
- return withListDefaults(transport.defaults, {
503
- include_adult: options.includeAdult,
504
- language: options.language,
505
- page: options.page,
506
- primary_release_year: options.primaryReleaseYear,
507
- query: toSearchQuery(query),
508
- region: options.region,
509
- year: options.year
510
- });
511
- }
512
- /** Build query parameters for TV search. */
594
+ return withListDefaults(transport.defaults, {
595
+ include_adult: options.includeAdult,
596
+ language: options.language,
597
+ page: options.page,
598
+ primary_release_year: options.primaryReleaseYear,
599
+ query: toSearchQuery(query),
600
+ region: options.region,
601
+ year: options.year
602
+ });
603
+ }
513
604
  function tvSearchQuery(transport, query, options) {
514
- return withLanguage(transport.defaults, {
515
- first_air_date_year: options.firstAirDateYear,
516
- include_adult: options.includeAdult,
517
- language: options.language,
518
- page: options.page,
519
- query: toSearchQuery(query),
520
- year: options.year
521
- });
522
- }
523
- /** Build query parameters for person and multi-search. */
605
+ return withLanguage(transport.defaults, {
606
+ first_air_date_year: options.firstAirDateYear,
607
+ include_adult: options.includeAdult,
608
+ language: options.language,
609
+ page: options.page,
610
+ query: toSearchQuery(query),
611
+ year: options.year
612
+ });
613
+ }
524
614
  function commonSearchQuery(transport, query, options) {
525
- return withLanguage(transport.defaults, {
526
- include_adult: options.includeAdult,
527
- language: options.language,
528
- page: options.page,
529
- query: toSearchQuery(query)
530
- });
531
- }
532
- //#endregion
533
- //#region src/resources/trending.ts
534
- /**
535
- * Access TMDB trending content (movies, TV, people) for day/week windows.
536
- *
537
- * Obtained via `client.trending`.
538
- */
539
- var TrendingResource = class {
540
- #transport;
541
- constructor(transport) {
542
- this.#transport = transport;
543
- }
544
- all(timeWindow = "day", options = {}) {
545
- return this.#transport.get(`/trending/all/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
546
- }
547
- movies(timeWindow = "day", options = {}) {
548
- return this.#transport.get(`/trending/movie/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
549
- }
550
- tv(timeWindow = "day", options = {}) {
551
- return this.#transport.get(`/trending/tv/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
552
- }
553
- people(timeWindow = "day", options = {}) {
554
- return this.#transport.get(`/trending/person/${toTimeWindow(timeWindow)}`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
555
- }
556
- };
557
- //#endregion
558
- //#region src/resources/tv.ts
559
- /**
560
- * Access TMDB TV show endpoints (popular, top-rated, details, seasons, etc.).
561
- *
562
- * Obtained via `client.tv`.
563
- */
564
- var TVResource = class {
565
- #transport;
566
- constructor(transport) {
567
- this.#transport = transport;
568
- }
569
- popular(options = {}) {
570
- return this.#transport.get("/tv/popular", { query: tvListQuery(this.#transport, options) });
571
- }
572
- topRated(options = {}) {
573
- return this.#transport.get("/tv/top_rated", { query: tvListQuery(this.#transport, options) });
574
- }
575
- airingToday(options = {}) {
576
- return this.#transport.get("/tv/airing_today", { query: tvListQuery(this.#transport, options) });
577
- }
578
- onTheAir(options = {}) {
579
- return this.#transport.get("/tv/on_the_air", { query: tvListQuery(this.#transport, options) });
580
- }
581
- details(seriesId, options = {}) {
582
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}`, { query: withLanguage(this.#transport.defaults, {
583
- append_to_response: toCommaList(options.appendToResponse),
584
- language: options.language
585
- }) });
586
- }
587
- credits(seriesId, options = {}) {
588
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/credits`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
589
- }
590
- images(seriesId, options = {}) {
591
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/images`, { query: withLanguage(this.#transport.defaults, {
592
- include_image_language: toCommaList(options.includeImageLanguage),
593
- language: options.language
594
- }) });
595
- }
596
- recommendations(seriesId, options = {}) {
597
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/recommendations`, { query: tvListQuery(this.#transport, options) });
598
- }
599
- similar(seriesId, options = {}) {
600
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/similar`, { query: tvListQuery(this.#transport, options) });
601
- }
602
- videos(seriesId, options = {}) {
603
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/videos`, { query: withLanguage(this.#transport.defaults, { language: options.language }) });
604
- }
605
- seasonDetails(seriesId, seasonNumber, options = {}) {
606
- return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toId(seasonNumber, "seasonNumber")}`, { query: withLanguage(this.#transport.defaults, {
607
- append_to_response: toCommaList(options.appendToResponse),
608
- language: options.language
609
- }) });
610
- }
611
- };
612
- /** Build query parameters for TV list endpoints. */
615
+ return withLanguage(transport.defaults, {
616
+ include_adult: options.includeAdult,
617
+ language: options.language,
618
+ page: options.page,
619
+ query: toSearchQuery(query)
620
+ });
621
+ }
622
+
623
+ // src/resources/trending.ts
624
+ class TrendingResource {
625
+ #transport;
626
+ constructor(transport) {
627
+ this.#transport = transport;
628
+ }
629
+ all(timeWindow = "day", options = {}) {
630
+ return this.#transport.get(`/trending/all/${toTimeWindow(timeWindow)}`, {
631
+ query: withLanguage(this.#transport.defaults, {
632
+ language: options.language,
633
+ page: options.page
634
+ }),
635
+ signal: options.signal
636
+ });
637
+ }
638
+ movies(timeWindow = "day", options = {}) {
639
+ return this.#transport.get(`/trending/movie/${toTimeWindow(timeWindow)}`, {
640
+ query: withLanguage(this.#transport.defaults, {
641
+ language: options.language,
642
+ page: options.page
643
+ }),
644
+ signal: options.signal
645
+ });
646
+ }
647
+ tv(timeWindow = "day", options = {}) {
648
+ return this.#transport.get(`/trending/tv/${toTimeWindow(timeWindow)}`, {
649
+ query: withLanguage(this.#transport.defaults, {
650
+ language: options.language,
651
+ page: options.page
652
+ }),
653
+ signal: options.signal
654
+ });
655
+ }
656
+ people(timeWindow = "day", options = {}) {
657
+ return this.#transport.get(`/trending/person/${toTimeWindow(timeWindow)}`, {
658
+ query: withLanguage(this.#transport.defaults, {
659
+ language: options.language,
660
+ page: options.page
661
+ }),
662
+ signal: options.signal
663
+ });
664
+ }
665
+ }
666
+
667
+ // src/resources/tv.ts
668
+ class TVResource {
669
+ #transport;
670
+ constructor(transport) {
671
+ this.#transport = transport;
672
+ }
673
+ popular(options = {}) {
674
+ return this.#transport.get("/tv/popular", {
675
+ query: tvListQuery(this.#transport, options),
676
+ signal: options.signal
677
+ });
678
+ }
679
+ topRated(options = {}) {
680
+ return this.#transport.get("/tv/top_rated", {
681
+ query: tvListQuery(this.#transport, options),
682
+ signal: options.signal
683
+ });
684
+ }
685
+ airingToday(options = {}) {
686
+ return this.#transport.get("/tv/airing_today", {
687
+ query: tvListQuery(this.#transport, options),
688
+ signal: options.signal
689
+ });
690
+ }
691
+ onTheAir(options = {}) {
692
+ return this.#transport.get("/tv/on_the_air", {
693
+ query: tvListQuery(this.#transport, options),
694
+ signal: options.signal
695
+ });
696
+ }
697
+ details(seriesId, options = {}) {
698
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}`, {
699
+ query: withLanguage(this.#transport.defaults, {
700
+ append_to_response: toCommaList(options.appendToResponse),
701
+ language: options.language
702
+ }),
703
+ signal: options.signal
704
+ });
705
+ }
706
+ credits(seriesId, options = {}) {
707
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/credits`, {
708
+ query: withLanguage(this.#transport.defaults, {
709
+ language: options.language
710
+ }),
711
+ signal: options.signal
712
+ });
713
+ }
714
+ images(seriesId, options = {}) {
715
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/images`, {
716
+ query: withLanguage(this.#transport.defaults, {
717
+ include_image_language: toCommaList(options.includeImageLanguage),
718
+ language: options.language
719
+ }),
720
+ signal: options.signal
721
+ });
722
+ }
723
+ recommendations(seriesId, options = {}) {
724
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/recommendations`, {
725
+ query: tvListQuery(this.#transport, options),
726
+ signal: options.signal
727
+ });
728
+ }
729
+ similar(seriesId, options = {}) {
730
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/similar`, {
731
+ query: tvListQuery(this.#transport, options),
732
+ signal: options.signal
733
+ });
734
+ }
735
+ videos(seriesId, options = {}) {
736
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/videos`, {
737
+ query: withLanguage(this.#transport.defaults, {
738
+ language: options.language
739
+ }),
740
+ signal: options.signal
741
+ });
742
+ }
743
+ seasonDetails(seriesId, seasonNumber, options = {}) {
744
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toSeasonNumber(seasonNumber)}`, {
745
+ query: withLanguage(this.#transport.defaults, {
746
+ append_to_response: toCommaList(options.appendToResponse),
747
+ language: options.language
748
+ }),
749
+ signal: options.signal
750
+ });
751
+ }
752
+ seasonCredits(seriesId, seasonNumber, options = {}) {
753
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toSeasonNumber(seasonNumber)}/credits`, {
754
+ query: withLanguage(this.#transport.defaults, {
755
+ language: options.language
756
+ }),
757
+ signal: options.signal
758
+ });
759
+ }
760
+ seasonAggregateCredits(seriesId, seasonNumber, options = {}) {
761
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toSeasonNumber(seasonNumber)}/aggregate_credits`, {
762
+ query: withLanguage(this.#transport.defaults, {
763
+ language: options.language
764
+ }),
765
+ signal: options.signal
766
+ });
767
+ }
768
+ seasonImages(seriesId, seasonNumber, options = {}) {
769
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toSeasonNumber(seasonNumber)}/images`, {
770
+ query: withLanguage(this.#transport.defaults, {
771
+ include_image_language: toCommaList(options.includeImageLanguage),
772
+ language: options.language
773
+ }),
774
+ signal: options.signal
775
+ });
776
+ }
777
+ seasonVideos(seriesId, seasonNumber, options = {}) {
778
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toSeasonNumber(seasonNumber)}/videos`, {
779
+ query: withLanguage(this.#transport.defaults, {
780
+ language: options.language
781
+ }),
782
+ signal: options.signal
783
+ });
784
+ }
785
+ episodeDetails(seriesId, seasonNumber, episodeNumber, options = {}) {
786
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toSeasonNumber(seasonNumber)}/episode/${toId(episodeNumber, "episodeNumber")}`, {
787
+ query: withLanguage(this.#transport.defaults, {
788
+ append_to_response: toCommaList(options.appendToResponse),
789
+ language: options.language
790
+ }),
791
+ signal: options.signal
792
+ });
793
+ }
794
+ aggregateCredits(seriesId, options = {}) {
795
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/aggregate_credits`, {
796
+ query: withLanguage(this.#transport.defaults, {
797
+ language: options.language
798
+ }),
799
+ signal: options.signal
800
+ });
801
+ }
802
+ episodeGroups(seriesId, options = {}) {
803
+ return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/episode_groups`, {
804
+ query: withLanguage(this.#transport.defaults, {
805
+ language: options.language
806
+ }),
807
+ signal: options.signal
808
+ });
809
+ }
810
+ episodeGroup(groupId, options = {}) {
811
+ return this.#transport.get(`/tv/episode_group/${toGroupId(groupId)}`, {
812
+ query: withLanguage(this.#transport.defaults, {
813
+ language: options.language
814
+ }),
815
+ signal: options.signal
816
+ });
817
+ }
818
+ }
613
819
  function tvListQuery(transport, options) {
614
- return withLanguage(transport.defaults, {
615
- language: options.language,
616
- page: options.page
617
- });
618
- }
619
- //#endregion
620
- //#region src/client.ts
621
- /**
622
- * Main SDK entry point.
623
- *
624
- * Resource properties are intentionally small and explicit. The SDK focuses on
625
- * common TMDB workflows first, while request<T>() keeps uncommon endpoints easy
626
- * to call without waiting for a generated surface area.
627
- */
628
- var TMDBClient = class {
629
- configuration;
630
- genres;
631
- images;
632
- movies;
633
- people;
634
- search;
635
- trending;
636
- tv;
637
- #transport;
638
- constructor(options) {
639
- const { transport, images, ...httpOptions } = options;
640
- const fallbackTransform = images?.transform;
641
- const builtInClient = transport === void 0 ? new TMDBHttpClient({
642
- ...httpOptions,
643
- images
644
- }) : void 0;
645
- this.#transport = builtInClient ?? transport;
646
- this.configuration = new ConfigurationResource(this.#transport);
647
- this.genres = new GenresResource(this.#transport);
648
- this.images = new ImagesHelper(this.#transport, builtInClient ? builtInClient.imageTransform : fallbackTransform);
649
- this.movies = new MoviesResource(this.#transport);
650
- this.people = new PeopleResource(this.#transport);
651
- this.search = new SearchResource(this.#transport);
652
- this.trending = new TrendingResource(this.#transport);
653
- this.tv = new TVResource(this.#transport);
654
- }
655
- /**
656
- * Make a raw GET request to any TMDB endpoint.
657
- *
658
- * This is an escape hatch for endpoints not covered by the typed resource
659
- * helpers. The `path` should be relative to the API base URL (e.g.
660
- * `/movie/{id}/credits`). Response is parsed as JSON and cast to `T`.
661
- *
662
- * @param path - API path relative to the base URL (e.g. `/movie/123`)
663
- * @param options - Optional request-level overrides (headers, query, signal)
664
- * @returns Parsed JSON response typed as `T`
665
- */
666
- request(path, options) {
667
- return this.#transport.get(path, options);
668
- }
669
- };
670
- /**
671
- * Create a new {@link TMDBClient} instance.
672
- *
673
- * @example
674
- * ```ts
675
- * const tmdb = createTMDB({ accessToken: 'YOUR_TOKEN' })
676
- * const { results } = await tmdb.search.movies('Inception')
677
- * ```
678
- *
679
- * @param options - Authentication and configuration options
680
- * @returns A configured TMDBClient ready to make API calls
681
- */
820
+ return withLanguage(transport.defaults, {
821
+ language: options.language,
822
+ page: options.page
823
+ });
824
+ }
825
+
826
+ // src/client.ts
827
+ class TMDBClient {
828
+ configuration;
829
+ genres;
830
+ images;
831
+ movies;
832
+ people;
833
+ search;
834
+ trending;
835
+ tv;
836
+ #transport;
837
+ constructor(options) {
838
+ let imageTransform = options.images?.transform;
839
+ if (options.transport === undefined) {
840
+ const builtInClient = new TMDBHttpClient(options);
841
+ this.#transport = builtInClient;
842
+ imageTransform = builtInClient.imageTransform;
843
+ } else {
844
+ this.#transport = options.transport;
845
+ }
846
+ this.configuration = new ConfigurationResource(this.#transport);
847
+ this.genres = new GenresResource(this.#transport);
848
+ this.images = new ImagesHelper(this.#transport, imageTransform);
849
+ this.movies = new MoviesResource(this.#transport);
850
+ this.people = new PeopleResource(this.#transport);
851
+ this.search = new SearchResource(this.#transport);
852
+ this.trending = new TrendingResource(this.#transport);
853
+ this.tv = new TVResource(this.#transport);
854
+ }
855
+ request(path, options) {
856
+ return this.#transport.get(path, options);
857
+ }
858
+ }
682
859
  function createTMDB(options) {
683
- return new TMDBClient(options);
860
+ return new TMDBClient(options);
684
861
  }
685
- //#endregion
686
- //#region src/search-guards.ts
862
+ // src/helpers/cache.ts
863
+ function withMemoryCache(transport, options = {}) {
864
+ const ttlMs = options.ttlMs ?? 5 * 60000;
865
+ const maxEntries = options.maxEntries ?? 100;
866
+ if (!Number.isFinite(ttlMs) || ttlMs <= 0) {
867
+ throw new RangeError("ttlMs must be a positive number");
868
+ }
869
+ if (!Number.isInteger(maxEntries) || maxEntries < 1) {
870
+ throw new RangeError("maxEntries must be a positive integer");
871
+ }
872
+ const entries = new Map;
873
+ return {
874
+ ...transport,
875
+ async get(path, requestOptions = {}) {
876
+ const key = cacheKey(path, requestOptions);
877
+ const cached = entries.get(key);
878
+ if (cached !== undefined) {
879
+ if (cached.expiresAt > Date.now()) {
880
+ entries.delete(key);
881
+ entries.set(key, cached);
882
+ return cached.value;
883
+ }
884
+ entries.delete(key);
885
+ }
886
+ const value = await transport.get(path, requestOptions);
887
+ entries.set(key, { expiresAt: Date.now() + ttlMs, value });
888
+ evictOverflow(entries, maxEntries);
889
+ return value;
890
+ },
891
+ clear() {
892
+ entries.clear();
893
+ }
894
+ };
895
+ }
896
+ function cacheKey(path, options) {
897
+ return `${path}?${serializeQuery(options.query)}|${serializeHeaders(options.headers)}`;
898
+ }
899
+ function serializeQuery(query) {
900
+ if (query === undefined) {
901
+ return "";
902
+ }
903
+ return Object.entries(query).filter(([, value]) => value !== undefined && value !== null).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}=${Array.isArray(value) ? value.map(String).join(",") : String(value)}`).join("&");
904
+ }
905
+ function serializeHeaders(headers) {
906
+ if (headers === undefined) {
907
+ return "";
908
+ }
909
+ return [...new Headers(headers)].sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}:${value}`).join("|");
910
+ }
911
+ function evictOverflow(entries, maxEntries) {
912
+ while (entries.size > maxEntries) {
913
+ entries.delete(entries.keys().next().value);
914
+ }
915
+ }
916
+ // src/helpers/pagination.ts
917
+ async function* paginate(fetchPage, options = {}) {
918
+ const startPage = options.startPage ?? 1;
919
+ const endPage = options.endPage ?? 500;
920
+ assertPositiveInteger(startPage, "startPage");
921
+ assertPositiveInteger(endPage, "endPage");
922
+ for (let page = startPage;page <= endPage; page += 1) {
923
+ options.signal?.throwIfAborted();
924
+ const response = await fetchPage(page);
925
+ yield response;
926
+ if (response.results.length === 0 || page >= response.total_pages) {
927
+ return;
928
+ }
929
+ }
930
+ }
931
+ async function* paginateItems(fetchPage, options = {}) {
932
+ for await (const page of paginate(fetchPage, options)) {
933
+ yield* page.results;
934
+ }
935
+ }
936
+ function assertPositiveInteger(value, name) {
937
+ if (!Number.isInteger(value) || value < 1) {
938
+ throw new RangeError(`${name} must be a positive integer`);
939
+ }
940
+ }
941
+ // src/helpers/retry.ts
942
+ var MAX_RETRY_AFTER_MS = 60000;
943
+ async function retry(task, options = {}) {
944
+ const retries = options.retries ?? 2;
945
+ if (!Number.isInteger(retries) || retries < 0) {
946
+ throw new RangeError("retries must be a non-negative integer");
947
+ }
948
+ const retryOn = options.retryOn ?? shouldRetry;
949
+ const signal = options.signal;
950
+ if (signal?.aborted) {
951
+ throw signal.reason;
952
+ }
953
+ for (let attempt = 0;; attempt += 1) {
954
+ try {
955
+ return await task();
956
+ } catch (error) {
957
+ if (signal?.aborted) {
958
+ throw signal.reason;
959
+ }
960
+ if (attempt >= retries || !retryOn(error, attempt)) {
961
+ throw error;
962
+ }
963
+ const delayMs = retryDelay(error, attempt, options);
964
+ options.onRetry?.({ attempt, delayMs, error });
965
+ await sleep(delayMs, signal);
966
+ }
967
+ }
968
+ }
969
+ function withRetry(transport, options = {}) {
970
+ return {
971
+ ...transport,
972
+ get(path, requestOptions) {
973
+ const { cleanup, signal } = combineSignals(options.signal, requestOptions?.signal);
974
+ const effectiveOptions = signal === undefined ? requestOptions : { ...requestOptions, signal };
975
+ return retry(() => transport.get(path, effectiveOptions), {
976
+ ...options,
977
+ signal
978
+ }).finally(cleanup);
979
+ }
980
+ };
981
+ }
982
+ function shouldRetry(error) {
983
+ if (error instanceof TMDBRateLimitError) {
984
+ return true;
985
+ }
986
+ if (error instanceof TMDBResponseError) {
987
+ return error.isServerError || error.status === 408;
988
+ }
989
+ if (error instanceof TMDBTimeoutError) {
990
+ return false;
991
+ }
992
+ if (error instanceof TMDBRequestError) {
993
+ if (error.cause === undefined || error.cause instanceof TMDBTimeoutError) {
994
+ return false;
995
+ }
996
+ return !isAbortError(error.cause);
997
+ }
998
+ return false;
999
+ }
1000
+ function retryDelay(error, attempt, options) {
1001
+ const retryAfter = retryAfterMs(error);
1002
+ if (retryAfter !== undefined) {
1003
+ return Math.min(Math.max(retryAfter, 0), MAX_RETRY_AFTER_MS);
1004
+ }
1005
+ if (error instanceof TMDBRateLimitError) {
1006
+ return Math.min(Math.max(error.retryAfter * 1000, 0), MAX_RETRY_AFTER_MS);
1007
+ }
1008
+ const baseDelayMs = options.baseDelayMs ?? 250;
1009
+ const maxDelayMs = options.maxDelayMs ?? 1e4;
1010
+ const factor = options.factor ?? 2;
1011
+ const delay = Math.min(maxDelayMs, baseDelayMs * factor ** attempt);
1012
+ return options.jitter === false ? delay : Math.random() * delay;
1013
+ }
1014
+ function retryAfterMs(error) {
1015
+ if (!(error instanceof TMDBResponseError)) {
1016
+ return;
1017
+ }
1018
+ const header = error.headers.get("retry-after");
1019
+ if (header === null || header.trim() === "") {
1020
+ return;
1021
+ }
1022
+ return parseRetryAfter(header) * 1000;
1023
+ }
1024
+ function combineSignals(first, second) {
1025
+ if (first === undefined || second === undefined || first === second) {
1026
+ return { cleanup: noop, signal: first ?? second };
1027
+ }
1028
+ const controller = new AbortController;
1029
+ const onAbort = () => controller.abort((first.aborted ? first : second).reason);
1030
+ first.addEventListener("abort", onAbort, { once: true });
1031
+ second.addEventListener("abort", onAbort, { once: true });
1032
+ if (first.aborted || second.aborted) {
1033
+ onAbort();
1034
+ }
1035
+ return {
1036
+ cleanup() {
1037
+ first.removeEventListener("abort", onAbort);
1038
+ second.removeEventListener("abort", onAbort);
1039
+ },
1040
+ signal: controller.signal
1041
+ };
1042
+ }
1043
+ function noop() {}
1044
+ function isAbortError(error) {
1045
+ return typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
1046
+ }
1047
+ function sleep(ms, signal) {
1048
+ return new Promise((resolve, reject) => {
1049
+ const onAbort = () => {
1050
+ clearTimeout(timer);
1051
+ signal?.removeEventListener("abort", onAbort);
1052
+ reject(signal.reason);
1053
+ };
1054
+ const timer = setTimeout(() => {
1055
+ signal?.removeEventListener("abort", onAbort);
1056
+ resolve();
1057
+ }, ms);
1058
+ signal?.addEventListener("abort", onAbort, { once: true });
1059
+ if (signal?.aborted) {
1060
+ onAbort();
1061
+ }
1062
+ });
1063
+ }
1064
+ // src/helpers/timeout.ts
1065
+ async function withTimeout(timeoutMs, task, options = {}) {
1066
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1067
+ throw new RangeError("timeoutMs must be a positive number");
1068
+ }
1069
+ const parent = options.signal;
1070
+ const controller = new AbortController;
1071
+ const timeoutError = new TMDBTimeoutError(timeoutMs, options.message);
1072
+ const onAbort = () => controller.abort(parent.reason);
1073
+ parent?.addEventListener("abort", onAbort, { once: true });
1074
+ if (parent?.aborted) {
1075
+ parent.removeEventListener("abort", onAbort);
1076
+ throw parent.reason;
1077
+ }
1078
+ const timer = setTimeout(() => controller.abort(timeoutError), timeoutMs);
1079
+ try {
1080
+ return await task(controller.signal);
1081
+ } catch (error) {
1082
+ if (controller.signal.reason === timeoutError) {
1083
+ throw timeoutError;
1084
+ }
1085
+ if (parent?.aborted) {
1086
+ throw parent.reason;
1087
+ }
1088
+ throw error;
1089
+ } finally {
1090
+ clearTimeout(timer);
1091
+ parent?.removeEventListener("abort", onAbort);
1092
+ }
1093
+ }
1094
+ // src/search-guards.ts
687
1095
  function isMovieSearchResult(result) {
688
- return isObjectWithMediaType(result, "movie");
1096
+ return isObjectWithMediaType(result, "movie");
689
1097
  }
690
1098
  function isTVSearchResult(result) {
691
- return isObjectWithMediaType(result, "tv");
1099
+ return isObjectWithMediaType(result, "tv");
692
1100
  }
693
1101
  function isPersonSearchResult(result) {
694
- return isObjectWithMediaType(result, "person");
1102
+ return isObjectWithMediaType(result, "person");
695
1103
  }
696
1104
  function isMovie(result) {
697
- return isObjectWithMediaType(result, "movie");
1105
+ return isObjectWithMediaType(result, "movie");
698
1106
  }
699
1107
  function isTV(result) {
700
- return isObjectWithMediaType(result, "tv");
1108
+ return isObjectWithMediaType(result, "tv");
701
1109
  }
702
1110
  function isPerson(result) {
703
- return isObjectWithMediaType(result, "person");
1111
+ return isObjectWithMediaType(result, "person");
704
1112
  }
705
- /** Internal helper: check if a value is an object with a matching `media_type` field. */
706
1113
  function isObjectWithMediaType(value, mediaType) {
707
- return typeof value === "object" && value !== null && "media_type" in value && value.media_type === mediaType;
708
- }
709
- //#endregion
710
- //#region src/types.ts
711
- /**
712
- * Public set of image sizes TMDB currently documents. The SDK does not
713
- * pin to a static copy of the TMDB docs — TMDB has added new sizes in
714
- * the past (e.g. `h632` for profile) without notice — but exposing the
715
- * canonical list lets callers:
716
- *
717
- * - iterate over the set to build a size picker
718
- * - validate user-supplied sizes with `isKnownBackdropSize(...)` etc.
719
- * - type a variable as a "known" size without giving up the
720
- * `(string & {})` escape hatch for forward-compatibility
721
- *
722
- * If TMDB publishes a new size, the SDK will still accept it at runtime
723
- * (every helper is `(string & {})` permissive), but you will need to
724
- * add the literal to these constants to get autocomplete on it.
725
- */
726
- const KNOWN_BACKDROP_SIZES = Object.freeze([
727
- "w300",
728
- "w780",
729
- "w1280",
730
- "original"
731
- ]);
732
- const KNOWN_LOGO_SIZES = Object.freeze([
733
- "w45",
734
- "w92",
735
- "w154",
736
- "w185",
737
- "w300",
738
- "w500",
739
- "original"
740
- ]);
741
- const KNOWN_POSTER_SIZES = Object.freeze([
742
- "w92",
743
- "w154",
744
- "w185",
745
- "w342",
746
- "w500",
747
- "w780",
748
- "original"
1114
+ return typeof value === "object" && value !== null && "media_type" in value && value.media_type === mediaType;
1115
+ }
1116
+ // src/types.ts
1117
+ var KNOWN_BACKDROP_SIZES = Object.freeze([
1118
+ "w300",
1119
+ "w780",
1120
+ "w1280",
1121
+ "original"
749
1122
  ]);
750
- const KNOWN_PROFILE_SIZES = Object.freeze([
751
- "w45",
752
- "w185",
753
- "h632",
754
- "original"
1123
+ var KNOWN_LOGO_SIZES = Object.freeze(["w45", "w92", "w154", "w185", "w300", "w500", "original"]);
1124
+ var KNOWN_POSTER_SIZES = Object.freeze(["w92", "w154", "w185", "w342", "w500", "w780", "original"]);
1125
+ var KNOWN_PROFILE_SIZES = Object.freeze([
1126
+ "w45",
1127
+ "w185",
1128
+ "h632",
1129
+ "original"
755
1130
  ]);
756
- const KNOWN_STILL_SIZES = Object.freeze([
757
- "w92",
758
- "w185",
759
- "w300",
760
- "original"
1131
+ var KNOWN_STILL_SIZES = Object.freeze([
1132
+ "w92",
1133
+ "w185",
1134
+ "w300",
1135
+ "original"
761
1136
  ]);
762
- /** Union of every documented image size. */
763
- const KNOWN_IMAGE_SIZES = Object.freeze([
764
- ...KNOWN_BACKDROP_SIZES,
765
- ...KNOWN_LOGO_SIZES,
766
- ...KNOWN_POSTER_SIZES,
767
- ...KNOWN_PROFILE_SIZES,
768
- ...KNOWN_STILL_SIZES
1137
+ var KNOWN_IMAGE_SIZES = Object.freeze([
1138
+ ...KNOWN_BACKDROP_SIZES,
1139
+ ...KNOWN_LOGO_SIZES,
1140
+ ...KNOWN_POSTER_SIZES,
1141
+ ...KNOWN_PROFILE_SIZES,
1142
+ ...KNOWN_STILL_SIZES
769
1143
  ]);
770
- /** O(1) membership check backed by a Set. */
771
- const KNOWN_BACKDROP_SET = new Set(KNOWN_BACKDROP_SIZES);
772
- const KNOWN_LOGO_SET = new Set(KNOWN_LOGO_SIZES);
773
- const KNOWN_POSTER_SET = new Set(KNOWN_POSTER_SIZES);
774
- const KNOWN_PROFILE_SET = new Set(KNOWN_PROFILE_SIZES);
775
- const KNOWN_STILL_SET = new Set(KNOWN_STILL_SIZES);
776
- const KNOWN_IMAGE_SET = new Set(KNOWN_IMAGE_SIZES);
1144
+ var KNOWN_BACKDROP_SET = new Set(KNOWN_BACKDROP_SIZES);
1145
+ var KNOWN_LOGO_SET = new Set(KNOWN_LOGO_SIZES);
1146
+ var KNOWN_POSTER_SET = new Set(KNOWN_POSTER_SIZES);
1147
+ var KNOWN_PROFILE_SET = new Set(KNOWN_PROFILE_SIZES);
1148
+ var KNOWN_STILL_SET = new Set(KNOWN_STILL_SIZES);
1149
+ var KNOWN_IMAGE_SET = new Set(KNOWN_IMAGE_SIZES);
777
1150
  function isKnownBackdropSize(value) {
778
- return KNOWN_BACKDROP_SET.has(value);
1151
+ return KNOWN_BACKDROP_SET.has(value);
779
1152
  }
780
1153
  function isKnownLogoSize(value) {
781
- return KNOWN_LOGO_SET.has(value);
1154
+ return KNOWN_LOGO_SET.has(value);
782
1155
  }
783
1156
  function isKnownPosterSize(value) {
784
- return KNOWN_POSTER_SET.has(value);
1157
+ return KNOWN_POSTER_SET.has(value);
785
1158
  }
786
1159
  function isKnownProfileSize(value) {
787
- return KNOWN_PROFILE_SET.has(value);
1160
+ return KNOWN_PROFILE_SET.has(value);
788
1161
  }
789
1162
  function isKnownStillSize(value) {
790
- return KNOWN_STILL_SET.has(value);
1163
+ return KNOWN_STILL_SET.has(value);
791
1164
  }
792
- /** True if `value` is in any documented size set. */
793
1165
  function isKnownImageSize(value) {
794
- return KNOWN_IMAGE_SET.has(value);
795
- }
796
- //#endregion
797
- exports.KNOWN_BACKDROP_SIZES = KNOWN_BACKDROP_SIZES;
798
- exports.KNOWN_IMAGE_SIZES = KNOWN_IMAGE_SIZES;
799
- exports.KNOWN_LOGO_SIZES = KNOWN_LOGO_SIZES;
800
- exports.KNOWN_POSTER_SIZES = KNOWN_POSTER_SIZES;
801
- exports.KNOWN_PROFILE_SIZES = KNOWN_PROFILE_SIZES;
802
- exports.KNOWN_STILL_SIZES = KNOWN_STILL_SIZES;
803
- exports.TMDBClient = TMDBClient;
804
- exports.TMDBError = TMDBError;
805
- exports.TMDBRateLimitError = TMDBRateLimitError;
806
- exports.TMDBRequestError = TMDBRequestError;
807
- exports.TMDBResponseError = TMDBResponseError;
808
- exports.buildImageUrl = buildImageUrl;
809
- exports.createTMDB = createTMDB;
810
- exports.isKnownBackdropSize = isKnownBackdropSize;
811
- exports.isKnownImageSize = isKnownImageSize;
812
- exports.isKnownLogoSize = isKnownLogoSize;
813
- exports.isKnownPosterSize = isKnownPosterSize;
814
- exports.isKnownProfileSize = isKnownProfileSize;
815
- exports.isKnownStillSize = isKnownStillSize;
816
- exports.isMovie = isMovie;
817
- exports.isMovieSearchResult = isMovieSearchResult;
818
- exports.isPerson = isPerson;
819
- exports.isPersonSearchResult = isPersonSearchResult;
820
- exports.isTV = isTV;
821
- exports.isTVSearchResult = isTVSearchResult;
1166
+ return KNOWN_IMAGE_SET.has(value);
1167
+ }
822
1168
 
823
- //# sourceMappingURL=index.cjs.map
1169
+ //# debugId=D1FA66D9B94DF6A164756E2164756E21
1170
+ //# sourceMappingURL=index.cjs.map