apify-client 3.0.0-beta.4 → 3.0.0-beta.6

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 (52) hide show
  1. package/README.md +3 -1
  2. package/dist/apify_api_error.d.ts +59 -3
  3. package/dist/apify_api_error.js +66 -2
  4. package/dist/base/resource_client.d.ts +4 -3
  5. package/dist/base/resource_client.js +7 -7
  6. package/dist/base/resource_collection_client.d.ts +5 -4
  7. package/dist/base/resource_collection_client.js +9 -9
  8. package/dist/bundle.js +16 -14
  9. package/dist/bundle.js.map +1 -1
  10. package/dist/generated/api.d.ts +287 -214
  11. package/dist/generated/schemas.d.ts +6699 -0
  12. package/dist/generated/schemas.js +1521 -0
  13. package/dist/http_client.js +1 -1
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +1 -0
  16. package/dist/lazy_schema.d.ts +8 -0
  17. package/dist/lazy_schema.js +11 -0
  18. package/dist/models.d.ts +21 -40
  19. package/dist/resource_clients/actor.js +7 -6
  20. package/dist/resource_clients/actor_collection.js +3 -2
  21. package/dist/resource_clients/actor_env_var.js +3 -2
  22. package/dist/resource_clients/actor_env_var_collection.js +3 -2
  23. package/dist/resource_clients/actor_version.js +3 -2
  24. package/dist/resource_clients/actor_version_collection.js +3 -2
  25. package/dist/resource_clients/build.js +5 -4
  26. package/dist/resource_clients/build_collection.js +2 -1
  27. package/dist/resource_clients/dataset.js +5 -4
  28. package/dist/resource_clients/dataset_collection.js +3 -2
  29. package/dist/resource_clients/key_value_store.js +5 -4
  30. package/dist/resource_clients/key_value_store_collection.js +3 -2
  31. package/dist/resource_clients/request_queue.js +24 -16
  32. package/dist/resource_clients/request_queue_collection.js +3 -2
  33. package/dist/resource_clients/run.js +9 -8
  34. package/dist/resource_clients/run_collection.js +2 -1
  35. package/dist/resource_clients/schedule.d.ts +4 -4
  36. package/dist/resource_clients/schedule.js +8 -5
  37. package/dist/resource_clients/schedule_collection.js +3 -2
  38. package/dist/resource_clients/store_collection.js +2 -1
  39. package/dist/resource_clients/task.js +5 -4
  40. package/dist/resource_clients/task_collection.js +3 -2
  41. package/dist/resource_clients/user.js +6 -6
  42. package/dist/resource_clients/webhook.js +5 -4
  43. package/dist/resource_clients/webhook_collection.js +3 -2
  44. package/dist/resource_clients/webhook_dispatch.js +2 -1
  45. package/dist/resource_clients/webhook_dispatch_collection.js +2 -1
  46. package/dist/response_validation_error.d.ts +26 -0
  47. package/dist/response_validation_error.js +37 -0
  48. package/dist/schemas.d.ts +15 -0
  49. package/dist/schemas.js +15 -0
  50. package/dist/utils.d.ts +12 -2
  51. package/dist/utils.js +26 -9
  52. package/package.json +3 -3
package/README.md CHANGED
@@ -47,7 +47,9 @@ Besides greatly simplifying the process of querying the Apify API, the client pr
47
47
  Based on the endpoint, the client automatically extracts the relevant data and returns it in the
48
48
  expected format. Date strings are automatically converted to `Date` objects. For exceptions,
49
49
  we throw an `ApifyApiError`, which wraps the plain JSON errors returned by API and enriches
50
- them with other context for easier debugging.
50
+ them with other context for easier debugging. The error is an instance of the subclass matching the
51
+ HTTP status code, such as `NotFoundError` or `RateLimitError`, so a `catch` block can tell them apart
52
+ with `instanceof`.
51
53
 
52
54
  ### Retries with exponential backoff
53
55
 
@@ -1,10 +1,20 @@
1
1
  import type { AxiosResponse } from 'axios';
2
+ import type { LiteralUnion } from 'type-fest';
3
+ import type { ApifyApiErrorType } from './models.js';
4
+ export type { ApifyApiErrorType } from './models.js';
2
5
  /**
3
6
  * An `ApifyApiError` is thrown for successful HTTP requests that reach the API,
4
7
  * but the API responds with an error response. Typically, those are rate limit
5
8
  * errors and internal errors, which are automatically retried, or validation
6
9
  * errors, which are thrown immediately, because a correction by the user is
7
10
  * needed.
11
+ *
12
+ * The thrown error is an instance of the subclass matching the HTTP status code of the response:
13
+ * {@link InvalidRequestError} (400), {@link UnauthorizedError} (401), {@link ForbiddenError} (403),
14
+ * {@link NotFoundError} (404), {@link ConflictError} (409), {@link RateLimitError} (429) or
15
+ * {@link ServerError} (5xx). Any other status code is thrown as a plain `ApifyApiError`. Every
16
+ * subclass extends `ApifyApiError`, so `instanceof ApifyApiError` matches all of them. Errors that
17
+ * share a status code are told apart by their `type`.
8
18
  */
9
19
  export declare class ApifyApiError extends Error {
10
20
  name: string;
@@ -18,9 +28,10 @@ export declare class ApifyApiError extends Error {
18
28
  */
19
29
  statusCode: number;
20
30
  /**
21
- * The type of the error, as returned by the API.
31
+ * The type of the error, as returned by the API. Typed as the known {@link ApifyApiErrorType}
32
+ * values for autocompletion, while still accepting any string the API may return.
22
33
  */
23
- type?: string;
34
+ type?: LiteralUnion<ApifyApiErrorType, string>;
24
35
  /**
25
36
  * Number of the API call attempt.
26
37
  */
@@ -46,6 +57,11 @@ export declare class ApifyApiError extends Error {
46
57
  * @hidden
47
58
  */
48
59
  constructor(response: AxiosResponse, attempt: number);
60
+ /**
61
+ * Creates the error for a failed response as an instance of the subclass matching its HTTP status code.
62
+ * @hidden
63
+ */
64
+ static fromResponse(response: AxiosResponse, attempt: number): ApifyApiError;
49
65
  private _safelyParsePathFromResponse;
50
66
  private _extractClientAndMethodFromStack;
51
67
  /**
@@ -54,7 +70,7 @@ export declare class ApifyApiError extends Error {
54
70
  *
55
71
  * Example:
56
72
  *
57
- * ApifyApiError: Actor task was not found
73
+ * NotFoundError: Actor task was not found
58
74
  * clientMethod: TaskClient.start
59
75
  * statusCode: 404
60
76
  * type: record-not-found
@@ -64,3 +80,43 @@ export declare class ApifyApiError extends Error {
64
80
  */
65
81
  private _createApiStack;
66
82
  }
83
+ /**
84
+ * Thrown when the Apify API responds with HTTP 400 Bad Request, typically because the request
85
+ * failed validation.
86
+ */
87
+ export declare class InvalidRequestError extends ApifyApiError {
88
+ }
89
+ /**
90
+ * Thrown when the Apify API responds with HTTP 401 Unauthorized, because the token is missing
91
+ * or invalid.
92
+ */
93
+ export declare class UnauthorizedError extends ApifyApiError {
94
+ }
95
+ /**
96
+ * Thrown when the Apify API responds with HTTP 403 Forbidden, because the token lacks the
97
+ * permission for the operation.
98
+ */
99
+ export declare class ForbiddenError extends ApifyApiError {
100
+ }
101
+ /**
102
+ * Thrown when the Apify API responds with HTTP 404 Not Found.
103
+ */
104
+ export declare class NotFoundError extends ApifyApiError {
105
+ }
106
+ /**
107
+ * Thrown when the Apify API responds with HTTP 409 Conflict.
108
+ */
109
+ export declare class ConflictError extends ApifyApiError {
110
+ }
111
+ /**
112
+ * Thrown when the Apify API responds with HTTP 429 Too Many Requests. The client retries such
113
+ * requests, so the error surfaces once the retries are exhausted.
114
+ */
115
+ export declare class RateLimitError extends ApifyApiError {
116
+ }
117
+ /**
118
+ * Thrown when the Apify API responds with an HTTP 5xx status. The client retries such requests,
119
+ * so the error surfaces once the retries are exhausted.
120
+ */
121
+ export declare class ServerError extends ApifyApiError {
122
+ }
@@ -16,6 +16,13 @@ const CLIENT_METHOD_REGEX = /at( async)? ([A-Za-z]+(Collection)?Client)\._?([A-Z
16
16
  * errors and internal errors, which are automatically retried, or validation
17
17
  * errors, which are thrown immediately, because a correction by the user is
18
18
  * needed.
19
+ *
20
+ * The thrown error is an instance of the subclass matching the HTTP status code of the response:
21
+ * {@link InvalidRequestError} (400), {@link UnauthorizedError} (401), {@link ForbiddenError} (403),
22
+ * {@link NotFoundError} (404), {@link ConflictError} (409), {@link RateLimitError} (429) or
23
+ * {@link ServerError} (5xx). Any other status code is thrown as a plain `ApifyApiError`. Every
24
+ * subclass extends `ApifyApiError`, so `instanceof ApifyApiError` matches all of them. Errors that
25
+ * share a status code are told apart by their `type`.
19
26
  */
20
27
  export class ApifyApiError extends Error {
21
28
  name;
@@ -29,7 +36,8 @@ export class ApifyApiError extends Error {
29
36
  */
30
37
  statusCode;
31
38
  /**
32
- * The type of the error, as returned by the API.
39
+ * The type of the error, as returned by the API. Typed as the known {@link ApifyApiErrorType}
40
+ * values for autocompletion, while still accepting any string the API may return.
33
41
  */
34
42
  type;
35
43
  /**
@@ -100,6 +108,14 @@ export class ApifyApiError extends Error {
100
108
  this.stack = this._createApiStack();
101
109
  this.data = errorData;
102
110
  }
111
+ /**
112
+ * Creates the error for a failed response as an instance of the subclass matching its HTTP status code.
113
+ * @hidden
114
+ */
115
+ static fromResponse(response, attempt) {
116
+ const ErrorClass = ERROR_CLASS_BY_STATUS[response.status] ?? (response.status >= 500 ? ServerError : ApifyApiError);
117
+ return new ErrorClass(response, attempt);
118
+ }
103
119
  _safelyParsePathFromResponse(response) {
104
120
  const urlString = response.config?.url;
105
121
  let url;
@@ -123,7 +139,7 @@ export class ApifyApiError extends Error {
123
139
  *
124
140
  * Example:
125
141
  *
126
- * ApifyApiError: Actor task was not found
142
+ * NotFoundError: Actor task was not found
127
143
  * clientMethod: TaskClient.start
128
144
  * statusCode: 404
129
145
  * type: record-not-found
@@ -145,3 +161,51 @@ export class ApifyApiError extends Error {
145
161
  return `${name}: ${this.message}\n${stack}`;
146
162
  }
147
163
  }
164
+ /**
165
+ * Thrown when the Apify API responds with HTTP 400 Bad Request, typically because the request
166
+ * failed validation.
167
+ */
168
+ export class InvalidRequestError extends ApifyApiError {
169
+ }
170
+ /**
171
+ * Thrown when the Apify API responds with HTTP 401 Unauthorized, because the token is missing
172
+ * or invalid.
173
+ */
174
+ export class UnauthorizedError extends ApifyApiError {
175
+ }
176
+ /**
177
+ * Thrown when the Apify API responds with HTTP 403 Forbidden, because the token lacks the
178
+ * permission for the operation.
179
+ */
180
+ export class ForbiddenError extends ApifyApiError {
181
+ }
182
+ /**
183
+ * Thrown when the Apify API responds with HTTP 404 Not Found.
184
+ */
185
+ export class NotFoundError extends ApifyApiError {
186
+ }
187
+ /**
188
+ * Thrown when the Apify API responds with HTTP 409 Conflict.
189
+ */
190
+ export class ConflictError extends ApifyApiError {
191
+ }
192
+ /**
193
+ * Thrown when the Apify API responds with HTTP 429 Too Many Requests. The client retries such
194
+ * requests, so the error surfaces once the retries are exhausted.
195
+ */
196
+ export class RateLimitError extends ApifyApiError {
197
+ }
198
+ /**
199
+ * Thrown when the Apify API responds with an HTTP 5xx status. The client retries such requests,
200
+ * so the error surfaces once the retries are exhausted.
201
+ */
202
+ export class ServerError extends ApifyApiError {
203
+ }
204
+ const ERROR_CLASS_BY_STATUS = {
205
+ 400: InvalidRequestError,
206
+ 401: UnauthorizedError,
207
+ 403: ForbiddenError,
208
+ 404: NotFoundError,
209
+ 409: ConflictError,
210
+ 429: RateLimitError,
211
+ };
@@ -1,4 +1,5 @@
1
1
  import type { ACT_JOB_STATUSES } from '@apify/consts';
2
+ import type { z } from 'zod';
2
3
  import { ApiClient } from './api_client.js';
3
4
  export declare const SMALL_TIMEOUT_MILLIS: number;
4
5
  export declare const MEDIUM_TIMEOUT_MILLIS: number;
@@ -8,8 +9,8 @@ export declare const DEFAULT_TIMEOUT_MILLIS: number;
8
9
  * @private
9
10
  */
10
11
  export declare class ResourceClient extends ApiClient {
11
- protected _get<T, R>(options?: T, timeoutMillis?: number): Promise<R | undefined>;
12
- protected _update<T, R>(newFields: T, timeoutMillis?: number): Promise<R>;
12
+ protected _get<T, R>(schema: z.ZodType, options?: T, timeoutMillis?: number): Promise<R | undefined>;
13
+ protected _update<T, R>(schema: z.ZodType, newFields: T, timeoutMillis?: number): Promise<R>;
13
14
  protected _delete(timeoutMillis?: number): Promise<void>;
14
15
  /**
15
16
  * This function is used in Build and Run endpoints so it's kept
@@ -17,7 +18,7 @@ export declare class ResourceClient extends ApiClient {
17
18
  */
18
19
  protected _waitForFinish<R extends {
19
20
  status: (typeof ACT_JOB_STATUSES)[keyof typeof ACT_JOB_STATUSES];
20
- }>(options?: WaitForFinishOptions): Promise<R>;
21
+ }>(schema: z.ZodType, options?: WaitForFinishOptions): Promise<R>;
21
22
  }
22
23
  export interface WaitForFinishOptions {
23
24
  waitSecs?: number;
@@ -1,5 +1,5 @@
1
1
  import { ACT_JOB_TERMINAL_STATUSES } from '@apify/consts';
2
- import { catchNotFoundOrThrow, parseDateFields, pluckData } from '../utils.js';
2
+ import { catchNotFoundOrThrow, parseResponse } from '../utils.js';
3
3
  import { ApiClient } from './api_client.js';
4
4
  /**
5
5
  * We need to supply some number for the API,
@@ -15,7 +15,7 @@ export const DEFAULT_TIMEOUT_MILLIS = 360 * 1000; // 6 minutes
15
15
  * @private
16
16
  */
17
17
  export class ResourceClient extends ApiClient {
18
- async _get(options = {}, timeoutMillis) {
18
+ async _get(schema, options = {}, timeoutMillis) {
19
19
  const requestOpts = {
20
20
  url: this._url(),
21
21
  method: 'GET',
@@ -24,14 +24,14 @@ export class ResourceClient extends ApiClient {
24
24
  };
25
25
  try {
26
26
  const response = await this.httpClient.call(requestOpts);
27
- return parseDateFields(pluckData(response.data));
27
+ return parseResponse(response, schema);
28
28
  }
29
29
  catch (err) {
30
30
  catchNotFoundOrThrow(err);
31
31
  }
32
32
  return undefined;
33
33
  }
34
- async _update(newFields, timeoutMillis) {
34
+ async _update(schema, newFields, timeoutMillis) {
35
35
  const response = await this.httpClient.call({
36
36
  url: this._url(),
37
37
  method: 'PUT',
@@ -39,7 +39,7 @@ export class ResourceClient extends ApiClient {
39
39
  data: newFields,
40
40
  timeout: timeoutMillis,
41
41
  });
42
- return parseDateFields(pluckData(response.data));
42
+ return parseResponse(response, schema);
43
43
  }
44
44
  async _delete(timeoutMillis) {
45
45
  try {
@@ -58,7 +58,7 @@ export class ResourceClient extends ApiClient {
58
58
  * This function is used in Build and Run endpoints so it's kept
59
59
  * here to stay DRY.
60
60
  */
61
- async _waitForFinish(options = {}) {
61
+ async _waitForFinish(schema, options = {}) {
62
62
  const { waitSecs = MAX_WAIT_FOR_FINISH } = options;
63
63
  const waitMillis = waitSecs * 1000;
64
64
  let job;
@@ -81,7 +81,7 @@ export class ResourceClient extends ApiClient {
81
81
  };
82
82
  try {
83
83
  const response = await this.httpClient.call(requestOpts);
84
- job = parseDateFields(pluckData(response.data));
84
+ job = parseResponse(response, schema);
85
85
  }
86
86
  catch (err) {
87
87
  catchNotFoundOrThrow(err);
@@ -1,3 +1,4 @@
1
+ import type { z } from 'zod';
1
2
  import type { PaginatedResponse, PaginationOptions } from '../utils.js';
2
3
  import { ApiClient } from './api_client.js';
3
4
  /**
@@ -8,11 +9,11 @@ export declare class ResourceCollectionClient extends ApiClient {
8
9
  /**
9
10
  * @private
10
11
  */
11
- protected _list<T, R>(options?: T): Promise<R>;
12
+ protected _list<T, R>(schema: z.ZodType, options?: T): Promise<R>;
12
13
  /**
13
14
  * Returns async iterator to iterate through all items and Promise that can be awaited to get first page of results.
14
15
  */
15
- protected _listPaginated<T extends PaginationOptions, Data, R extends PaginatedResponse<Data>>(options?: T): AsyncIterable<Data> & Promise<R>;
16
- protected _create<D, R>(resource: D): Promise<R>;
17
- protected _getOrCreate<D, R>(name?: string, resource?: D): Promise<R>;
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>;
18
19
  }
@@ -1,4 +1,4 @@
1
- import { parseDateFields, pluckData } from '../utils.js';
1
+ import { parseResponse } from '../utils.js';
2
2
  import { ApiClient } from './api_client.js';
3
3
  /**
4
4
  * Resource collection client.
@@ -8,36 +8,36 @@ export class ResourceCollectionClient extends ApiClient {
8
8
  /**
9
9
  * @private
10
10
  */
11
- async _list(options = {}) {
11
+ async _list(schema, options = {}) {
12
12
  const response = await this.httpClient.call({
13
13
  url: this._url(),
14
14
  method: 'GET',
15
15
  params: this._params(options),
16
16
  });
17
- return parseDateFields(pluckData(response.data));
17
+ return parseResponse(response, schema);
18
18
  }
19
19
  /**
20
20
  * Returns async iterator to iterate through all items and Promise that can be awaited to get first page of results.
21
21
  */
22
- _listPaginated(options = {}) {
23
- return this._listPaginatedFromCallback((this._list.bind(this)), options);
22
+ _listPaginated(schema, options = {}) {
23
+ return this._listPaginatedFromCallback(async (listOptions) => this._list(schema, listOptions), options);
24
24
  }
25
- async _create(resource) {
25
+ async _create(schema, resource) {
26
26
  const response = await this.httpClient.call({
27
27
  url: this._url(),
28
28
  method: 'POST',
29
29
  params: this._params(),
30
30
  data: resource,
31
31
  });
32
- return parseDateFields(pluckData(response.data));
32
+ return parseResponse(response, schema);
33
33
  }
34
- async _getOrCreate(name, resource) {
34
+ async _getOrCreate(schema, name, resource) {
35
35
  const response = await this.httpClient.call({
36
36
  url: this._url(),
37
37
  method: 'POST',
38
38
  params: this._params({ name }),
39
39
  data: resource,
40
40
  });
41
- return parseDateFields(pluckData(response.data));
41
+ return parseResponse(response, schema);
42
42
  }
43
43
  }