tsarr 2.9.1 → 2.11.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 (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -233
  3. package/dist/cli/commands/doctor.d.ts.map +1 -1
  4. package/dist/cli/commands/manual-import.d.ts +30 -0
  5. package/dist/cli/commands/manual-import.d.ts.map +1 -0
  6. package/dist/cli/commands/radarr.d.ts.map +1 -1
  7. package/dist/cli/commands/sonarr.d.ts.map +1 -1
  8. package/dist/cli/index.js +5230 -4783
  9. package/dist/cli/index.js.map +133 -0
  10. package/dist/clients/base.d.ts +8 -3
  11. package/dist/clients/base.d.ts.map +1 -1
  12. package/dist/clients/bazarr.d.ts +125 -124
  13. package/dist/clients/bazarr.d.ts.map +1 -1
  14. package/dist/clients/bazarr.js +183 -100
  15. package/dist/clients/bazarr.js.map +22 -0
  16. package/dist/clients/lidarr.d.ts +148 -147
  17. package/dist/clients/lidarr.d.ts.map +1 -1
  18. package/dist/clients/lidarr.js +190 -102
  19. package/dist/clients/lidarr.js.map +23 -0
  20. package/dist/clients/prowlarr.d.ts +30 -29
  21. package/dist/clients/prowlarr.d.ts.map +1 -1
  22. package/dist/clients/prowlarr.js +190 -102
  23. package/dist/clients/prowlarr.js.map +23 -0
  24. package/dist/clients/qbittorrent.d.ts +3 -1
  25. package/dist/clients/qbittorrent.d.ts.map +1 -1
  26. package/dist/clients/qbittorrent.js +213 -107
  27. package/dist/clients/qbittorrent.js.map +21 -0
  28. package/dist/clients/radarr.d.ts +195 -150
  29. package/dist/clients/radarr.d.ts.map +1 -1
  30. package/dist/clients/radarr.js +230 -102
  31. package/dist/clients/radarr.js.map +23 -0
  32. package/dist/clients/readarr.d.ts +150 -149
  33. package/dist/clients/readarr.d.ts.map +1 -1
  34. package/dist/clients/readarr.js +190 -102
  35. package/dist/clients/readarr.js.map +23 -0
  36. package/dist/clients/seerr-types.d.ts +1 -1
  37. package/dist/clients/seerr-types.d.ts.map +1 -1
  38. package/dist/clients/seerr.d.ts +17 -16
  39. package/dist/clients/seerr.d.ts.map +1 -1
  40. package/dist/clients/seerr.js +183 -100
  41. package/dist/clients/seerr.js.map +22 -0
  42. package/dist/clients/sonarr.d.ts +203 -168
  43. package/dist/clients/sonarr.d.ts.map +1 -1
  44. package/dist/clients/sonarr.js +206 -112
  45. package/dist/clients/sonarr.js.map +23 -0
  46. package/dist/core/client.d.ts +2 -0
  47. package/dist/core/client.d.ts.map +1 -1
  48. package/dist/core/fetch.d.ts +23 -0
  49. package/dist/core/fetch.d.ts.map +1 -0
  50. package/dist/core/index.d.ts +1 -0
  51. package/dist/core/index.d.ts.map +1 -1
  52. package/dist/core/types.d.ts +7 -0
  53. package/dist/core/types.d.ts.map +1 -1
  54. package/dist/generated/bazarr/client/client.gen.d.ts.map +1 -1
  55. package/dist/generated/bazarr/client/types.gen.d.ts +5 -2
  56. package/dist/generated/bazarr/client/types.gen.d.ts.map +1 -1
  57. package/dist/generated/bazarr/client/utils.gen.d.ts +5 -1
  58. package/dist/generated/bazarr/client/utils.gen.d.ts.map +1 -1
  59. package/dist/generated/lidarr/client/client.gen.d.ts.map +1 -1
  60. package/dist/generated/lidarr/client/types.gen.d.ts +5 -2
  61. package/dist/generated/lidarr/client/types.gen.d.ts.map +1 -1
  62. package/dist/generated/lidarr/client/utils.gen.d.ts +5 -1
  63. package/dist/generated/lidarr/client/utils.gen.d.ts.map +1 -1
  64. package/dist/generated/prowlarr/client/client.gen.d.ts.map +1 -1
  65. package/dist/generated/prowlarr/client/types.gen.d.ts +5 -2
  66. package/dist/generated/prowlarr/client/types.gen.d.ts.map +1 -1
  67. package/dist/generated/prowlarr/client/utils.gen.d.ts +5 -1
  68. package/dist/generated/prowlarr/client/utils.gen.d.ts.map +1 -1
  69. package/dist/generated/qbittorrent/client/client.gen.d.ts.map +1 -1
  70. package/dist/generated/qbittorrent/client/types.gen.d.ts +5 -2
  71. package/dist/generated/qbittorrent/client/types.gen.d.ts.map +1 -1
  72. package/dist/generated/qbittorrent/client/utils.gen.d.ts +5 -1
  73. package/dist/generated/qbittorrent/client/utils.gen.d.ts.map +1 -1
  74. package/dist/generated/radarr/client/client.gen.d.ts.map +1 -1
  75. package/dist/generated/radarr/client/types.gen.d.ts +5 -2
  76. package/dist/generated/radarr/client/types.gen.d.ts.map +1 -1
  77. package/dist/generated/radarr/client/utils.gen.d.ts +5 -1
  78. package/dist/generated/radarr/client/utils.gen.d.ts.map +1 -1
  79. package/dist/generated/readarr/client/client.gen.d.ts.map +1 -1
  80. package/dist/generated/readarr/client/types.gen.d.ts +5 -2
  81. package/dist/generated/readarr/client/types.gen.d.ts.map +1 -1
  82. package/dist/generated/readarr/client/utils.gen.d.ts +5 -1
  83. package/dist/generated/readarr/client/utils.gen.d.ts.map +1 -1
  84. package/dist/generated/seerr/client/client.gen.d.ts.map +1 -1
  85. package/dist/generated/seerr/client/types.gen.d.ts +5 -2
  86. package/dist/generated/seerr/client/types.gen.d.ts.map +1 -1
  87. package/dist/generated/seerr/client/utils.gen.d.ts +5 -1
  88. package/dist/generated/seerr/client/utils.gen.d.ts.map +1 -1
  89. package/dist/generated/seerr/index.d.ts +2 -2
  90. package/dist/generated/seerr/index.d.ts.map +1 -1
  91. package/dist/generated/seerr/sdk.gen.d.ts +13 -1
  92. package/dist/generated/seerr/sdk.gen.d.ts.map +1 -1
  93. package/dist/generated/seerr/types.gen.d.ts +78 -7
  94. package/dist/generated/seerr/types.gen.d.ts.map +1 -1
  95. package/dist/generated/sonarr/client/client.gen.d.ts.map +1 -1
  96. package/dist/generated/sonarr/client/types.gen.d.ts +5 -2
  97. package/dist/generated/sonarr/client/types.gen.d.ts.map +1 -1
  98. package/dist/generated/sonarr/client/utils.gen.d.ts +5 -1
  99. package/dist/generated/sonarr/client/utils.gen.d.ts.map +1 -1
  100. package/dist/index.js +4 -1
  101. package/dist/index.js.map +12 -0
  102. package/dist/tsarr-2.11.0.tgz +0 -0
  103. package/package.json +18 -9
  104. package/dist/tsarr-2.9.1.tgz +0 -0
@@ -26,6 +26,93 @@ 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
30
117
  var DEFAULT_TIMEOUT_MS = 30000;
31
118
  function createServarrClient(config) {
@@ -40,6 +127,10 @@ function createServarrClient(config) {
40
127
  baseUrl: config.baseUrl.replace(/\/$/, "")
41
128
  };
42
129
  const timeoutMs = validatedConfig.timeout ?? DEFAULT_TIMEOUT_MS;
130
+ const resilientFetch = createResilientFetch({
131
+ timeout: timeoutMs,
132
+ retry: validatedConfig.retry
133
+ });
43
134
  return {
44
135
  config: validatedConfig,
45
136
  getHeaders: () => ({
@@ -48,7 +139,8 @@ function createServarrClient(config) {
48
139
  ...validatedConfig.headers
49
140
  }),
50
141
  getBaseUrl: () => validatedConfig.baseUrl,
51
- getTimeout: () => timeoutMs
142
+ getTimeout: () => timeoutMs,
143
+ getFetch: () => resilientFetch
52
144
  };
53
145
  }
54
146
 
@@ -694,126 +786,115 @@ var createClient = (config = {}) => {
694
786
  return { opts: resolvedOpts, url };
695
787
  };
696
788
  const request = async (options) => {
697
- const { opts, url } = await beforeRequest(options);
698
- const requestInit = {
699
- redirect: "follow",
700
- ...opts,
701
- body: getValidRequestBody(opts)
702
- };
703
- let request2 = new Request(url, requestInit);
704
- for (const fn of interceptors.request.fns) {
705
- if (fn) {
706
- request2 = await fn(request2, opts);
707
- }
708
- }
709
- const _fetch = opts.fetch;
789
+ const throwOnError = options.throwOnError ?? _config.throwOnError;
790
+ const responseStyle = options.responseStyle ?? _config.responseStyle;
791
+ let request2;
710
792
  let response;
711
793
  try {
712
- response = await _fetch(request2);
713
- } catch (error2) {
714
- let finalError2 = error2;
715
- for (const fn of interceptors.error.fns) {
794
+ const { opts, url } = await beforeRequest(options);
795
+ const requestInit = {
796
+ redirect: "follow",
797
+ ...opts,
798
+ body: getValidRequestBody(opts)
799
+ };
800
+ request2 = new Request(url, requestInit);
801
+ for (const fn of interceptors.request.fns) {
716
802
  if (fn) {
717
- finalError2 = await fn(error2, undefined, request2, opts);
803
+ request2 = await fn(request2, opts);
718
804
  }
719
805
  }
720
- finalError2 = finalError2 || {};
721
- if (opts.throwOnError) {
722
- throw finalError2;
806
+ const _fetch = opts.fetch;
807
+ response = await _fetch(request2);
808
+ for (const fn of interceptors.response.fns) {
809
+ if (fn) {
810
+ response = await fn(response, request2, opts);
811
+ }
723
812
  }
724
- return opts.responseStyle === "data" ? undefined : {
725
- error: finalError2,
813
+ const result = {
726
814
  request: request2,
727
- response: undefined
815
+ response
728
816
  };
729
- }
730
- for (const fn of interceptors.response.fns) {
731
- if (fn) {
732
- response = await fn(response, request2, opts);
733
- }
734
- }
735
- const result = {
736
- request: request2,
737
- response
738
- };
739
- if (response.ok) {
740
- const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
741
- if (response.status === 204 || response.headers.get("Content-Length") === "0") {
742
- let emptyData;
817
+ if (response.ok) {
818
+ const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
819
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
820
+ let emptyData;
821
+ switch (parseAs) {
822
+ case "arrayBuffer":
823
+ case "blob":
824
+ case "text":
825
+ emptyData = await response[parseAs]();
826
+ break;
827
+ case "formData":
828
+ emptyData = new FormData;
829
+ break;
830
+ case "stream":
831
+ emptyData = response.body;
832
+ break;
833
+ case "json":
834
+ default:
835
+ emptyData = {};
836
+ break;
837
+ }
838
+ return opts.responseStyle === "data" ? emptyData : {
839
+ data: emptyData,
840
+ ...result
841
+ };
842
+ }
843
+ let data;
743
844
  switch (parseAs) {
744
845
  case "arrayBuffer":
745
846
  case "blob":
847
+ case "formData":
746
848
  case "text":
747
- emptyData = await response[parseAs]();
849
+ data = await response[parseAs]();
748
850
  break;
749
- case "formData":
750
- emptyData = new FormData;
851
+ case "json": {
852
+ const text = await response.text();
853
+ data = text ? JSON.parse(text) : {};
751
854
  break;
855
+ }
752
856
  case "stream":
753
- emptyData = response.body;
754
- break;
755
- case "json":
756
- default:
757
- emptyData = {};
758
- break;
857
+ return opts.responseStyle === "data" ? response.body : {
858
+ data: response.body,
859
+ ...result
860
+ };
759
861
  }
760
- return opts.responseStyle === "data" ? emptyData : {
761
- data: emptyData,
862
+ if (parseAs === "json") {
863
+ if (opts.responseValidator) {
864
+ await opts.responseValidator(data);
865
+ }
866
+ if (opts.responseTransformer) {
867
+ data = await opts.responseTransformer(data);
868
+ }
869
+ }
870
+ return opts.responseStyle === "data" ? data : {
871
+ data,
762
872
  ...result
763
873
  };
764
874
  }
765
- let data;
766
- switch (parseAs) {
767
- case "arrayBuffer":
768
- case "blob":
769
- case "formData":
770
- case "text":
771
- data = await response[parseAs]();
772
- break;
773
- case "json": {
774
- const text = await response.text();
775
- data = text ? JSON.parse(text) : {};
776
- break;
875
+ const textError = await response.text();
876
+ let jsonError;
877
+ try {
878
+ jsonError = JSON.parse(textError);
879
+ } catch {}
880
+ throw jsonError ?? textError;
881
+ } catch (error) {
882
+ let finalError = error;
883
+ for (const fn of interceptors.error.fns) {
884
+ if (fn) {
885
+ finalError = await fn(finalError, response, request2, options);
777
886
  }
778
- case "stream":
779
- return opts.responseStyle === "data" ? response.body : {
780
- data: response.body,
781
- ...result
782
- };
783
887
  }
784
- if (parseAs === "json") {
785
- if (opts.responseValidator) {
786
- await opts.responseValidator(data);
787
- }
788
- if (opts.responseTransformer) {
789
- data = await opts.responseTransformer(data);
790
- }
888
+ finalError = finalError || {};
889
+ if (throwOnError) {
890
+ throw finalError;
791
891
  }
792
- return opts.responseStyle === "data" ? data : {
793
- data,
794
- ...result
892
+ return responseStyle === "data" ? undefined : {
893
+ error: finalError,
894
+ request: request2,
895
+ response
795
896
  };
796
897
  }
797
- const textError = await response.text();
798
- let jsonError;
799
- try {
800
- jsonError = JSON.parse(textError);
801
- } catch {}
802
- const error = jsonError ?? textError;
803
- let finalError = error;
804
- for (const fn of interceptors.error.fns) {
805
- if (fn) {
806
- finalError = await fn(error, response, request2, opts);
807
- }
808
- }
809
- finalError = finalError || {};
810
- if (opts.throwOnError) {
811
- throw finalError;
812
- }
813
- return opts.responseStyle === "data" ? undefined : {
814
- error: finalError,
815
- ...result
816
- };
817
898
  };
818
899
  const makeMethodFn = (method) => (options) => request({ ...options, method });
819
900
  const makeSseFn = (method) => async (options) => {
@@ -821,7 +902,6 @@ var createClient = (config = {}) => {
821
902
  return createSseClient({
822
903
  ...opts,
823
904
  body: opts.body,
824
- headers: opts.headers,
825
905
  method,
826
906
  onRequest: async (url2, init) => {
827
907
  let request2 = new Request(url2, init);
@@ -1212,7 +1292,7 @@ class BazarrClient {
1212
1292
  baseUrl: getBazarrApiBaseUrl(this.clientConfig.getBaseUrl()),
1213
1293
  headers: getBazarrHeaders(this.clientConfig),
1214
1294
  auth: this.clientConfig.config.apiKey,
1215
- signal: AbortSignal.timeout(this.clientConfig.getTimeout())
1295
+ fetch: this.clientConfig.getFetch()
1216
1296
  });
1217
1297
  }
1218
1298
  async getSystemStatus() {
@@ -1554,7 +1634,7 @@ class BazarrClient {
1554
1634
  baseUrl: getBazarrApiBaseUrl(this.clientConfig.getBaseUrl()),
1555
1635
  headers: getBazarrHeaders(this.clientConfig),
1556
1636
  auth: this.clientConfig.config.apiKey,
1557
- signal: AbortSignal.timeout(this.clientConfig.getTimeout())
1637
+ fetch: this.clientConfig.getFetch()
1558
1638
  });
1559
1639
  return this.clientConfig.config;
1560
1640
  }
@@ -1562,3 +1642,6 @@ class BazarrClient {
1562
1642
  export {
1563
1643
  BazarrClient
1564
1644
  };
1645
+
1646
+ //# debugId=2BD161259ECE024964756E2164756E21
1647
+ //# sourceMappingURL=bazarr.js.map