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.
Files changed (49) hide show
  1. package/README.md +7 -5
  2. package/dist/cli/commands/bazarr.d.ts +2 -0
  3. package/dist/cli/commands/bazarr.d.ts.map +1 -1
  4. package/dist/cli/commands/config.d.ts.map +1 -1
  5. package/dist/cli/commands/lidarr.d.ts +2 -0
  6. package/dist/cli/commands/lidarr.d.ts.map +1 -1
  7. package/dist/cli/commands/radarr.d.ts.map +1 -1
  8. package/dist/cli/commands/readarr.d.ts +2 -0
  9. package/dist/cli/commands/readarr.d.ts.map +1 -1
  10. package/dist/cli/commands/sonarr.d.ts.map +1 -1
  11. package/dist/cli/index.js +2138 -2405
  12. package/dist/clients/base.d.ts +136 -0
  13. package/dist/clients/base.d.ts.map +1 -0
  14. package/dist/clients/bazarr.d.ts +1 -1
  15. package/dist/clients/bazarr.d.ts.map +1 -1
  16. package/dist/clients/bazarr.js +100 -3
  17. package/dist/clients/lidarr.d.ts +24 -681
  18. package/dist/clients/lidarr.d.ts.map +1 -1
  19. package/dist/clients/lidarr.js +323 -196
  20. package/dist/clients/prowlarr.d.ts +25 -638
  21. package/dist/clients/prowlarr.d.ts.map +1 -1
  22. package/dist/clients/prowlarr.js +331 -175
  23. package/dist/clients/qbittorrent.d.ts +1 -17
  24. package/dist/clients/qbittorrent.d.ts.map +1 -1
  25. package/dist/clients/qbittorrent.js +97 -2
  26. package/dist/clients/radarr.d.ts +4 -657
  27. package/dist/clients/radarr.d.ts.map +1 -1
  28. package/dist/clients/radarr.js +323 -164
  29. package/dist/clients/readarr.d.ts +4 -635
  30. package/dist/clients/readarr.d.ts.map +1 -1
  31. package/dist/clients/readarr.js +323 -164
  32. package/dist/clients/seerr.d.ts +1 -1
  33. package/dist/clients/seerr.d.ts.map +1 -1
  34. package/dist/clients/seerr.js +100 -3
  35. package/dist/clients/sonarr.d.ts +181 -772
  36. package/dist/clients/sonarr.d.ts.map +1 -1
  37. package/dist/clients/sonarr.js +346 -157
  38. package/dist/core/client.d.ts +3 -0
  39. package/dist/core/client.d.ts.map +1 -1
  40. package/dist/core/fetch.d.ts +23 -0
  41. package/dist/core/fetch.d.ts.map +1 -0
  42. package/dist/core/index.d.ts +1 -0
  43. package/dist/core/index.d.ts.map +1 -1
  44. package/dist/core/types.d.ts +7 -0
  45. package/dist/core/types.d.ts.map +1 -1
  46. package/dist/index.js +1 -1
  47. package/dist/tsarr-2.10.0.tgz +0 -0
  48. package/package.json +2 -4
  49. package/dist/tsarr-2.9.0.tgz +0 -0
@@ -26,7 +26,95 @@ class ConnectionError extends TsarrError {
26
26
  }
27
27
  }
28
28
 
29
+ // src/core/fetch.ts
30
+ var DEFAULT_TIMEOUT = 30000;
31
+ var DEFAULT_MAX_RETRIES = 3;
32
+ var DEFAULT_INITIAL_DELAY = 1000;
33
+ var DEFAULT_MAX_DELAY = 1e4;
34
+ var RETRYABLE_STATUS_CODES = new Set([408, 429, 502, 503, 504]);
35
+ function isRetryable(error) {
36
+ if (error instanceof DOMException && error.name === "AbortError") {
37
+ return false;
38
+ }
39
+ if (error instanceof TypeError) {
40
+ return true;
41
+ }
42
+ return false;
43
+ }
44
+ function getRetryDelay(attempt, initialDelayMs, maxDelayMs) {
45
+ const delay = initialDelayMs * 2 ** attempt;
46
+ const jitter = delay * 0.2 * Math.random();
47
+ return Math.min(delay + jitter, maxDelayMs);
48
+ }
49
+ function createResilientFetch(options = {}) {
50
+ const timeout = options.timeout ?? DEFAULT_TIMEOUT;
51
+ const maxRetries = options.retry ? options.retry.maxRetries ?? DEFAULT_MAX_RETRIES : 0;
52
+ const initialDelayMs = options.retry?.initialDelayMs ?? DEFAULT_INITIAL_DELAY;
53
+ const maxDelayMs = options.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY;
54
+ const resilientFetch = async (input, init) => {
55
+ let lastError;
56
+ const template = createRequestTemplate(input, init);
57
+ for (let attempt = 0;attempt <= maxRetries; attempt++) {
58
+ const controller = new AbortController;
59
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
60
+ const callerSignal = init?.signal;
61
+ if (callerSignal?.aborted) {
62
+ clearTimeout(timeoutId);
63
+ throw callerSignal.reason ?? new DOMException("The operation was aborted.", "AbortError");
64
+ }
65
+ const onCallerAbort = () => controller.abort(callerSignal.reason);
66
+ callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
67
+ try {
68
+ const response = await globalThis.fetch(new Request(template.clone(), { signal: controller.signal }));
69
+ clearTimeout(timeoutId);
70
+ callerSignal?.removeEventListener("abort", onCallerAbort);
71
+ if (RETRYABLE_STATUS_CODES.has(response.status) && attempt < maxRetries) {
72
+ lastError = new ConnectionError(`Request failed with status ${response.status}`);
73
+ const delay = getRetryDelay(attempt, initialDelayMs, maxDelayMs);
74
+ await new Promise((resolve) => setTimeout(resolve, delay));
75
+ continue;
76
+ }
77
+ return response;
78
+ } catch (error) {
79
+ clearTimeout(timeoutId);
80
+ callerSignal?.removeEventListener("abort", onCallerAbort);
81
+ if (callerSignal?.aborted) {
82
+ throw callerSignal.reason ?? new DOMException("The operation was aborted.", "AbortError");
83
+ }
84
+ if (error instanceof DOMException && error.name === "AbortError") {
85
+ lastError = new ConnectionError(`Request timed out after ${timeout}ms`);
86
+ if (attempt < maxRetries) {
87
+ const delay = getRetryDelay(attempt, initialDelayMs, maxDelayMs);
88
+ await new Promise((resolve) => setTimeout(resolve, delay));
89
+ continue;
90
+ }
91
+ throw lastError;
92
+ }
93
+ if (isRetryable(error) && attempt < maxRetries) {
94
+ lastError = error;
95
+ const delay = getRetryDelay(attempt, initialDelayMs, maxDelayMs);
96
+ await new Promise((resolve) => setTimeout(resolve, delay));
97
+ continue;
98
+ }
99
+ throw error;
100
+ }
101
+ }
102
+ throw lastError;
103
+ };
104
+ return Object.assign(resilientFetch, {
105
+ preconnect: globalThis.fetch.preconnect?.bind(globalThis.fetch)
106
+ });
107
+ }
108
+ function createRequestTemplate(input, init) {
109
+ const { signal: _signal, ...requestInit } = init ?? {};
110
+ if (input instanceof Request) {
111
+ return init ? new Request(input.clone(), requestInit) : input.clone();
112
+ }
113
+ return new Request(input, requestInit);
114
+ }
115
+
29
116
  // src/core/client.ts
117
+ var DEFAULT_TIMEOUT_MS = 30000;
30
118
  function createServarrClient(config) {
31
119
  if (!config.apiKey) {
32
120
  throw new ApiKeyError;
@@ -38,6 +126,11 @@ function createServarrClient(config) {
38
126
  ...config,
39
127
  baseUrl: config.baseUrl.replace(/\/$/, "")
40
128
  };
129
+ const timeoutMs = validatedConfig.timeout ?? DEFAULT_TIMEOUT_MS;
130
+ const resilientFetch = createResilientFetch({
131
+ timeout: timeoutMs,
132
+ retry: validatedConfig.retry
133
+ });
41
134
  return {
42
135
  config: validatedConfig,
43
136
  getHeaders: () => ({
@@ -45,7 +138,9 @@ function createServarrClient(config) {
45
138
  "Content-Type": "application/json",
46
139
  ...validatedConfig.headers
47
140
  }),
48
- getBaseUrl: () => validatedConfig.baseUrl
141
+ getBaseUrl: () => validatedConfig.baseUrl,
142
+ getTimeout: () => timeoutMs,
143
+ getFetch: () => resilientFetch
49
144
  };
50
145
  }
51
146
  // src/generated/seerr/core/serverSentEvents.gen.ts
@@ -924,7 +1019,8 @@ class SeerrClient {
924
1019
  headers: {
925
1020
  "X-Api-Key": this.clientConfig.config.apiKey,
926
1021
  ...this.clientConfig.config.headers ?? {}
927
- }
1022
+ },
1023
+ fetch: this.clientConfig.getFetch()
928
1024
  });
929
1025
  }
930
1026
  async getSystemStatus() {
@@ -999,7 +1095,8 @@ class SeerrClient {
999
1095
  headers: {
1000
1096
  "X-Api-Key": this.clientConfig.config.apiKey,
1001
1097
  ...this.clientConfig.config.headers ?? {}
1002
- }
1098
+ },
1099
+ fetch: this.clientConfig.getFetch()
1003
1100
  });
1004
1101
  return this.clientConfig.config;
1005
1102
  }