@media-engine/providers 0.1.0 → 1.0.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 +149 -242
- package/README.ru.md +204 -0
- package/dist/aniliberty-streaming/client.d.ts +33 -0
- package/dist/aniliberty-streaming/client.js +188 -0
- package/dist/aniliberty-streaming/client.js.map +1 -0
- package/dist/aniliberty-streaming/config.d.ts +24 -0
- package/dist/aniliberty-streaming/config.js +61 -0
- package/dist/aniliberty-streaming/config.js.map +1 -0
- package/dist/aniliberty-streaming/index.d.ts +4 -0
- package/dist/aniliberty-streaming/index.js +45 -0
- package/dist/aniliberty-streaming/index.js.map +1 -0
- package/dist/aniliberty-streaming/mapping.d.ts +3 -0
- package/dist/aniliberty-streaming/mapping.js +87 -0
- package/dist/aniliberty-streaming/mapping.js.map +1 -0
- package/dist/aniliberty-streaming/matching.d.ts +4 -0
- package/dist/aniliberty-streaming/matching.js +44 -0
- package/dist/aniliberty-streaming/matching.js.map +1 -0
- package/dist/anilist/graphql.d.ts +2 -0
- package/dist/anilist/graphql.js +135 -0
- package/dist/anilist/graphql.js.map +1 -0
- package/dist/anilist/index.js +11 -6
- package/dist/anilist/index.js.map +1 -1
- package/dist/bitsearch-torrent/client.d.ts +19 -0
- package/dist/bitsearch-torrent/client.js +181 -0
- package/dist/bitsearch-torrent/client.js.map +1 -0
- package/dist/bitsearch-torrent/config.d.ts +26 -0
- package/dist/bitsearch-torrent/config.js +74 -0
- package/dist/bitsearch-torrent/config.js.map +1 -0
- package/dist/bitsearch-torrent/index.d.ts +4 -0
- package/dist/bitsearch-torrent/index.js +35 -0
- package/dist/bitsearch-torrent/index.js.map +1 -0
- package/dist/bitsearch-torrent/mapping.d.ts +3 -0
- package/dist/bitsearch-torrent/mapping.js +53 -0
- package/dist/bitsearch-torrent/mapping.js.map +1 -0
- package/dist/bitsearch-torrent/matching.d.ts +3 -0
- package/dist/bitsearch-torrent/matching.js +13 -0
- package/dist/bitsearch-torrent/matching.js.map +1 -0
- package/dist/bitsearch-torrent/quota.d.ts +9 -0
- package/dist/bitsearch-torrent/quota.js +53 -0
- package/dist/bitsearch-torrent/quota.js.map +1 -0
- package/dist/cinemeta/index.js +53 -35
- package/dist/cinemeta/index.js.map +1 -1
- package/dist/ddbb-streaming/client.d.ts +24 -0
- package/dist/ddbb-streaming/client.js +98 -0
- package/dist/ddbb-streaming/client.js.map +1 -0
- package/dist/ddbb-streaming/config.d.ts +31 -0
- package/dist/ddbb-streaming/config.js +67 -0
- package/dist/ddbb-streaming/config.js.map +1 -0
- package/dist/ddbb-streaming/index.d.ts +4 -0
- package/dist/ddbb-streaming/index.js +53 -0
- package/dist/ddbb-streaming/index.js.map +1 -0
- package/dist/ddbb-streaming/mapping.d.ts +8 -0
- package/dist/ddbb-streaming/mapping.js +164 -0
- package/dist/ddbb-streaming/mapping.js.map +1 -0
- package/dist/ddbb-streaming/validation.d.ts +3 -0
- package/dist/ddbb-streaming/validation.js +84 -0
- package/dist/ddbb-streaming/validation.js.map +1 -0
- package/dist/experimental-streaming/index.js +55 -0
- package/dist/experimental-streaming/index.js.map +1 -1
- package/dist/flixhq-streaming/client.d.ts +12 -0
- package/dist/flixhq-streaming/client.js +103 -0
- package/dist/flixhq-streaming/client.js.map +1 -0
- package/dist/flixhq-streaming/index.d.ts +2 -2
- package/dist/flixhq-streaming/index.js +67 -106
- package/dist/flixhq-streaming/index.js.map +1 -1
- package/dist/imdb-dataset/index.d.ts +20 -5
- package/dist/imdb-dataset/index.js +83 -197
- package/dist/imdb-dataset/index.js.map +1 -1
- package/dist/imdb-dataset/memory-storage.d.ts +7 -0
- package/dist/imdb-dataset/memory-storage.js +168 -0
- package/dist/imdb-dataset/memory-storage.js.map +1 -0
- package/dist/imdb-dataset/sqlite-import.d.ts +24 -0
- package/dist/imdb-dataset/sqlite-import.js +298 -0
- package/dist/imdb-dataset/sqlite-import.js.map +1 -0
- package/dist/imdb-dataset/sqlite-runtime.d.ts +3 -0
- package/dist/imdb-dataset/sqlite-runtime.js +11 -0
- package/dist/imdb-dataset/sqlite-runtime.js.map +1 -0
- package/dist/imdb-dataset/sqlite-schema.d.ts +6 -0
- package/dist/imdb-dataset/sqlite-schema.js +88 -0
- package/dist/imdb-dataset/sqlite-schema.js.map +1 -0
- package/dist/imdb-dataset/sqlite-storage.d.ts +12 -0
- package/dist/imdb-dataset/sqlite-storage.js +208 -0
- package/dist/imdb-dataset/sqlite-storage.js.map +1 -0
- package/dist/imdb-dataset/storage.d.ts +33 -0
- package/dist/imdb-dataset/storage.js +2 -0
- package/dist/imdb-dataset/storage.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/jacred-torrent/client.d.ts +24 -0
- package/dist/jacred-torrent/client.js +254 -0
- package/dist/jacred-torrent/client.js.map +1 -0
- package/dist/jacred-torrent/config.d.ts +24 -0
- package/dist/jacred-torrent/config.js +70 -0
- package/dist/jacred-torrent/config.js.map +1 -0
- package/dist/jacred-torrent/index.d.ts +4 -0
- package/dist/jacred-torrent/index.js +45 -0
- package/dist/jacred-torrent/index.js.map +1 -0
- package/dist/jacred-torrent/mapping.d.ts +3 -0
- package/dist/jacred-torrent/mapping.js +129 -0
- package/dist/jacred-torrent/mapping.js.map +1 -0
- package/dist/jacred-torrent/matching.d.ts +3 -0
- package/dist/jacred-torrent/matching.js +19 -0
- package/dist/jacred-torrent/matching.js.map +1 -0
- package/dist/kinobd/index.js +15 -33
- package/dist/kinobd/index.js.map +1 -1
- package/dist/kinobd-streaming/availability.d.ts +3 -0
- package/dist/kinobd-streaming/availability.js +179 -0
- package/dist/kinobd-streaming/availability.js.map +1 -0
- package/dist/kinobd-streaming/candidates.d.ts +32 -0
- package/dist/kinobd-streaming/candidates.js +282 -0
- package/dist/kinobd-streaming/candidates.js.map +1 -0
- package/dist/kinobd-streaming/config.d.ts +64 -0
- package/dist/kinobd-streaming/config.js +129 -0
- package/dist/kinobd-streaming/config.js.map +1 -0
- package/dist/kinobd-streaming/index.d.ts +3 -30
- package/dist/kinobd-streaming/index.js +2 -904
- package/dist/kinobd-streaming/index.js.map +1 -1
- package/dist/kinobd-streaming/players.d.ts +24 -0
- package/dist/kinobd-streaming/players.js +270 -0
- package/dist/kinobd-streaming/players.js.map +1 -0
- package/dist/kinobd-streaming/request-budget.d.ts +15 -0
- package/dist/kinobd-streaming/request-budget.js +61 -0
- package/dist/kinobd-streaming/request-budget.js.map +1 -0
- package/dist/kinobd-streaming/validation.d.ts +11 -0
- package/dist/kinobd-streaming/validation.js +170 -0
- package/dist/kinobd-streaming/validation.js.map +1 -0
- package/dist/magnetz-torrent/client.d.ts +16 -0
- package/dist/magnetz-torrent/client.js +235 -0
- package/dist/magnetz-torrent/client.js.map +1 -0
- package/dist/magnetz-torrent/config.d.ts +27 -0
- package/dist/magnetz-torrent/config.js +73 -0
- package/dist/magnetz-torrent/config.js.map +1 -0
- package/dist/magnetz-torrent/index.d.ts +4 -0
- package/dist/magnetz-torrent/index.js +35 -0
- package/dist/magnetz-torrent/index.js.map +1 -0
- package/dist/magnetz-torrent/mapping.d.ts +3 -0
- package/dist/magnetz-torrent/mapping.js +52 -0
- package/dist/magnetz-torrent/mapping.js.map +1 -0
- package/dist/magnetz-torrent/matching.d.ts +3 -0
- package/dist/magnetz-torrent/matching.js +5 -0
- package/dist/magnetz-torrent/matching.js.map +1 -0
- package/dist/magnetz-torrent/request-gate.d.ts +9 -0
- package/dist/magnetz-torrent/request-gate.js +48 -0
- package/dist/magnetz-torrent/request-gate.js.map +1 -0
- package/dist/package-version.d.ts +2 -0
- package/dist/package-version.js +5 -0
- package/dist/package-version.js.map +1 -0
- package/dist/shared/abort.d.ts +3 -0
- package/dist/shared/abort.js +30 -0
- package/dist/shared/abort.js.map +1 -0
- package/dist/shared/http.d.ts +13 -2
- package/dist/shared/http.js +77 -75
- package/dist/shared/http.js.map +1 -1
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/mapping.d.ts +5 -0
- package/dist/shared/mapping.js +32 -0
- package/dist/shared/mapping.js.map +1 -0
- package/dist/shared/options.d.ts +1 -0
- package/dist/shared/options.js +10 -0
- package/dist/shared/options.js.map +1 -0
- package/dist/shared/output-url.d.ts +2 -0
- package/dist/shared/output-url.js +50 -0
- package/dist/shared/output-url.js.map +1 -0
- package/dist/shared/rate-limit.d.ts +11 -0
- package/dist/shared/rate-limit.js +52 -0
- package/dist/shared/rate-limit.js.map +1 -0
- package/dist/shared/response-body.d.ts +6 -0
- package/dist/shared/response-body.js +109 -0
- package/dist/shared/response-body.js.map +1 -0
- package/dist/shared/retry.d.ts +10 -0
- package/dist/shared/retry.js +31 -0
- package/dist/shared/retry.js.map +1 -0
- package/dist/shared/safe-fetch.d.ts +14 -0
- package/dist/shared/safe-fetch.js +274 -0
- package/dist/shared/safe-fetch.js.map +1 -0
- package/dist/shared/torrent-release-matching.d.ts +7 -0
- package/dist/shared/torrent-release-matching.js +143 -0
- package/dist/shared/torrent-release-matching.js.map +1 -0
- package/dist/shared/torrent-release-metadata.d.ts +4 -0
- package/dist/shared/torrent-release-metadata.js +95 -0
- package/dist/shared/torrent-release-metadata.js.map +1 -0
- package/dist/shikimori/index.js +19 -11
- package/dist/shikimori/index.js.map +1 -1
- package/dist/tvmaze/index.d.ts +11 -0
- package/dist/tvmaze/index.js +274 -0
- package/dist/tvmaze/index.js.map +1 -0
- package/dist/wikidata/cache.d.ts +11 -0
- package/dist/wikidata/cache.js +30 -0
- package/dist/wikidata/cache.js.map +1 -0
- package/dist/wikidata/candidates.d.ts +12 -0
- package/dist/wikidata/candidates.js +67 -0
- package/dist/wikidata/candidates.js.map +1 -0
- package/dist/wikidata/client.d.ts +40 -0
- package/dist/wikidata/client.js +224 -0
- package/dist/wikidata/client.js.map +1 -0
- package/dist/wikidata/index.d.ts +3 -0
- package/dist/wikidata/index.js +34 -111
- package/dist/wikidata/index.js.map +1 -1
- package/dist/yts-torrent/client.d.ts +25 -0
- package/dist/yts-torrent/client.js +163 -0
- package/dist/yts-torrent/client.js.map +1 -0
- package/dist/yts-torrent/config.d.ts +22 -0
- package/dist/yts-torrent/config.js +57 -0
- package/dist/yts-torrent/config.js.map +1 -0
- package/dist/yts-torrent/index.d.ts +4 -0
- package/dist/yts-torrent/index.js +42 -0
- package/dist/yts-torrent/index.js.map +1 -0
- package/dist/yts-torrent/mapping.d.ts +4 -0
- package/dist/yts-torrent/mapping.js +107 -0
- package/dist/yts-torrent/mapping.js.map +1 -0
- package/package.json +23 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abort.js","sourceRoot":"","sources":["../../src/shared/abort.ts"],"names":[],"mappings":"AAEA,+FAA+F;AAC/F,oGAAoG;AACpG,MAAM,UAAU,wBAAwB,CACtC,OAAwC,EACxC,KAAc;IAEd,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC;IACvC,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CACnC,YAAoB,EACpB,MAA+B;IAE/B,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7E,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,YAAY,CAAC,CAAC;QACjB,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC;QACF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/shared/http.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { ProviderError, type ProviderErrorCode } from "@media-engine/core";
|
|
2
2
|
import type { ProviderContext } from "@media-engine/core";
|
|
3
|
+
import type { ProviderRateLimitGate } from "./rate-limit.js";
|
|
3
4
|
export type ProviderFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
|
|
4
|
-
export
|
|
5
|
+
export interface ProviderHttpScheduler {
|
|
6
|
+
setTimeout(callback: () => void, delayMs: number): unknown;
|
|
7
|
+
clearTimeout(handle: unknown): void;
|
|
8
|
+
}
|
|
5
9
|
export interface FetchJsonOptions {
|
|
6
10
|
provider: string;
|
|
7
11
|
url: string | URL;
|
|
@@ -10,8 +14,15 @@ export interface FetchJsonOptions {
|
|
|
10
14
|
fetch?: ProviderFetch;
|
|
11
15
|
maxRetries?: number;
|
|
12
16
|
retryDelayMs?: number;
|
|
17
|
+
maxRetryDelayMs?: number;
|
|
18
|
+
retryJitterRatio?: number;
|
|
19
|
+
maxResponseBytes?: number;
|
|
20
|
+
rateLimitGate?: ProviderRateLimitGate;
|
|
21
|
+
scheduler?: ProviderHttpScheduler;
|
|
13
22
|
}
|
|
14
23
|
export declare function fetchJson<T>(options: FetchJsonOptions): Promise<T>;
|
|
15
|
-
export declare function parseJsonResponse<T>(provider: string, response: Response): Promise<T>;
|
|
24
|
+
export declare function parseJsonResponse<T>(provider: string, response: Response, maxResponseBytes?: number, signal?: AbortSignal): Promise<T>;
|
|
16
25
|
export declare function mapProviderHttpError(provider: string, error: unknown): ProviderError;
|
|
17
26
|
export declare function mapHttpStatusToProviderErrorCode(status: number): ProviderErrorCode;
|
|
27
|
+
export declare function mapHttpResponseToProviderError(provider: string, response: Response): ProviderError;
|
|
28
|
+
export declare function getProviderHttpStatus(error: unknown): number | undefined;
|
package/dist/shared/http.js
CHANGED
|
@@ -1,68 +1,32 @@
|
|
|
1
1
|
import { ProviderError } from "@media-engine/core";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
isPrivateHostname(url.hostname)) {
|
|
14
|
-
return undefined;
|
|
15
|
-
}
|
|
16
|
-
return url.href;
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function isPrivateHostname(value) {
|
|
23
|
-
const hostname = value
|
|
24
|
-
.toLowerCase()
|
|
25
|
-
.replace(/^\[|\]$/g, "")
|
|
26
|
-
.replace(/\.$/, "");
|
|
27
|
-
if (hostname === "localhost" ||
|
|
28
|
-
hostname.endsWith(".localhost") ||
|
|
29
|
-
hostname === "0.0.0.0" ||
|
|
30
|
-
hostname === "::" ||
|
|
31
|
-
hostname === "::1") {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
if (hostname.includes(":")) {
|
|
35
|
-
const first = Number.parseInt(hostname.split(":")[0] ?? "", 16);
|
|
36
|
-
return (hostname.startsWith("::ffff:") ||
|
|
37
|
-
(first >= 0xfc00 && first <= 0xfdff) ||
|
|
38
|
-
(first >= 0xfe80 && first <= 0xfebf));
|
|
39
|
-
}
|
|
40
|
-
const octets = hostname.split(".").map(Number);
|
|
41
|
-
if (octets.length !== 4 ||
|
|
42
|
-
octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
const [first, second] = octets;
|
|
46
|
-
return (first === 0 ||
|
|
47
|
-
first === 10 ||
|
|
48
|
-
first === 127 ||
|
|
49
|
-
(first === 100 && second >= 64 && second <= 127) ||
|
|
50
|
-
(first === 169 && second === 254) ||
|
|
51
|
-
(first === 172 && second >= 16 && second <= 31) ||
|
|
52
|
-
(first === 192 && second === 0) ||
|
|
53
|
-
(first === 192 && second === 168) ||
|
|
54
|
-
(first === 198 && (second === 18 || second === 19)) ||
|
|
55
|
-
first >= 224);
|
|
56
|
-
}
|
|
2
|
+
import { readBoundedResponseText } from "./response-body.js";
|
|
3
|
+
import { calculateRetryDelayMs, parseRetryAfterMs } from "./retry.js";
|
|
4
|
+
const DEFAULT_MAX_JSON_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
5
|
+
const defaultScheduler = {
|
|
6
|
+
setTimeout(callback, delayMs) {
|
|
7
|
+
return setTimeout(callback, delayMs);
|
|
8
|
+
},
|
|
9
|
+
clearTimeout(handle) {
|
|
10
|
+
clearTimeout(handle);
|
|
11
|
+
},
|
|
12
|
+
};
|
|
57
13
|
// Reads JSON through fetch and maps failures to ProviderError.
|
|
58
14
|
// Читает JSON через fetch и преобразует сбои в ProviderError.
|
|
59
15
|
export async function fetchJson(options) {
|
|
60
16
|
const maxRetries = options.maxRetries ?? 1;
|
|
61
17
|
const retryDelayMs = options.retryDelayMs ?? 150;
|
|
62
|
-
const
|
|
18
|
+
const maxRetryDelayMs = options.maxRetryDelayMs ?? 2_000;
|
|
19
|
+
const retryJitterRatio = options.retryJitterRatio ?? 0.2;
|
|
20
|
+
const maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_JSON_RESPONSE_BYTES;
|
|
21
|
+
if (!Number.isSafeInteger(maxResponseBytes) || maxResponseBytes <= 0) {
|
|
22
|
+
throw new TypeError("fetchJson maxResponseBytes must be a positive safe integer.");
|
|
23
|
+
}
|
|
24
|
+
const scheduler = options.scheduler ?? defaultScheduler;
|
|
25
|
+
const timeout = createProviderTimeout(options.provider, options.context, scheduler);
|
|
63
26
|
const signal = mergeAbortSignals(options.context?.signal, timeout.controller.signal);
|
|
64
27
|
const boundedOptions = {
|
|
65
28
|
...options,
|
|
29
|
+
maxResponseBytes,
|
|
66
30
|
context: {
|
|
67
31
|
...options.context,
|
|
68
32
|
signal,
|
|
@@ -74,15 +38,25 @@ export async function fetchJson(options) {
|
|
|
74
38
|
try {
|
|
75
39
|
while (attempt <= maxRetries) {
|
|
76
40
|
try {
|
|
41
|
+
await options.rateLimitGate?.wait(signal);
|
|
77
42
|
return await fetchJsonAttempt(boundedOptions);
|
|
78
43
|
}
|
|
79
44
|
catch (error) {
|
|
80
45
|
const providerError = mapProviderHttpError(options.provider, error);
|
|
46
|
+
const retryDelay = calculateRetryDelayMs({
|
|
47
|
+
baseDelayMs: retryDelayMs,
|
|
48
|
+
attempt,
|
|
49
|
+
maxDelayMs: maxRetryDelayMs,
|
|
50
|
+
jitterRatio: retryJitterRatio,
|
|
51
|
+
randomValue: Math.random(),
|
|
52
|
+
retryAfterMs: getRetryAfterMs(providerError),
|
|
53
|
+
});
|
|
81
54
|
lastError = providerError;
|
|
55
|
+
deferSharedRateLimit(options.rateLimitGate, providerError, retryDelay);
|
|
82
56
|
if (!providerError.retryable || attempt >= maxRetries) {
|
|
83
57
|
throw providerError;
|
|
84
58
|
}
|
|
85
|
-
await delay(
|
|
59
|
+
await delay(retryDelay, signal, scheduler);
|
|
86
60
|
attempt += 1;
|
|
87
61
|
}
|
|
88
62
|
}
|
|
@@ -96,7 +70,7 @@ export async function fetchJson(options) {
|
|
|
96
70
|
// Выполняет одну попытку JSON HTTP с новым timeout signal.
|
|
97
71
|
async function fetchJsonAttempt(options) {
|
|
98
72
|
const fetchImpl = options.fetch ?? fetch;
|
|
99
|
-
const timeout = createProviderTimeout(options.provider, options.context);
|
|
73
|
+
const timeout = createProviderTimeout(options.provider, options.context, options.scheduler ?? defaultScheduler);
|
|
100
74
|
const signal = mergeAbortSignals(options.context?.signal, timeout.controller.signal);
|
|
101
75
|
try {
|
|
102
76
|
const response = await fetchImpl(options.url, {
|
|
@@ -104,9 +78,9 @@ async function fetchJsonAttempt(options) {
|
|
|
104
78
|
signal,
|
|
105
79
|
});
|
|
106
80
|
if (!response.ok) {
|
|
107
|
-
throw
|
|
81
|
+
throw mapHttpResponseToProviderError(options.provider, response);
|
|
108
82
|
}
|
|
109
|
-
return await parseJsonResponse(options.provider, response);
|
|
83
|
+
return await parseJsonResponse(options.provider, response, options.maxResponseBytes ?? DEFAULT_MAX_JSON_RESPONSE_BYTES, signal);
|
|
110
84
|
}
|
|
111
85
|
finally {
|
|
112
86
|
timeout.clear();
|
|
@@ -114,9 +88,10 @@ async function fetchJsonAttempt(options) {
|
|
|
114
88
|
}
|
|
115
89
|
// Parses response JSON and maps invalid bodies to ProviderError.
|
|
116
90
|
// Парсит JSON ответа и преобразует невалидное тело в ProviderError.
|
|
117
|
-
export async function parseJsonResponse(provider, response) {
|
|
91
|
+
export async function parseJsonResponse(provider, response, maxResponseBytes = DEFAULT_MAX_JSON_RESPONSE_BYTES, signal) {
|
|
92
|
+
const text = await readBoundedResponseText(provider, response, maxResponseBytes, { signal });
|
|
118
93
|
try {
|
|
119
|
-
return
|
|
94
|
+
return JSON.parse(text);
|
|
120
95
|
}
|
|
121
96
|
catch (error) {
|
|
122
97
|
throw new ProviderError({
|
|
@@ -176,18 +151,50 @@ export function mapHttpStatusToProviderErrorCode(status) {
|
|
|
176
151
|
}
|
|
177
152
|
// Creates a ProviderError from an HTTP response status.
|
|
178
153
|
// Создает ProviderError из HTTP status ответа.
|
|
179
|
-
function
|
|
154
|
+
export function mapHttpResponseToProviderError(provider, response) {
|
|
155
|
+
const status = response.status;
|
|
180
156
|
const code = mapHttpStatusToProviderErrorCode(status);
|
|
181
|
-
return new
|
|
157
|
+
return new HttpProviderError({
|
|
182
158
|
provider,
|
|
183
159
|
code,
|
|
184
160
|
message: `Provider "${provider}" returned HTTP ${status}.`,
|
|
185
161
|
retryable: code === "PROVIDER_RATE_LIMITED" || code === "PROVIDER_UNAVAILABLE",
|
|
162
|
+
status,
|
|
163
|
+
retryAfterMs: parseRetryAfterMs(response.headers.get("retry-after")),
|
|
186
164
|
});
|
|
187
165
|
}
|
|
166
|
+
// Returns the HTTP status retained by errors created from provider responses.
|
|
167
|
+
// Возвращает HTTP status, сохраненный в ошибках из provider response.
|
|
168
|
+
export function getProviderHttpStatus(error) {
|
|
169
|
+
return error instanceof HttpProviderError ? error.status : undefined;
|
|
170
|
+
}
|
|
171
|
+
class HttpProviderError extends ProviderError {
|
|
172
|
+
status;
|
|
173
|
+
retryAfterMs;
|
|
174
|
+
constructor(options) {
|
|
175
|
+
super(options);
|
|
176
|
+
this.status = options.status;
|
|
177
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function getRetryAfterMs(error) {
|
|
181
|
+
return error instanceof HttpProviderError ? error.retryAfterMs : undefined;
|
|
182
|
+
}
|
|
183
|
+
function deferSharedRateLimit(gate, error, fallbackDelayMs) {
|
|
184
|
+
if (!gate || !(error instanceof HttpProviderError)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (error.code === "PROVIDER_RATE_LIMITED") {
|
|
188
|
+
gate.defer(error.retryAfterMs ?? fallbackDelayMs);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (error.retryAfterMs !== undefined) {
|
|
192
|
+
gate.defer(error.retryAfterMs);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
188
195
|
// Creates a timeout controller for provider HTTP calls.
|
|
189
196
|
// Создает timeout controller для HTTP-вызовов провайдера.
|
|
190
|
-
function createProviderTimeout(provider, context) {
|
|
197
|
+
function createProviderTimeout(provider, context, scheduler) {
|
|
191
198
|
const controller = new AbortController();
|
|
192
199
|
const timeoutMs = context?.timeoutMs;
|
|
193
200
|
if (timeoutMs === undefined) {
|
|
@@ -213,13 +220,13 @@ function createProviderTimeout(provider, context) {
|
|
|
213
220
|
},
|
|
214
221
|
};
|
|
215
222
|
}
|
|
216
|
-
const timeout = setTimeout(() => {
|
|
223
|
+
const timeout = scheduler.setTimeout(() => {
|
|
217
224
|
controller.abort(timeoutError);
|
|
218
225
|
}, timeoutMs);
|
|
219
226
|
return {
|
|
220
227
|
controller,
|
|
221
228
|
clear() {
|
|
222
|
-
clearTimeout(timeout);
|
|
229
|
+
scheduler.clearTimeout(timeout);
|
|
223
230
|
},
|
|
224
231
|
};
|
|
225
232
|
}
|
|
@@ -234,14 +241,9 @@ function isAbortError(error) {
|
|
|
234
241
|
return ((error instanceof DOMException && error.name === "AbortError") ||
|
|
235
242
|
(error instanceof Error && error.name === "AbortError"));
|
|
236
243
|
}
|
|
237
|
-
// Calculates a small linear backoff for provider retries.
|
|
238
|
-
// Считает небольшой линейный backoff для provider retry.
|
|
239
|
-
function getRetryDelayMs(baseDelayMs, attempt) {
|
|
240
|
-
return Math.max(0, baseDelayMs * (attempt + 1));
|
|
241
|
-
}
|
|
242
244
|
// Waits before the next provider retry.
|
|
243
245
|
// Ждет перед следующей provider retry.
|
|
244
|
-
function delay(ms, signal) {
|
|
246
|
+
function delay(ms, signal, scheduler) {
|
|
245
247
|
if (ms <= 0) {
|
|
246
248
|
return Promise.resolve();
|
|
247
249
|
}
|
|
@@ -250,12 +252,12 @@ function delay(ms, signal) {
|
|
|
250
252
|
reject(signal.reason);
|
|
251
253
|
return;
|
|
252
254
|
}
|
|
253
|
-
const timeout = setTimeout(() => {
|
|
255
|
+
const timeout = scheduler.setTimeout(() => {
|
|
254
256
|
signal?.removeEventListener("abort", onAbort);
|
|
255
257
|
resolve();
|
|
256
258
|
}, ms);
|
|
257
259
|
const onAbort = () => {
|
|
258
|
-
clearTimeout(timeout);
|
|
260
|
+
scheduler.clearTimeout(timeout);
|
|
259
261
|
reject(signal?.reason);
|
|
260
262
|
};
|
|
261
263
|
signal?.addEventListener("abort", onAbort, { once: true });
|
package/dist/shared/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/shared/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA0B,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/shared/http.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/index.d.ts
CHANGED
package/dist/shared/index.js
CHANGED
package/dist/shared/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Genre, Image, MediaType } from "@media-engine/core";
|
|
2
|
+
export declare function mapGenreNames(genres: string[] | undefined, source: string): Genre[] | undefined;
|
|
3
|
+
export declare function createProviderImage(url: string | null | undefined, type: Image["type"], source: string): Image | undefined;
|
|
4
|
+
export declare function normalizeProviderSearchText(value: string): string;
|
|
5
|
+
export declare function mapKinoBdMediaType(type: string | null | undefined): MediaType | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { normalizeProviderOutputUrl } from "./output-url.js";
|
|
2
|
+
// Maps simple genre labels into normalized provider-attributed values.
|
|
3
|
+
// Преобразует простые названия жанров в нормализованные значения с источником.
|
|
4
|
+
export function mapGenreNames(genres, source) {
|
|
5
|
+
return genres?.map((name) => ({ name, source }));
|
|
6
|
+
}
|
|
7
|
+
// Creates one normalized provider-attributed image from a direct URL.
|
|
8
|
+
// Создает одно нормализованное изображение с источником из прямого URL.
|
|
9
|
+
export function createProviderImage(url, type, source) {
|
|
10
|
+
const normalizedUrl = normalizeProviderOutputUrl(url);
|
|
11
|
+
return normalizedUrl ? { url: normalizedUrl, type, source } : undefined;
|
|
12
|
+
}
|
|
13
|
+
// Normalizes text for conservative provider-local title comparisons.
|
|
14
|
+
// Нормализует текст для консервативного сравнения названий внутри провайдеров.
|
|
15
|
+
export function normalizeProviderSearchText(value) {
|
|
16
|
+
return value
|
|
17
|
+
.toLocaleLowerCase()
|
|
18
|
+
.replaceAll(/[^\p{L}\p{N}]+/gu, " ")
|
|
19
|
+
.trim();
|
|
20
|
+
}
|
|
21
|
+
// Maps KinoBD API type labels shared by metadata and streaming adapters.
|
|
22
|
+
// Преобразует общие для metadata и streaming метки типов KinoBD API.
|
|
23
|
+
export function mapKinoBdMediaType(type) {
|
|
24
|
+
if (type === "film") {
|
|
25
|
+
return "movie";
|
|
26
|
+
}
|
|
27
|
+
if (type === "serial" || type === "series") {
|
|
28
|
+
return "series";
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=mapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapping.js","sourceRoot":"","sources":["../../src/shared/mapping.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE7D,uEAAuE;AACvE,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAC,MAA4B,EAAE,MAAc;IACxE,OAAO,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,sEAAsE;AACtE,wEAAwE;AACxE,MAAM,UAAU,mBAAmB,CACjC,GAA8B,EAC9B,IAAmB,EACnB,MAAc;IAEd,MAAM,aAAa,GAAG,0BAA0B,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1E,CAAC;AAED,qEAAqE;AACrE,+EAA+E;AAC/E,MAAM,UAAU,2BAA2B,CAAC,KAAa;IACvD,OAAO,KAAK;SACT,iBAAiB,EAAE;SACnB,UAAU,CAAC,kBAAkB,EAAE,GAAG,CAAC;SACnC,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,yEAAyE;AACzE,qEAAqE;AACrE,MAAM,UAAU,kBAAkB,CAAC,IAA+B;IAChE,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveBoundedIntegerOption(value: number | undefined, fallback: number, name: string, min: number, max: number): number;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Resolves a bounded integer option and fails early on unsafe provider configuration.
|
|
2
|
+
// Выбирает ограниченную integer-опцию и сразу отклоняет небезопасную конфигурацию провайдера.
|
|
3
|
+
export function resolveBoundedIntegerOption(value, fallback, name, min, max) {
|
|
4
|
+
const normalized = value ?? fallback;
|
|
5
|
+
if (!Number.isSafeInteger(normalized) || normalized < min || normalized > max) {
|
|
6
|
+
throw new RangeError(`${name} must be an integer between ${min} and ${max}.`);
|
|
7
|
+
}
|
|
8
|
+
return normalized;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/shared/options.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,8FAA8F;AAC9F,MAAM,UAAU,2BAA2B,CACzC,KAAyB,EACzB,QAAgB,EAChB,IAAY,EACZ,GAAW,EACX,GAAW;IAEX,MAAM,UAAU,GAAG,KAAK,IAAI,QAAQ,CAAC;IAErC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,GAAG,IAAI,UAAU,GAAG,GAAG,EAAE,CAAC;QAC9E,MAAM,IAAI,UAAU,CAAC,GAAG,IAAI,+BAA+B,GAAG,QAAQ,GAAG,GAAG,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isPublicIpAddress } from "./safe-fetch.js";
|
|
2
|
+
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/u;
|
|
3
|
+
// Normalizes a provider URL before it is exposed through metadata or streaming output.
|
|
4
|
+
// Нормализует URL провайдера перед публикацией в metadata или streaming output.
|
|
5
|
+
export function normalizeProviderOutputUrl(value) {
|
|
6
|
+
if (!value || CONTROL_CHARACTERS.test(value)) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const url = new URL(value);
|
|
11
|
+
if ((url.protocol !== "http:" && url.protocol !== "https:") ||
|
|
12
|
+
url.username !== "" ||
|
|
13
|
+
url.password !== "" ||
|
|
14
|
+
isLiteralLocalTarget(url.hostname)) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
return url.href;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// Backwards-compatible name for the provider output URL policy.
|
|
24
|
+
// Обратно совместимое имя политики provider output URL.
|
|
25
|
+
export function normalizePublicHttpUrl(value) {
|
|
26
|
+
return normalizeProviderOutputUrl(value);
|
|
27
|
+
}
|
|
28
|
+
function isLiteralLocalTarget(value) {
|
|
29
|
+
const hostname = value
|
|
30
|
+
.toLowerCase()
|
|
31
|
+
.replace(/^\[|\]$/g, "")
|
|
32
|
+
.replace(/\.$/, "");
|
|
33
|
+
if (hostname === "localhost" ||
|
|
34
|
+
hostname.endsWith(".localhost") ||
|
|
35
|
+
hostname === "0.0.0.0" ||
|
|
36
|
+
hostname === "::" ||
|
|
37
|
+
hostname === "::1") {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
if (hostname.includes(":")) {
|
|
41
|
+
return !isPublicIpAddress(hostname);
|
|
42
|
+
}
|
|
43
|
+
const octets = hostname.split(".").map(Number);
|
|
44
|
+
if (octets.length !== 4 ||
|
|
45
|
+
octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return !isPublicIpAddress(hostname);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=output-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-url.js","sourceRoot":"","sources":["../../src/shared/output-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAEpD,uFAAuF;AACvF,gFAAgF;AAChF,MAAM,UAAU,0BAA0B,CAAC,KAAgC;IACzE,IAAI,CAAC,KAAK,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAE3B,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;YACvD,GAAG,CAAC,QAAQ,KAAK,EAAE;YACnB,GAAG,CAAC,QAAQ,KAAK,EAAE;YACnB,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAClC,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,wDAAwD;AACxD,MAAM,UAAU,sBAAsB,CAAC,KAAgC;IACrE,OAAO,0BAA0B,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa;IACzC,MAAM,QAAQ,GAAG,KAAK;SACnB,WAAW,EAAE;SACb,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEtB,IACE,QAAQ,KAAK,WAAW;QACxB,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC/B,QAAQ,KAAK,SAAS;QACtB,QAAQ,KAAK,IAAI;QACjB,QAAQ,KAAK,KAAK,EAClB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE/C,IACE,MAAM,CAAC,MAAM,KAAK,CAAC;QACnB,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC,EAC5E,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ProviderRateLimitGateOptions {
|
|
2
|
+
maxCooldownMs?: number;
|
|
3
|
+
now?: () => number;
|
|
4
|
+
}
|
|
5
|
+
export declare class ProviderRateLimitGate {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(options?: ProviderRateLimitGateOptions);
|
|
8
|
+
defer(delayMs: number): void;
|
|
9
|
+
wait(signal?: AbortSignal): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare function deferProviderRateLimitFromResponse(gate: ProviderRateLimitGate, response: Response, fallbackDelayMs?: number): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { waitForAbortableDelay } from "./abort.js";
|
|
2
|
+
import { parseRetryAfterMs } from "./retry.js";
|
|
3
|
+
const DEFAULT_MAX_COOLDOWN_MS = 30_000;
|
|
4
|
+
const DEFAULT_RATE_LIMIT_FALLBACK_MS = 1_000;
|
|
5
|
+
// Shares an upstream rate-limit deadline between requests from one provider instance.
|
|
6
|
+
// Разделяет deadline upstream rate limit между запросами одного экземпляра provider.
|
|
7
|
+
export class ProviderRateLimitGate {
|
|
8
|
+
#maxCooldownMs;
|
|
9
|
+
#now;
|
|
10
|
+
#blockedUntil = 0;
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
const maxCooldownMs = options.maxCooldownMs ?? DEFAULT_MAX_COOLDOWN_MS;
|
|
13
|
+
if (!Number.isFinite(maxCooldownMs) || maxCooldownMs < 0) {
|
|
14
|
+
throw new RangeError("Provider rate-limit maxCooldownMs must be a non-negative number.");
|
|
15
|
+
}
|
|
16
|
+
this.#maxCooldownMs = maxCooldownMs;
|
|
17
|
+
this.#now = options.now ?? Date.now;
|
|
18
|
+
}
|
|
19
|
+
// Extends the shared deadline without shortening an existing longer cooldown.
|
|
20
|
+
// Продлевает общий deadline, не сокращая уже установленный более длинный cooldown.
|
|
21
|
+
defer(delayMs) {
|
|
22
|
+
if (!Number.isFinite(delayMs) || delayMs <= 0 || this.#maxCooldownMs === 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const boundedDelayMs = Math.min(delayMs, this.#maxCooldownMs);
|
|
26
|
+
this.#blockedUntil = Math.max(this.#blockedUntil, this.#now() + boundedDelayMs);
|
|
27
|
+
}
|
|
28
|
+
// Waits for the current deadline and follows extensions announced while waiting.
|
|
29
|
+
// Ждет текущий deadline и учитывает продления, объявленные во время ожидания.
|
|
30
|
+
async wait(signal) {
|
|
31
|
+
while (true) {
|
|
32
|
+
const remainingMs = this.#blockedUntil - this.#now();
|
|
33
|
+
if (remainingMs <= 0) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
await waitForAbortableDelay(remainingMs, signal);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Records a server rate-limit hint for raw HTTP helpers that do not use fetchJson.
|
|
41
|
+
// Записывает server rate-limit hint для raw HTTP helpers, не использующих fetchJson.
|
|
42
|
+
export function deferProviderRateLimitFromResponse(gate, response, fallbackDelayMs = DEFAULT_RATE_LIMIT_FALLBACK_MS) {
|
|
43
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
|
|
44
|
+
if (response.status === 429) {
|
|
45
|
+
gate.defer(retryAfterMs ?? fallbackDelayMs);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (response.status >= 500 && retryAfterMs !== undefined) {
|
|
49
|
+
gate.defer(retryAfterMs);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/shared/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,uBAAuB,GAAG,MAAM,CAAC;AACvC,MAAM,8BAA8B,GAAG,KAAK,CAAC;AAO7C,sFAAsF;AACtF,qFAAqF;AACrF,MAAM,OAAO,qBAAqB;IACvB,cAAc,CAAS;IACvB,IAAI,CAAe;IAC5B,aAAa,GAAG,CAAC,CAAC;IAElB,YAAY,UAAwC,EAAE;QACpD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,uBAAuB,CAAC;QAEvE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,UAAU,CAAC,kEAAkE,CAAC,CAAC;QAC3F,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACtC,CAAC;IAED,8EAA8E;IAC9E,mFAAmF;IACnF,KAAK,CAAC,OAAe;QACnB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,IAAI,CAAC,cAAc,KAAK,CAAC,EAAE,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9D,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,cAAc,CAAC,CAAC;IAClF,CAAC;IAED,iFAAiF;IACjF,8EAA8E;IAC9E,KAAK,CAAC,IAAI,CAAC,MAAoB;QAC7B,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAErD,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;gBACrB,OAAO;YACT,CAAC;YAED,MAAM,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;CACF;AAED,mFAAmF;AACnF,qFAAqF;AACrF,MAAM,UAAU,kCAAkC,CAChD,IAA2B,EAC3B,QAAkB,EAClB,eAAe,GAAG,8BAA8B;IAEhD,MAAM,YAAY,GAAG,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAE5E,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,eAAe,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACzD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface ReadBoundedResponseBodyOptions {
|
|
2
|
+
signal?: AbortSignal;
|
|
3
|
+
overflow?: "throw" | "truncate";
|
|
4
|
+
}
|
|
5
|
+
export declare function readBoundedResponseBytes(provider: string, response: Response, maxBytes: number, options?: ReadBoundedResponseBodyOptions): Promise<Uint8Array>;
|
|
6
|
+
export declare function readBoundedResponseText(provider: string, response: Response, maxBytes: number, options?: ReadBoundedResponseBodyOptions): Promise<string>;
|