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.
- package/README.md +455 -196
- package/dist/cli.js +3823 -0
- package/dist/client.d.cts +71 -0
- package/dist/client.d.ts +71 -0
- package/dist/errors.d.cts +86 -0
- package/dist/errors.d.ts +86 -0
- package/dist/helpers/cache.d.cts +28 -0
- package/dist/helpers/cache.d.ts +28 -0
- package/dist/helpers/pagination.d.cts +35 -0
- package/dist/helpers/pagination.d.ts +35 -0
- package/dist/helpers/retry.d.cts +47 -0
- package/dist/helpers/retry.d.ts +47 -0
- package/dist/helpers/timeout.d.cts +20 -0
- package/dist/helpers/timeout.d.ts +20 -0
- package/dist/http.d.cts +80 -0
- package/dist/http.d.ts +80 -0
- package/dist/index.cjs +1115 -768
- package/dist/index.cjs.map +27 -1
- package/dist/index.d.cts +13 -783
- package/dist/index.d.ts +13 -783
- package/dist/index.js +1074 -744
- package/dist/index.js.map +27 -1
- package/dist/query.d.cts +91 -0
- package/dist/query.d.ts +91 -0
- package/dist/resources/configuration.d.cts +17 -0
- package/dist/resources/configuration.d.ts +17 -0
- package/dist/resources/genres.d.cts +13 -0
- package/dist/resources/genres.d.ts +13 -0
- package/dist/resources/images.d.cts +17 -0
- package/dist/resources/images.d.ts +17 -0
- package/dist/resources/movies.d.cts +21 -0
- package/dist/resources/movies.d.ts +21 -0
- package/dist/resources/people.d.cts +14 -0
- package/dist/resources/people.d.ts +14 -0
- package/dist/resources/search.d.cts +15 -0
- package/dist/resources/search.d.ts +15 -0
- package/dist/resources/trending.d.cts +23 -0
- package/dist/resources/trending.d.ts +23 -0
- package/dist/resources/tv.d.cts +30 -0
- package/dist/resources/tv.d.ts +30 -0
- package/dist/search-guards.d.cts +32 -0
- package/dist/search-guards.d.ts +32 -0
- package/dist/types.d.cts +550 -0
- package/dist/types.d.ts +550 -0
- package/package.json +26 -19
package/README.md
CHANGED
|
@@ -6,29 +6,70 @@
|
|
|
6
6
|
[](https://nodejs.org)
|
|
7
7
|
[](https://github.com/isaced/tmdb-kit/actions/workflows/ci.yml)
|
|
8
8
|
|
|
9
|
-
A minimal, fully typed
|
|
10
|
-
|
|
11
|
-
`tmdb-kit` covers
|
|
9
|
+
A minimal, fully typed SDK and read-only command-line interface (CLI) for The Movie Database (TMDB). Zero runtime dependencies. Built for Node.js, Bun, and edge runtimes.
|
|
10
|
+
|
|
11
|
+
`tmdb-kit` covers common TMDB workflows: movies, TV shows, search, trending, people, genres, and images. Use it as a library, or run the bundled `tmdb` command in your terminal.
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- [Features](#features)
|
|
16
|
+
- [Install](#install)
|
|
17
|
+
- [SDK](#sdk)
|
|
18
|
+
- [Create a client](#create-a-client)
|
|
19
|
+
- [Authentication](#authentication)
|
|
20
|
+
- [Configuration](#configuration)
|
|
21
|
+
- [Custom transport](#custom-transport)
|
|
22
|
+
- [Cancellation](#cancellation)
|
|
23
|
+
- [Supported resources](#supported-resources)
|
|
24
|
+
- [Image URLs](#image-urls)
|
|
25
|
+
- [Search](#search)
|
|
26
|
+
- [Image sizes](#image-sizes)
|
|
27
|
+
- [Errors](#errors)
|
|
28
|
+
- [Optional helpers](#optional-helpers)
|
|
29
|
+
- [CLI](#cli)
|
|
30
|
+
- [Credentials and config](#credentials-and-config)
|
|
31
|
+
- [Commands](#commands)
|
|
32
|
+
- [Common options](#common-options)
|
|
33
|
+
- [Output and exit codes](#output-and-exit-codes)
|
|
34
|
+
- [Examples](#examples)
|
|
35
|
+
- [Development](#development)
|
|
36
|
+
- [References](#references)
|
|
12
37
|
|
|
13
38
|
## Features
|
|
14
39
|
|
|
15
|
-
- **Zero dependencies
|
|
16
|
-
- **Universal runtime
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
40
|
+
- **Zero dependencies**: nothing to audit, nothing to conflict.
|
|
41
|
+
- **Universal runtime**: uses only `fetch`, `Headers`, `URL`, and `AbortSignal`. Works on Node.js 18+, Bun, Cloudflare Workers, Vercel Edge, and any fetch-compatible environment.
|
|
42
|
+
- **SDK and CLI**: typed resource methods for your app, plus `tmdb` and `tmdb-kit` binaries for terminal use.
|
|
43
|
+
- **Strict TypeScript**: full type safety with autocomplete for request options, response shapes, image sizes, and error handling.
|
|
44
|
+
- **ESM output**: modern module output with bundled type declarations.
|
|
45
|
+
- **Typed resources**: first-class methods for movies, TV, search, trending, people, genres, configuration, and images.
|
|
46
|
+
- **Injectable transport**: swap the HTTP layer for tests, caching, or instrumentation without mocking `fetch`.
|
|
47
|
+
- **Optional helpers**: async pagination, `Retry-After`-aware retries, `AbortSignal` timeouts, and an LRU memory cache — all opt-in and tree-shakeable.
|
|
48
|
+
- **Image helpers**: build content delivery network (CDN), proxy, or signed URLs with per-request transform overrides.
|
|
49
|
+
- **Search type guards**: narrow `search.multi()` results to movies, TV, or people with runtime-checked helpers.
|
|
50
|
+
- **Tested**: unit and resource tests mock `fetch`; an optional live integration suite validates real API behavior, including the helpers.
|
|
24
51
|
|
|
25
52
|
## Install
|
|
26
53
|
|
|
54
|
+
Install the SDK with npm:
|
|
55
|
+
|
|
27
56
|
```bash
|
|
28
57
|
npm install tmdb-kit
|
|
29
58
|
```
|
|
30
59
|
|
|
31
|
-
|
|
60
|
+
Install the CLI globally:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install --global tmdb-kit
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The CLI is available as `tmdb`.
|
|
67
|
+
|
|
68
|
+
## SDK
|
|
69
|
+
|
|
70
|
+
Create a client, authenticate, and call typed resource methods. The client uses the Fetch API and has no runtime dependencies.
|
|
71
|
+
|
|
72
|
+
### Create a client
|
|
32
73
|
|
|
33
74
|
```ts
|
|
34
75
|
import { createTMDB } from 'tmdb-kit'
|
|
@@ -46,79 +87,60 @@ const movie = await tmdb.movies.details(popular.results[0]!.id, {
|
|
|
46
87
|
const posterUrl = tmdb.images.url(movie.poster_path, 'w500')
|
|
47
88
|
```
|
|
48
89
|
|
|
49
|
-
|
|
90
|
+
### Authentication
|
|
50
91
|
|
|
51
|
-
|
|
52
|
-
const { createTMDB } = require('tmdb-kit')
|
|
92
|
+
The SDK targets the TMDB v3 API at `api.themoviedb.org/3`. Two authentication methods are supported.
|
|
53
93
|
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Deno:
|
|
94
|
+
An API Read Access Token is recommended and works with both v3 and v4:
|
|
58
95
|
|
|
59
96
|
```ts
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const tmdb = createTMDB({ accessToken: Deno.env.get('TMDB_ACCESS_TOKEN')! })
|
|
97
|
+
createTMDB({ accessToken: 'your_access_token_here' })
|
|
63
98
|
```
|
|
64
99
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
The SDK targets the **TMDB v3 API** (`api.themoviedb.org/3`). Two authentication methods are supported:
|
|
68
|
-
|
|
69
|
-
**API Read Access Token** (recommended) — works with both v3 and v4:
|
|
100
|
+
A legacy v3 API key is sent as an `api_key` query parameter:
|
|
70
101
|
|
|
71
102
|
```ts
|
|
72
|
-
createTMDB({
|
|
103
|
+
createTMDB({ apiKey: 'your_api_key_here' })
|
|
73
104
|
```
|
|
74
105
|
|
|
75
|
-
|
|
106
|
+
Pass exactly one of `accessToken` or `apiKey`. The client throws when both or neither are set. When you supply a `transport`, credentials are optional because the transport owns authentication.
|
|
76
107
|
|
|
77
|
-
|
|
78
|
-
createTMDB({ apiKey: 'tmdb-v3-api-key' })
|
|
79
|
-
```
|
|
108
|
+
### Configuration
|
|
80
109
|
|
|
81
|
-
|
|
110
|
+
`createTMDB` accepts these options:
|
|
82
111
|
|
|
83
|
-
|
|
112
|
+
| Option | Default | Description |
|
|
113
|
+
| ------------------ | --------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
114
|
+
| `accessToken` | required unless `apiKey` or `transport` is set | API Read Access Token, sent as a Bearer header. |
|
|
115
|
+
| `apiKey` | required unless `accessToken` or `transport` is set | Legacy v3 API key, sent as `api_key`. |
|
|
116
|
+
| `baseUrl` | `https://api.themoviedb.org/3` | API base URL. Useful for proxies and tests. |
|
|
117
|
+
| `fetch` | `globalThis.fetch` at request time | Custom fetch implementation. |
|
|
118
|
+
| `defaultLanguage` | TMDB default | Language for endpoints that accept `language`. |
|
|
119
|
+
| `defaultRegion` | TMDB default | Region for movie lists and search endpoints that accept `region`. |
|
|
120
|
+
| `imageBaseUrl` | `https://image.tmdb.org/t/p` | Image host used by `tmdb.images`. |
|
|
121
|
+
| `images.transform` | none | Default URL transform for `tmdb.images.url()`. |
|
|
122
|
+
| `headers` | none | Extra headers merged into every request before authentication. |
|
|
123
|
+
| `transport` | built-in HTTP client | Custom transport; credentials are not required. See [Custom transport](#custom-transport). |
|
|
84
124
|
|
|
85
|
-
|
|
125
|
+
A typical client:
|
|
86
126
|
|
|
87
127
|
```ts
|
|
88
|
-
import { createTMDB } from 'tmdb-kit'
|
|
89
|
-
|
|
90
128
|
const tmdb = createTMDB({
|
|
91
|
-
accessToken: '
|
|
92
|
-
|
|
93
|
-
// Defaults to https://api.themoviedb.org/3. Useful for tests or proxies.
|
|
94
|
-
baseUrl: 'https://api.themoviedb.org/3',
|
|
95
|
-
|
|
96
|
-
// Inject a fetch implementation. The SDK reads `globalThis.fetch` lazily
|
|
97
|
-
// on every request, so test-time mocks (vi.spyOn, etc.) are picked up
|
|
98
|
-
// automatically after the client has been constructed.
|
|
99
|
-
fetch: customFetch,
|
|
100
|
-
|
|
101
|
-
// Defaults applied to every request that supports them.
|
|
129
|
+
accessToken: 'your_access_token_here',
|
|
102
130
|
defaultLanguage: 'en-US',
|
|
103
131
|
defaultRegion: 'US',
|
|
104
|
-
|
|
105
|
-
// Custom image host. Defaults to https://image.tmdb.org/t/p.
|
|
106
|
-
imageBaseUrl: 'https://image.tmdb.org/t/p',
|
|
107
|
-
|
|
108
|
-
// Image URL transform applied by the ImagesHelper. See "Image URLs".
|
|
132
|
+
headers: { 'X-Client': 'my-app' },
|
|
109
133
|
images: {
|
|
110
134
|
transform: (url) => url.replace('image.tmdb.org/t/p', 'img-proxy.example/tmdb'),
|
|
111
135
|
},
|
|
112
|
-
|
|
113
|
-
// Extra headers merged into every request before authentication.
|
|
114
|
-
headers: { 'X-Client': 'my-app' },
|
|
115
136
|
})
|
|
116
137
|
```
|
|
117
138
|
|
|
118
|
-
|
|
139
|
+
The SDK reads `globalThis.fetch` lazily on every request. Spies on `globalThis.fetch` are picked up after the client has been constructed.
|
|
119
140
|
|
|
120
|
-
|
|
121
|
-
|
|
141
|
+
### Custom transport
|
|
142
|
+
|
|
143
|
+
For tests, caching, or instrumentation, swap the entire transport layer instead of mocking `fetch`:
|
|
122
144
|
|
|
123
145
|
```ts
|
|
124
146
|
import { createTMDB, type TMDBTransport } from 'tmdb-kit'
|
|
@@ -128,64 +150,39 @@ const stub: TMDBTransport = {
|
|
|
128
150
|
get: async (path, _options) => ({ results: [] }),
|
|
129
151
|
}
|
|
130
152
|
|
|
131
|
-
const tmdb = createTMDB({
|
|
153
|
+
const tmdb = createTMDB({ transport: stub })
|
|
132
154
|
```
|
|
133
155
|
|
|
134
|
-
`transport.get()`
|
|
135
|
-
|
|
136
|
-
|
|
156
|
+
`transport.get()` runs for every resource and for `request()`, so a single stub covers the whole surface. `TMDBTransport` is part of the public API. The built-in `TMDBHttpClient` is exported too, so you can wrap it instead of reimplementing authentication.
|
|
157
|
+
|
|
158
|
+
### Cancellation
|
|
137
159
|
|
|
138
|
-
|
|
160
|
+
Every resource method accepts an `AbortSignal` through its options. Pass the same signal to cancel one or more requests:
|
|
139
161
|
|
|
140
162
|
```ts
|
|
141
|
-
|
|
142
|
-
tmdb.movies.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
tmdb.movies.credits(550)
|
|
147
|
-
tmdb.movies.images(550)
|
|
148
|
-
tmdb.movies.recommendations(550)
|
|
149
|
-
tmdb.movies.similar(550)
|
|
150
|
-
tmdb.movies.videos(550)
|
|
151
|
-
|
|
152
|
-
tmdb.tv.popular()
|
|
153
|
-
tmdb.tv.topRated()
|
|
154
|
-
tmdb.tv.airingToday()
|
|
155
|
-
tmdb.tv.onTheAir()
|
|
156
|
-
tmdb.tv.details(1399)
|
|
157
|
-
tmdb.tv.credits(1399)
|
|
158
|
-
tmdb.tv.images(1399)
|
|
159
|
-
tmdb.tv.recommendations(1399)
|
|
160
|
-
tmdb.tv.similar(1399)
|
|
161
|
-
tmdb.tv.videos(1399)
|
|
162
|
-
tmdb.tv.seasonDetails(1399, 1)
|
|
163
|
-
|
|
164
|
-
tmdb.search.movies('Dune')
|
|
165
|
-
tmdb.search.tv('Dark')
|
|
166
|
-
tmdb.search.people('Sofia Coppola')
|
|
167
|
-
tmdb.search.multi('Tom Hardy')
|
|
168
|
-
|
|
169
|
-
tmdb.trending.all('week')
|
|
170
|
-
tmdb.trending.movies('day')
|
|
171
|
-
tmdb.trending.tv('day')
|
|
172
|
-
tmdb.trending.people('week')
|
|
173
|
-
|
|
174
|
-
tmdb.people.popular()
|
|
175
|
-
tmdb.people.details(31)
|
|
176
|
-
|
|
177
|
-
tmdb.genres.movies()
|
|
178
|
-
tmdb.genres.tv()
|
|
179
|
-
|
|
180
|
-
tmdb.configuration.details()
|
|
181
|
-
tmdb.configuration.countries()
|
|
182
|
-
tmdb.configuration.jobs()
|
|
183
|
-
tmdb.configuration.languages()
|
|
184
|
-
tmdb.configuration.primaryTranslations()
|
|
185
|
-
tmdb.configuration.timezones()
|
|
163
|
+
const controller = new AbortController()
|
|
164
|
+
const promise = tmdb.movies.popular({ signal: controller.signal })
|
|
165
|
+
|
|
166
|
+
controller.abort()
|
|
167
|
+
await promise // rejects with an AbortError
|
|
186
168
|
```
|
|
187
169
|
|
|
188
|
-
|
|
170
|
+
`client.request()` accepts the same `signal`. The SDK does not impose a timeout by default; use the optional `withTimeout()` helper (see [Optional helpers](#optional-helpers)) or your runtime's `AbortSignal.timeout()` when you need one.
|
|
171
|
+
|
|
172
|
+
### Supported resources
|
|
173
|
+
|
|
174
|
+
| Resource | Methods |
|
|
175
|
+
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
176
|
+
| `tmdb.movies` | `popular()`, `topRated()`, `nowPlaying()`, `upcoming()`, `details()`, `credits()`, `images()`, `recommendations()`, `similar()`, `videos()` |
|
|
177
|
+
| `tmdb.tv` | `popular()`, `topRated()`, `airingToday()`, `onTheAir()`, `details()`, `credits()`, `images()`, `recommendations()`, `similar()`, `videos()`, `seasonDetails()`, `seasonCredits()`, `seasonAggregateCredits()`, `seasonImages()`, `seasonVideos()`, `episodeDetails()`, `aggregateCredits()`, `episodeGroups()`, `episodeGroup()` |
|
|
178
|
+
| `tmdb.search` | `movies()`, `tv()`, `people()`, `multi()` |
|
|
179
|
+
| `tmdb.trending` | `all()`, `movies()`, `tv()`, `people()` |
|
|
180
|
+
| `tmdb.people` | `popular()`, `details()`, `combinedCredits()` |
|
|
181
|
+
| `tmdb.genres` | `movies()`, `tv()` |
|
|
182
|
+
| `tmdb.configuration` | `details()`, `countries()`, `jobs()`, `languages()`, `primaryTranslations()`, `timezones()` |
|
|
183
|
+
| `tmdb.images` | `url()` |
|
|
184
|
+
|
|
185
|
+
For an endpoint that is not wrapped yet, use the `request()` escape hatch:
|
|
189
186
|
|
|
190
187
|
```ts
|
|
191
188
|
const response = await tmdb.request<{ results: unknown[] }>('/discover/movie', {
|
|
@@ -196,34 +193,29 @@ const response = await tmdb.request<{ results: unknown[] }>('/discover/movie', {
|
|
|
196
193
|
})
|
|
197
194
|
```
|
|
198
195
|
|
|
199
|
-
|
|
196
|
+
### Image URLs
|
|
200
197
|
|
|
201
|
-
`tmdb.images.url(path, size)` builds a fully
|
|
202
|
-
helper returns `null` for nullish paths so UI code can branch naturally:
|
|
198
|
+
`tmdb.images.url(path, size)` builds a fully qualified image URL. It returns `null` for nullish paths so UI code can branch naturally:
|
|
203
199
|
|
|
204
200
|
```ts
|
|
205
201
|
const posterUrl = tmdb.images.url(movie.poster_path, 'w500')
|
|
206
202
|
```
|
|
207
203
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
Pass a `transform` callback to rewrite the resolved URL. The most common
|
|
211
|
-
use case is pointing TMDB image requests at a self-hosted proxy:
|
|
204
|
+
Pass a `transform` callback to route images through a CDN or proxy:
|
|
212
205
|
|
|
213
206
|
```ts
|
|
214
207
|
const tmdb = createTMDB({
|
|
215
|
-
accessToken: '
|
|
208
|
+
accessToken: 'your_access_token_here',
|
|
216
209
|
images: {
|
|
217
210
|
transform: (url) => url.replace('https://image.tmdb.org/t/p', 'https://img-proxy.example/tmdb'),
|
|
218
211
|
},
|
|
219
212
|
})
|
|
220
213
|
|
|
221
214
|
tmdb.images.url('/abc.jpg', 'w500')
|
|
222
|
-
//
|
|
215
|
+
// 'https://img-proxy.example/tmdb/w500/abc.jpg'
|
|
223
216
|
```
|
|
224
217
|
|
|
225
|
-
|
|
226
|
-
signed query parameters for selected sizes:
|
|
218
|
+
Pass a one-off transform per call to add signed query parameters:
|
|
227
219
|
|
|
228
220
|
```ts
|
|
229
221
|
tmdb.images.url('/abc.jpg', 'original', {
|
|
@@ -231,25 +223,14 @@ tmdb.images.url('/abc.jpg', 'original', {
|
|
|
231
223
|
})
|
|
232
224
|
```
|
|
233
225
|
|
|
234
|
-
The transform is never invoked for nullish paths, so `null` results stay
|
|
235
|
-
`null`.
|
|
236
|
-
|
|
237
|
-
`buildImageUrl(path, size, options)` is exported directly for callers
|
|
238
|
-
that want to build URLs without a `TMDBClient` instance.
|
|
226
|
+
The transform is never invoked for nullish paths, so `null` results stay `null`. `buildImageUrl(path, size, options)` is exported for callers that build URLs without a `TMDBClient` instance.
|
|
239
227
|
|
|
240
|
-
|
|
228
|
+
### Search
|
|
241
229
|
|
|
242
|
-
`search.multi()` returns a union of movie
|
|
243
|
-
out media types you do not want and narrow the result type with the
|
|
244
|
-
provided type guards:
|
|
230
|
+
`search.multi()` returns a union of movie, TV, and person results. Filter media types and narrow the result type with the provided type guards:
|
|
245
231
|
|
|
246
232
|
```ts
|
|
247
|
-
import {
|
|
248
|
-
createTMDB,
|
|
249
|
-
isMovieSearchResult,
|
|
250
|
-
isTVSearchResult,
|
|
251
|
-
isPersonSearchResult,
|
|
252
|
-
} from 'tmdb-kit'
|
|
233
|
+
import { createTMDB, isMovieSearchResult, isTVSearchResult, isPersonSearchResult } from 'tmdb-kit'
|
|
253
234
|
|
|
254
235
|
const { results } = await tmdb.search.multi('Inception', {
|
|
255
236
|
exclude: ['person'],
|
|
@@ -260,104 +241,382 @@ const tvShows = results.filter(isTVSearchResult) // TVMultiResult[]
|
|
|
260
241
|
const people = results.filter(isPersonSearchResult) // PersonMultiResult[]
|
|
261
242
|
```
|
|
262
243
|
|
|
263
|
-
|
|
264
|
-
endpoint has no server-side media_type filter. `total_results` reflects
|
|
265
|
-
the unfiltered payload; the filtered count is just `results.length`.
|
|
266
|
-
- Short-name aliases `isMovie` / `isTV` / `isPerson` are also exported
|
|
267
|
-
for callers that prefer them.
|
|
268
|
-
- The single-resource search methods (`search.movies`, `search.tv`,
|
|
269
|
-
`search.people`) already return the narrowed result type, so the
|
|
270
|
-
guards are only useful for `search.multi()` payloads.
|
|
244
|
+
`exclude` performs client-side filtering because the TMDB multi-search endpoint has no server-side media type filter. `total_results` reflects the unfiltered payload, and the filtered count is `results.length`.
|
|
271
245
|
|
|
272
|
-
|
|
246
|
+
The short-name aliases `isMovie`, `isTV`, and `isPerson` are also exported. The single-resource search methods already return narrowed types, so the guards matter only for `search.multi()`.
|
|
273
247
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
keeps the `(string & {})` escape hatch
|
|
277
|
-
working at runtime. If you need the canonical set of documented sizes,
|
|
278
|
-
the SDK ships them as readonly constants:
|
|
248
|
+
### Image sizes
|
|
249
|
+
|
|
250
|
+
The `ImageSize` type is intentionally permissive. TMDB has added sizes without notice, such as `h632` for profiles, so the SDK keeps the `(string & {})` escape hatch for forward compatibility. The SDK also ships the documented sizes as readonly constants:
|
|
279
251
|
|
|
280
252
|
```ts
|
|
281
|
-
import {
|
|
282
|
-
|
|
283
|
-
KNOWN_LOGO_SIZES,
|
|
284
|
-
KNOWN_POSTER_SIZES,
|
|
285
|
-
KNOWN_PROFILE_SIZES,
|
|
286
|
-
KNOWN_STILL_SIZES,
|
|
287
|
-
KNOWN_IMAGE_SIZES,
|
|
288
|
-
isKnownBackdropSize,
|
|
289
|
-
isKnownImageSize,
|
|
290
|
-
// …plus one helper per type
|
|
291
|
-
} from 'tmdb-kit'
|
|
292
|
-
|
|
293
|
-
// Iterate to build a size picker
|
|
253
|
+
import { KNOWN_POSTER_SIZES, isKnownPosterSize } from 'tmdb-kit'
|
|
254
|
+
|
|
294
255
|
for (const size of KNOWN_POSTER_SIZES) {
|
|
295
256
|
console.log(size) // 'w92' | 'w154' | 'w185' | 'w342' | 'w500' | 'w780' | 'original'
|
|
296
257
|
}
|
|
297
258
|
|
|
298
|
-
// Validate user-supplied sizes at runtime
|
|
299
259
|
if (!isKnownPosterSize(userInput)) {
|
|
300
260
|
throw new Error(`Unknown TMDB poster size: ${userInput}`)
|
|
301
261
|
}
|
|
302
262
|
```
|
|
303
263
|
|
|
304
|
-
`
|
|
305
|
-
`KnownProfileSize` / `KnownStillSize` / `KnownImageSize` are the
|
|
306
|
-
matching TS literal-union types for callers that want strict typing
|
|
307
|
-
without giving up forward-compatibility.
|
|
264
|
+
The SDK also exports `KNOWN_BACKDROP_SIZES`, `KNOWN_LOGO_SIZES`, `KNOWN_PROFILE_SIZES`, `KNOWN_STILL_SIZES`, `KNOWN_IMAGE_SIZES`, and a matching type guard for each list. The literal-union types are `KnownBackdropSize`, `KnownPosterSize`, `KnownLogoSize`, `KnownProfileSize`, `KnownStillSize`, and `KnownImageSize`.
|
|
308
265
|
|
|
309
|
-
|
|
266
|
+
### Errors
|
|
310
267
|
|
|
311
268
|
```ts
|
|
312
|
-
import {
|
|
313
|
-
TMDBRateLimitError,
|
|
314
|
-
TMDBRequestError,
|
|
315
|
-
TMDBResponseError,
|
|
316
|
-
} from 'tmdb-kit'
|
|
269
|
+
import { TMDBRateLimitError, TMDBRequestError, TMDBResponseError, TMDBTimeoutError } from 'tmdb-kit'
|
|
317
270
|
|
|
318
271
|
try {
|
|
319
272
|
await tmdb.movies.popular()
|
|
320
273
|
} catch (error) {
|
|
321
274
|
if (error instanceof TMDBRateLimitError) {
|
|
322
|
-
// 429
|
|
323
|
-
//
|
|
324
|
-
// policy) and try again.
|
|
275
|
+
// 429: TMDB asked the caller to back off. The SDK does not retry by
|
|
276
|
+
// default; use retry() or withRetry() if you want automatic backoff.
|
|
325
277
|
console.log('rate limited; retry in', error.retryAfter, 's')
|
|
326
278
|
} else if (error instanceof TMDBResponseError) {
|
|
327
279
|
console.log(error.status, error.statusCode, error.statusMessage)
|
|
328
280
|
} else if (error instanceof TMDBRequestError) {
|
|
329
|
-
//
|
|
330
|
-
// error, no fetch implementation found, or invalid client configuration).
|
|
281
|
+
// Network failure, missing fetch, or invalid client configuration.
|
|
331
282
|
console.log('request error:', error.message)
|
|
283
|
+
} else if (error instanceof TMDBTimeoutError) {
|
|
284
|
+
// Thrown by withTimeout(), not by the HTTP layer.
|
|
285
|
+
console.log('timed out after', error.timeoutMs, 'ms')
|
|
332
286
|
}
|
|
333
287
|
}
|
|
334
288
|
```
|
|
335
289
|
|
|
336
|
-
`TMDBResponseError` exposes convenience getters for
|
|
337
|
-
|
|
290
|
+
`TMDBResponseError` exposes convenience getters for common status codes:
|
|
291
|
+
|
|
292
|
+
| Getter | Status |
|
|
293
|
+
| ---------------- | ------ |
|
|
294
|
+
| `isUnauthorized` | 401 |
|
|
295
|
+
| `isForbidden` | 403 |
|
|
296
|
+
| `isNotFound` | 404 |
|
|
297
|
+
| `isRateLimit` | 429 |
|
|
298
|
+
| `isServerError` | 5xx |
|
|
299
|
+
|
|
300
|
+
All errors extend `TMDBError`, which you can use as a single catch-all. `TMDBTimeoutError` is thrown by `withTimeout()` and exposes `timeoutMs`; the HTTP layer never throws it directly.
|
|
301
|
+
|
|
302
|
+
### Optional helpers
|
|
303
|
+
|
|
304
|
+
These helpers are opt-in and never change the default client behavior. They are exported from the package root and tree-shake out of ESM bundles when unused.
|
|
305
|
+
|
|
306
|
+
**Pagination**
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
import { paginate, paginateItems } from 'tmdb-kit'
|
|
310
|
+
|
|
311
|
+
for await (const page of paginate((page) => tmdb.movies.popular({ page, region: 'CN' }))) {
|
|
312
|
+
console.log(page.page, page.results.length)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Or iterate items directly.
|
|
316
|
+
for await (const movie of paginateItems((page) => tmdb.movies.popular({ page }))) {
|
|
317
|
+
console.log(movie.title)
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
`startPage` defaults to 1. `paginate` stops at `total_pages`, an empty page, `endPage` (default 500), or an aborted signal. `endPage` is the last page number to request, so it yields nothing when it is lower than `startPage`.
|
|
322
|
+
|
|
323
|
+
**Retry**
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import { createTMDB, retry, TMDBHttpClient, withRetry } from 'tmdb-kit'
|
|
327
|
+
|
|
328
|
+
// Wrap one call.
|
|
329
|
+
const movie = await retry(() => tmdb.movies.details(550), { retries: 3 })
|
|
330
|
+
|
|
331
|
+
// Or wrap the transport once. The transport owns authentication, so the
|
|
332
|
+
// factory does not need credentials.
|
|
333
|
+
const http = new TMDBHttpClient({ accessToken: 'your_access_token_here' })
|
|
334
|
+
const retrying = createTMDB({ transport: withRetry(http, { retries: 3 }) })
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Retries 429 and any response that carries `Retry-After` (including 503), retries 408, 5xx and network failures with exponential backoff, and leaves other errors untouched. Defaults are 2 retries, a 250 ms base delay, factor 2, full jitter, and a 60 s cap on `Retry-After`; use `retryOn` to replace the predicate and `onRetry` to observe delays. A wrapper-level `signal` and a per-request `signal` are combined, so aborting either cancels the call. The SDK itself still never retries by default.
|
|
338
|
+
|
|
339
|
+
**Timeout**
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
import { withTimeout } from 'tmdb-kit'
|
|
343
|
+
|
|
344
|
+
const movie = await withTimeout(5_000, (signal) => tmdb.movies.details(550, { signal }))
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Timeouts reject with `TMDBTimeoutError`. The task must forward the signal to the SDK. Pass a parent `signal` in the options to cancel it externally; the parent's reason is preserved.
|
|
348
|
+
|
|
349
|
+
**Memory cache**
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
import { createTMDB, TMDBHttpClient, withMemoryCache } from 'tmdb-kit'
|
|
353
|
+
|
|
354
|
+
const http = new TMDBHttpClient({ accessToken: 'your_access_token_here' })
|
|
355
|
+
const cached = createTMDB({
|
|
356
|
+
transport: withMemoryCache(http, { ttlMs: 60_000, maxEntries: 200 }),
|
|
357
|
+
})
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Defaults are a 5-minute TTL and 100 entries. The cache key includes the path, query, and headers, only successful responses are stored, and `clear()` invalidates every entry. Use one cache instance per client or credential: authentication is not part of the key.
|
|
361
|
+
|
|
362
|
+
## CLI
|
|
363
|
+
|
|
364
|
+
The `tmdb` command is a read-only client for the same TMDB API. It reads credentials from the environment or a config file, prints human-readable summaries by default, and accepts `--format json` (or its `--json` alias) for raw TMDB payloads and `--format ndjson` for line-oriented output.
|
|
365
|
+
|
|
366
|
+
The CLI runs on Node.js 18+ and Bun.
|
|
367
|
+
|
|
368
|
+
### Credentials and config
|
|
369
|
+
|
|
370
|
+
The CLI checks credentials in this order:
|
|
371
|
+
|
|
372
|
+
1. `TMDB_ACCESS_TOKEN`
|
|
373
|
+
2. `TMDB_API_KEY` (legacy v3 API key)
|
|
374
|
+
3. `accessToken` in the config file
|
|
375
|
+
4. `apiKey` in the config file
|
|
376
|
+
|
|
377
|
+
Environment variables take precedence over the config file. `TMDB_BASE_URL` overrides the API base URL for every command.
|
|
378
|
+
|
|
379
|
+
The config file lives at:
|
|
380
|
+
|
|
381
|
+
- Windows: `%APPDATA%\tmdb-kit\config.json`
|
|
382
|
+
- macOS and Linux: `$XDG_CONFIG_HOME/tmdb-kit/config.json`, or `~/.config/tmdb-kit/config.json` when `XDG_CONFIG_HOME` is unset
|
|
383
|
+
|
|
384
|
+
On Unix, the directory is created with mode `0700` and the file with mode `0600`.
|
|
385
|
+
|
|
386
|
+
Set up credentials with the auth commands:
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
tmdb auth login # prompt, validate, and save a credential
|
|
390
|
+
tmdb auth login --force # replace existing credentials
|
|
391
|
+
printf '%s' "$TMDB_ACCESS_TOKEN" | tmdb auth login --token-stdin --force
|
|
392
|
+
tmdb auth status # source, masked token, and config path
|
|
393
|
+
tmdb auth logout # remove saved credentials
|
|
394
|
+
tmdb config test # verify credentials with a TMDB request
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
`auth login` validates the credential with a TMDB request before saving it. `config test` performs the same check without changing the config. Use `--force` to replace existing credentials, or to save a config token while an environment variable is set and stdin is not a TTY.
|
|
398
|
+
|
|
399
|
+
Manage defaults with `config`:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
tmdb config set language zh-CN
|
|
403
|
+
tmdb config set region CN
|
|
404
|
+
tmdb config set token # prompts; secrets are not accepted as arguments
|
|
405
|
+
tmdb config unset language
|
|
406
|
+
tmdb config show # masked values and config path
|
|
407
|
+
tmdb config path
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Config keys are `token` or `accessToken`, `api-key` or `apiKey`, `language`, and `region`. Secrets entered with `config set token` or `config set api-key` are read from a prompt, never from the command line. `auth status` and `config show` mask stored secrets.
|
|
411
|
+
|
|
412
|
+
Use `--lang` to override the config language for a single command. `auth logout` removes saved credentials but leaves environment variables in place.
|
|
413
|
+
|
|
414
|
+
### Commands
|
|
415
|
+
|
|
416
|
+
Every API command accepts `--lang`, `--format`, `--fields`, and `--compact`. Commands that return a paginated list also accept `--all` and `--max-items` with `--format ndjson`. Run `tmdb <command> --help` for the full option list.
|
|
417
|
+
|
|
418
|
+
| Command | Description | Command options |
|
|
419
|
+
| ------------------------------------------------ | --------------------------------------------------------------------------------- | ---------------------------- |
|
|
420
|
+
| `tmdb search <query>` | Search all media, movies, TV, or people. | `--type`, `--year`, `--page` |
|
|
421
|
+
| `tmdb movie list [category]` | List movies. Default `popular`; also `top-rated`, `now-playing`, `upcoming`. | `--page`, `--region` |
|
|
422
|
+
| `tmdb movie get <id>` | Movie details. | `--append` |
|
|
423
|
+
| `tmdb movie credits <id>` | Movie cast and crew. | `--limit` |
|
|
424
|
+
| `tmdb movie images <id>` | Movie image URLs. | `--image-language` |
|
|
425
|
+
| `tmdb movie videos <id>` | Movie videos and trailers. | none |
|
|
426
|
+
| `tmdb movie similar <id>` | Similar movies. | `--page`, `--region` |
|
|
427
|
+
| `tmdb movie recommendations <id>` | Recommended movies. | `--page`, `--region` |
|
|
428
|
+
| `tmdb tv list [category]` | List TV shows. Default `popular`; also `top-rated`, `airing-today`, `on-the-air`. | `--page` |
|
|
429
|
+
| `tmdb tv get <id>` | TV show details. | `--append` |
|
|
430
|
+
| `tmdb tv credits <id>` | TV cast and crew. | `--limit` |
|
|
431
|
+
| `tmdb tv images <id>` | TV image URLs. | `--image-language` |
|
|
432
|
+
| `tmdb tv videos <id>` | TV videos and trailers. | none |
|
|
433
|
+
| `tmdb tv similar <id>` | Similar TV shows. | `--page` |
|
|
434
|
+
| `tmdb tv recommendations <id>` | Recommended TV shows. | `--page` |
|
|
435
|
+
| `tmdb tv season <id> <season>` | TV season and episodes. Use `0` for specials. | none |
|
|
436
|
+
| `tmdb tv episode <id> <season> <episode>` | TV episode details. Use `0` for specials. | `--append` |
|
|
437
|
+
| `tmdb tv aggregate-credits <id>` | Aggregate cast and crew credits for a show. | `--limit` |
|
|
438
|
+
| `tmdb tv season-credits <id> <season>` | Season cast and crew credits. | `--limit` |
|
|
439
|
+
| `tmdb tv season-aggregate-credits <id> <season>` | Aggregate season cast and crew credits. | `--limit` |
|
|
440
|
+
| `tmdb tv season-images <id> <season>` | Season image URLs. | `--image-language` |
|
|
441
|
+
| `tmdb tv season-videos <id> <season>` | Season videos and trailers. | none |
|
|
442
|
+
| `tmdb tv episode-groups <id>` | Alternate episode groups for a show. | none |
|
|
443
|
+
| `tmdb tv episode-group <group-id>` | Episodes in an alternate group. | none |
|
|
444
|
+
| `tmdb person get <id>` | Person details. | none |
|
|
445
|
+
| `tmdb person credits <id>` | Combined cast and crew credits. | `--limit` |
|
|
446
|
+
| `tmdb trending [type]` | Trending media. Default `all`; also `movie`, `tv`, `person`. | `--window`, `--page` |
|
|
447
|
+
| `tmdb genres [type]` | Genres. Default `movie`; also `tv`. | none |
|
|
448
|
+
|
|
449
|
+
Credential and config commands:
|
|
450
|
+
|
|
451
|
+
| Command | Description | Command options |
|
|
452
|
+
| ------------------------------- | ------------------------------------------------------ | ----------------------------------- |
|
|
453
|
+
| `tmdb auth login` | Validate and save credentials. | `--token-stdin`, `--force` |
|
|
454
|
+
| `tmdb auth status` | Show credential source, masked token, and config path. | `--format`, `--fields`, `--compact` |
|
|
455
|
+
| `tmdb auth logout` | Remove saved credentials. | none |
|
|
456
|
+
| `tmdb config show` | Show config values with secrets masked. | `--format`, `--fields`, `--compact` |
|
|
457
|
+
| `tmdb config path` | Print the config file path. | none |
|
|
458
|
+
| `tmdb config test` | Verify credentials with an authenticated request. | `--format`, `--fields`, `--compact` |
|
|
459
|
+
| `tmdb config set <key> [value]` | Set `token`, `api-key`, `language`, or `region`. | none |
|
|
460
|
+
| `tmdb config unset <key>` | Remove a config value. | none |
|
|
461
|
+
|
|
462
|
+
### Common options
|
|
463
|
+
|
|
464
|
+
| Option | Description |
|
|
465
|
+
| ------------------------------- | ----------------------------------------------------------------------------------- |
|
|
466
|
+
| `--format <text\|json\|ndjson>` | Output format. `json` prints the raw response, `ndjson` prints one record per line. |
|
|
467
|
+
| `--fields <list>` | Comma-separated top-level fields to keep. Requires `--format json` or `ndjson`. |
|
|
468
|
+
| `--json` | Alias for `--format json`. |
|
|
469
|
+
| `--compact` | Print JSON on a single line instead of pretty-printing it. |
|
|
470
|
+
| `--all` | Follow pagination to the last page. List commands only; requires `ndjson`. |
|
|
471
|
+
| `--max-items <number>` | Stop after this many items. List commands only; requires `ndjson`. |
|
|
472
|
+
| `--lang <code>` | Language for this command. Defaults to config `language`, then `en-US`. |
|
|
473
|
+
| `--page <number>` | Page number. Defaults to `1`. |
|
|
474
|
+
| `--region <code>` | Region for movie lists, similar, and recommendations. Defaults to config `region`. |
|
|
475
|
+
| `--limit <number>` | Maximum rows for credits. Defaults to `10`. |
|
|
476
|
+
| `--append <list>` | Comma-separated `append_to_response` values, such as `credits,videos`. |
|
|
477
|
+
| `--image-language <list>` | Comma-separated image language codes. |
|
|
478
|
+
| `--year <year>` | Movie release year or TV first-air year. Only with `--type movie` or `--type tv`. |
|
|
479
|
+
| `--type <value>` | Media selector for `search`: `all`, `movie`, `tv`, or `person`. |
|
|
480
|
+
| `--window <day\|week>` | Trending window. Defaults to `week`. |
|
|
481
|
+
|
|
482
|
+
`--version` prints the CLI version.
|
|
483
|
+
|
|
484
|
+
### Output and exit codes
|
|
485
|
+
|
|
486
|
+
The default output is a compact summary for reading in a terminal. Use `--format json` for scripts; `--json` is a shorter alias:
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
tmdb movie get 550 --format json | jq '.title, .release_date'
|
|
490
|
+
tmdb movie get 550 --json | jq '.title'
|
|
491
|
+
tmdb movie get 550 --format json --compact # single line, for line-oriented tools
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
`--compact` only affects `json` output and is ignored for `text`. Combining `--json` with an explicit `--format text` or `--format ndjson` is a usage error.
|
|
495
|
+
|
|
496
|
+
#### NDJSON
|
|
497
|
+
|
|
498
|
+
`--format ndjson` (alias `jsonl`) prints one JSON object per line. Responses with a `results` array stream as three record kinds:
|
|
499
|
+
|
|
500
|
+
<!-- prettier-ignore -->
|
|
501
|
+
```json
|
|
502
|
+
{"type":"meta","page":1,"total_pages":5,"total_results":100}
|
|
503
|
+
{"type":"item","index":0,"value":{"id":550,"title":"Fight Club"}}
|
|
504
|
+
{"type":"summary","count":20,"pages":1}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
`meta` is the response envelope without `results`, `index` is zero-based, and `summary` closes the stream with the item count and pages read. Every other response emits a single record:
|
|
508
|
+
|
|
509
|
+
<!-- prettier-ignore -->
|
|
510
|
+
```json
|
|
511
|
+
{"type":"result","value":{"id":550,"title":"Fight Club"}}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Because the stream is line-oriented, a missing `summary` line means the command failed; the reason is still on stderr as a single `{"type":"error",...}` record.
|
|
338
515
|
|
|
339
|
-
|
|
340
|
-
| --- | --- |
|
|
341
|
-
| `isUnauthorized` | 401 |
|
|
342
|
-
| `isForbidden` | 403 |
|
|
343
|
-
| `isNotFound` | 404 |
|
|
344
|
-
| `isRateLimit` | 429 |
|
|
345
|
-
| `isServerError` | 5xx |
|
|
516
|
+
#### Pagination
|
|
346
517
|
|
|
347
|
-
|
|
348
|
-
|
|
518
|
+
List commands (`search`, `trending`, `movie list/similar/recommendations`, and `tv list/similar/recommendations`) accept `--all` to follow pagination from `--page` to the last page, and `--max-items` to stop early:
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
tmdb trending movie --format ndjson --all --max-items 100
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
`--max-items` caps the number of `item` records with or without `--all`. Both flags require `--format ndjson`, and `--all` may issue many requests: TMDB caps lists at 500 pages and the command stops at that limit.
|
|
525
|
+
|
|
526
|
+
#### Selecting fields
|
|
527
|
+
|
|
528
|
+
`--fields` keeps only the listed top-level fields. For detail commands it projects the response; for list commands it projects each entry in `results` while keeping the envelope:
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
tmdb movie get 550 --format json --fields id,title,release_date
|
|
532
|
+
tmdb movie list --format ndjson --fields id,title | jq -c 'select(.type == "item")'
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Fields that a record does not have are omitted. If none of the requested fields exist, the command exits `2` and lists the available names. Nested paths are not supported, and `--fields` requires `--format json` or `--format ndjson`.
|
|
536
|
+
|
|
537
|
+
When JSON output is active, errors go to stderr as one JSON object and stdout stays empty, so a pipeline never receives a partial payload:
|
|
538
|
+
|
|
539
|
+
<!-- prettier-ignore -->
|
|
540
|
+
```json
|
|
541
|
+
{"type":"error","kind":"not_found","message":"TMDB request failed (404): ...","exitCode":4,"status":404}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
| Field | Meaning |
|
|
545
|
+
| ------------ | ---------------------------------------------------------------------------- |
|
|
546
|
+
| `type` | Always `error`. |
|
|
547
|
+
| `kind` | `usage`, `auth`, `not_found`, `rate_limit`, `network`, `api`, or `internal`. |
|
|
548
|
+
| `message` | Human-readable description. |
|
|
549
|
+
| `exitCode` | Process exit code, matching the table below. |
|
|
550
|
+
| `status` | HTTP status, when the failure came from a TMDB response. |
|
|
551
|
+
| `requestId` | TMDB `x-request-id`, when the response included one. |
|
|
552
|
+
| `retryAfter` | Seconds to wait before retrying, for rate limit errors. |
|
|
553
|
+
|
|
554
|
+
Exit codes:
|
|
555
|
+
|
|
556
|
+
| Code | Meaning |
|
|
557
|
+
| ---- | -------------------------------------------------------------- |
|
|
558
|
+
| `0` | Success. |
|
|
559
|
+
| `1` | Unexpected error, network failure, or non-auth TMDB response. |
|
|
560
|
+
| `2` | Invalid command usage or input. |
|
|
561
|
+
| `3` | Missing or rejected credentials, or a config read/write error. |
|
|
562
|
+
| `4` | TMDB returned `404 Not Found`. |
|
|
563
|
+
| `5` | TMDB rate limit (`429 Too Many Requests`). |
|
|
564
|
+
|
|
565
|
+
### Examples
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
# Search movies released in 2010
|
|
569
|
+
tmdb search "Inception" --type movie --year 2010
|
|
570
|
+
|
|
571
|
+
# Movie details with credits and videos
|
|
572
|
+
tmdb movie get 550 --append credits,videos
|
|
573
|
+
|
|
574
|
+
# Trending movies today, raw JSON
|
|
575
|
+
tmdb trending movie --window day --json | jq '.results[].title'
|
|
576
|
+
|
|
577
|
+
# Season 1 episodes for a TV show
|
|
578
|
+
tmdb tv season 1399 1 --json | jq '.episodes[].name'
|
|
579
|
+
|
|
580
|
+
# Episode details (season 0 = specials)
|
|
581
|
+
tmdb tv episode 1399 1 1
|
|
582
|
+
|
|
583
|
+
# Alternate episode groups
|
|
584
|
+
tmdb tv episode-groups 1399
|
|
585
|
+
|
|
586
|
+
# Save defaults for later commands
|
|
587
|
+
tmdb config set language zh-CN
|
|
588
|
+
tmdb config set region CN
|
|
589
|
+
```
|
|
349
590
|
|
|
350
591
|
## Development
|
|
351
592
|
|
|
593
|
+
Requires [Bun](https://bun.sh) 1.4.4+. The published package still runs on Node.js 18+.
|
|
594
|
+
|
|
595
|
+
```bash
|
|
596
|
+
bun install
|
|
597
|
+
bun run format
|
|
598
|
+
bun run typecheck
|
|
599
|
+
bun run test:coverage
|
|
600
|
+
bun run build
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Run the integration suite with a real token. It exercises every SDK resource, the optional helpers, and the CLI against the live API:
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
TMDB_ACCESS_TOKEN=your_access_token_here bun run test:integration
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
Set `TMDB_API_ENDPOINT` to run the SDK suites against a compatible mirror. The `Integration` GitHub workflow runs the same suite nightly, on manual dispatch, and on pull requests that touch the SDK, CLI, or integration tests. Add a `TMDB_ACCESS_TOKEN` repository secret to enable it, and an optional `TMDB_API_KEY` secret to also cover legacy v3 key auth; fork and Dependabot pull requests skip the live job because repository secrets are not available to them.
|
|
610
|
+
|
|
611
|
+
Build and run the CLI from source:
|
|
612
|
+
|
|
352
613
|
```bash
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
npm run test:coverage
|
|
356
|
-
npm run build
|
|
614
|
+
bun run build:cli
|
|
615
|
+
bun dist/cli.js --help
|
|
357
616
|
```
|
|
358
617
|
|
|
359
618
|
## References
|
|
360
619
|
|
|
361
620
|
- [TMDB authentication](https://developer.themoviedb.org/docs/authentication-application)
|
|
362
621
|
- [TMDB API reference](https://developer.themoviedb.org/reference/intro/getting-started)
|
|
363
|
-
- [
|
|
622
|
+
- [Bun bundler docs](https://bun.com/docs/bundler)
|