apify-client 3.0.0-beta.9 → 3.0.0-rc.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 (116) hide show
  1. package/README.md +10 -2
  2. package/dist/apify_api_error.d.ts +11 -26
  3. package/dist/apify_api_error.js +31 -22
  4. package/dist/apify_client.d.ts +125 -10
  5. package/dist/apify_client.js +133 -48
  6. package/dist/base/api_client.d.ts +7 -7
  7. package/dist/base/api_client.js +36 -24
  8. package/dist/base/resource_client.d.ts +21 -8
  9. package/dist/base/resource_client.js +67 -33
  10. package/dist/base/resource_collection_client.d.ts +12 -4
  11. package/dist/base/resource_collection_client.js +34 -11
  12. package/dist/body_parser.d.ts +3 -4
  13. package/dist/body_parser.js +19 -26
  14. package/dist/bundle.js +27 -22
  15. package/dist/bundle.js.map +1 -1
  16. package/dist/generated/api.d.ts +785 -290
  17. package/dist/generated/schemas.d.ts +720 -747
  18. package/dist/generated/schemas.js +166 -162
  19. package/dist/http_clients/axios.d.ts +60 -0
  20. package/dist/http_clients/axios.js +117 -0
  21. package/dist/http_clients/base.d.ts +331 -0
  22. package/dist/http_clients/base.js +563 -0
  23. package/dist/http_clients/index.d.ts +4 -0
  24. package/dist/http_clients/index.js +2 -0
  25. package/dist/http_compressors/base.d.ts +40 -0
  26. package/dist/http_compressors/base.js +9 -0
  27. package/dist/http_compressors/brotli.d.ts +33 -0
  28. package/dist/http_compressors/brotli.js +39 -0
  29. package/dist/http_compressors/gzip.d.ts +33 -0
  30. package/dist/http_compressors/gzip.js +39 -0
  31. package/dist/http_compressors/index.d.ts +6 -0
  32. package/dist/http_compressors/index.js +2 -0
  33. package/dist/http_compressors/resolve.d.ts +23 -0
  34. package/dist/http_compressors/resolve.js +27 -0
  35. package/dist/index.d.ts +4 -1
  36. package/dist/index.js +3 -1
  37. package/dist/invalid_response_body_error.d.ts +13 -0
  38. package/dist/invalid_response_body_error.js +17 -0
  39. package/dist/models.d.ts +162 -194
  40. package/dist/models.js +6 -4
  41. package/dist/resource_clients/actor.d.ts +74 -34
  42. package/dist/resource_clients/actor.js +87 -56
  43. package/dist/resource_clients/actor_collection.d.ts +18 -12
  44. package/dist/resource_clients/actor_collection.js +11 -3
  45. package/dist/resource_clients/actor_env_var.d.ts +11 -4
  46. package/dist/resource_clients/actor_env_var.js +16 -6
  47. package/dist/resource_clients/actor_env_var_collection.d.ts +9 -4
  48. package/dist/resource_clients/actor_env_var_collection.js +11 -4
  49. package/dist/resource_clients/actor_version.d.ts +20 -5
  50. package/dist/resource_clients/actor_version.js +19 -9
  51. package/dist/resource_clients/actor_version_collection.d.ts +11 -4
  52. package/dist/resource_clients/actor_version_collection.js +13 -4
  53. package/dist/resource_clients/build.d.ts +20 -7
  54. package/dist/resource_clients/build.js +35 -15
  55. package/dist/resource_clients/build_collection.d.ts +7 -5
  56. package/dist/resource_clients/build_collection.js +4 -1
  57. package/dist/resource_clients/dataset.d.ts +53 -35
  58. package/dist/resource_clients/dataset.js +105 -80
  59. package/dist/resource_clients/dataset_collection.d.ts +10 -6
  60. package/dist/resource_clients/dataset_collection.js +13 -2
  61. package/dist/resource_clients/key_value_store.d.ts +62 -20
  62. package/dist/resource_clients/key_value_store.js +78 -40
  63. package/dist/resource_clients/key_value_store_collection.d.ts +10 -6
  64. package/dist/resource_clients/key_value_store_collection.js +13 -2
  65. package/dist/resource_clients/log.d.ts +13 -20
  66. package/dist/resource_clients/log.js +141 -59
  67. package/dist/resource_clients/request_queue.d.ts +68 -31
  68. package/dist/resource_clients/request_queue.js +173 -91
  69. package/dist/resource_clients/request_queue_collection.d.ts +9 -5
  70. package/dist/resource_clients/request_queue_collection.js +9 -3
  71. package/dist/resource_clients/run.d.ts +119 -28
  72. package/dist/resource_clients/run.js +190 -49
  73. package/dist/resource_clients/run_collection.d.ts +5 -3
  74. package/dist/resource_clients/run_collection.js +4 -1
  75. package/dist/resource_clients/schedule.d.ts +16 -7
  76. package/dist/resource_clients/schedule.js +30 -22
  77. package/dist/resource_clients/schedule_collection.d.ts +6 -2
  78. package/dist/resource_clients/schedule_collection.js +9 -3
  79. package/dist/resource_clients/store_collection.d.ts +6 -4
  80. package/dist/resource_clients/store_collection.js +4 -1
  81. package/dist/resource_clients/task.d.ts +36 -13
  82. package/dist/resource_clients/task.js +79 -46
  83. package/dist/resource_clients/task_collection.d.ts +9 -5
  84. package/dist/resource_clients/task_collection.js +9 -3
  85. package/dist/resource_clients/user.d.ts +19 -10
  86. package/dist/resource_clients/user.js +42 -38
  87. package/dist/resource_clients/webhook.d.ts +17 -8
  88. package/dist/resource_clients/webhook.js +30 -22
  89. package/dist/resource_clients/webhook_collection.d.ts +8 -4
  90. package/dist/resource_clients/webhook_collection.js +9 -3
  91. package/dist/resource_clients/webhook_dispatch.d.ts +4 -1
  92. package/dist/resource_clients/webhook_dispatch.js +7 -2
  93. package/dist/resource_clients/webhook_dispatch_collection.d.ts +3 -1
  94. package/dist/resource_clients/webhook_dispatch_collection.js +4 -1
  95. package/dist/runtime/node.d.ts +6 -0
  96. package/dist/runtime/node.js +49 -0
  97. package/dist/runtime/types.d.ts +52 -0
  98. package/dist/runtime/types.js +1 -0
  99. package/dist/runtime/web.d.ts +5 -0
  100. package/dist/runtime/web.js +18 -0
  101. package/dist/schemas.d.ts +1 -1
  102. package/dist/schemas.js +1 -1
  103. package/dist/statistics.d.ts +1 -6
  104. package/dist/statistics.js +2 -2
  105. package/dist/timeouts.d.ts +84 -0
  106. package/dist/timeouts.js +37 -0
  107. package/dist/timezones.d.ts +1 -1
  108. package/dist/utils.d.ts +82 -45
  109. package/dist/utils.js +197 -146
  110. package/dist/wait_for_resources.d.ts +8 -0
  111. package/dist/wait_for_resources.js +39 -0
  112. package/package.json +32 -29
  113. package/dist/http_client.d.ts +0 -88
  114. package/dist/http_client.js +0 -255
  115. package/dist/interceptors.d.ts +0 -19
  116. package/dist/interceptors.js +0 -105
@@ -0,0 +1,60 @@
1
+ import type http from 'node:http';
2
+ import type https from 'node:https';
3
+ import type { AxiosInstance, AxiosInterceptorManager, InternalAxiosRequestConfig } from 'axios';
4
+ import type { HttpClientOptions, HttpRequest, HttpResponse } from './base.js';
5
+ import { HttpClient } from './base.js';
6
+ /**
7
+ * An [axios request interceptor](https://axios-http.com/docs/interceptors). It runs on every attempt, right before
8
+ * the request is handed to axios, and sees the request as the shared pipeline prepared it: headers merged and the
9
+ * body already serialized and compressed.
10
+ */
11
+ export type RequestInterceptorFunction = Parameters<AxiosInterceptorManager<InternalAxiosRequestConfig>['use']>[0];
12
+ /**
13
+ * Configuration of {@link AxiosHttpClient}.
14
+ */
15
+ export interface AxiosHttpClientOptions extends HttpClientOptions {
16
+ /** @default [] */
17
+ requestInterceptors?: RequestInterceptorFunction[];
18
+ }
19
+ /**
20
+ * The default HTTP client of {@link ApifyClient}, built on [axios](https://axios-http.com).
21
+ *
22
+ * It inherits the request pipeline from {@link HttpClient} and adds the transport: in Node.js, keep-alive agents
23
+ * that honor the `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables; in the browser, the XHR
24
+ * adapter of axios. Network errors are retried, timeouts included, and a stream body is sent without following
25
+ * redirects, since the part of it already sent could not be replayed.
26
+ */
27
+ export declare class AxiosHttpClient extends HttpClient {
28
+ #private;
29
+ /** The axios instance the requests go through. */
30
+ axios: AxiosInstance;
31
+ /**
32
+ * Keep-alive agent for plain HTTP, created with the first request in Node.js. It is the same `ProxyAgent` as
33
+ * {@link httpsAgent}, so the socket pool is shared across both schemes.
34
+ */
35
+ httpAgent?: http.Agent;
36
+ /** Keep-alive agent for HTTPS. The same instance as {@link httpAgent}. */
37
+ httpsAgent?: https.Agent;
38
+ constructor(options?: AxiosHttpClientOptions);
39
+ /**
40
+ * A timeout is an axios error coded `ECONNABORTED` or `ETIMEDOUT`, besides the `TimeoutError` the base class
41
+ * recognizes.
42
+ */
43
+ isTimeoutError(error: unknown): boolean;
44
+ /**
45
+ * A network failure is an axios error that carries the request it was sending: a connection that could not be
46
+ * made, dropped mid-way or timed out. Errors raised before a request exists, such as an invalid URL, are not
47
+ * retried.
48
+ */
49
+ isRetryableTransportError(error: unknown): boolean;
50
+ /**
51
+ * Destroys the keep-alive agents, closing every pooled socket. A client that never sent a request in Node.js
52
+ * has nothing to close.
53
+ */
54
+ close(): Promise<void>;
55
+ /**
56
+ * Sends the request through axios and hands the raw response back. A stream body is sent without following
57
+ * redirects, since the part of it already sent could not be replayed.
58
+ */
59
+ sendRequest(request: HttpRequest): Promise<HttpResponse>;
60
+ }
@@ -0,0 +1,117 @@
1
+ import axios, { AxiosError, AxiosHeaders } from 'axios';
2
+ import { runtime } from '#runtime';
3
+ import { isStream } from '../utils.js';
4
+ import { HttpClient } from './base.js';
5
+ /**
6
+ * The default HTTP client of {@link ApifyClient}, built on [axios](https://axios-http.com).
7
+ *
8
+ * It inherits the request pipeline from {@link HttpClient} and adds the transport: in Node.js, keep-alive agents
9
+ * that honor the `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables; in the browser, the XHR
10
+ * adapter of axios. Network errors are retried, timeouts included, and a stream body is sent without following
11
+ * redirects, since the part of it already sent could not be replayed.
12
+ */
13
+ export class AxiosHttpClient extends HttpClient {
14
+ /** The axios instance the requests go through. */
15
+ axios;
16
+ /**
17
+ * Keep-alive agent for plain HTTP, created with the first request in Node.js. It is the same `ProxyAgent` as
18
+ * {@link httpsAgent}, so the socket pool is shared across both schemes.
19
+ */
20
+ httpAgent;
21
+ /** Keep-alive agent for HTTPS. The same instance as {@link httpAgent}. */
22
+ httpsAgent;
23
+ #httpAgentsPromise;
24
+ constructor(options = {}) {
25
+ super(options);
26
+ this.axios = axios.create({
27
+ // The agents handle the proxy environment variables.
28
+ proxy: false,
29
+ validateStatus: null,
30
+ // The shared pipeline serializes and parses the bodies, so axios only moves bytes.
31
+ transformRequest: [],
32
+ transformResponse: [],
33
+ responseType: 'arraybuffer',
34
+ // maxBodyLength needs to be Infinity, because -1 falls back to a 10 MB default
35
+ // from an axios subdependency - 'follow-redirects'
36
+ maxBodyLength: Infinity,
37
+ // maxContentLength must be -1, because Infinity will cause axios to run super slow
38
+ // thanks to a bug that's now fixed, but not released yet https://github.com/axios/axios/pull/3738
39
+ maxContentLength: -1,
40
+ });
41
+ // The pipeline merges every header the client sends, so the axios defaults would only get in the way.
42
+ this.axios.defaults.headers = new AxiosHeaders();
43
+ for (const interceptor of options.requestInterceptors ?? []) {
44
+ this.axios.interceptors.request.use(interceptor);
45
+ }
46
+ }
47
+ /**
48
+ * A timeout is an axios error coded `ECONNABORTED` or `ETIMEDOUT`, besides the `TimeoutError` the base class
49
+ * recognizes.
50
+ */
51
+ isTimeoutError(error) {
52
+ if (super.isTimeoutError(error))
53
+ return true;
54
+ // Axios aborts the request when its own timeout fires, which gives ECONNABORTED, or ETIMEDOUT under
55
+ // `clarifyTimeoutError`. ETIMEDOUT also arrives straight from the socket, when the connection itself
56
+ // times out.
57
+ return (axios.isAxiosError(error) && (error.code === AxiosError.ECONNABORTED || error.code === AxiosError.ETIMEDOUT));
58
+ }
59
+ /**
60
+ * A network failure is an axios error that carries the request it was sending: a connection that could not be
61
+ * made, dropped mid-way or timed out. Errors raised before a request exists, such as an invalid URL, are not
62
+ * retried.
63
+ */
64
+ isRetryableTransportError(error) {
65
+ if (!axios.isAxiosError(error))
66
+ return false;
67
+ return typeof error.request === 'object' && error.request !== null && error.config != null;
68
+ }
69
+ /**
70
+ * Destroys the keep-alive agents, closing every pooled socket. A client that never sent a request in Node.js
71
+ * has nothing to close.
72
+ */
73
+ async close() {
74
+ // A failed initialization left nothing to release, and its error belongs to the request that hit it.
75
+ await this.#httpAgentsPromise?.catch(() => { });
76
+ this.httpAgent?.destroy();
77
+ this.httpsAgent?.destroy();
78
+ }
79
+ /**
80
+ * Sends the request through axios and hands the raw response back. A stream body is sent without following
81
+ * redirects, since the part of it already sent could not be replayed.
82
+ */
83
+ async sendRequest(request) {
84
+ await this.#ensureHttpAgents();
85
+ const { method, url, headers, body, timeoutMillis, stream, signal } = request;
86
+ const response = await this.axios.request({
87
+ method,
88
+ url,
89
+ headers,
90
+ data: body,
91
+ // Axios reads 0 as no timeout.
92
+ timeout: timeoutMillis ?? 0,
93
+ signal,
94
+ responseType: stream ? 'stream' : 'arraybuffer',
95
+ // See axios/axios#1045 for why axios must not buffer a stream body to follow redirects.
96
+ ...(isStream(body) ? { maxRedirects: 0 } : {}),
97
+ });
98
+ return {
99
+ status: response.status,
100
+ headers: AxiosHeaders.from(response.headers).toJSON(),
101
+ body: response.data,
102
+ };
103
+ }
104
+ async #ensureHttpAgents() {
105
+ this.#httpAgentsPromise ??= this.#initHttpAgents();
106
+ return this.#httpAgentsPromise;
107
+ }
108
+ async #initHttpAgents() {
109
+ const agents = await runtime.createHttpAgents({ timeoutMillis: this.timeoutMaxMillis });
110
+ if (!agents)
111
+ return;
112
+ this.httpAgent = agents.httpAgent;
113
+ this.httpsAgent = agents.httpsAgent;
114
+ this.axios.defaults.httpAgent = this.httpAgent;
115
+ this.axios.defaults.httpsAgent = this.httpsAgent;
116
+ }
117
+ }
@@ -0,0 +1,331 @@
1
+ import type { Readable } from 'node:stream';
2
+ import { z } from 'zod';
3
+ import type { Log } from '@apify/log';
4
+ import type { HttpCompressor } from '../http_compressors/base.js';
5
+ import type { HttpCompressionAlgorithm } from '../http_compressors/resolve.js';
6
+ import type { HttpMethod } from '../models.js';
7
+ import { Statistics } from '../statistics.js';
8
+ import type { Timeout, TimeoutTier } from '../timeouts.js';
9
+ export type { HttpMethod } from '../models.js';
10
+ export declare const DEFAULT_MAX_RETRIES = 8;
11
+ export declare const DEFAULT_MIN_DELAY_BETWEEN_RETRIES_MILLIS = 500;
12
+ /**
13
+ * Bounds of the numeric {@link HttpClientOptions}. `ApifyClientOptions` checks the same bounds and adds the defaults.
14
+ * @internal
15
+ */
16
+ export declare const httpClientOptionsShape: {
17
+ maxRetries: z.ZodNumber;
18
+ minDelayBetweenRetriesMillis: z.ZodNumber;
19
+ timeoutShortSecs: z.ZodNumber;
20
+ timeoutMediumSecs: z.ZodNumber;
21
+ timeoutLongSecs: z.ZodNumber;
22
+ timeoutMaxSecs: z.ZodNumber;
23
+ };
24
+ /**
25
+ * Response headers keyed by lowercase header name. A header the server sent more than once may arrive as an array.
26
+ */
27
+ export type HttpResponseHeaders = Record<string, string | string[] | undefined>;
28
+ /**
29
+ * A request body as the transport receives it: already serialized, and compressed when that paid off. A `Readable`
30
+ * is passed through untouched and is only available in Node.js.
31
+ */
32
+ export type HttpRequestBody = string | Buffer | ArrayBuffer | ArrayBufferView | Readable;
33
+ /**
34
+ * A response body as the transport hands it back: the raw bytes, a `Readable` when the request asked for a streamed
35
+ * response, or `undefined` when the response carried no body.
36
+ */
37
+ export type HttpResponseBody = Buffer | ArrayBuffer | Readable | undefined;
38
+ /**
39
+ * How {@link HttpClient.call} hands back the response body.
40
+ *
41
+ * - `parsed` (the default) decodes it by content type: JSON becomes an object, text and XML become a string, anything
42
+ * else stays a `Buffer` (an `ArrayBuffer` in the browser).
43
+ * - `buffer` skips the decoding and hands back the raw bytes.
44
+ * - `stream` hands back a `Readable` with the body unread. Node.js only.
45
+ */
46
+ export type ApifyResponseType = 'parsed' | 'buffer' | 'stream';
47
+ /**
48
+ * A request as the resource clients hand it to {@link HttpClient.call}.
49
+ */
50
+ export interface ApifyRequestConfig {
51
+ /** Full URL of the endpoint, without the query string. */
52
+ url: string;
53
+ /** HTTP method. */
54
+ method: HttpMethod;
55
+ /**
56
+ * Query parameters. `undefined` values are dropped, booleans are sent as `1` and `0`, `Date` values as ISO 8601
57
+ * strings and arrays comma-separated.
58
+ */
59
+ params?: Record<string, unknown>;
60
+ /** Per-request headers. They win over the client's default headers, header names compared case-insensitively. */
61
+ headers?: Record<string, string>;
62
+ /**
63
+ * Request body. A plain object or array is serialized to JSON and sent as `application/json`, or form-encoded
64
+ * when a `Content-Type: application/x-www-form-urlencoded` header asks for it. A string, binary value
65
+ * (`Buffer`, `ArrayBuffer`, typed array) or `Readable` is sent as it is, and `URLSearchParams` is sent
66
+ * form-encoded. A `Blob`, `File`, `FormData` or web `ReadableStream` is rejected with a `TypeError`, since
67
+ * serializing one would send an empty body.
68
+ */
69
+ data?: unknown;
70
+ /**
71
+ * Timeout of the request: a tier name, a number of seconds, or `'noTimeout'`. The client resolves it to the
72
+ * timeout of each attempt in milliseconds, doubling it with every retry up to `timeoutMaxSecs`.
73
+ * @default 'medium'
74
+ */
75
+ timeoutSecs?: Timeout;
76
+ /** @default 'parsed' */
77
+ responseType?: ApifyResponseType;
78
+ /**
79
+ * Serialize function-valued fields of a JSON body to their source instead of dropping them, which is how
80
+ * Actor input carrying page functions reaches the API.
81
+ */
82
+ stringifyFunctions?: boolean;
83
+ /** Give up on the first transport timeout instead of retrying it. */
84
+ doNotRetryTimeouts?: boolean;
85
+ /**
86
+ * Aborts the call. Once the signal aborts, the attempt in flight is ended, no retry follows, and the call
87
+ * rejects with the signal's `reason`.
88
+ */
89
+ signal?: AbortSignal;
90
+ }
91
+ /**
92
+ * A successful response as {@link HttpClient.call} resolves to it.
93
+ *
94
+ * @template T - Type of the parsed body.
95
+ */
96
+ export interface ApifyResponse<T = any> {
97
+ /** HTTP status code. */
98
+ status: number;
99
+ /** Response headers keyed by lowercase header name. */
100
+ headers: HttpResponseHeaders;
101
+ /** The response body, decoded according to the request's {@link ApifyRequestConfig.responseType}. */
102
+ data: T;
103
+ /** The request this response answers, as it was passed to {@link HttpClient.call}. */
104
+ config: ApifyRequestConfig;
105
+ }
106
+ /**
107
+ * One prepared request attempt, as {@link HttpClient.sendRequest} receives it from the shared pipeline.
108
+ */
109
+ export interface HttpRequest {
110
+ /** HTTP method. */
111
+ method: HttpMethod;
112
+ /** Full request URL with the query string already encoded into it. */
113
+ url: string;
114
+ /** Final request headers, with the client's default headers already merged in. */
115
+ headers: Record<string, string>;
116
+ /** Request body, already serialized and compressed, or `undefined` for a request without one. */
117
+ body?: HttpRequestBody;
118
+ /**
119
+ * Timeout for this attempt in milliseconds, or `undefined` for a request that runs without one, which is what
120
+ * `timeoutSecs: 'noTimeout'` asks for.
121
+ */
122
+ timeoutMillis?: number;
123
+ /** Whether to hand the body back unread as a `Readable`, so the caller can stream it. */
124
+ stream: boolean;
125
+ /**
126
+ * The caller's abort signal, to hand to the HTTP library alongside the timeout. The pipeline stops retrying
127
+ * once it aborts, so the transport only has to end the request in flight.
128
+ */
129
+ signal?: AbortSignal;
130
+ }
131
+ /**
132
+ * A response as the transport returns it from {@link HttpClient.sendRequest}, error statuses included.
133
+ */
134
+ export interface HttpResponse {
135
+ /** HTTP status code. */
136
+ status: number;
137
+ /** Response headers keyed by lowercase header name. */
138
+ headers: HttpResponseHeaders;
139
+ /** The body as raw bytes, or unread as a `Readable` when the request asked for a stream. */
140
+ body: HttpResponseBody;
141
+ }
142
+ /**
143
+ * Configuration shared by every {@link HttpClient}.
144
+ */
145
+ export interface HttpClientOptions {
146
+ /** Apify API token, sent as a `Bearer` token in the `Authorization` header. */
147
+ token?: string;
148
+ /** How many times a failed request is retried at most. @default 8 */
149
+ maxRetries?: number;
150
+ /**
151
+ * Lower bound for the delay before the first retry in milliseconds. It doubles with every further retry.
152
+ * @default 500
153
+ */
154
+ minDelayBetweenRetriesMillis?: number;
155
+ /** Duration of the `short` timeout tier, in seconds. @default 5 */
156
+ timeoutShortSecs?: number;
157
+ /** Duration of the `medium` timeout tier, in seconds. @default 30 */
158
+ timeoutMediumSecs?: number;
159
+ /** Duration of the `long` timeout tier, in seconds. @default 360 */
160
+ timeoutLongSecs?: number;
161
+ /** Upper bound for the timeout of a single attempt, in seconds. @default 360 */
162
+ timeoutMaxSecs?: number;
163
+ /**
164
+ * Compression of request bodies: the name of a built-in algorithm, or an {@link HttpCompressor} for a custom
165
+ * quality or algorithm.
166
+ * @default 'brotli'
167
+ */
168
+ compression?: HttpCompressionAlgorithm | HttpCompressor;
169
+ /** Additional headers sent with every request. They win over the built-in defaults. */
170
+ headers?: Record<string, string>;
171
+ /** Statistics the client records its calls into. Created when omitted. */
172
+ stats?: Statistics;
173
+ /** Logger for the retry warnings. Defaults to a child of the `@apify/log` default with an `ApifyClient` prefix. */
174
+ logger?: Log;
175
+ /** Value of the `X-Apify-Workflow-Key` header. Defaults to the `APIFY_WORKFLOW_KEY` environment variable. */
176
+ workflowKey?: string;
177
+ /** @internal */
178
+ userAgentSuffix?: string | string[];
179
+ }
180
+ /**
181
+ * Base class for the HTTP clients used by {@link ApifyClient}.
182
+ *
183
+ * It holds the shared request pipeline: {@link call} merges the default headers in, serializes and compresses the
184
+ * body, encodes the query parameters, retries transient failures with exponential backoff, grows the timeout with
185
+ * every attempt, decodes the response body by content type, records statistics and converts error statuses to
186
+ * {@link ApifyApiError}. A concrete client only has to implement {@link sendRequest}, the transport that moves one
187
+ * prepared request over the wire, and can override the classification and lifecycle hooks {@link isTimeoutError},
188
+ * {@link isRetryableTransportError} and {@link close}.
189
+ *
190
+ * Overriding {@link call} itself is also supported and bypasses the transport hooks entirely. Such a client has
191
+ * to send the default headers from `defaultHeaders` with every request, otherwise the `Authorization` header never
192
+ * reaches the API. The protected helpers `prepareRequest()`, `buildUrl()` and `computeTimeoutMillis()` stay
193
+ * available to it.
194
+ *
195
+ * @example
196
+ * ```javascript
197
+ * import { ApifyClient, HttpClient } from 'apify-client';
198
+ *
199
+ * class FetchHttpClient extends HttpClient {
200
+ * async sendRequest({ method, url, headers, body, timeoutMillis, signal }) {
201
+ * const signals = signal ? [signal] : [];
202
+ * if (timeoutMillis !== undefined) signals.push(AbortSignal.timeout(timeoutMillis));
203
+ * const response = await fetch(url, { method, headers, body, signal: AbortSignal.any(signals) });
204
+ * return {
205
+ * status: response.status,
206
+ * headers: Object.fromEntries(response.headers),
207
+ * body: Buffer.from(await response.arrayBuffer()),
208
+ * };
209
+ * }
210
+ *
211
+ * isRetryableTransportError(error) {
212
+ * // Without this the client gives up on the first connection failure.
213
+ * return this.isTimeoutError(error) || error instanceof TypeError;
214
+ * }
215
+ * }
216
+ *
217
+ * const client = ApifyClient.withCustomHttpClient({ token: 'my-token', httpClient: new FetchHttpClient() });
218
+ * ```
219
+ */
220
+ export declare abstract class HttpClient {
221
+ #private;
222
+ /** Statistics of the API calls made through this client. */
223
+ stats: Statistics;
224
+ /** Logger for the retry warnings. */
225
+ logger: Log;
226
+ /** How many times a failed request is retried at most. */
227
+ maxRetries: number;
228
+ /** Lower bound for the delay before the first retry in milliseconds. It doubles with every further retry. */
229
+ minDelayBetweenRetriesMillis: number;
230
+ /** Duration of each timeout tier, in milliseconds. */
231
+ timeoutMillis: Record<TimeoutTier, number>;
232
+ /** Upper bound for the timeout of a single attempt, in milliseconds. */
233
+ timeoutMaxMillis: number;
234
+ /** Compressor the request pipeline runs the bodies worth compressing through. */
235
+ readonly httpCompressor: HttpCompressor;
236
+ /**
237
+ * Headers sent with every request: the `Authorization` header built from the token, the `User-Agent` where the
238
+ * runtime lets a client set one, the `X-Apify-Workflow-Key` when a workflow key is configured, and whatever
239
+ * {@link HttpClientOptions.headers} added.
240
+ */
241
+ protected readonly defaultHeaders: Record<string, string>;
242
+ /**
243
+ * @param options - Configuration of the pipeline. The retry and timeout options are validated the same way the
244
+ * `ApifyClient` constructor validates them.
245
+ * @throws {ArgumentValidationError} When a retry or timeout option is out of bounds.
246
+ */
247
+ constructor(options?: HttpClientOptions);
248
+ /**
249
+ * Sets the `Authorization` header from the token, unless an authorization header is already configured.
250
+ *
251
+ * @param token - The Apify API token to send as the `Bearer` token.
252
+ */
253
+ setDefaultAuthorization(token: string): void;
254
+ /**
255
+ * Whether an error thrown by the transport is a timeout.
256
+ *
257
+ * Recognizes errors named `TimeoutError`, which is what `AbortSignal.timeout()` produces. Transports extend it
258
+ * with the timeout errors their HTTP library throws. The classification is independent of retryability: a
259
+ * timeout the retry loop should retry has to be covered by {@link isRetryableTransportError} too.
260
+ */
261
+ isTimeoutError(error: unknown): boolean;
262
+ /**
263
+ * Whether an error thrown by the transport is worth retrying.
264
+ *
265
+ * The default classifies nothing as retryable, so a transport that does not override it gives up on the first
266
+ * connection failure. Every transport should map its own transient errors here: connection resets, refused
267
+ * connections, timeouts and the like. Error responses are not the transport's concern, the pipeline decides on
268
+ * them from the status code.
269
+ */
270
+ isRetryableTransportError(_error: unknown): boolean;
271
+ /**
272
+ * Releases resources owned by the transport, such as a connection pool. The default does nothing.
273
+ */
274
+ close(): Promise<void>;
275
+ /**
276
+ * Sends one prepared request through the underlying HTTP library.
277
+ *
278
+ * The inherited {@link call} needs it, so every transport has to implement it. Let the library's errors
279
+ * propagate unwrapped: {@link call} classifies them through {@link isRetryableTransportError} and
280
+ * {@link isTimeoutError}. Return error responses as they are too, the pipeline turns them into
281
+ * {@link ApifyApiError} and decides whether to retry.
282
+ *
283
+ * @param request - The request to send, with the headers merged, the body serialized and the query encoded.
284
+ * @returns The response, with the body unread when `request.stream` is set and as raw bytes otherwise.
285
+ */
286
+ sendRequest(request: HttpRequest): Promise<HttpResponse>;
287
+ /**
288
+ * Makes an API request with automatic retries and exponential backoff.
289
+ *
290
+ * Network errors the transport classifies as retryable, rate limits (HTTP 429) and server errors (HTTP 5xx)
291
+ * are retried up to {@link maxRetries} times. Any other error status is thrown as {@link ApifyApiError} right
292
+ * away. A request whose body is a `Readable` is never retried, since part of the stream has already been
293
+ * consumed by the time the failure shows. Aborting `config.signal` ends the attempt in flight, skips the
294
+ * remaining retries and rejects the call with the signal's `reason`.
295
+ *
296
+ * @template T - Type of the parsed response body.
297
+ * @param config - The request to make.
298
+ * @returns The successful response.
299
+ * @throws {ApifyApiError} When the API responds with an error status the retries could not fix.
300
+ */
301
+ call<T = any>(config: ApifyRequestConfig): Promise<ApifyResponse<T>>;
302
+ /**
303
+ * Prepares the headers and the body of a request.
304
+ *
305
+ * Merges the client's default headers with the per-request ones, header names compared case-insensitively and
306
+ * the per-request values winning. Serializes an object body to JSON, setting `Content-Type: application/json`
307
+ * unless the caller supplied a content type. Runs the body through {@link httpCompressor} unless a
308
+ * `Content-Encoding` header is already set, the body is too small, or its content type says the payload is
309
+ * already compressed. A caller-supplied `Content-Encoding` is forwarded as it is, which is how a pre-encoded
310
+ * body is uploaded, and `Content-Encoding: identity` opts a single request out of compression.
311
+ */
312
+ protected prepareRequest(config: ApifyRequestConfig): Promise<{
313
+ headers: Record<string, string>;
314
+ body: HttpRequestBody | undefined;
315
+ }>;
316
+ /**
317
+ * Appends the query parameters to the URL. `undefined` values are dropped, booleans are sent as `1` and `0`,
318
+ * `Date` values as ISO 8601 strings and arrays comma-separated.
319
+ */
320
+ protected buildUrl(url: string, params?: Record<string, unknown>): string;
321
+ /**
322
+ * Resolves `timeoutSecs` to the number of milliseconds the given attempt gets. A tier name resolves to its
323
+ * configured duration, a number is taken as seconds, and `'noTimeout'` becomes `undefined`. The result doubles
324
+ * with each attempt and is capped at `timeoutMaxMillis`. A requested value above the cap is capped too, which
325
+ * warns once, since it does not take effect in full.
326
+ *
327
+ * @param attempt - Current attempt number, starting at 1.
328
+ * @param timeoutSecs - The request's timeout. Defaults to the `medium` tier.
329
+ */
330
+ protected computeTimeoutMillis(attempt: number, timeoutSecs?: Timeout): number | undefined;
331
+ }