apify-client 3.0.0-beta.88 → 3.0.0-beta.89

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.
@@ -54,7 +54,8 @@ export declare class AxiosHttpClient extends HttpClient {
54
54
  close(): Promise<void>;
55
55
  /**
56
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.
57
+ * redirects, since the part of it already sent could not be replayed, and so is a request with
58
+ * `followRedirects: false`. In the browser, the browser follows redirects itself.
58
59
  */
59
60
  sendRequest(request: HttpRequest): Promise<HttpResponse>;
60
61
  }
@@ -78,11 +78,12 @@ export class AxiosHttpClient extends HttpClient {
78
78
  }
79
79
  /**
80
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.
81
+ * redirects, since the part of it already sent could not be replayed, and so is a request with
82
+ * `followRedirects: false`. In the browser, the browser follows redirects itself.
82
83
  */
83
84
  async sendRequest(request) {
84
85
  await this.#ensureHttpAgents();
85
- const { method, url, headers, body, timeoutMillis, stream, signal } = request;
86
+ const { method, url, headers, body, timeoutMillis, stream, followRedirects, signal } = request;
86
87
  const response = await this.axios.request({
87
88
  method,
88
89
  url,
@@ -92,8 +93,9 @@ export class AxiosHttpClient extends HttpClient {
92
93
  timeout: timeoutMillis ?? 0,
93
94
  signal,
94
95
  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 } : {}),
96
+ // See axios/axios#1045 for why axios must not buffer a stream body to follow redirects. The XHR adapter
97
+ // ignores `maxRedirects`, since the browser follows redirects itself.
98
+ ...(isStream(body) || !followRedirects ? { maxRedirects: 0 } : {}),
97
99
  });
98
100
  return {
99
101
  status: response.status,
@@ -84,6 +84,40 @@ export interface ApifyRequestConfig {
84
84
  stringifyFunctions?: boolean;
85
85
  /** Give up on the first transport timeout instead of retrying it. */
86
86
  doNotRetryTimeouts?: boolean;
87
+ /**
88
+ * How to compress the request body: an {@link HttpCompressor} for this request only, or `false` to send the body
89
+ * uncompressed. Defaults to the client's {@link HttpClient.httpCompressor}.
90
+ */
91
+ compression?: HttpCompressor | false;
92
+ /**
93
+ * Header that carries the client's API token for this request. The Apify API reads `Authorization`. Actor
94
+ * servers also accept `X-Apify-Authorization`, which the platform removes before the request reaches the Actor,
95
+ * so the `Authorization` header stays free for the Actor's own authentication. A per-request header of either
96
+ * name still wins.
97
+ * @default 'Authorization'
98
+ */
99
+ authorizationHeader?: 'Authorization' | 'X-Apify-Authorization';
100
+ /**
101
+ * Whether an error status throws {@link ApifyApiError}. With `false`, the call resolves to the error response
102
+ * once no retry follows, and a rate limit (429) doesn't count toward the client's statistics, which track the
103
+ * API's rate limits.
104
+ * @default true
105
+ */
106
+ throwOnErrorStatus?: boolean;
107
+ /** Status codes to retry. Defaults to rate limits (429) and server errors (5xx). */
108
+ retryStatusCodes?: readonly number[];
109
+ /**
110
+ * Whether transport errors, timeouts included, are retried. With `false`, the first one fails the call, since the
111
+ * request may have reached the server before it failed.
112
+ * @default true
113
+ */
114
+ retryTransportErrors?: boolean;
115
+ /**
116
+ * Whether the transport follows redirects. With `false`, a redirect response is handled like an error status, so
117
+ * headers that carry the token never go to a host the server picked.
118
+ * @default true
119
+ */
120
+ followRedirects?: boolean;
87
121
  /**
88
122
  * Aborts the call. Once the signal aborts, the attempt in flight is ended, no retry follows, and the call
89
123
  * rejects with the signal's `reason`.
@@ -91,7 +125,8 @@ export interface ApifyRequestConfig {
91
125
  signal?: AbortSignal;
92
126
  }
93
127
  /**
94
- * A successful response as {@link HttpClient.call} resolves to it.
128
+ * A response as {@link HttpClient.call} resolves to it: a success, or an error response when the request sets
129
+ * {@link ApifyRequestConfig.throwOnErrorStatus} to `false`.
95
130
  *
96
131
  * @template T - Type of the parsed body.
97
132
  */
@@ -124,6 +159,11 @@ export interface HttpRequest {
124
159
  timeoutMillis?: number;
125
160
  /** Whether to hand the body back unread as a `Readable`, so the caller can stream it. */
126
161
  stream: boolean;
162
+ /**
163
+ * Whether to follow redirects. With `false`, return a redirect response as it is: the request carries a token
164
+ * that must not follow a redirect to another host.
165
+ */
166
+ followRedirects: boolean;
127
167
  /**
128
168
  * The caller's abort signal, to hand to the HTTP library alongside the timeout. The pipeline stops retrying
129
169
  * once it aborts, so the transport only has to end the request in flight.
@@ -191,8 +231,13 @@ export interface HttpClientOptions {
191
231
  *
192
232
  * Overriding {@link call} itself is also supported and bypasses the transport hooks entirely. Such a client has
193
233
  * to send the default headers from `defaultHeaders` with every request, otherwise the `Authorization` header never
194
- * reaches the API. The protected helpers `prepareRequest()`, `buildUrl()` and `computeTimeoutMillis()` stay
195
- * available to it.
234
+ * reaches the API. It also has to honor the per-request options {@link ApifyRequestConfig.compression},
235
+ * {@link ApifyRequestConfig.authorizationHeader}, {@link ApifyRequestConfig.throwOnErrorStatus},
236
+ * {@link ApifyRequestConfig.retryStatusCodes}, {@link ApifyRequestConfig.retryTransportErrors} and
237
+ * {@link ApifyRequestConfig.followRedirects}.
238
+ * {@link ActorServerClient.request} relies on them to keep the token away from the Actor's code, to return the
239
+ * server's error responses and to avoid sending a request to the Actor twice. The protected helpers
240
+ * `prepareRequest()`, `buildUrl()` and `computeTimeoutMillis()` stay available to it.
196
241
  *
197
242
  * @example
198
243
  * ```javascript
@@ -281,7 +326,8 @@ export declare abstract class HttpClient {
281
326
  * propagate unwrapped: {@link call} classifies them through {@link isRetryableTransportError} and
282
327
  * {@link isTimeoutError}. Return error responses as they are too, the pipeline turns them into
283
328
  * {@link ApifyApiError} and decides whether to retry. Reject when the connection drops before the body is
284
- * complete: the pipeline takes a returned body as whole and does not retry one that fails to parse.
329
+ * complete: the pipeline takes a returned body as whole and does not retry one that fails to parse. When
330
+ * `request.followRedirects` is `false`, return a redirect response as it is, since the request carries a token.
285
331
  *
286
332
  * @param request - The request to send, with the headers merged, the body serialized and the query encoded.
287
333
  * @returns The response, with the body unread when `request.stream` is set and as raw bytes otherwise.
@@ -291,8 +337,9 @@ export declare abstract class HttpClient {
291
337
  * Makes an API request with automatic retries and exponential backoff.
292
338
  *
293
339
  * Network errors the transport classifies as retryable, rate limits (HTTP 429) and server errors (HTTP 5xx)
294
- * are retried up to {@link maxRetries} times. Any other error status is thrown as {@link ApifyApiError} right
295
- * away. A request whose body is a `Readable` is never retried, since part of the stream has already been
340
+ * are retried up to {@link maxRetries} times, and `config.retryStatusCodes` picks other statuses to retry. Any
341
+ * other error status is thrown as {@link ApifyApiError} right away, or returned when `config.throwOnErrorStatus`
342
+ * is `false`. A request whose body is a `Readable` is never retried, since part of the stream has already been
296
343
  * consumed by the time the failure shows. A `Blob` body is read again for every attempt, so it is retried like
297
344
  * any other, unless reading the blob itself fails: that error is thrown right away, with the transport error
298
345
  * as its `cause` when that error does not already wrap it. Aborting `config.signal` ends the attempt in flight,
@@ -300,19 +347,22 @@ export declare abstract class HttpClient {
300
347
  *
301
348
  * @template T - Type of the parsed response body.
302
349
  * @param config - The request to make.
303
- * @returns The successful response.
304
- * @throws {ApifyApiError} When the API responds with an error status the retries could not fix.
350
+ * @returns The successful response, or the error response when `config.throwOnErrorStatus` is `false`.
351
+ * @throws {ApifyApiError} When the API responds with an error status the retries could not fix, unless
352
+ * `config.throwOnErrorStatus` is `false`.
305
353
  */
306
354
  call<T = any>(config: ApifyRequestConfig): Promise<ApifyResponse<T>>;
307
355
  /**
308
356
  * Prepares the headers and the body of a request.
309
357
  *
310
- * Merges the client's default headers with the per-request ones, header names compared case-insensitively and
311
- * the per-request values winning. Serializes an object body to JSON, setting `Content-Type: application/json`
312
- * unless the caller supplied a content type. Runs the body through {@link httpCompressor} unless a
313
- * `Content-Encoding` header is already set, the body is too small, or its content type says the payload is
314
- * already compressed. A caller-supplied `Content-Encoding` is forwarded as it is, which is how a pre-encoded
315
- * body is uploaded, and `Content-Encoding: identity` opts a single request out of compression.
358
+ * Merges the client's default headers with the per-request ones, header names compared case-insensitively and the
359
+ * per-request values winning, after moving the default `Authorization` header to `X-Apify-Authorization` when
360
+ * `config.authorizationHeader` asks for it. Serializes an object body to JSON, setting
361
+ * `Content-Type: application/json` unless the caller supplied a content type. Runs the body through
362
+ * {@link httpCompressor}, or the compressor in `config.compression`, unless `config.compression` is `false`, a
363
+ * `Content-Encoding` header is already set, the body is too small, or its content type says the payload is already
364
+ * compressed. A caller-supplied `Content-Encoding` is forwarded as it is, which is how a pre-encoded body is
365
+ * uploaded, and `Content-Encoding: identity` opts a single request out of compression.
316
366
  */
317
367
  protected prepareRequest(config: ApifyRequestConfig): Promise<{
318
368
  headers: Record<string, string>;
@@ -42,8 +42,13 @@ const UNSERIALIZABLE_OBJECT_TAGS = new Set(['FormData', 'ReadableStream']);
42
42
  *
43
43
  * Overriding {@link call} itself is also supported and bypasses the transport hooks entirely. Such a client has
44
44
  * to send the default headers from `defaultHeaders` with every request, otherwise the `Authorization` header never
45
- * reaches the API. The protected helpers `prepareRequest()`, `buildUrl()` and `computeTimeoutMillis()` stay
46
- * available to it.
45
+ * reaches the API. It also has to honor the per-request options {@link ApifyRequestConfig.compression},
46
+ * {@link ApifyRequestConfig.authorizationHeader}, {@link ApifyRequestConfig.throwOnErrorStatus},
47
+ * {@link ApifyRequestConfig.retryStatusCodes}, {@link ApifyRequestConfig.retryTransportErrors} and
48
+ * {@link ApifyRequestConfig.followRedirects}.
49
+ * {@link ActorServerClient.request} relies on them to keep the token away from the Actor's code, to return the
50
+ * server's error responses and to avoid sending a request to the Actor twice. The protected helpers
51
+ * `prepareRequest()`, `buildUrl()` and `computeTimeoutMillis()` stay available to it.
47
52
  *
48
53
  * @example
49
54
  * ```javascript
@@ -170,7 +175,8 @@ export class HttpClient {
170
175
  * propagate unwrapped: {@link call} classifies them through {@link isRetryableTransportError} and
171
176
  * {@link isTimeoutError}. Return error responses as they are too, the pipeline turns them into
172
177
  * {@link ApifyApiError} and decides whether to retry. Reject when the connection drops before the body is
173
- * complete: the pipeline takes a returned body as whole and does not retry one that fails to parse.
178
+ * complete: the pipeline takes a returned body as whole and does not retry one that fails to parse. When
179
+ * `request.followRedirects` is `false`, return a redirect response as it is, since the request carries a token.
174
180
  *
175
181
  * @param request - The request to send, with the headers merged, the body serialized and the query encoded.
176
182
  * @returns The response, with the body unread when `request.stream` is set and as raw bytes otherwise.
@@ -182,8 +188,9 @@ export class HttpClient {
182
188
  * Makes an API request with automatic retries and exponential backoff.
183
189
  *
184
190
  * Network errors the transport classifies as retryable, rate limits (HTTP 429) and server errors (HTTP 5xx)
185
- * are retried up to {@link maxRetries} times. Any other error status is thrown as {@link ApifyApiError} right
186
- * away. A request whose body is a `Readable` is never retried, since part of the stream has already been
191
+ * are retried up to {@link maxRetries} times, and `config.retryStatusCodes` picks other statuses to retry. Any
192
+ * other error status is thrown as {@link ApifyApiError} right away, or returned when `config.throwOnErrorStatus`
193
+ * is `false`. A request whose body is a `Readable` is never retried, since part of the stream has already been
187
194
  * consumed by the time the failure shows. A `Blob` body is read again for every attempt, so it is retried like
188
195
  * any other, unless reading the blob itself fails: that error is thrown right away, with the transport error
189
196
  * as its `cause` when that error does not already wrap it. Aborting `config.signal` ends the attempt in flight,
@@ -191,8 +198,9 @@ export class HttpClient {
191
198
  *
192
199
  * @template T - Type of the parsed response body.
193
200
  * @param config - The request to make.
194
- * @returns The successful response.
195
- * @throws {ApifyApiError} When the API responds with an error status the retries could not fix.
201
+ * @returns The successful response, or the error response when `config.throwOnErrorStatus` is `false`.
202
+ * @throws {ApifyApiError} When the API responds with an error status the retries could not fix, unless
203
+ * `config.throwOnErrorStatus` is `false`.
196
204
  */
197
205
  async call(config) {
198
206
  config.signal?.throwIfAborted();
@@ -204,22 +212,25 @@ export class HttpClient {
204
212
  /**
205
213
  * Prepares the headers and the body of a request.
206
214
  *
207
- * Merges the client's default headers with the per-request ones, header names compared case-insensitively and
208
- * the per-request values winning. Serializes an object body to JSON, setting `Content-Type: application/json`
209
- * unless the caller supplied a content type. Runs the body through {@link httpCompressor} unless a
210
- * `Content-Encoding` header is already set, the body is too small, or its content type says the payload is
211
- * already compressed. A caller-supplied `Content-Encoding` is forwarded as it is, which is how a pre-encoded
212
- * body is uploaded, and `Content-Encoding: identity` opts a single request out of compression.
215
+ * Merges the client's default headers with the per-request ones, header names compared case-insensitively and the
216
+ * per-request values winning, after moving the default `Authorization` header to `X-Apify-Authorization` when
217
+ * `config.authorizationHeader` asks for it. Serializes an object body to JSON, setting
218
+ * `Content-Type: application/json` unless the caller supplied a content type. Runs the body through
219
+ * {@link httpCompressor}, or the compressor in `config.compression`, unless `config.compression` is `false`, a
220
+ * `Content-Encoding` header is already set, the body is too small, or its content type says the payload is already
221
+ * compressed. A caller-supplied `Content-Encoding` is forwarded as it is, which is how a pre-encoded body is
222
+ * uploaded, and `Content-Encoding: identity` opts a single request out of compression.
213
223
  */
214
224
  async prepareRequest(config) {
215
- let headers = mergeHeaders(this.defaultHeaders, config.headers);
225
+ let headers = mergeHeaders(withAuthorizationHeader(this.defaultHeaders, config.authorizationHeader), config.headers);
216
226
  let body = serializeBody(config.data, headers, config.stringifyFunctions);
217
- const bytes = compressibleBytes(body, headers);
227
+ const compressor = config.compression ?? this.httpCompressor;
228
+ const bytes = compressor && compressibleBytes(body, headers);
218
229
  if (bytes) {
219
- body = await this.httpCompressor.compress(Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength));
230
+ body = await compressor.compress(Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength));
220
231
  // Compressing changes the body length, so a `Content-Length` the caller set describes the wrong body
221
232
  // and would leave the server waiting for bytes that never arrive.
222
- headers = mergeHeaders(headers, { 'Content-Encoding': this.httpCompressor.contentEncoding });
233
+ headers = mergeHeaders(headers, { 'Content-Encoding': compressor.contentEncoding });
223
234
  deleteHeader(headers, 'content-length');
224
235
  }
225
236
  // A blob reaches a Node.js transport as a stream, which would go out chunked without a known length.
@@ -304,8 +315,8 @@ export class HttpClient {
304
315
  }
305
316
  /**
306
317
  * Executes one attempt: sends the request, decodes the body and turns an error status into {@link ApifyApiError}.
307
- * Throws for anything that is not a success, and flags the failure as final through `stopRetrying()` when a
308
- * retry could not fix it.
318
+ * Throws for anything that is not a success, unless `config.throwOnErrorStatus` is `false` and no retry follows,
319
+ * and flags the failure as final through `stopRetrying()` when a retry could not fix it.
309
320
  */
310
321
  async #makeRequest(options) {
311
322
  const { config, url, headers, body, attempt, stopRetrying } = options;
@@ -327,6 +338,7 @@ export class HttpClient {
327
338
  body: attemptBody,
328
339
  timeoutMillis: this.computeTimeoutMillis(attempt, config.timeoutSecs),
329
340
  stream: config.responseType === 'stream',
341
+ followRedirects: config.followRedirects ?? true,
330
342
  signal: config.signal,
331
343
  });
332
344
  }
@@ -347,10 +359,16 @@ export class HttpClient {
347
359
  if (attemptBody !== body && isStream(attemptBody))
348
360
  attemptBody.destroy();
349
361
  }
362
+ const isError = response.status >= 300;
363
+ const isRetryable = isError && this.#isStatusCodeRetryable(response.status, config.retryStatusCodes);
364
+ // An error response goes back to the caller as it is once no retry follows, which a stream body rules out.
365
+ const shouldReturnError = isError &&
366
+ config.throwOnErrorStatus === false &&
367
+ (!isRetryable || requestIsStream || attempt > this.maxRetries);
350
368
  // A failed streaming request carries the API error body in the stream, so read it and let
351
369
  // `ApifyApiError` parse it like any other error body. A body that cannot be read leaves the error
352
370
  // without a message, which beats losing the status code to a stream error.
353
- if (response.status >= 300 && isStream(response.body)) {
371
+ if (isError && !shouldReturnError && isStream(response.body)) {
354
372
  response.body = await concatStreamToBuffer(response.body).catch(() => undefined);
355
373
  }
356
374
  let data;
@@ -360,7 +378,7 @@ export class HttpClient {
360
378
  catch (err) {
361
379
  // The body of a success arrived in full, since a transfer cut short fails in `sendRequest()`, so a
362
380
  // retry would get the same body back.
363
- if (response.status < 300) {
381
+ if (!isError) {
364
382
  stopRetrying();
365
383
  throw err;
366
384
  }
@@ -373,13 +391,17 @@ export class HttpClient {
373
391
  data: data,
374
392
  config,
375
393
  };
376
- if (response.status < 300)
394
+ if (!isError)
377
395
  return apifyResponse;
378
- if (response.status === RATE_LIMIT_EXCEEDED_STATUS_CODE) {
396
+ // The statistics track the API's rate limits. Only API calls throw on an error status, so a call with
397
+ // `throwOnErrorStatus: false` is taken for a non-API one and its 429s stay out of the statistics.
398
+ if (response.status === RATE_LIMIT_EXCEEDED_STATUS_CODE && config.throwOnErrorStatus !== false) {
379
399
  this.stats.addRateLimitError(attempt);
380
400
  }
401
+ if (shouldReturnError)
402
+ return apifyResponse;
381
403
  const apiError = ApifyApiError.fromResponse(apifyResponse, attempt);
382
- if (!this.#isStatusCodeRetryable(response.status)) {
404
+ if (!isRetryable) {
383
405
  stopRetrying();
384
406
  }
385
407
  else if (requestIsStream) {
@@ -409,15 +431,16 @@ export class HttpClient {
409
431
  }
410
432
  }
411
433
  /**
412
- * Decides whether a transport error ends the call. Timeouts the request opted out of retrying and errors the
413
- * transport does not classify as retryable are final, and so is any error on a request with a stream body.
434
+ * Decides whether a transport error ends the call. Timeouts the request opted out of retrying, any error on a
435
+ * request that retries no transport errors, errors the transport does not classify as retryable and any error on
436
+ * a request with a stream body are final.
414
437
  */
415
438
  #handleRequestError(err, config, stopRetrying) {
416
439
  if (config.doNotRetryTimeouts && this.isTimeoutError(err)) {
417
440
  stopRetrying();
418
441
  return;
419
442
  }
420
- if (!this.isRetryableTransportError(err)) {
443
+ if (config.retryTransportErrors === false || !this.isRetryableTransportError(err)) {
421
444
  stopRetrying();
422
445
  return;
423
446
  }
@@ -427,10 +450,13 @@ export class HttpClient {
427
450
  }
428
451
  }
429
452
  /**
430
- * Rate limits (429) and server errors (500+) are retried. Anything else in 300-499 is a redirect the client
431
- * cannot follow or invalid input, which repeating the request cannot fix.
453
+ * Rate limits (429) and server errors (500+) are retried, unless the request lists its own `retryStatusCodes`.
454
+ * Anything else in 300-499 is a redirect the client cannot follow or invalid input, which repeating the request
455
+ * cannot fix.
432
456
  */
433
- #isStatusCodeRetryable(statusCode) {
457
+ #isStatusCodeRetryable(statusCode, retryStatusCodes) {
458
+ if (retryStatusCodes)
459
+ return retryStatusCodes.includes(statusCode);
434
460
  return statusCode === RATE_LIMIT_EXCEEDED_STATUS_CODE || statusCode >= 500;
435
461
  }
436
462
  #informAboutStreamNoRetry() {
@@ -466,6 +492,18 @@ function mergeHeaders(base, override) {
466
492
  }
467
493
  return merged;
468
494
  }
495
+ /**
496
+ * Moves the `Authorization` header of `headers` to the header named `name`, or returns `headers` unchanged when
497
+ * `name` is `Authorization`.
498
+ */
499
+ function withAuthorizationHeader(headers, name = 'Authorization') {
500
+ const authorization = getHeader(headers, 'authorization');
501
+ if (name === 'Authorization' || authorization === undefined)
502
+ return headers;
503
+ const moved = { ...headers };
504
+ deleteHeader(moved, 'authorization');
505
+ return mergeHeaders(moved, { [name]: authorization });
506
+ }
469
507
  /**
470
508
  * Removes a header by name, compared case-insensitively.
471
509
  */
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './resource_clients/actor.js';
3
3
  export * from './resource_clients/actor_collection.js';
4
4
  export * from './resource_clients/actor_env_var.js';
5
5
  export * from './resource_clients/actor_env_var_collection.js';
6
+ export * from './resource_clients/actor_server.js';
6
7
  export * from './resource_clients/actor_version.js';
7
8
  export * from './resource_clients/actor_version_collection.js';
8
9
  export * from './resource_clients/build.js';
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export * from './resource_clients/actor.js';
3
3
  export * from './resource_clients/actor_collection.js';
4
4
  export * from './resource_clients/actor_env_var.js';
5
5
  export * from './resource_clients/actor_env_var_collection.js';
6
+ export * from './resource_clients/actor_server.js';
6
7
  export * from './resource_clients/actor_version.js';
7
8
  export * from './resource_clients/actor_version_collection.js';
8
9
  export * from './resource_clients/build.js';
@@ -5,6 +5,7 @@ import { ResourceClient } from '../base/resource_client.js';
5
5
  import type { ActorResource, Run } from '../models.js';
6
6
  import type { TimeoutOptions } from '../timeouts.js';
7
7
  import type { Dictionary } from '../utils.js';
8
+ import { ActorServerClient } from './actor_server.js';
8
9
  import { ActorVersionClient } from './actor_version.js';
9
10
  import { ActorVersionCollectionClient } from './actor_version_collection.js';
10
11
  import type { Build, BuildClientGetOptions } from './build.js';
@@ -37,6 +38,7 @@ export type { ActorResource, ActorChargeEvent, ActorChargeEvents, ActorDefinitio
37
38
  * @see https://docs.apify.com/platform/actors
38
39
  */
39
40
  export declare class ActorClient extends ResourceClient {
41
+ #private;
40
42
  /**
41
43
  * @hidden
42
44
  */
@@ -293,6 +295,34 @@ export declare class ActorClient extends ResourceClient {
293
295
  * @see https://docs.apify.com/api/v2/act-webhooks-get
294
296
  */
295
297
  webhooks(): WebhookCollectionClient;
298
+ /**
299
+ * Returns a client for the server interface of this Actor.
300
+ *
301
+ * A Server Actor runs a web server, its server interface, that is called over HTTP without starting a run for
302
+ * each call. Server Actors were formerly called Actor Standby, and {@link standby} is a deprecated alias of this
303
+ * method. Every call returns the same client, so the server URL it fetches is reused.
304
+ *
305
+ * @returns The client for the server interface of this Actor
306
+ * @see https://docs.apify.com/platform/actors/running/standby
307
+ *
308
+ * @example
309
+ * ```javascript
310
+ * const response = await client.actor('username/actor-name').server().request('/search', {
311
+ * params: { q: 'apify' },
312
+ * });
313
+ * ```
314
+ */
315
+ server(): ActorServerClient;
316
+ /**
317
+ * Returns a client for the server interface of this Actor in Standby mode.
318
+ *
319
+ * Named after Actor Standby, the former name of Server Actors.
320
+ *
321
+ * @deprecated Use {@link server} instead. Will be removed in v4.
322
+ * @returns The client for the server interface of this Actor
323
+ * @see https://docs.apify.com/platform/actors/running/standby
324
+ */
325
+ standby(): ActorServerClient;
296
326
  }
297
327
  /**
298
328
  * Fields that can be updated when modifying an Actor.
@@ -6,6 +6,7 @@ import * as schemas from '../schemas.js';
6
6
  import { timeoutOptionsSchema, timeoutOptionsShape } from '../timeouts.js';
7
7
  import { anyObjectSchema, isStream, parseArgument, parseResponse, stringifyWebhooksToBase64 } from '../utils.js';
8
8
  import { startWaitingForResources } from '../wait_for_resources.js';
9
+ import { ActorServerClient } from './actor_server.js';
9
10
  import { ActorVersionClient } from './actor_version.js';
10
11
  import { ActorVersionCollectionClient } from './actor_version_collection.js';
11
12
  import { BuildClient } from './build.js';
@@ -81,6 +82,7 @@ const lastRunOptionsSchema = z.strictObject({
81
82
  * @see https://docs.apify.com/platform/actors
82
83
  */
83
84
  export class ActorClient extends ResourceClient {
85
+ #serverClient;
84
86
  /**
85
87
  * @hidden
86
88
  */
@@ -475,4 +477,45 @@ export class ActorClient extends ResourceClient {
475
477
  webhooks() {
476
478
  return new WebhookCollectionClient(this.subResourceOptions());
477
479
  }
480
+ /**
481
+ * Returns a client for the server interface of this Actor.
482
+ *
483
+ * A Server Actor runs a web server, its server interface, that is called over HTTP without starting a run for
484
+ * each call. Server Actors were formerly called Actor Standby, and {@link standby} is a deprecated alias of this
485
+ * method. Every call returns the same client, so the server URL it fetches is reused.
486
+ *
487
+ * @returns The client for the server interface of this Actor
488
+ * @see https://docs.apify.com/platform/actors/running/standby
489
+ *
490
+ * @example
491
+ * ```javascript
492
+ * const response = await client.actor('username/actor-name').server().request('/search', {
493
+ * params: { q: 'apify' },
494
+ * });
495
+ * ```
496
+ */
497
+ server() {
498
+ this.#serverClient ??= new ActorServerClient({
499
+ baseUrl: this.baseUrl,
500
+ publicBaseUrl: this.publicBaseUrl,
501
+ apifyClient: this.apifyClient,
502
+ httpClient: this.httpClient,
503
+ id: this.id,
504
+ params: this.params,
505
+ });
506
+ return this.#serverClient;
507
+ }
508
+ /**
509
+ * Returns a client for the server interface of this Actor in Standby mode.
510
+ *
511
+ * Named after Actor Standby, the former name of Server Actors.
512
+ *
513
+ * @deprecated Use {@link server} instead. Will be removed in v4.
514
+ * @returns The client for the server interface of this Actor
515
+ * @see https://docs.apify.com/platform/actors/running/standby
516
+ */
517
+ standby() {
518
+ this.httpClient.logger.deprecated('`standby()` is deprecated and will be removed in v4. Use `server()` instead.');
519
+ return this.server();
520
+ }
478
521
  }