apify-client 3.0.0-beta.5 → 3.0.0-beta.50

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 (115) hide show
  1. package/README.md +13 -3
  2. package/dist/apify_api_error.d.ts +62 -21
  3. package/dist/apify_api_error.js +96 -23
  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 +54 -26
  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 +610 -112
  17. package/dist/generated/schemas.d.ts +726 -703
  18. package/dist/generated/schemas.js +92 -85
  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 +333 -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 +19 -22
  40. package/dist/resource_clients/actor.d.ts +72 -32
  41. package/dist/resource_clients/actor.js +87 -56
  42. package/dist/resource_clients/actor_collection.d.ts +9 -5
  43. package/dist/resource_clients/actor_collection.js +11 -3
  44. package/dist/resource_clients/actor_env_var.d.ts +10 -3
  45. package/dist/resource_clients/actor_env_var.js +16 -6
  46. package/dist/resource_clients/actor_env_var_collection.d.ts +14 -18
  47. package/dist/resource_clients/actor_env_var_collection.js +17 -11
  48. package/dist/resource_clients/actor_version.d.ts +18 -3
  49. package/dist/resource_clients/actor_version.js +19 -9
  50. package/dist/resource_clients/actor_version_collection.d.ts +16 -17
  51. package/dist/resource_clients/actor_version_collection.js +19 -11
  52. package/dist/resource_clients/build.d.ts +18 -6
  53. package/dist/resource_clients/build.js +34 -15
  54. package/dist/resource_clients/build_collection.d.ts +3 -1
  55. package/dist/resource_clients/build_collection.js +4 -1
  56. package/dist/resource_clients/dataset.d.ts +51 -33
  57. package/dist/resource_clients/dataset.js +105 -80
  58. package/dist/resource_clients/dataset_collection.d.ts +6 -2
  59. package/dist/resource_clients/dataset_collection.js +13 -2
  60. package/dist/resource_clients/key_value_store.d.ts +58 -16
  61. package/dist/resource_clients/key_value_store.js +78 -40
  62. package/dist/resource_clients/key_value_store_collection.d.ts +6 -2
  63. package/dist/resource_clients/key_value_store_collection.js +13 -2
  64. package/dist/resource_clients/log.d.ts +11 -19
  65. package/dist/resource_clients/log.js +64 -46
  66. package/dist/resource_clients/request_queue.d.ts +56 -26
  67. package/dist/resource_clients/request_queue.js +176 -103
  68. package/dist/resource_clients/request_queue_collection.d.ts +6 -2
  69. package/dist/resource_clients/request_queue_collection.js +9 -3
  70. package/dist/resource_clients/run.d.ts +108 -18
  71. package/dist/resource_clients/run.js +183 -43
  72. package/dist/resource_clients/run_collection.d.ts +3 -1
  73. package/dist/resource_clients/run_collection.js +4 -1
  74. package/dist/resource_clients/schedule.d.ts +14 -5
  75. package/dist/resource_clients/schedule.js +29 -21
  76. package/dist/resource_clients/schedule_collection.d.ts +6 -2
  77. package/dist/resource_clients/schedule_collection.js +9 -3
  78. package/dist/resource_clients/store_collection.d.ts +3 -1
  79. package/dist/resource_clients/store_collection.js +4 -1
  80. package/dist/resource_clients/task.d.ts +33 -10
  81. package/dist/resource_clients/task.js +79 -46
  82. package/dist/resource_clients/task_collection.d.ts +6 -2
  83. package/dist/resource_clients/task_collection.js +9 -3
  84. package/dist/resource_clients/user.d.ts +17 -8
  85. package/dist/resource_clients/user.js +42 -38
  86. package/dist/resource_clients/webhook.d.ts +14 -5
  87. package/dist/resource_clients/webhook.js +30 -22
  88. package/dist/resource_clients/webhook_collection.d.ts +6 -2
  89. package/dist/resource_clients/webhook_collection.js +9 -3
  90. package/dist/resource_clients/webhook_dispatch.d.ts +4 -1
  91. package/dist/resource_clients/webhook_dispatch.js +7 -2
  92. package/dist/resource_clients/webhook_dispatch_collection.d.ts +3 -1
  93. package/dist/resource_clients/webhook_dispatch_collection.js +4 -1
  94. package/dist/runtime/node.d.ts +6 -0
  95. package/dist/runtime/node.js +49 -0
  96. package/dist/runtime/types.d.ts +52 -0
  97. package/dist/runtime/types.js +1 -0
  98. package/dist/runtime/web.d.ts +5 -0
  99. package/dist/runtime/web.js +18 -0
  100. package/dist/schemas.d.ts +1 -1
  101. package/dist/schemas.js +1 -1
  102. package/dist/statistics.d.ts +1 -6
  103. package/dist/statistics.js +2 -2
  104. package/dist/timeouts.d.ts +84 -0
  105. package/dist/timeouts.js +37 -0
  106. package/dist/timezones.d.ts +1 -1
  107. package/dist/utils.d.ts +81 -52
  108. package/dist/utils.js +201 -170
  109. package/dist/wait_for_resources.d.ts +8 -0
  110. package/dist/wait_for_resources.js +39 -0
  111. package/package.json +32 -29
  112. package/dist/http_client.d.ts +0 -88
  113. package/dist/http_client.js +0 -255
  114. package/dist/interceptors.d.ts +0 -19
  115. package/dist/interceptors.js +0 -105
@@ -1,5 +1,5 @@
1
1
  import { ACT_JOB_TERMINAL_STATUSES } from '@apify/consts';
2
- import { catchNotFoundOrThrow, parseResponse } from '../utils.js';
2
+ import { catchNotFoundForResourceOrThrow, catchNotFoundOrThrow, parseResponse, sleep } from '../utils.js';
3
3
  import { ApiClient } from './api_client.js';
4
4
  /**
5
5
  * We need to supply some number for the API,
@@ -7,59 +7,85 @@ import { ApiClient } from './api_client.js';
7
7
  * 999999 seconds is more than 10 days.
8
8
  */
9
9
  const MAX_WAIT_FOR_FINISH = 999999;
10
- export const SMALL_TIMEOUT_MILLIS = 5 * 1000; // For fast and common actions. Suitable for idempotent actions.
11
- export const MEDIUM_TIMEOUT_MILLIS = 30 * 1000; // For actions that may take longer.
12
- export const DEFAULT_TIMEOUT_MILLIS = 360 * 1000; // 6 minutes
10
+ /** The API holds a `waitForFinish` response for at most a minute, however long the parameter asks for. */
11
+ const MAX_WAIT_FOR_FINISH_HOLD_SECS = 60;
13
12
  /**
14
13
  * Resource client.
15
14
  * @private
16
15
  */
17
16
  export class ResourceClient extends ApiClient {
18
- async _get(schema, options = {}, timeoutMillis) {
17
+ /**
18
+ * Picks the timeout of a request that asks the API to hold its response with `waitForFinish`. The request
19
+ * gets the hold the caller asked for plus the round trip its tier allows, so the client does not abort a
20
+ * request while the API is still holding it - which for `start()` and `build()` would retry a call that
21
+ * creates a resource. An explicit per-call `timeoutSecs` is used as given.
22
+ */
23
+ timeoutForWaitForFinish(timeoutSecs, tier, waitForFinishSecs) {
24
+ if (timeoutSecs !== undefined)
25
+ return timeoutSecs;
26
+ if (waitForFinishSecs === undefined)
27
+ return tier;
28
+ const holdSecs = Math.min(waitForFinishSecs, MAX_WAIT_FOR_FINISH_HOLD_SECS);
29
+ if (holdSecs <= 0)
30
+ return tier;
31
+ return holdSecs + this.httpClient.timeoutMillis[tier] / 1000;
32
+ }
33
+ /**
34
+ * A 404 resolves to `undefined` only when the client names its resource by ID. A chained client without one, such
35
+ * as `run.dataset()`, throws it instead (see `catchNotFoundForResourceOrThrow()`).
36
+ */
37
+ async getResource(schema, options, timeoutSecs, signal) {
19
38
  const requestOpts = {
20
- url: this._url(),
39
+ url: this.buildUrl(),
21
40
  method: 'GET',
22
- params: this._params(options),
23
- timeout: timeoutMillis,
41
+ params: this.buildParams(options),
42
+ timeoutSecs,
43
+ signal,
24
44
  };
25
45
  try {
26
46
  const response = await this.httpClient.call(requestOpts);
27
47
  return parseResponse(response, schema);
28
48
  }
29
49
  catch (err) {
30
- catchNotFoundOrThrow(err);
50
+ catchNotFoundForResourceOrThrow(err, this.id);
31
51
  }
32
52
  return undefined;
33
53
  }
34
- async _update(schema, newFields, timeoutMillis) {
54
+ async updateResource(schema, newFields, timeoutSecs, signal) {
35
55
  const response = await this.httpClient.call({
36
- url: this._url(),
56
+ url: this.buildUrl(),
37
57
  method: 'PUT',
38
- params: this._params(),
58
+ params: this.buildParams(),
39
59
  data: newFields,
40
- timeout: timeoutMillis,
60
+ timeoutSecs,
61
+ signal,
41
62
  });
42
63
  return parseResponse(response, schema);
43
64
  }
44
- async _delete(timeoutMillis) {
65
+ /**
66
+ * A 404 is swallowed, keeping the DELETE idempotent, only when the client names its resource by ID. A chained client
67
+ * without one throws it instead (see `catchNotFoundForResourceOrThrow()`).
68
+ */
69
+ async deleteResource(timeoutSecs, signal) {
45
70
  try {
46
71
  await this.httpClient.call({
47
- url: this._url(),
72
+ url: this.buildUrl(),
48
73
  method: 'DELETE',
49
- params: this._params(),
50
- timeout: timeoutMillis,
74
+ params: this.buildParams(),
75
+ timeoutSecs,
76
+ signal,
51
77
  });
52
78
  }
53
79
  catch (err) {
54
- catchNotFoundOrThrow(err);
80
+ catchNotFoundForResourceOrThrow(err, this.id);
55
81
  }
56
82
  }
57
83
  /**
58
84
  * This function is used in Build and Run endpoints so it's kept
59
85
  * here to stay DRY.
60
86
  */
61
- async _waitForFinish(schema, options = {}) {
62
- const { waitSecs = MAX_WAIT_FOR_FINISH } = options;
87
+ async waitForJobFinish(schema, options = {}) {
88
+ const { waitSecs = MAX_WAIT_FOR_FINISH, timeoutSecs = 'noTimeout', signal } = options;
63
89
  const waitMillis = waitSecs * 1000;
64
90
  let job;
65
91
  const startedAt = Date.now();
@@ -75,9 +101,11 @@ export class ResourceClient extends ApiClient {
75
101
  const remainingWaitSeconds = Math.round((waitMillis - millisSinceStart) / 1000);
76
102
  const waitForFinish = Math.max(0, remainingWaitSeconds);
77
103
  const requestOpts = {
78
- url: this._url(),
104
+ url: this.buildUrl(),
79
105
  method: 'GET',
80
- params: this._params({ waitForFinish }),
106
+ params: this.buildParams({ waitForFinish }),
107
+ timeoutSecs,
108
+ signal,
81
109
  };
82
110
  try {
83
111
  const response = await this.httpClient.call(requestOpts);
@@ -89,10 +117,10 @@ export class ResourceClient extends ApiClient {
89
117
  }
90
118
  // It might take some time for database replicas to get up-to-date,
91
119
  // so getRun() might return null. Wait a little bit and try it again.
92
- if (!job)
93
- await new Promise((resolve) => {
94
- setTimeout(resolve, 250);
95
- });
120
+ if (!job) {
121
+ await sleep(250, signal);
122
+ signal?.throwIfAborted();
123
+ }
96
124
  } while (shouldRepeat());
97
125
  if (!job) {
98
126
  const constructorName = this.constructor.name;
@@ -1,4 +1,5 @@
1
1
  import type { z } from 'zod';
2
+ import type { Timeout, TimeoutOptions } from '../timeouts.js';
2
3
  import type { PaginatedResponse, PaginationOptions } from '../utils.js';
3
4
  import { ApiClient } from './api_client.js';
4
5
  /**
@@ -9,11 +10,18 @@ export declare class ResourceCollectionClient extends ApiClient {
9
10
  /**
10
11
  * @private
11
12
  */
12
- protected _list<T, R>(schema: z.ZodType, options?: T): Promise<R>;
13
+ protected listResources<T, R>(schema: z.ZodType, options: T | undefined, timeoutSecs: Timeout, signal?: AbortSignal): Promise<R>;
14
+ /**
15
+ * Lists an endpoint that returns every item in one response and ignores `offset` and `limit`. The result can be
16
+ * awaited as that response or iterated over its items, with a single request either way.
17
+ */
18
+ protected listUnpaginatedResources<Data, R extends PaginatedResponse<Data>>(schema: z.ZodType, timeoutSecs: Timeout, signal?: AbortSignal): AsyncIterable<Data> & Promise<R>;
13
19
  /**
14
20
  * Returns async iterator to iterate through all items and Promise that can be awaited to get first page of results.
21
+ * `defaultTimeoutSecs` applies to every page request unless `options.timeoutSecs` overrides it, and
22
+ * `options.signal` goes to every page request.
15
23
  */
16
- protected _listPaginated<T extends PaginationOptions, Data, R extends PaginatedResponse<Data>>(schema: z.ZodType, options?: T): AsyncIterable<Data> & Promise<R>;
17
- protected _create<D, R>(schema: z.ZodType, resource: D): Promise<R>;
18
- protected _getOrCreate<D, R>(schema: z.ZodType, name?: string, resource?: D): Promise<R>;
24
+ protected listResourcesPaginated<T extends PaginationOptions & TimeoutOptions, Data, R extends PaginatedResponse<Data>>(schema: z.ZodType, options: T, defaultTimeoutSecs: Timeout): AsyncIterable<Data> & Promise<R>;
25
+ protected createResource<D, R>(schema: z.ZodType, resource: D, timeoutSecs: Timeout, signal?: AbortSignal): Promise<R>;
26
+ protected getOrCreateResource<D, R>(schema: z.ZodType, name: string | undefined, resource: D | undefined, timeoutSecs: Timeout, signal?: AbortSignal): Promise<R>;
19
27
  }
@@ -8,35 +8,58 @@ export class ResourceCollectionClient extends ApiClient {
8
8
  /**
9
9
  * @private
10
10
  */
11
- async _list(schema, options = {}) {
11
+ async listResources(schema, options, timeoutSecs, signal) {
12
12
  const response = await this.httpClient.call({
13
- url: this._url(),
13
+ url: this.buildUrl(),
14
14
  method: 'GET',
15
- params: this._params(options),
15
+ params: this.buildParams(options),
16
+ timeoutSecs,
17
+ signal,
16
18
  });
17
19
  return parseResponse(response, schema);
18
20
  }
21
+ /**
22
+ * Lists an endpoint that returns every item in one response and ignores `offset` and `limit`. The result can be
23
+ * awaited as that response or iterated over its items, with a single request either way.
24
+ */
25
+ listUnpaginatedResources(schema, timeoutSecs, signal) {
26
+ const listPromise = this.listResources(schema, undefined, timeoutSecs, signal);
27
+ return Object.defineProperty(listPromise, Symbol.asyncIterator, {
28
+ async *value() {
29
+ yield* (await listPromise).items;
30
+ },
31
+ });
32
+ }
19
33
  /**
20
34
  * Returns async iterator to iterate through all items and Promise that can be awaited to get first page of results.
35
+ * `defaultTimeoutSecs` applies to every page request unless `options.timeoutSecs` overrides it, and
36
+ * `options.signal` goes to every page request.
21
37
  */
22
- _listPaginated(schema, options = {}) {
23
- return this._listPaginatedFromCallback(async (listOptions) => this._list(schema, listOptions), options);
38
+ listResourcesPaginated(schema, options, defaultTimeoutSecs) {
39
+ // `timeoutSecs` and `signal` only apply to the page requests; they are not API parameters, so they must not
40
+ // reach the query string.
41
+ const { timeoutSecs = defaultTimeoutSecs, signal, ...listOptions } = options;
42
+ return this.listPaginatedFromCallback(async (pageOptions) => this.listResources(schema, pageOptions, timeoutSecs, signal), listOptions);
24
43
  }
25
- async _create(schema, resource) {
44
+ async createResource(schema, resource, timeoutSecs, signal) {
26
45
  const response = await this.httpClient.call({
27
- url: this._url(),
46
+ url: this.buildUrl(),
28
47
  method: 'POST',
29
- params: this._params(),
48
+ params: this.buildParams(),
30
49
  data: resource,
50
+ timeoutSecs,
51
+ signal,
31
52
  });
32
53
  return parseResponse(response, schema);
33
54
  }
34
- async _getOrCreate(schema, name, resource) {
55
+ async getOrCreateResource(schema, name, resource, timeoutSecs, signal) {
35
56
  const response = await this.httpClient.call({
36
- url: this._url(),
57
+ url: this.buildUrl(),
37
58
  method: 'POST',
38
- params: this._params({ name }),
59
+ params: this.buildParams({ name }),
39
60
  data: resource,
61
+ timeoutSecs,
62
+ signal,
40
63
  });
41
64
  return parseResponse(response, schema);
42
65
  }
@@ -1,13 +1,12 @@
1
1
  import type { JsonArray, JsonObject } from 'type-fest';
2
2
  /**
3
- * Parses a Buffer or ArrayBuffer using the provided content type header.
3
+ * Parses a binary response body using the provided content type header.
4
4
  *
5
5
  * - application/json is returned as a parsed object.
6
6
  * - application/*xml and text/* are returned as strings.
7
7
  * - everything else is returned as original body.
8
8
  *
9
9
  * If the header includes a charset, the body will be stringified only
10
- * if the charset represents a known encoding to Node.js or Browser.
10
+ * if the charset is an encoding `TextDecoder` knows.
11
11
  */
12
- export declare function maybeParseBody(body: Buffer | ArrayBuffer, contentTypeHeader: string): string | Buffer | ArrayBuffer | JsonObject | JsonArray;
13
- export declare function isomorphicBufferToString(buffer: Buffer | ArrayBuffer, encoding: BufferEncoding): string;
12
+ export declare function maybeParseBody(body: ArrayBuffer | ArrayBufferView, contentTypeHeader: string): string | ArrayBuffer | ArrayBufferView | JsonObject | JsonArray;
@@ -1,22 +1,21 @@
1
- import contentTypeParser from 'content-type';
2
- import { isNode } from './utils.js';
1
+ import { parse as parseContentType } from 'content-type';
3
2
  const CONTENT_TYPE_JSON = 'application/json';
4
3
  const STRINGIFIABLE_CONTENT_TYPE_RXS = [new RegExp(`^${CONTENT_TYPE_JSON}`, 'i'), /^application\/.*xml$/i, /^text\//i];
5
4
  /**
6
- * Parses a Buffer or ArrayBuffer using the provided content type header.
5
+ * Parses a binary response body using the provided content type header.
7
6
  *
8
7
  * - application/json is returned as a parsed object.
9
8
  * - application/*xml and text/* are returned as strings.
10
9
  * - everything else is returned as original body.
11
10
  *
12
11
  * If the header includes a charset, the body will be stringified only
13
- * if the charset represents a known encoding to Node.js or Browser.
12
+ * if the charset is an encoding `TextDecoder` knows.
14
13
  */
15
14
  export function maybeParseBody(body, contentTypeHeader) {
16
15
  let contentType;
17
16
  let charset;
18
17
  try {
19
- const result = contentTypeParser.parse(contentTypeHeader);
18
+ const result = parseContentType(contentTypeHeader);
20
19
  contentType = result.type;
21
20
  charset = result.parameters.charset;
22
21
  }
@@ -24,35 +23,29 @@ export function maybeParseBody(body, contentTypeHeader) {
24
23
  // can't parse, keep original body
25
24
  return body;
26
25
  }
27
- // If we can't successfully parse it, we return
26
+ if (!isContentTypeStringifiable(contentType))
27
+ return body;
28
+ // If we can't successfully decode it, we return
28
29
  // the original buffer rather than a mangled string.
29
- if (!areDataStringifiable(contentType, charset))
30
+ const decoder = createDecoder(charset);
31
+ if (!decoder)
30
32
  return body;
31
- const dataString = isomorphicBufferToString(body, charset);
33
+ const dataString = decoder.decode(body);
32
34
  return contentType === CONTENT_TYPE_JSON ? JSON.parse(dataString) : dataString;
33
35
  }
34
- export function isomorphicBufferToString(buffer, encoding) {
35
- if (buffer.constructor.name !== ArrayBuffer.name) {
36
- return buffer.toString(encoding);
36
+ function createDecoder(charset) {
37
+ try {
38
+ // No charset defaults to utf-8. A leading BOM is kept, so a BOM-prefixed CSV stored in a key-value store
39
+ // round-trips through `getRecord()` unchanged.
40
+ return new TextDecoder(charset, { ignoreBOM: true });
41
+ }
42
+ catch {
43
+ // `TextDecoder` throws a `RangeError` for a label it does not know.
44
+ return undefined;
37
45
  }
38
- // Browser decoding only works with UTF-8.
39
- const utf8decoder = new TextDecoder();
40
- return utf8decoder.decode(new Uint8Array(buffer));
41
- }
42
- function isCharsetStringifiable(charset) {
43
- if (!charset)
44
- return true; // hope that it's utf-8
45
- if (isNode())
46
- return Buffer.isEncoding(charset);
47
- const normalizedCharset = charset.toLowerCase().replace('-', '');
48
- // Browsers only support decoding utf-8 buffers.
49
- return normalizedCharset === 'utf8';
50
46
  }
51
47
  function isContentTypeStringifiable(contentType) {
52
48
  if (!contentType)
53
49
  return false; // keep buffer
54
50
  return STRINGIFIABLE_CONTENT_TYPE_RXS.some((rx) => rx.test(contentType));
55
51
  }
56
- function areDataStringifiable(contentType, charset) {
57
- return isContentTypeStringifiable(contentType) && isCharsetStringifiable(charset);
58
- }