apify-client 2.23.5-beta.8 → 2.24.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.
@@ -122,7 +122,7 @@ class HttpClient {
122
122
  this.axios.defaults.httpsAgent = this.httpsAgent;
123
123
  // Works only in Node. Cannot be set in browser
124
124
  const isAtHome = !!process.env[consts_1.APIFY_ENV_VARS.IS_AT_HOME];
125
- let userAgent = `ApifyClient/${version} (${os.type()}; Node/${process.version}); isAtHome/${isAtHome}`;
125
+ let userAgent = `ApifyClient/${version} (${os.platform()}; Node/${process.version}); isAtHome/${isAtHome}`;
126
126
  if (this.userAgentSuffix) {
127
127
  userAgent += `; ${(0, utils_1.asArray)(this.userAgentSuffix).join('; ')}`;
128
128
  }
@@ -69,14 +69,14 @@ function stringifyWithFunctions(obj) {
69
69
  return typeof value === 'function' ? value.toString() : value;
70
70
  });
71
71
  }
72
- async function maybeGzipRequest(config) {
72
+ async function maybeCompressRequest(config) {
73
73
  if (config.headers?.['content-encoding'])
74
74
  return config;
75
- const maybeZippedData = await (0, utils_1.maybeGzipValue)(config.data);
76
- if (maybeZippedData) {
75
+ const maybeCompressed = await (0, utils_1.maybeCompressValue)(config.data);
76
+ if (maybeCompressed) {
77
77
  config.headers ??= {};
78
- config.headers['content-encoding'] = 'gzip';
79
- config.data = maybeZippedData;
78
+ config.headers['content-encoding'] = maybeCompressed.encoding;
79
+ config.data = maybeCompressed.data;
80
80
  }
81
81
  return config;
82
82
  }
@@ -103,7 +103,7 @@ function parseResponseData(response) {
103
103
  return response;
104
104
  }
105
105
  exports.requestInterceptors = [
106
- maybeGzipRequest,
106
+ maybeCompressRequest,
107
107
  serializeRequest,
108
108
  ensureHeadersPrototype,
109
109
  ];
@@ -1,5 +1,5 @@
1
1
  import type { RUN_GENERAL_ACCESS } from '@apify/consts';
2
- import { ACT_JOB_STATUSES, ACTOR_PERMISSION_LEVEL } from '@apify/consts';
2
+ import { ACTOR_JOB_STATUSES, ACTOR_PERMISSION_LEVEL, META_ORIGINS } from '@apify/consts';
3
3
  import { Log } from '@apify/log';
4
4
  import type { ApiClientSubResourceOptions } from '../base/api_client';
5
5
  import { ResourceClient } from '../base/resource_client';
@@ -13,6 +13,7 @@ import { RunClient } from './run';
13
13
  import { RunCollectionClient } from './run_collection';
14
14
  import type { WebhookUpdateData } from './webhook';
15
15
  import { WebhookCollectionClient } from './webhook_collection';
16
+ import type { ValueOf } from 'type-fest';
16
17
  /**
17
18
  * Client for managing a specific Actor.
18
19
  *
@@ -132,6 +133,37 @@ export declare class ActorClient extends ResourceClient {
132
133
  * ```
133
134
  */
134
135
  call(input?: unknown, options?: ActorCallOptions): Promise<ActorRun>;
136
+ /**
137
+ * Validates the provided input for the Actor against its input schema.
138
+ *
139
+ * Sends the input to the API, which validates it against the Actor's input schema without
140
+ * starting a run. If the input is valid, the method resolves with `true`. If the input is
141
+ * invalid, the API responds with an error that is thrown as an `ApifyApiError` describing the
142
+ * validation problem.
143
+ *
144
+ * @param input - Input to validate against the Actor's input schema. Can be any JSON-serializable
145
+ * value (object, array, string, number). If `contentType` is specified in options,
146
+ * input should be a string or Buffer.
147
+ * @param options - Validation options
148
+ * @param options.build - Tag or number of the build whose input schema the input is validated against
149
+ * (e.g., `'latest'` or `'1.2.345'`). If not provided, uses the default build.
150
+ * @param options.contentType - Content type of the input. If specified, input must be a string or Buffer.
151
+ * @returns `true` if the input is valid. Invalid input causes the underlying API call to throw an `ApifyApiError`.
152
+ * @see https://docs.apify.com/api/v2/act-validate-input-post
153
+ *
154
+ * @example
155
+ * ```javascript
156
+ * // Validate input against the default build's input schema
157
+ * const isValid = await client.actor('my-actor').validateInput({ url: 'https://example.com' });
158
+ *
159
+ * // Validate against a specific build
160
+ * const isValid = await client.actor('my-actor').validateInput(
161
+ * { url: 'https://example.com' },
162
+ * { build: 'beta' },
163
+ * );
164
+ * ```
165
+ */
166
+ validateInput(input?: unknown, options?: ActorValidateInputOptions): Promise<boolean>;
135
167
  /**
136
168
  * Builds the Actor.
137
169
  *
@@ -462,7 +494,7 @@ export interface ActorRunListItem {
462
494
  actorTaskId?: string;
463
495
  startedAt: Date;
464
496
  finishedAt: Date;
465
- status: (typeof ACT_JOB_STATUSES)[keyof typeof ACT_JOB_STATUSES];
497
+ status: (typeof ACTOR_JOB_STATUSES)[keyof typeof ACTOR_JOB_STATUSES];
466
498
  meta: ActorRunMeta;
467
499
  buildId: string;
468
500
  buildNumber: string;
@@ -585,6 +617,23 @@ export interface ActorRunOptions {
585
617
  maxTotalChargeUsd?: number;
586
618
  restartOnError?: boolean;
587
619
  }
620
+ /**
621
+ * Options for validating an Actor input.
622
+ */
623
+ export interface ActorValidateInputOptions {
624
+ /**
625
+ * Tag or number of the Actor build whose input schema the input is validated against
626
+ * (e.g. `beta` or `1.2.345`). If not provided, the default build is used.
627
+ */
628
+ build?: string;
629
+ /**
630
+ * Content type for the `input`. If not specified,
631
+ * `input` is expected to be an object that will be stringified to JSON and content type set to
632
+ * `application/json; charset=utf-8`. If `options.contentType` is specified, then `input` must be a
633
+ * `String` or `Buffer`.
634
+ */
635
+ contentType?: string;
636
+ }
588
637
  /**
589
638
  * Options for building an Actor.
590
639
  */
@@ -598,7 +647,8 @@ export interface ActorBuildOptions {
598
647
  * Options for filtering the last run of an Actor.
599
648
  */
600
649
  export interface ActorLastRunOptions {
601
- status?: keyof typeof ACT_JOB_STATUSES;
650
+ status?: ValueOf<typeof ACTOR_JOB_STATUSES>;
651
+ origin?: ValueOf<typeof META_ORIGINS>;
602
652
  }
603
653
  /**
604
654
  * Actor definition from the `.actor/actor.json` file.
@@ -140,9 +140,6 @@ class ActorClient extends resource_client_1.ResourceClient {
140
140
  params: this._params(params),
141
141
  // Apify internal property. Tells the request serialization interceptor
142
142
  // to stringify functions to JSON, instead of omitting them.
143
- // TODO: remove this ts-expect-error once we migrate HttpClient to TS and define Apify
144
- // extension of Axios configs
145
- // @ts-expect-error Apify extension
146
143
  stringifyFunctions: true,
147
144
  };
148
145
  if (options.contentType) {
@@ -221,6 +218,60 @@ class ActorClient extends resource_client_1.ResourceClient {
221
218
  await streamedLog?.stop();
222
219
  });
223
220
  }
221
+ /**
222
+ * Validates the provided input for the Actor against its input schema.
223
+ *
224
+ * Sends the input to the API, which validates it against the Actor's input schema without
225
+ * starting a run. If the input is valid, the method resolves with `true`. If the input is
226
+ * invalid, the API responds with an error that is thrown as an `ApifyApiError` describing the
227
+ * validation problem.
228
+ *
229
+ * @param input - Input to validate against the Actor's input schema. Can be any JSON-serializable
230
+ * value (object, array, string, number). If `contentType` is specified in options,
231
+ * input should be a string or Buffer.
232
+ * @param options - Validation options
233
+ * @param options.build - Tag or number of the build whose input schema the input is validated against
234
+ * (e.g., `'latest'` or `'1.2.345'`). If not provided, uses the default build.
235
+ * @param options.contentType - Content type of the input. If specified, input must be a string or Buffer.
236
+ * @returns `true` if the input is valid. Invalid input causes the underlying API call to throw an `ApifyApiError`.
237
+ * @see https://docs.apify.com/api/v2/act-validate-input-post
238
+ *
239
+ * @example
240
+ * ```javascript
241
+ * // Validate input against the default build's input schema
242
+ * const isValid = await client.actor('my-actor').validateInput({ url: 'https://example.com' });
243
+ *
244
+ * // Validate against a specific build
245
+ * const isValid = await client.actor('my-actor').validateInput(
246
+ * { url: 'https://example.com' },
247
+ * { build: 'beta' },
248
+ * );
249
+ * ```
250
+ */
251
+ async validateInput(input, options = {}) {
252
+ // input can be anything, so no point in validating it. E.g. if you set content-type to application/pdf
253
+ // then it will process input as a buffer.
254
+ (0, ow_1.default)(options, ow_1.default.object.exactShape({
255
+ build: ow_1.default.optional.string,
256
+ contentType: ow_1.default.optional.string,
257
+ }));
258
+ const request = {
259
+ url: this._url('validate-input'),
260
+ method: 'POST',
261
+ data: input,
262
+ params: this._params({ build: options.build }),
263
+ // Apify internal property. Tells the request serialization interceptor
264
+ // to stringify functions to JSON, instead of omitting them.
265
+ stringifyFunctions: true,
266
+ };
267
+ if (options.contentType) {
268
+ request.headers = {
269
+ 'content-type': options.contentType,
270
+ };
271
+ }
272
+ const response = await this.httpClient.call(request);
273
+ return response.data.valid;
274
+ }
224
275
  /**
225
276
  * Builds the Actor.
226
277
  *
@@ -326,7 +377,7 @@ class ActorClient extends resource_client_1.ResourceClient {
326
377
  */
327
378
  lastRun(options = {}) {
328
379
  (0, ow_1.default)(options, ow_1.default.object.exactShape({
329
- status: ow_1.default.optional.string.oneOf(Object.values(consts_1.ACT_JOB_STATUSES)),
380
+ status: ow_1.default.optional.string.oneOf(Object.values(consts_1.ACTOR_JOB_STATUSES)),
330
381
  origin: ow_1.default.optional.string.oneOf(Object.values(consts_1.META_ORIGINS)),
331
382
  }));
332
383
  return new run_1.RunClient(this._subResourceOptions({
@@ -1,8 +1,7 @@
1
- import { ACT_JOB_STATUSES } from '@apify/consts';
2
1
  import type { ApiClientSubResourceOptions } from '../base/api_client';
3
2
  import { ResourceClient } from '../base/resource_client';
4
3
  import type { Dictionary } from '../utils';
5
- import type { ActorRun, ActorStandby, ActorStartOptions } from './actor';
4
+ import type { ActorLastRunOptions, ActorRun, ActorStandby, ActorStartOptions } from './actor';
6
5
  import { RunClient } from './run';
7
6
  import { RunCollectionClient } from './run_collection';
8
7
  import { WebhookCollectionClient } from './webhook_collection';
@@ -170,8 +169,7 @@ export type TaskUpdateData = Partial<Pick<Task, 'name' | 'title' | 'description'
170
169
  /**
171
170
  * Options for filtering the last run of a Task.
172
171
  */
173
- export interface TaskLastRunOptions {
174
- status?: keyof typeof ACT_JOB_STATUSES;
172
+ export interface TaskLastRunOptions extends ActorLastRunOptions {
175
173
  }
176
174
  /**
177
175
  * Options for starting a Task.
package/dist/utils.d.ts CHANGED
@@ -41,10 +41,15 @@ export declare function parseDateFields(input: JsonValue, shouldParseField?: ((k
41
41
  * Helper function that converts array of webhooks to base64 string
42
42
  */
43
43
  export declare function stringifyWebhooksToBase64(webhooks: WebhookUpdateData[]): string | undefined;
44
+ export interface CompressedValue {
45
+ data: Buffer;
46
+ encoding: 'br' | 'gzip';
47
+ }
44
48
  /**
45
- * Gzip provided value, otherwise returns undefined.
49
+ * Compress the passed value using brotli if available or using gzip as a fallback. Returns undefined
50
+ * if the data is too small / wrong type.
46
51
  */
47
- export declare function maybeGzipValue(value: unknown): Promise<Buffer | undefined>;
52
+ export declare function maybeCompressValue(value: unknown): Promise<CompressedValue | undefined>;
48
53
  /**
49
54
  * Helper function slice the items from array to fit the max byte length.
50
55
  */
package/dist/utils.js CHANGED
@@ -5,7 +5,7 @@ exports.pluckData = pluckData;
5
5
  exports.catchNotFoundOrThrow = catchNotFoundOrThrow;
6
6
  exports.parseDateFields = parseDateFields;
7
7
  exports.stringifyWebhooksToBase64 = stringifyWebhooksToBase64;
8
- exports.maybeGzipValue = maybeGzipValue;
8
+ exports.maybeCompressValue = maybeCompressValue;
9
9
  exports.sliceArrayByByteLength = sliceArrayByByteLength;
10
10
  exports.isNode = isNode;
11
11
  exports.isBuffer = isBuffer;
@@ -19,7 +19,7 @@ const ow_1 = tslib_1.__importDefault(require("ow"));
19
19
  const NOT_FOUND_STATUS_CODE = 404;
20
20
  const RECORD_NOT_FOUND_TYPE = 'record-not-found';
21
21
  const RECORD_OR_TOKEN_NOT_FOUND_TYPE = 'record-or-token-not-found';
22
- const MIN_GZIP_BYTES = 1024;
22
+ const MIN_COMPRESS_BYTES = 1024;
23
23
  /**
24
24
  * Returns object's 'data' property or throws if parameter is not an object,
25
25
  * or an object without a 'data' property.
@@ -99,26 +99,59 @@ function stringifyWebhooksToBase64(webhooks) {
99
99
  }
100
100
  let gzipPromisified;
101
101
  /**
102
- * Gzip provided value, otherwise returns undefined.
102
+ * Gzip-compress the provided value.
103
103
  */
104
- async function maybeGzipValue(value) {
105
- if (!isNode())
106
- return;
107
- if (typeof value !== 'string' && !Buffer.isBuffer(value))
108
- return;
109
- // Request compression is not that important so let's
110
- // skip it instead of throwing for unsupported types.
111
- const areDataLargeEnough = Buffer.byteLength(value) >= MIN_GZIP_BYTES;
112
- if (areDataLargeEnough) {
113
- if (!gzipPromisified) {
114
- const { promisify } = await import('node:util');
115
- const { gzip } = await import('node:zlib');
116
- gzipPromisified = promisify(gzip);
104
+ async function gzipValue(value) {
105
+ if (!gzipPromisified) {
106
+ const { promisify } = await import('node:util');
107
+ const { gzip } = await import('node:zlib');
108
+ gzipPromisified = promisify(gzip);
109
+ }
110
+ return gzipPromisified(value);
111
+ }
112
+ // null = confirmed unavailable; undefined = not yet checked
113
+ let brotliCompressPromisified;
114
+ /**
115
+ * Brotli-compress the provided value, or return undefined if brotli is unavailable
116
+ * (Node.js < v10.16.0), this is a strict defensive guard.
117
+ */
118
+ async function maybeBrotliValue(value) {
119
+ if (brotliCompressPromisified === undefined) {
120
+ const { promisify } = await import('node:util');
121
+ const { brotliCompress, constants } = await import('node:zlib');
122
+ if (typeof brotliCompress === 'function') {
123
+ const compress = promisify(brotliCompress);
124
+ brotliCompressPromisified = async (value) => compress(value, { params: { [constants.BROTLI_PARAM_QUALITY]: 6 } });
117
125
  }
118
- return gzipPromisified(value);
126
+ else {
127
+ brotliCompressPromisified = null;
128
+ }
129
+ }
130
+ if (brotliCompressPromisified !== null) {
131
+ return brotliCompressPromisified(value);
119
132
  }
120
133
  return undefined;
121
134
  }
135
+ /**
136
+ * Compress the passed value using brotli if available or using gzip as a fallback. Returns undefined
137
+ * if the data is too small / wrong type.
138
+ */
139
+ async function maybeCompressValue(value) {
140
+ if (!isNode())
141
+ return undefined;
142
+ // Request compression is not that important so let's
143
+ // skip it instead of throwing for unsupported types.
144
+ if (typeof value !== 'string' && !Buffer.isBuffer(value))
145
+ return undefined;
146
+ const areDataLargeEnough = Buffer.byteLength(value) >= MIN_COMPRESS_BYTES;
147
+ if (!areDataLargeEnough)
148
+ return undefined;
149
+ const brotli = await maybeBrotliValue(value);
150
+ if (brotli)
151
+ return { data: brotli, encoding: 'br' };
152
+ const gzipped = await gzipValue(value);
153
+ return { data: gzipped, encoding: 'gzip' };
154
+ }
122
155
  /**
123
156
  * Helper function slice the items from array to fit the max byte length.
124
157
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apify-client",
3
- "version": "2.23.5-beta.8",
3
+ "version": "2.24.0",
4
4
  "description": "Apify API client for JavaScript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -63,7 +63,7 @@
63
63
  "type-fest": "^4.0.0"
64
64
  },
65
65
  "devDependencies": {
66
- "@apify/oxlint-config": "^0.2.5",
66
+ "@apify/oxlint-config": "^0.3.0",
67
67
  "@apify/tsconfig": "^0.2.0",
68
68
  "@crawlee/puppeteer": "^3.2.2",
69
69
  "@rsbuild/core": "^2.0.0",
@@ -81,9 +81,9 @@
81
81
  "esbuild": "0.28.1",
82
82
  "express": "^5.0.0",
83
83
  "gen-esm-wrapper": "^1.1.2",
84
- "oxfmt": "0.55.0",
85
- "oxlint": "1.69.0",
86
- "oxlint-tsgolint": "0.23.0",
84
+ "oxfmt": "0.61.0",
85
+ "oxlint": "1.75.0",
86
+ "oxlint-tsgolint": "7.0.2001",
87
87
  "puppeteer": "^25.0.0",
88
88
  "rimraf": "^6.0.0",
89
89
  "rolldown": "^1.0.0-rc.4",