diff --git a/src/resource_clients/actor.ts b/src/resource_clients/actor.ts index 7414fd9e7..01c09969a 100644 --- a/src/resource_clients/actor.ts +++ b/src/resource_clients/actor.ts @@ -66,9 +66,10 @@ export class ActorClient extends ResourceClient { timeout: ow.optional.number, waitForFinish: ow.optional.number, webhooks: ow.optional.array.ofType(ow.object), + maxItems: ow.optional.number.not.negative, })); - const { waitForFinish, timeout, memory, build } = options; + const { waitForFinish, timeout, memory, build, maxItems } = options; const params = { waitForFinish, @@ -76,6 +77,7 @@ export class ActorClient extends ResourceClient { memory, build, webhooks: stringifyWebhooksToBase64(options.webhooks), + maxItems, }; const request: AxiosRequestConfig = { @@ -115,6 +117,7 @@ export class ActorClient extends ResourceClient { timeout: ow.optional.number.not.negative, waitSecs: ow.optional.number.not.negative, webhooks: ow.optional.array.ofType(ow.object), + maxItems: ow.optional.number.not.negative, })); const { waitSecs, ...startOptions } = options; @@ -324,6 +327,13 @@ export interface ActorStartOptions { * [ad hook webhooks documentation](https://docs.apify.com/webhooks/ad-hoc-webhooks) for detailed description. */ webhooks?: readonly WebhookUpdateData[]; + + /** + * Specifies maximum number of items that the actor run should return. + * This is used by pay per result actors to limit the maximum number of results that will be charged to customer. + * Value can be accessed in actor run using `APIFY_ACTOR_MAX_ITEMS` environment variable. + */ + maxItems?: number; } export interface ActorCallOptions extends Omit { diff --git a/src/resource_clients/task.ts b/src/resource_clients/task.ts index d7b2fcc29..fef49cad3 100644 --- a/src/resource_clients/task.ts +++ b/src/resource_clients/task.ts @@ -63,9 +63,10 @@ export class TaskClient extends ResourceClient { timeout: ow.optional.number, waitForFinish: ow.optional.number, webhooks: ow.optional.array.ofType(ow.object), + maxItems: ow.optional.number.not.negative, })); - const { waitForFinish, timeout, memory, build } = options; + const { waitForFinish, timeout, memory, build, maxItems } = options; const params = { waitForFinish, @@ -73,6 +74,7 @@ export class TaskClient extends ResourceClient { memory, build, webhooks: stringifyWebhooksToBase64(options.webhooks), + maxItems, }; const request: ApifyRequestConfig = { @@ -105,6 +107,7 @@ export class TaskClient extends ResourceClient { timeout: ow.optional.number.not.negative, waitSecs: ow.optional.number.not.negative, webhooks: ow.optional.array.ofType(ow.object), + maxItems: ow.optional.number.not.negative, })); const { waitSecs, ...startOptions } = options; diff --git a/test/actors.test.js b/test/actors.test.js index 4fc6325fe..ca7b586a4 100644 --- a/test/actors.test.js +++ b/test/actors.test.js @@ -197,6 +197,18 @@ describe('Actor methods', () => { validateRequest({ webhooks: stringifyWebhooksToBase64(webhooks) }, { actorId }); }); + test('start() with max items works', async () => { + const actorId = 'some-id'; + + const res = await client.actor(actorId).start(undefined, { maxItems: 100 }); + expect(res.id).toEqual('run-actor'); + validateRequest({ maxItems: 100 }, { actorId }); + + const browserRes = await page.evaluate((id, opts) => client.actor(id).start(undefined, opts), actorId, { maxItems: 100 }); + expect(browserRes).toEqual(res); + validateRequest({ maxItems: 100 }, { actorId }); + }); + test('call() works', async () => { const actorId = 'some-id'; const contentType = 'application/x-www-form-urlencoded'; @@ -244,6 +256,32 @@ describe('Actor methods', () => { }, { actorId }, { some: 'body' }, { 'content-type': contentType }); }); + test('call() works with maxItems', async () => { + const actorId = 'some-id'; + const runId = 'started-run-id'; + const data = { id: runId, actId: actorId, status: 'SUCCEEDED' }; + const body = { data }; + const waitSecs = 1; + const maxItems = 100; + + mockServer.setResponse({ body }); + const res = await client.actor(actorId).call(undefined, { waitSecs, maxItems }); + + expect(res).toEqual(data); + validateRequest({ waitForFinish: waitSecs }, { runId }); + validateRequest({ maxItems }, { actorId }); + + const callBrowserRes = await page.evaluate( + (id, i, opts) => client.actor(id).call(i, opts), actorId, undefined, { + waitSecs, + maxItems, + }, + ); + expect(callBrowserRes).toEqual(res); + validateRequest({ waitForFinish: waitSecs }, { runId }); + validateRequest({ maxItems }, { actorId }); + }); + test('build() works', async () => { const actorId = 'some-id'; diff --git a/test/tasks.test.js b/test/tasks.test.js index d5facff6a..fdf401d55 100644 --- a/test/tasks.test.js +++ b/test/tasks.test.js @@ -249,6 +249,17 @@ describe('Task methods', () => { validateRequest(query, { taskId }); }); + test('start() works with maxItems', async () => { + const taskId = 'some-id'; + const res = await client.task(taskId).start(undefined, { maxItems: 100 }); + expect(res.id).toEqual('run-task'); + validateRequest({ maxItems: 100 }, { taskId }); + + const browserRes = await page.evaluate((id, opts) => client.task(id).start(undefined, opts), taskId, { maxItems: 100 }); + expect(browserRes).toEqual(res); + validateRequest({ maxItems: 100 }, { taskId }); + }); + test('call() works', async () => { const taskId = 'some-task-id'; const input = { some: 'body' }; @@ -297,6 +308,39 @@ describe('Task methods', () => { }, { taskId }, { some: 'body' }); }); + test('call() works with maxItems', async () => { + const taskId = 'some-task-id'; + const actId = 'started-actor-id'; + const runId = 'started-run-id'; + const data = { id: runId, actId, status: 'SUCCEEDED' }; + const body = { data }; + const waitSecs = 1; + const maxItems = 100; + + const query = { maxItems }; + + mockServer.setResponse({ body }); + const res = await client.task(taskId).call(undefined, { + waitSecs, + maxItems, + }); + expect(res).toEqual(data); + + expect(res).toEqual(data); + validateRequest({ waitForFinish: waitSecs }, { runId }); + validateRequest(query, { taskId }); + + const callBrowserRes = await page.evaluate( + (id, i, opts) => client.task(id).call(i, opts), taskId, undefined, { + waitSecs, + maxItems, + }, + ); + expect(callBrowserRes).toEqual(res); + validateRequest({ waitForFinish: waitSecs }, { runId }); + validateRequest({ maxItems }, { taskId }); + }); + test('webhooks().list() works', async () => { const taskId = 'some-task-id'; const query = {