tsarr 2.9.0 → 2.10.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 +7 -5
- package/dist/cli/commands/bazarr.d.ts +2 -0
- package/dist/cli/commands/bazarr.d.ts.map +1 -1
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/lidarr.d.ts +2 -0
- package/dist/cli/commands/lidarr.d.ts.map +1 -1
- package/dist/cli/commands/radarr.d.ts.map +1 -1
- package/dist/cli/commands/readarr.d.ts +2 -0
- package/dist/cli/commands/readarr.d.ts.map +1 -1
- package/dist/cli/commands/sonarr.d.ts.map +1 -1
- package/dist/cli/index.js +2138 -2405
- package/dist/clients/base.d.ts +136 -0
- package/dist/clients/base.d.ts.map +1 -0
- package/dist/clients/bazarr.d.ts +1 -1
- package/dist/clients/bazarr.d.ts.map +1 -1
- package/dist/clients/bazarr.js +100 -3
- package/dist/clients/lidarr.d.ts +24 -681
- package/dist/clients/lidarr.d.ts.map +1 -1
- package/dist/clients/lidarr.js +323 -196
- package/dist/clients/prowlarr.d.ts +25 -638
- package/dist/clients/prowlarr.d.ts.map +1 -1
- package/dist/clients/prowlarr.js +331 -175
- package/dist/clients/qbittorrent.d.ts +1 -17
- package/dist/clients/qbittorrent.d.ts.map +1 -1
- package/dist/clients/qbittorrent.js +97 -2
- package/dist/clients/radarr.d.ts +4 -657
- package/dist/clients/radarr.d.ts.map +1 -1
- package/dist/clients/radarr.js +323 -164
- package/dist/clients/readarr.d.ts +4 -635
- package/dist/clients/readarr.d.ts.map +1 -1
- package/dist/clients/readarr.js +323 -164
- package/dist/clients/seerr.d.ts +1 -1
- package/dist/clients/seerr.d.ts.map +1 -1
- package/dist/clients/seerr.js +100 -3
- package/dist/clients/sonarr.d.ts +181 -772
- package/dist/clients/sonarr.d.ts.map +1 -1
- package/dist/clients/sonarr.js +346 -157
- package/dist/core/client.d.ts +3 -0
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/fetch.d.ts +23 -0
- package/dist/core/fetch.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/tsarr-2.10.0.tgz +0 -0
- package/package.json +2 -4
- package/dist/tsarr-2.9.0.tgz +0 -0
|
@@ -18,6 +18,93 @@ class ConnectionError extends TsarrError {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// src/core/fetch.ts
|
|
22
|
+
var DEFAULT_TIMEOUT = 30000;
|
|
23
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
24
|
+
var DEFAULT_INITIAL_DELAY = 1000;
|
|
25
|
+
var DEFAULT_MAX_DELAY = 1e4;
|
|
26
|
+
var RETRYABLE_STATUS_CODES = new Set([408, 429, 502, 503, 504]);
|
|
27
|
+
function isRetryable(error) {
|
|
28
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (error instanceof TypeError) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
function getRetryDelay(attempt, initialDelayMs, maxDelayMs) {
|
|
37
|
+
const delay = initialDelayMs * 2 ** attempt;
|
|
38
|
+
const jitter = delay * 0.2 * Math.random();
|
|
39
|
+
return Math.min(delay + jitter, maxDelayMs);
|
|
40
|
+
}
|
|
41
|
+
function createResilientFetch(options = {}) {
|
|
42
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
43
|
+
const maxRetries = options.retry ? options.retry.maxRetries ?? DEFAULT_MAX_RETRIES : 0;
|
|
44
|
+
const initialDelayMs = options.retry?.initialDelayMs ?? DEFAULT_INITIAL_DELAY;
|
|
45
|
+
const maxDelayMs = options.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY;
|
|
46
|
+
const resilientFetch = async (input, init) => {
|
|
47
|
+
let lastError;
|
|
48
|
+
const template = createRequestTemplate(input, init);
|
|
49
|
+
for (let attempt = 0;attempt <= maxRetries; attempt++) {
|
|
50
|
+
const controller = new AbortController;
|
|
51
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
52
|
+
const callerSignal = init?.signal;
|
|
53
|
+
if (callerSignal?.aborted) {
|
|
54
|
+
clearTimeout(timeoutId);
|
|
55
|
+
throw callerSignal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
56
|
+
}
|
|
57
|
+
const onCallerAbort = () => controller.abort(callerSignal.reason);
|
|
58
|
+
callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
59
|
+
try {
|
|
60
|
+
const response = await globalThis.fetch(new Request(template.clone(), { signal: controller.signal }));
|
|
61
|
+
clearTimeout(timeoutId);
|
|
62
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
63
|
+
if (RETRYABLE_STATUS_CODES.has(response.status) && attempt < maxRetries) {
|
|
64
|
+
lastError = new ConnectionError(`Request failed with status ${response.status}`);
|
|
65
|
+
const delay = getRetryDelay(attempt, initialDelayMs, maxDelayMs);
|
|
66
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
return response;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
clearTimeout(timeoutId);
|
|
72
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
73
|
+
if (callerSignal?.aborted) {
|
|
74
|
+
throw callerSignal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
75
|
+
}
|
|
76
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
77
|
+
lastError = new ConnectionError(`Request timed out after ${timeout}ms`);
|
|
78
|
+
if (attempt < maxRetries) {
|
|
79
|
+
const delay = getRetryDelay(attempt, initialDelayMs, maxDelayMs);
|
|
80
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
throw lastError;
|
|
84
|
+
}
|
|
85
|
+
if (isRetryable(error) && attempt < maxRetries) {
|
|
86
|
+
lastError = error;
|
|
87
|
+
const delay = getRetryDelay(attempt, initialDelayMs, maxDelayMs);
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw lastError;
|
|
95
|
+
};
|
|
96
|
+
return Object.assign(resilientFetch, {
|
|
97
|
+
preconnect: globalThis.fetch.preconnect?.bind(globalThis.fetch)
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function createRequestTemplate(input, init) {
|
|
101
|
+
const { signal: _signal, ...requestInit } = init ?? {};
|
|
102
|
+
if (input instanceof Request) {
|
|
103
|
+
return init ? new Request(input.clone(), requestInit) : input.clone();
|
|
104
|
+
}
|
|
105
|
+
return new Request(input, requestInit);
|
|
106
|
+
}
|
|
107
|
+
|
|
21
108
|
// src/generated/qbittorrent/core/bodySerializer.gen.ts
|
|
22
109
|
var serializeUrlSearchParamsPair = (data, key, value) => {
|
|
23
110
|
if (typeof value === "string") {
|
|
@@ -917,11 +1004,14 @@ var torrentsDeletePost = (options) => (options.client ?? client).post({
|
|
|
917
1004
|
}
|
|
918
1005
|
});
|
|
919
1006
|
// src/clients/qbittorrent.ts
|
|
1007
|
+
var DEFAULT_TIMEOUT_MS = 30000;
|
|
1008
|
+
|
|
920
1009
|
class QBittorrentClient {
|
|
921
1010
|
baseUrl;
|
|
922
1011
|
username;
|
|
923
1012
|
password;
|
|
924
1013
|
sid = null;
|
|
1014
|
+
fetch;
|
|
925
1015
|
constructor(config) {
|
|
926
1016
|
if (!config.baseUrl) {
|
|
927
1017
|
throw new ConnectionError("No base URL provided");
|
|
@@ -929,9 +1019,14 @@ class QBittorrentClient {
|
|
|
929
1019
|
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
930
1020
|
this.username = config.username;
|
|
931
1021
|
this.password = config.password;
|
|
1022
|
+
this.fetch = createResilientFetch({
|
|
1023
|
+
timeout: config.timeout ?? DEFAULT_TIMEOUT_MS,
|
|
1024
|
+
retry: config.retry
|
|
1025
|
+
});
|
|
932
1026
|
client.setConfig({
|
|
933
1027
|
baseUrl: `${this.baseUrl}/api/v2`,
|
|
934
|
-
auth: () => this.ensureAuth()
|
|
1028
|
+
auth: () => this.ensureAuth(),
|
|
1029
|
+
fetch: this.fetch
|
|
935
1030
|
});
|
|
936
1031
|
}
|
|
937
1032
|
async ensureAuth() {
|
|
@@ -941,7 +1036,7 @@ class QBittorrentClient {
|
|
|
941
1036
|
return this.sid;
|
|
942
1037
|
}
|
|
943
1038
|
async login() {
|
|
944
|
-
const response = await fetch(`${this.baseUrl}/api/v2/auth/login`, {
|
|
1039
|
+
const response = await this.fetch(`${this.baseUrl}/api/v2/auth/login`, {
|
|
945
1040
|
method: "POST",
|
|
946
1041
|
headers: {
|
|
947
1042
|
"Content-Type": "application/x-www-form-urlencoded",
|