@lorenzopant/tmdb 1.17.0 → 1.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +34 -0
- package/dist/client.js +52 -0
- package/dist/tmdb.js +1 -1
- package/dist/types/config/options.d.ts +10 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -3,10 +3,44 @@ export declare class ApiClient {
|
|
|
3
3
|
private accessToken;
|
|
4
4
|
private baseUrl;
|
|
5
5
|
private logger?;
|
|
6
|
+
/**
|
|
7
|
+
* Tracks in-flight requests keyed by a deterministic string derived from the endpoint
|
|
8
|
+
* and its parameters. When two identical requests are fired concurrently, the second
|
|
9
|
+
* caller receives the same Promise as the first — only one fetch is made.
|
|
10
|
+
* Entries are removed via `.finally()` so the map never holds settled promises.
|
|
11
|
+
*/
|
|
12
|
+
private inflightRequests;
|
|
13
|
+
private deduplication;
|
|
6
14
|
constructor(accessToken: string, options?: {
|
|
7
15
|
logger?: boolean | TMDBLoggerFn;
|
|
16
|
+
deduplication?: boolean;
|
|
8
17
|
});
|
|
18
|
+
/**
|
|
19
|
+
* Builds a stable, order-independent cache key for a request.
|
|
20
|
+
*
|
|
21
|
+
* `undefined` values are excluded (they are never serialised into the URL),
|
|
22
|
+
* and the remaining entries are sorted alphabetically before joining so that
|
|
23
|
+
* `{ language, page }` and `{ page, language }` produce the same key.
|
|
24
|
+
*/
|
|
25
|
+
private buildRequestKey;
|
|
26
|
+
/**
|
|
27
|
+
* Makes an authenticated GET request to the TMDB API, returning the parsed and
|
|
28
|
+
* null-sanitised response.
|
|
29
|
+
*
|
|
30
|
+
* **Deduplication:** when enabled (the default), concurrent calls with the same
|
|
31
|
+
* `endpoint` + `params` share a single in-flight fetch. The second (and any
|
|
32
|
+
* subsequent) caller receives the same `Promise` — no extra network request is made.
|
|
33
|
+
* Once the promise settles (success or error) it is evicted from the map so the next
|
|
34
|
+
* call triggers a fresh fetch. Deduplication can be disabled globally via
|
|
35
|
+
* `TMDBOptions.deduplication = false`.
|
|
36
|
+
*/
|
|
9
37
|
request<T>(endpoint: string, params?: Record<string, unknown | undefined>): Promise<T>;
|
|
38
|
+
/**
|
|
39
|
+
* The actual fetch + response-parsing pipeline. Called by `request()` only when no
|
|
40
|
+
* matching in-flight promise exists. Handles URL construction, auth headers, logging,
|
|
41
|
+
* error mapping, and null sanitisation.
|
|
42
|
+
*/
|
|
43
|
+
private doRequest;
|
|
10
44
|
/**
|
|
11
45
|
* Recursively converts null values to undefined in API responses.
|
|
12
46
|
* This allows optional properties to model fields that TMDB returns as nullable.
|
package/dist/client.js
CHANGED
|
@@ -5,11 +5,63 @@ export class ApiClient {
|
|
|
5
5
|
accessToken;
|
|
6
6
|
baseUrl = "https://api.themoviedb.org/3";
|
|
7
7
|
logger;
|
|
8
|
+
/**
|
|
9
|
+
* Tracks in-flight requests keyed by a deterministic string derived from the endpoint
|
|
10
|
+
* and its parameters. When two identical requests are fired concurrently, the second
|
|
11
|
+
* caller receives the same Promise as the first — only one fetch is made.
|
|
12
|
+
* Entries are removed via `.finally()` so the map never holds settled promises.
|
|
13
|
+
*/
|
|
14
|
+
inflightRequests = new Map();
|
|
15
|
+
deduplication;
|
|
8
16
|
constructor(accessToken, options = {}) {
|
|
9
17
|
this.accessToken = accessToken;
|
|
10
18
|
this.logger = TMDBLogger.from(options.logger);
|
|
19
|
+
this.deduplication = options.deduplication !== false;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Builds a stable, order-independent cache key for a request.
|
|
23
|
+
*
|
|
24
|
+
* `undefined` values are excluded (they are never serialised into the URL),
|
|
25
|
+
* and the remaining entries are sorted alphabetically before joining so that
|
|
26
|
+
* `{ language, page }` and `{ page, language }` produce the same key.
|
|
27
|
+
*/
|
|
28
|
+
buildRequestKey(endpoint, params) {
|
|
29
|
+
const definedEntries = Object.entries(params)
|
|
30
|
+
.filter(([, v]) => v !== undefined)
|
|
31
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
32
|
+
.map(([k, v]) => `${k}=${String(v)}`);
|
|
33
|
+
return definedEntries.length > 0 ? `${endpoint}?${definedEntries.join("&")}` : endpoint;
|
|
11
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Makes an authenticated GET request to the TMDB API, returning the parsed and
|
|
37
|
+
* null-sanitised response.
|
|
38
|
+
*
|
|
39
|
+
* **Deduplication:** when enabled (the default), concurrent calls with the same
|
|
40
|
+
* `endpoint` + `params` share a single in-flight fetch. The second (and any
|
|
41
|
+
* subsequent) caller receives the same `Promise` — no extra network request is made.
|
|
42
|
+
* Once the promise settles (success or error) it is evicted from the map so the next
|
|
43
|
+
* call triggers a fresh fetch. Deduplication can be disabled globally via
|
|
44
|
+
* `TMDBOptions.deduplication = false`.
|
|
45
|
+
*/
|
|
12
46
|
async request(endpoint, params = {}) {
|
|
47
|
+
if (!this.deduplication)
|
|
48
|
+
return this.doRequest(endpoint, params);
|
|
49
|
+
const key = this.buildRequestKey(endpoint, params);
|
|
50
|
+
const existing = this.inflightRequests.get(key);
|
|
51
|
+
if (existing)
|
|
52
|
+
return existing;
|
|
53
|
+
const promise = this.doRequest(endpoint, params).finally(() => {
|
|
54
|
+
this.inflightRequests.delete(key);
|
|
55
|
+
});
|
|
56
|
+
this.inflightRequests.set(key, promise);
|
|
57
|
+
return promise;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The actual fetch + response-parsing pipeline. Called by `request()` only when no
|
|
61
|
+
* matching in-flight promise exists. Handles URL construction, auth headers, logging,
|
|
62
|
+
* error mapping, and null sanitisation.
|
|
63
|
+
*/
|
|
64
|
+
async doRequest(endpoint, params) {
|
|
13
65
|
const url = new URL(`${this.baseUrl}${endpoint}`);
|
|
14
66
|
const jwt = isJwt(this.accessToken);
|
|
15
67
|
for (const [key, value] of Object.entries(params)) {
|
package/dist/tmdb.js
CHANGED
|
@@ -64,7 +64,7 @@ export class TMDB {
|
|
|
64
64
|
if (!accessToken)
|
|
65
65
|
throw new Error(Errors.NO_ACCESS_TOKEN);
|
|
66
66
|
this.options = options;
|
|
67
|
-
this.client = new ApiClient(accessToken, { logger: options.logger });
|
|
67
|
+
this.client = new ApiClient(accessToken, { logger: options.logger, deduplication: options.deduplication });
|
|
68
68
|
this.movies = new MoviesAPI(this.client, this.options);
|
|
69
69
|
this.movie_lists = new MovieListsAPI(this.client, this.options);
|
|
70
70
|
this.search = new SearchAPI(this.client, this.options);
|
|
@@ -33,4 +33,14 @@ export type TMDBOptions = {
|
|
|
33
33
|
* - Pass a function to customize logging output.
|
|
34
34
|
*/
|
|
35
35
|
logger?: boolean | TMDBLoggerFn;
|
|
36
|
+
/**
|
|
37
|
+
* Controls whether concurrent identical requests are deduplicated.
|
|
38
|
+
* When `true` (default), multiple in-flight calls with the same endpoint and
|
|
39
|
+
* parameters share a single fetch and resolve from the same Promise.
|
|
40
|
+
* Set to `false` to disable deduplication — every call always triggers its
|
|
41
|
+
* own fetch. Useful for polling loops, force-refreshes after mutations, or
|
|
42
|
+
* any scenario where stale in-flight data must not be reused.
|
|
43
|
+
* @default true
|
|
44
|
+
*/
|
|
45
|
+
deduplication?: boolean;
|
|
36
46
|
};
|
package/package.json
CHANGED