From f797a0533afd57d2c7971f707e83ad20a10a0a03 Mon Sep 17 00:00:00 2001 From: Aman Raj Date: Fri, 3 Jul 2026 22:07:10 +0530 Subject: [PATCH 01/15] feat: add Apify plugin --- packages/apify/client.ts | 139 ++ packages/apify/endpoints/index.ts | 139 ++ packages/apify/endpoints/operations.ts | 2286 ++++++++++++++++++++++++ packages/apify/endpoints/types.ts | 19 + packages/apify/error-handlers.ts | 70 + packages/apify/index.ts | 123 ++ packages/apify/package.json | 40 + packages/apify/schema/database.ts | 147 ++ packages/apify/schema/index.ts | 28 + packages/apify/tsconfig.json | 20 + packages/apify/tsup.config.ts | 15 + packages/corsair/core/constants.ts | 7 +- pnpm-lock.yaml | 15 + 13 files changed, 3046 insertions(+), 2 deletions(-) create mode 100644 packages/apify/client.ts create mode 100644 packages/apify/endpoints/index.ts create mode 100644 packages/apify/endpoints/operations.ts create mode 100644 packages/apify/endpoints/types.ts create mode 100644 packages/apify/error-handlers.ts create mode 100644 packages/apify/index.ts create mode 100644 packages/apify/package.json create mode 100644 packages/apify/schema/database.ts create mode 100644 packages/apify/schema/index.ts create mode 100644 packages/apify/tsconfig.json create mode 100644 packages/apify/tsup.config.ts diff --git a/packages/apify/client.ts b/packages/apify/client.ts new file mode 100644 index 000000000..a188b567e --- /dev/null +++ b/packages/apify/client.ts @@ -0,0 +1,139 @@ +import type { ApiRequestOptions, OpenAPIConfig } from 'corsair/http'; +import { ApiError, request } from 'corsair/http'; +import type { ApifyOperationDefinition } from './endpoints/operations'; +import type { + ApifyOperationInput, + ApifyOperationOutput, +} from './endpoints/types'; + +export class ApifyAPIError extends Error { + constructor( + message: string, + public readonly code?: string, + ) { + super(message); + this.name = 'ApifyAPIError'; + } +} + +const APIFY_API_BASE = 'https://api.apify.com'; + +const RESERVED_INPUT_KEYS = new Set([ + 'body', + 'query', + 'headers', + 'contentType', + 'mediaType', +]); + +function isRecord(value: unknown): value is Record { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +function pickDefined( + input: ApifyOperationInput, + keys: readonly string[] | undefined, +): Record | undefined { + if (!keys?.length) return undefined; + + const output: Record = {}; + for (const key of keys) { + const value = input[key]; + if (value !== undefined) output[key] = value; + } + + return Object.keys(output).length > 0 ? output : undefined; +} + +function buildQuery( + operation: ApifyOperationDefinition, + input: ApifyOperationInput, +): Record | undefined { + const query = { + ...(isRecord(input.query) ? input.query : {}), + ...(pickDefined(input, operation.queryParams) ?? {}), + }; + + return Object.keys(query).length > 0 ? query : undefined; +} + +function buildBody( + operation: ApifyOperationDefinition, + input: ApifyOperationInput, +): unknown { + if (input.body !== undefined) return input.body; + if (operation.method === 'GET' || operation.method === 'HEAD') + return undefined; + + const queryParams = new Set(operation.queryParams ?? []); + const pathParams = new Set(operation.pathParams); + const body: Record = {}; + + for (const [key, value] of Object.entries(input)) { + if ( + value === undefined || + RESERVED_INPUT_KEYS.has(key) || + queryParams.has(key) || + pathParams.has(key) + ) { + continue; + } + + body[key] = value; + } + + return Object.keys(body).length > 0 ? body : undefined; +} + +export async function makeApifyRequest( + operation: ApifyOperationDefinition, + apiKey: string, + input: ApifyOperationInput = {}, +): Promise { + const config: OpenAPIConfig = { + BASE: APIFY_API_BASE, + VERSION: '2.0.0', + WITH_CREDENTIALS: false, + CREDENTIALS: 'omit', + TOKEN: apiKey, + HEADERS: { + 'Content-Type': 'application/json', + }, + ENCODE_PATH: encodeURIComponent, + }; + + const body = buildBody(operation, input); + const mediaType = + input.mediaType ?? input.contentType ?? 'application/json; charset=utf-8'; + const headers = isRecord(input.headers) ? input.headers : undefined; + + const requestOptions: ApiRequestOptions = { + method: operation.method, + url: operation.path, + path: pickDefined(input, operation.pathParams), + query: buildQuery(operation, input), + headers, + body, + mediaType: body === undefined ? undefined : mediaType, + }; + + try { + const response = await request(config, requestOptions); + if (response === undefined && operation.method === 'HEAD') { + return { exists: true }; + } + if (response === undefined) return { success: true }; + return response; + } catch (error) { + if ( + error instanceof ApiError && + operation.method === 'HEAD' && + error.status === 404 + ) { + return { exists: false }; + } + if (error instanceof ApiError) throw error; + if (error instanceof Error) throw new ApifyAPIError(error.message); + throw new ApifyAPIError('Unknown error'); + } +} diff --git a/packages/apify/endpoints/index.ts b/packages/apify/endpoints/index.ts new file mode 100644 index 000000000..099d670fe --- /dev/null +++ b/packages/apify/endpoints/index.ts @@ -0,0 +1,139 @@ +import type { + CorsairEndpoint, + EndpointMetaEntry, + RequiredPluginEndpointMeta, + RequiredPluginEndpointSchemas, +} from 'corsair/core'; +import { logEventFromContext } from 'corsair/core'; +import { z } from 'zod'; +import { makeApifyRequest } from '../client'; +import type { ApifyContext } from '../index'; +import type { + ApifyOperationDefinition, + ApifyOperationTree, +} from './operations'; +import { apifyOperations } from './operations'; +import type { ApifyOperationInput, ApifyOperationOutput } from './types'; +import { ApifyOperationOutputSchema } from './types'; + +type ApifyEndpoint = CorsairEndpoint< + ApifyContext, + ApifyOperationInput, + ApifyOperationOutput +>; + +export type ApifyEndpointTree = { + [K in keyof T]: T[K] extends ApifyOperationDefinition + ? ApifyEndpoint + : T[K] extends ApifyOperationTree + ? ApifyEndpointTree + : never; +}; + +function isOperationDefinition( + value: ApifyOperationDefinition | ApifyOperationTree, +): value is ApifyOperationDefinition { + return 'method' in value && 'path' in value; +} + +function buildEndpointTree( + tree: T, + segments: string[] = [], +): ApifyEndpointTree { + const endpoints: Record = {}; + + for (const [key, value] of Object.entries(tree)) { + if (isOperationDefinition(value)) { + const operationPath = [...segments, key].join('.'); + endpoints[key] = async ( + ctx: ApifyContext, + input: ApifyOperationInput, + ) => { + const response = await makeApifyRequest(value, ctx.key, input ?? {}); + await logEventFromContext( + ctx, + `apify.${operationPath}`, + { + method: value.method, + path: value.path, + }, + 'completed', + ); + return response; + }; + } else { + endpoints[key] = buildEndpointTree(value, [...segments, key]); + } + } + + return endpoints as ApifyEndpointTree; +} + +function createOperationInputSchema(operation: ApifyOperationDefinition) { + const shape: Record = { + body: z.unknown().optional(), + query: z.record(z.string(), z.unknown()).optional(), + headers: z.record(z.string(), z.unknown()).optional(), + contentType: z.string().optional(), + mediaType: z.string().optional(), + }; + + for (const param of operation.pathParams) { + shape[param] = z.union([z.string(), z.number()]); + } + + for (const param of operation.queryParams ?? []) { + shape[param] = z.unknown().optional(); + } + + return z.object(shape).loose(); +} + +export function buildApifyEndpointSchemas( + tree: T, + segments: string[] = [], +): RequiredPluginEndpointSchemas> { + const schemas: Record = {}; + + for (const [key, value] of Object.entries(tree)) { + if (isOperationDefinition(value)) { + schemas[[...segments, key].join('.')] = { + input: createOperationInputSchema(value), + output: ApifyOperationOutputSchema, + }; + } else { + Object.assign( + schemas, + buildApifyEndpointSchemas(value, [...segments, key]), + ); + } + } + + return schemas as RequiredPluginEndpointSchemas>; +} + +export function buildApifyEndpointMeta( + tree: T, + segments: string[] = [], +): RequiredPluginEndpointMeta> { + const meta: Record = {}; + + for (const [key, value] of Object.entries(tree)) { + if (isOperationDefinition(value)) { + meta[[...segments, key].join('.')] = { + riskLevel: value.riskLevel, + irreversible: value.irreversible, + description: value.description, + }; + } else { + Object.assign(meta, buildApifyEndpointMeta(value, [...segments, key])); + } + } + + return meta as RequiredPluginEndpointMeta>; +} + +export const ApifyEndpoints = buildEndpointTree(apifyOperations); + +export * from './operations'; +export * from './types'; diff --git a/packages/apify/endpoints/operations.ts b/packages/apify/endpoints/operations.ts new file mode 100644 index 000000000..91e008025 --- /dev/null +++ b/packages/apify/endpoints/operations.ts @@ -0,0 +1,2286 @@ +import type { EndpointRiskLevel } from 'corsair/core'; + +export type ApifyOperationMethod = + | 'GET' + | 'POST' + | 'PUT' + | 'DELETE' + | 'PATCH' + | 'HEAD'; + +export type ApifyOperationDefinition = { + method: ApifyOperationMethod; + path: string; + pathParams: readonly string[]; + queryParams?: readonly string[]; + riskLevel: EndpointRiskLevel; + irreversible?: boolean; + description: string; +}; + +export type ApifyOperationTree = { + readonly [key: string]: ApifyOperationDefinition | ApifyOperationTree; +}; + +export const apifyOperations = { + act: { + buildAbortPost: { + method: 'POST', + path: '/v2/actors/{actorId}/builds/{buildId}/abort', + pathParams: ['actorId', 'buildId'], + riskLevel: 'write', + description: 'Deprecated. Abort build', + }, + buildDefaultGet: { + method: 'GET', + path: '/v2/actors/{actorId}/builds/default', + pathParams: ['actorId'], + queryParams: ['waitForFinish'], + riskLevel: 'read', + description: 'Get default build', + }, + buildGet: { + method: 'GET', + path: '/v2/actors/{actorId}/builds/{buildId}', + pathParams: ['actorId', 'buildId'], + queryParams: ['waitForFinish'], + riskLevel: 'read', + description: 'Deprecated. Get build', + }, + buildsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/builds', + pathParams: ['actorId'], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get list of builds', + }, + buildsPost: { + method: 'POST', + path: '/v2/actors/{actorId}/builds', + pathParams: ['actorId'], + queryParams: [ + 'version', + 'useCache', + 'betaPackages', + 'tag', + 'waitForFinish', + ], + riskLevel: 'write', + description: 'Build Actor', + }, + delete: { + method: 'DELETE', + path: '/v2/actors/{actorId}', + pathParams: ['actorId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete Actor', + }, + get: { + method: 'GET', + path: '/v2/actors/{actorId}', + pathParams: ['actorId'], + riskLevel: 'read', + description: 'Get Actor', + }, + openapiJsonGet: { + method: 'GET', + path: '/v2/actors/{actorId}/builds/{buildId}/openapi.json', + pathParams: ['actorId', 'buildId'], + riskLevel: 'read', + description: 'Get OpenAPI definition', + }, + put: { + method: 'PUT', + path: '/v2/actors/{actorId}', + pathParams: ['actorId'], + riskLevel: 'write', + description: 'Update Actor', + }, + runAbortPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/{runId}/abort', + pathParams: ['actorId', 'runId'], + queryParams: ['gracefully'], + riskLevel: 'write', + description: 'Deprecated. Abort run', + }, + runGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/{runId}', + pathParams: ['actorId', 'runId'], + queryParams: ['waitForFinish'], + riskLevel: 'read', + description: 'Deprecated. Get run', + }, + runMetamorphPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/{runId}/metamorph', + pathParams: ['actorId', 'runId'], + queryParams: ['targetActorId', 'build'], + riskLevel: 'write', + description: 'Deprecated. Metamorph run', + }, + runResurrectPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/{runId}/resurrect', + pathParams: ['actorId', 'runId'], + queryParams: ['build', 'timeout', 'memory', 'restartOnError'], + riskLevel: 'write', + description: 'Resurrect run', + }, + runsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs', + pathParams: ['actorId'], + queryParams: [ + 'offset', + 'limit', + 'desc', + 'status', + 'startedAfter', + 'startedBefore', + ], + riskLevel: 'read', + description: 'Get list of runs', + }, + runsLastAbortPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/abort', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'gracefully'], + riskLevel: 'write', + description: "Abort Actor's last run", + }, + runsLastDatasetDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/runs/last/dataset', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last run's default dataset", + }, + runsLastDatasetGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/dataset', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last run's default dataset", + }, + runsLastDatasetItemsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/dataset/items', + pathParams: ['actorId'], + queryParams: [ + 'status', + 'origin', + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + 'signature', + ], + riskLevel: 'read', + description: "Get last run's dataset items", + }, + runsLastDatasetItemsPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/dataset/items', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Store items in last run's dataset", + }, + runsLastDatasetPut: { + method: 'PUT', + path: '/v2/actors/{actorId}/runs/last/dataset', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Update last run's default dataset", + }, + runsLastDatasetStatisticsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/dataset/statistics', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last run's dataset statistics", + }, + runsLastGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'waitForFinish'], + riskLevel: 'read', + description: 'Get last run', + }, + runsLastKeyValueStoreDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/runs/last/key-value-store', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last run's default store", + }, + runsLastKeyValueStoreGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/key-value-store', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last run's default store", + }, + runsLastKeyValueStoreKeysGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/key-value-store/keys', + pathParams: ['actorId'], + queryParams: [ + 'status', + 'origin', + 'exclusiveStartKey', + 'limit', + 'collection', + 'prefix', + 'signature', + ], + riskLevel: 'read', + description: "Get last run's default store's list of keys", + }, + runsLastKeyValueStorePut: { + method: 'PUT', + path: '/v2/actors/{actorId}/runs/last/key-value-store', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Update last run's default store", + }, + runsLastKeyValueStoreRecordDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorId', 'recordKey'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last run's default store's record", + }, + runsLastKeyValueStoreRecordGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorId', 'recordKey'], + queryParams: ['status', 'origin', 'signature', 'attachment'], + riskLevel: 'read', + description: "Get last run's default store's record", + }, + runsLastKeyValueStoreRecordPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorId', 'recordKey'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Store record in last run's default store (POST)", + }, + runsLastKeyValueStoreRecordPut: { + method: 'PUT', + path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorId', 'recordKey'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Store record in last run's default store", + }, + runsLastKeyValueStoreRecordsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/key-value-store/records', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'collection', 'prefix', 'signature'], + riskLevel: 'read', + description: "Download last run's default store's records", + }, + runsLastLogGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/log', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'stream', 'download', 'raw'], + riskLevel: 'read', + description: "Get last Actor run's log", + }, + runsLastMetamorphPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/metamorph', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'targetActorId', 'build'], + riskLevel: 'write', + description: "Metamorph Actor's last run", + }, + runsLastRebootPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/reboot', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Reboot Actor's last run", + }, + runsLastRequestQueueDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/runs/last/request-queue', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last run's default request queue", + }, + runsLastRequestQueueGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/request-queue', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last run's default request queue", + }, + runsLastRequestQueueHeadGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/request-queue/head', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'limit', 'clientKey'], + riskLevel: 'read', + description: "Get last run's default request queue head", + }, + runsLastRequestQueueHeadLockPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/request-queue/head/lock', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'lockSecs', 'limit', 'clientKey'], + riskLevel: 'write', + description: "Get and lock last run's default request queue head", + }, + runsLastRequestQueuePut: { + method: 'PUT', + path: '/v2/actors/{actorId}/runs/last/request-queue', + pathParams: ['actorId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Update last run's default request queue", + }, + runsLastRequestQueueRequestDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}', + pathParams: ['actorId', 'requestId'], + queryParams: ['status', 'origin', 'clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete request from last run's default request queue", + }, + runsLastRequestQueueRequestGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}', + pathParams: ['actorId', 'requestId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get request from last run's default request queue", + }, + runsLastRequestQueueRequestLockDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}/lock', + pathParams: ['actorId', 'requestId'], + queryParams: ['status', 'origin', 'clientKey', 'forefront'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete lock on request in last run's default request queue", + }, + runsLastRequestQueueRequestLockPut: { + method: 'PUT', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}/lock', + pathParams: ['actorId', 'requestId'], + queryParams: ['status', 'origin', 'lockSecs', 'clientKey', 'forefront'], + riskLevel: 'write', + description: + "Prolong lock on request in last run's default request queue", + }, + runsLastRequestQueueRequestPut: { + method: 'PUT', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}', + pathParams: ['actorId', 'requestId'], + queryParams: ['status', 'origin', 'forefront', 'clientKey'], + riskLevel: 'write', + description: "Update request in last run's default request queue", + }, + runsLastRequestQueueRequestsBatchDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/batch', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: + "Batch delete requests from last run's default request queue", + }, + runsLastRequestQueueRequestsBatchPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/batch', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'clientKey', 'forefront'], + riskLevel: 'write', + description: "Batch add requests to last run's default request queue", + }, + runsLastRequestQueueRequestsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests', + pathParams: ['actorId'], + queryParams: [ + 'status', + 'origin', + 'clientKey', + 'exclusiveStartId', + 'limit', + 'cursor', + 'filter', + ], + riskLevel: 'read', + description: "List last run's default request queue's requests", + }, + runsLastRequestQueueRequestsPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'clientKey', 'forefront'], + riskLevel: 'write', + description: "Add request to last run's default request queue", + }, + runsLastRequestQueueRequestsUnlockPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs/last/request-queue/requests/unlock', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'clientKey'], + riskLevel: 'write', + description: "Unlock requests in last run's default request queue", + }, + runsPost: { + method: 'POST', + path: '/v2/actors/{actorId}/runs', + pathParams: ['actorId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'waitForFinish', + 'webhooks', + 'forcePermissionLevel', + ], + riskLevel: 'write', + description: 'Run Actor', + }, + runSyncGet: { + method: 'GET', + path: '/v2/actors/{actorId}/run-sync', + pathParams: ['actorId'], + queryParams: [ + 'outputRecordKey', + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'webhooks', + ], + riskLevel: 'write', + description: 'Run Actor synchronously without input', + }, + runSyncGetDatasetItemsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/run-sync-get-dataset-items', + pathParams: ['actorId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'webhooks', + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + ], + riskLevel: 'write', + description: + 'Run Actor synchronously without input and get dataset items', + }, + runSyncGetDatasetItemsPost: { + method: 'POST', + path: '/v2/actors/{actorId}/run-sync-get-dataset-items', + pathParams: ['actorId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'webhooks', + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + ], + riskLevel: 'write', + description: 'Run Actor synchronously and get dataset items', + }, + runSyncPost: { + method: 'POST', + path: '/v2/actors/{actorId}/run-sync', + pathParams: ['actorId'], + queryParams: [ + 'outputRecordKey', + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'webhooks', + ], + riskLevel: 'write', + description: 'Run Actor synchronously and return key-value store record', + }, + validateInputPost: { + method: 'POST', + path: '/v2/actors/{actorId}/validate-input', + pathParams: ['actorId'], + queryParams: ['build'], + riskLevel: 'write', + description: 'Validate Actor input', + }, + versionDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/versions/{versionNumber}', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete version', + }, + versionEnvVarDelete: { + method: 'DELETE', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', + pathParams: ['actorId', 'versionNumber', 'envVarName'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete environment variable', + }, + versionEnvVarGet: { + method: 'GET', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', + pathParams: ['actorId', 'versionNumber', 'envVarName'], + riskLevel: 'read', + description: 'Get environment variable', + }, + versionEnvVarPost: { + method: 'POST', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', + pathParams: ['actorId', 'versionNumber', 'envVarName'], + riskLevel: 'write', + description: 'Update environment variable (POST)', + }, + versionEnvVarPut: { + method: 'PUT', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', + pathParams: ['actorId', 'versionNumber', 'envVarName'], + riskLevel: 'write', + description: 'Update environment variable', + }, + versionEnvVarsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'read', + description: 'Get list of environment variables', + }, + versionEnvVarsPost: { + method: 'POST', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'write', + description: 'Create environment variable', + }, + versionGet: { + method: 'GET', + path: '/v2/actors/{actorId}/versions/{versionNumber}', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'read', + description: 'Get version', + }, + versionPost: { + method: 'POST', + path: '/v2/actors/{actorId}/versions/{versionNumber}', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'write', + description: 'Update version (POST)', + }, + versionPut: { + method: 'PUT', + path: '/v2/actors/{actorId}/versions/{versionNumber}', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'write', + description: 'Update version', + }, + versionsGet: { + method: 'GET', + path: '/v2/actors/{actorId}/versions', + pathParams: ['actorId'], + riskLevel: 'read', + description: 'Get list of versions', + }, + versionsPost: { + method: 'POST', + path: '/v2/actors/{actorId}/versions', + pathParams: ['actorId'], + riskLevel: 'write', + description: 'Create version', + }, + webhooksGet: { + method: 'GET', + path: '/v2/actors/{actorId}/webhooks', + pathParams: ['actorId'], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get list of webhooks', + }, + }, + actorBuild: { + abortPost: { + method: 'POST', + path: '/v2/actor-builds/{buildId}/abort', + pathParams: ['buildId'], + riskLevel: 'write', + description: 'Abort build', + }, + delete: { + method: 'DELETE', + path: '/v2/actor-builds/{buildId}', + pathParams: ['buildId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete build', + }, + get: { + method: 'GET', + path: '/v2/actor-builds/{buildId}', + pathParams: ['buildId'], + queryParams: ['waitForFinish'], + riskLevel: 'read', + description: 'Get build', + }, + logGet: { + method: 'GET', + path: '/v2/actor-builds/{buildId}/log', + pathParams: ['buildId'], + queryParams: ['stream', 'download'], + riskLevel: 'read', + description: "Get build's Log", + }, + openapiJsonGet: { + method: 'GET', + path: '/v2/actor-builds/{buildId}/openapi.json', + pathParams: ['buildId'], + riskLevel: 'read', + description: 'Get OpenAPI definition', + }, + }, + actorBuilds: { + get: { + method: 'GET', + path: '/v2/actor-builds', + pathParams: [], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get user builds list', + }, + }, + actorRun: { + abortPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/abort', + pathParams: ['runId'], + queryParams: ['gracefully'], + riskLevel: 'write', + description: 'Abort run', + }, + datasetDelete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}/dataset', + pathParams: ['runId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete default dataset', + }, + datasetGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/dataset', + pathParams: ['runId'], + riskLevel: 'read', + description: 'Get default dataset', + }, + datasetItemsGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/dataset/items', + pathParams: ['runId'], + queryParams: [ + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + 'signature', + ], + riskLevel: 'read', + description: 'Get default dataset items', + }, + datasetItemsPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/dataset/items', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Store items', + }, + datasetPut: { + method: 'PUT', + path: '/v2/actor-runs/{runId}/dataset', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Update default dataset', + }, + datasetStatisticsGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/dataset/statistics', + pathParams: ['runId'], + riskLevel: 'read', + description: 'Get default dataset statistics', + }, + delete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}', + pathParams: ['runId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete run', + }, + get: { + method: 'GET', + path: '/v2/actor-runs/{runId}', + pathParams: ['runId'], + queryParams: ['waitForFinish'], + riskLevel: 'read', + description: 'Get run', + }, + keyValueStoreDelete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}/key-value-store', + pathParams: ['runId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete default store', + }, + keyValueStoreGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/key-value-store', + pathParams: ['runId'], + riskLevel: 'read', + description: 'Get default store', + }, + keyValueStoreKeysGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/key-value-store/keys', + pathParams: ['runId'], + queryParams: [ + 'exclusiveStartKey', + 'limit', + 'collection', + 'prefix', + 'signature', + ], + riskLevel: 'read', + description: "Get default store's list of keys", + }, + keyValueStorePut: { + method: 'PUT', + path: '/v2/actor-runs/{runId}/key-value-store', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Update default store', + }, + keyValueStoreRecordDelete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', + pathParams: ['runId', 'recordKey'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete default store's record", + }, + keyValueStoreRecordGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', + pathParams: ['runId', 'recordKey'], + queryParams: ['signature', 'attachment'], + riskLevel: 'read', + description: "Get default store's record", + }, + keyValueStoreRecordPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', + pathParams: ['runId', 'recordKey'], + riskLevel: 'write', + description: 'Store record in default store (POST)', + }, + keyValueStoreRecordPut: { + method: 'PUT', + path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', + pathParams: ['runId', 'recordKey'], + riskLevel: 'write', + description: 'Store record in default store', + }, + keyValueStoreRecordsGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/key-value-store/records', + pathParams: ['runId'], + queryParams: ['collection', 'prefix', 'signature'], + riskLevel: 'read', + description: "Download default store's records", + }, + logGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/log', + pathParams: ['runId'], + queryParams: ['stream', 'download', 'raw'], + riskLevel: 'read', + description: "Get run's log", + }, + metamorphPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/metamorph', + pathParams: ['runId'], + queryParams: ['targetActorId', 'build'], + riskLevel: 'write', + description: 'Metamorph run', + }, + put: { + method: 'PUT', + path: '/v2/actor-runs/{runId}', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Update run', + }, + rebootPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/reboot', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Reboot run', + }, + requestQueueDelete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}/request-queue', + pathParams: ['runId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete default request queue', + }, + requestQueueGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/request-queue', + pathParams: ['runId'], + riskLevel: 'read', + description: 'Get default request queue', + }, + requestQueueHeadGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/request-queue/head', + pathParams: ['runId'], + queryParams: ['limit', 'clientKey'], + riskLevel: 'read', + description: 'Get default request queue head', + }, + requestQueueHeadLockPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/request-queue/head/lock', + pathParams: ['runId'], + queryParams: ['lockSecs', 'limit', 'clientKey'], + riskLevel: 'write', + description: 'Get and lock default request queue head', + }, + requestQueuePut: { + method: 'PUT', + path: '/v2/actor-runs/{runId}/request-queue', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Update default request queue', + }, + requestQueueRequestDelete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}', + pathParams: ['runId', 'requestId'], + queryParams: ['clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete request from default request queue', + }, + requestQueueRequestGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}', + pathParams: ['runId', 'requestId'], + riskLevel: 'read', + description: 'Get request from default request queue', + }, + requestQueueRequestLockDelete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}/lock', + pathParams: ['runId', 'requestId'], + queryParams: ['clientKey', 'forefront'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete lock on request in default request queue', + }, + requestQueueRequestLockPut: { + method: 'PUT', + path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}/lock', + pathParams: ['runId', 'requestId'], + queryParams: ['lockSecs', 'clientKey', 'forefront'], + riskLevel: 'write', + description: 'Prolong lock on request in default request queue', + }, + requestQueueRequestPut: { + method: 'PUT', + path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}', + pathParams: ['runId', 'requestId'], + queryParams: ['forefront', 'clientKey'], + riskLevel: 'write', + description: 'Update request in default request queue', + }, + requestQueueRequestsBatchDelete: { + method: 'DELETE', + path: '/v2/actor-runs/{runId}/request-queue/requests/batch', + pathParams: ['runId'], + queryParams: ['clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: 'Batch delete requests from default request queue', + }, + requestQueueRequestsBatchPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/request-queue/requests/batch', + pathParams: ['runId'], + queryParams: ['clientKey', 'forefront'], + riskLevel: 'write', + description: 'Batch add requests to default request queue', + }, + requestQueueRequestsGet: { + method: 'GET', + path: '/v2/actor-runs/{runId}/request-queue/requests', + pathParams: ['runId'], + queryParams: [ + 'clientKey', + 'exclusiveStartId', + 'limit', + 'cursor', + 'filter', + ], + riskLevel: 'read', + description: "List default request queue's requests", + }, + requestQueueRequestsPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/request-queue/requests', + pathParams: ['runId'], + queryParams: ['clientKey', 'forefront'], + riskLevel: 'write', + description: 'Add request to default request queue', + }, + requestQueueRequestsUnlockPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/request-queue/requests/unlock', + pathParams: ['runId'], + queryParams: ['clientKey'], + riskLevel: 'write', + description: 'Unlock requests in default request queue', + }, + }, + actorRuns: { + get: { + method: 'GET', + path: '/v2/actor-runs', + pathParams: [], + queryParams: [ + 'offset', + 'limit', + 'desc', + 'status', + 'startedAfter', + 'startedBefore', + ], + riskLevel: 'read', + description: 'Get user runs list', + }, + }, + actorTask: { + delete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}', + pathParams: ['actorTaskId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete task', + }, + get: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}', + pathParams: ['actorTaskId'], + riskLevel: 'read', + description: 'Get task', + }, + inputGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/input', + pathParams: ['actorTaskId'], + riskLevel: 'read', + description: 'Get task input', + }, + inputPut: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}/input', + pathParams: ['actorTaskId'], + riskLevel: 'write', + description: 'Update task input', + }, + lastLogGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/log', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'stream', 'download', 'raw'], + riskLevel: 'read', + description: "Get last Actor task run's log", + }, + put: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}', + pathParams: ['actorTaskId'], + riskLevel: 'write', + description: 'Update task', + }, + runsGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs', + pathParams: ['actorTaskId'], + queryParams: ['offset', 'limit', 'desc', 'status'], + riskLevel: 'read', + description: 'Get list of task runs', + }, + runsLastAbortPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/abort', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'gracefully'], + riskLevel: 'write', + description: "Abort Actor task's last run", + }, + runsLastDatasetDelete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last task run's default dataset", + }, + runsLastDatasetGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last task run's default dataset", + }, + runsLastDatasetItemsGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset/items', + pathParams: ['actorTaskId'], + queryParams: [ + 'status', + 'origin', + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + 'signature', + ], + riskLevel: 'read', + description: "Get last task run's dataset items", + }, + runsLastDatasetItemsPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset/items', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Store items in last task run's dataset", + }, + runsLastDatasetPut: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Update last task run's default dataset", + }, + runsLastDatasetStatisticsGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset/statistics', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last task run's dataset statistics", + }, + runsLastGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'waitForFinish'], + riskLevel: 'read', + description: 'Get last run', + }, + runsLastKeyValueStoreDelete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last task run's default store", + }, + runsLastKeyValueStoreGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last task run's default store", + }, + runsLastKeyValueStoreKeysGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/keys', + pathParams: ['actorTaskId'], + queryParams: [ + 'status', + 'origin', + 'exclusiveStartKey', + 'limit', + 'collection', + 'prefix', + 'signature', + ], + riskLevel: 'read', + description: "Get last task run's default store's list of keys", + }, + runsLastKeyValueStorePut: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Update last task run's default store", + }, + runsLastKeyValueStoreRecordDelete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorTaskId', 'recordKey'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last task run's default store's record", + }, + runsLastKeyValueStoreRecordGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorTaskId', 'recordKey'], + queryParams: ['status', 'origin', 'signature', 'attachment'], + riskLevel: 'read', + description: "Get last task run's default store's record", + }, + runsLastKeyValueStoreRecordPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorTaskId', 'recordKey'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Store record in last task run's default store (POST)", + }, + runsLastKeyValueStoreRecordPut: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', + pathParams: ['actorTaskId', 'recordKey'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Store record in last task run's default store", + }, + runsLastKeyValueStoreRecordsGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'collection', 'prefix', 'signature'], + riskLevel: 'read', + description: "Download last task run's default store's records", + }, + runsLastMetamorphPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/metamorph', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'targetActorId', 'build'], + riskLevel: 'write', + description: "Metamorph Actor task's last run", + }, + runsLastRebootPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/reboot', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Reboot Actor task's last run", + }, + runsLastRequestQueueDelete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete last task run's default request queue", + }, + runsLastRequestQueueGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get last task run's default request queue", + }, + runsLastRequestQueueHeadGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/head', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'limit', 'clientKey'], + riskLevel: 'read', + description: "Get last task run's default request queue head", + }, + runsLastRequestQueueHeadLockPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/head/lock', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'lockSecs', 'limit', 'clientKey'], + riskLevel: 'write', + description: "Get and lock last task run's default request queue head", + }, + runsLastRequestQueuePut: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin'], + riskLevel: 'write', + description: "Update last task run's default request queue", + }, + runsLastRequestQueueRequestDelete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}', + pathParams: ['actorTaskId', 'requestId'], + queryParams: ['status', 'origin', 'clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: "Delete request from last task run's default request queue", + }, + runsLastRequestQueueRequestGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}', + pathParams: ['actorTaskId', 'requestId'], + queryParams: ['status', 'origin'], + riskLevel: 'read', + description: "Get request from last task run's default request queue", + }, + runsLastRequestQueueRequestLockDelete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}/lock', + pathParams: ['actorTaskId', 'requestId'], + queryParams: ['status', 'origin', 'clientKey', 'forefront'], + riskLevel: 'destructive', + irreversible: true, + description: + "Delete lock on request in last task run's default request queue", + }, + runsLastRequestQueueRequestLockPut: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}/lock', + pathParams: ['actorTaskId', 'requestId'], + queryParams: ['status', 'origin', 'lockSecs', 'clientKey', 'forefront'], + riskLevel: 'write', + description: + "Prolong lock on request in last task run's default request queue", + }, + runsLastRequestQueueRequestPut: { + method: 'PUT', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}', + pathParams: ['actorTaskId', 'requestId'], + queryParams: ['status', 'origin', 'forefront', 'clientKey'], + riskLevel: 'write', + description: "Update request in last task run's default request queue", + }, + runsLastRequestQueueRequestsBatchDelete: { + method: 'DELETE', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/batch', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: + "Batch delete requests from last task run's default request queue", + }, + runsLastRequestQueueRequestsBatchPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/batch', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'clientKey', 'forefront'], + riskLevel: 'write', + description: + "Batch add requests to last task run's default request queue", + }, + runsLastRequestQueueRequestsGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests', + pathParams: ['actorTaskId'], + queryParams: [ + 'status', + 'origin', + 'clientKey', + 'exclusiveStartId', + 'limit', + 'cursor', + 'filter', + ], + riskLevel: 'read', + description: "List last task run's default request queue's requests", + }, + runsLastRequestQueueRequestsPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'clientKey', 'forefront'], + riskLevel: 'write', + description: "Add request to last task run's default request queue", + }, + runsLastRequestQueueRequestsUnlockPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/unlock', + pathParams: ['actorTaskId'], + queryParams: ['status', 'origin', 'clientKey'], + riskLevel: 'write', + description: "Unlock requests in last task run's default request queue", + }, + runsPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/runs', + pathParams: ['actorTaskId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'waitForFinish', + 'webhooks', + ], + riskLevel: 'write', + description: 'Run task', + }, + runSyncGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/run-sync', + pathParams: ['actorTaskId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'build', + 'outputRecordKey', + 'webhooks', + ], + riskLevel: 'write', + description: 'Run task synchronously', + }, + runSyncGetDatasetItemsGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items', + pathParams: ['actorTaskId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'build', + 'webhooks', + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + ], + riskLevel: 'write', + description: 'Run task synchronously and get dataset items', + }, + runSyncGetDatasetItemsPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items', + pathParams: ['actorTaskId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'webhooks', + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + ], + riskLevel: 'write', + description: 'Run task synchronously and get dataset items', + }, + runSyncPost: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/run-sync', + pathParams: ['actorTaskId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'outputRecordKey', + 'webhooks', + ], + riskLevel: 'write', + description: 'Run task synchronously', + }, + webhooksGet: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/webhooks', + pathParams: ['actorTaskId'], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get list of webhooks', + }, + }, + actorTasks: { + get: { + method: 'GET', + path: '/v2/actor-tasks', + pathParams: [], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get list of tasks', + }, + post: { + method: 'POST', + path: '/v2/actor-tasks', + pathParams: [], + riskLevel: 'write', + description: 'Create task', + }, + }, + acts: { + get: { + method: 'GET', + path: '/v2/actors', + pathParams: [], + queryParams: ['my', 'offset', 'limit', 'desc', 'sortBy'], + riskLevel: 'read', + description: 'Get list of Actors', + }, + post: { + method: 'POST', + path: '/v2/actors', + pathParams: [], + riskLevel: 'write', + description: 'Create Actor', + }, + }, + dataset: { + delete: { + method: 'DELETE', + path: '/v2/datasets/{datasetId}', + pathParams: ['datasetId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete dataset', + }, + get: { + method: 'GET', + path: '/v2/datasets/{datasetId}', + pathParams: ['datasetId'], + riskLevel: 'read', + description: 'Get dataset', + }, + itemsGet: { + method: 'GET', + path: '/v2/datasets/{datasetId}/items', + pathParams: ['datasetId'], + queryParams: [ + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + 'signature', + ], + riskLevel: 'read', + description: 'Get dataset items', + }, + itemsHead: { + method: 'HEAD', + path: '/v2/datasets/{datasetId}/items', + pathParams: ['datasetId'], + queryParams: [ + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + 'signature', + ], + riskLevel: 'read', + description: 'Get dataset items headers', + }, + itemsPost: { + method: 'POST', + path: '/v2/datasets/{datasetId}/items', + pathParams: ['datasetId'], + riskLevel: 'write', + description: 'Store items', + }, + put: { + method: 'PUT', + path: '/v2/datasets/{datasetId}', + pathParams: ['datasetId'], + riskLevel: 'write', + description: 'Update dataset', + }, + statisticsGet: { + method: 'GET', + path: '/v2/datasets/{datasetId}/statistics', + pathParams: ['datasetId'], + riskLevel: 'read', + description: 'Get dataset statistics', + }, + }, + datasets: { + get: { + method: 'GET', + path: '/v2/datasets', + pathParams: [], + queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], + riskLevel: 'read', + description: 'Get list of datasets', + }, + post: { + method: 'POST', + path: '/v2/datasets', + pathParams: [], + queryParams: ['name'], + riskLevel: 'write', + description: 'Create dataset', + }, + }, + keyValueStore: { + delete: { + method: 'DELETE', + path: '/v2/key-value-stores/{storeId}', + pathParams: ['storeId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete store', + }, + get: { + method: 'GET', + path: '/v2/key-value-stores/{storeId}', + pathParams: ['storeId'], + riskLevel: 'read', + description: 'Get store', + }, + keysGet: { + method: 'GET', + path: '/v2/key-value-stores/{storeId}/keys', + pathParams: ['storeId'], + queryParams: [ + 'exclusiveStartKey', + 'limit', + 'collection', + 'prefix', + 'signature', + ], + riskLevel: 'read', + description: 'Get list of keys', + }, + put: { + method: 'PUT', + path: '/v2/key-value-stores/{storeId}', + pathParams: ['storeId'], + riskLevel: 'write', + description: 'Update store', + }, + recordDelete: { + method: 'DELETE', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete record', + }, + recordGet: { + method: 'GET', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], + queryParams: ['attachment', 'signature'], + riskLevel: 'read', + description: 'Get record', + }, + recordHead: { + method: 'HEAD', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], + riskLevel: 'read', + description: 'Check if a record exists', + }, + recordPost: { + method: 'POST', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], + riskLevel: 'write', + description: 'Store record (POST)', + }, + recordPut: { + method: 'PUT', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], + riskLevel: 'write', + description: 'Store record', + }, + recordsGet: { + method: 'GET', + path: '/v2/key-value-stores/{storeId}/records', + pathParams: ['storeId'], + queryParams: ['collection', 'prefix', 'signature'], + riskLevel: 'read', + description: 'Download records', + }, + }, + keyValueStores: { + get: { + method: 'GET', + path: '/v2/key-value-stores', + pathParams: [], + queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], + riskLevel: 'read', + description: 'Get list of key-value stores', + }, + post: { + method: 'POST', + path: '/v2/key-value-stores', + pathParams: [], + queryParams: ['name'], + riskLevel: 'write', + description: 'Create key-value store', + }, + }, + log: { + get: { + method: 'GET', + path: '/v2/logs/{buildOrRunId}', + pathParams: ['buildOrRunId'], + queryParams: ['stream', 'download', 'raw'], + riskLevel: 'read', + description: 'Get log', + }, + }, + postChargeRun: { + method: 'POST', + path: '/v2/actor-runs/{runId}/charge', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Charge events in run', + }, + postResurrectRun: { + method: 'POST', + path: '/v2/actor-runs/{runId}/resurrect', + pathParams: ['runId'], + queryParams: [ + 'build', + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + ], + riskLevel: 'write', + description: 'Resurrect run', + }, + requestQueue: { + delete: { + method: 'DELETE', + path: '/v2/request-queues/{queueId}', + pathParams: ['queueId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete request queue', + }, + get: { + method: 'GET', + path: '/v2/request-queues/{queueId}', + pathParams: ['queueId'], + riskLevel: 'read', + description: 'Get request queue', + }, + headGet: { + method: 'GET', + path: '/v2/request-queues/{queueId}/head', + pathParams: ['queueId'], + queryParams: ['limit', 'clientKey'], + riskLevel: 'read', + description: 'Get head', + }, + headLockPost: { + method: 'POST', + path: '/v2/request-queues/{queueId}/head/lock', + pathParams: ['queueId'], + queryParams: ['lockSecs', 'limit', 'clientKey'], + riskLevel: 'write', + description: 'Get head and lock', + }, + put: { + method: 'PUT', + path: '/v2/request-queues/{queueId}', + pathParams: ['queueId'], + riskLevel: 'write', + description: 'Update request queue', + }, + requestDelete: { + method: 'DELETE', + path: '/v2/request-queues/{queueId}/requests/{requestId}', + pathParams: ['queueId', 'requestId'], + queryParams: ['clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete request', + }, + requestGet: { + method: 'GET', + path: '/v2/request-queues/{queueId}/requests/{requestId}', + pathParams: ['queueId', 'requestId'], + riskLevel: 'read', + description: 'Get request', + }, + requestLockDelete: { + method: 'DELETE', + path: '/v2/request-queues/{queueId}/requests/{requestId}/lock', + pathParams: ['queueId', 'requestId'], + queryParams: ['clientKey', 'forefront'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete request lock', + }, + requestLockPut: { + method: 'PUT', + path: '/v2/request-queues/{queueId}/requests/{requestId}/lock', + pathParams: ['queueId', 'requestId'], + queryParams: ['lockSecs', 'clientKey', 'forefront'], + riskLevel: 'write', + description: 'Prolong request lock', + }, + requestPut: { + method: 'PUT', + path: '/v2/request-queues/{queueId}/requests/{requestId}', + pathParams: ['queueId', 'requestId'], + queryParams: ['forefront', 'clientKey'], + riskLevel: 'write', + description: 'Update request', + }, + requestsBatchDelete: { + method: 'DELETE', + path: '/v2/request-queues/{queueId}/requests/batch', + pathParams: ['queueId'], + queryParams: ['clientKey'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete requests', + }, + requestsBatchPost: { + method: 'POST', + path: '/v2/request-queues/{queueId}/requests/batch', + pathParams: ['queueId'], + queryParams: ['clientKey', 'forefront'], + riskLevel: 'write', + description: 'Add requests', + }, + requestsGet: { + method: 'GET', + path: '/v2/request-queues/{queueId}/requests', + pathParams: ['queueId'], + queryParams: [ + 'clientKey', + 'exclusiveStartId', + 'limit', + 'cursor', + 'filter', + ], + riskLevel: 'read', + description: 'List requests', + }, + requestsPost: { + method: 'POST', + path: '/v2/request-queues/{queueId}/requests', + pathParams: ['queueId'], + queryParams: ['clientKey', 'forefront'], + riskLevel: 'write', + description: 'Add request', + }, + requestsUnlockPost: { + method: 'POST', + path: '/v2/request-queues/{queueId}/requests/unlock', + pathParams: ['queueId'], + queryParams: ['clientKey'], + riskLevel: 'write', + description: 'Unlock requests', + }, + }, + requestQueues: { + get: { + method: 'GET', + path: '/v2/request-queues', + pathParams: [], + queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], + riskLevel: 'read', + description: 'Get list of request queues', + }, + post: { + method: 'POST', + path: '/v2/request-queues', + pathParams: [], + queryParams: ['name'], + riskLevel: 'write', + description: 'Create request queue', + }, + }, + schedule: { + delete: { + method: 'DELETE', + path: '/v2/schedules/{scheduleId}', + pathParams: ['scheduleId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete schedule', + }, + get: { + method: 'GET', + path: '/v2/schedules/{scheduleId}', + pathParams: ['scheduleId'], + riskLevel: 'read', + description: 'Get schedule', + }, + logGet: { + method: 'GET', + path: '/v2/schedules/{scheduleId}/log', + pathParams: ['scheduleId'], + riskLevel: 'read', + description: 'Get schedule log', + }, + put: { + method: 'PUT', + path: '/v2/schedules/{scheduleId}', + pathParams: ['scheduleId'], + riskLevel: 'write', + description: 'Update schedule', + }, + }, + schedules: { + get: { + method: 'GET', + path: '/v2/schedules', + pathParams: [], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get list of schedules', + }, + post: { + method: 'POST', + path: '/v2/schedules', + pathParams: [], + riskLevel: 'write', + description: 'Create schedule', + }, + }, + store: { + get: { + method: 'GET', + path: '/v2/store', + pathParams: [], + queryParams: [ + 'limit', + 'offset', + 'search', + 'sortBy', + 'category', + 'username', + 'pricingModel', + 'allowsAgenticUsers', + 'responseFormat', + 'includeUnrunnableActors', + ], + riskLevel: 'read', + description: 'Get list of Actors in Store', + }, + }, + tools: { + browserInfoDelete: { + method: 'DELETE', + path: '/v2/browser-info', + pathParams: [], + queryParams: ['skipHeaders', 'rawHeaders'], + riskLevel: 'destructive', + irreversible: true, + description: 'Get browser info', + }, + browserInfoGet: { + method: 'GET', + path: '/v2/browser-info', + pathParams: [], + queryParams: ['skipHeaders', 'rawHeaders'], + riskLevel: 'read', + description: 'Get browser info', + }, + browserInfoPost: { + method: 'POST', + path: '/v2/browser-info', + pathParams: [], + queryParams: ['skipHeaders', 'rawHeaders'], + riskLevel: 'write', + description: 'Get browser info', + }, + browserInfoPut: { + method: 'PUT', + path: '/v2/browser-info', + pathParams: [], + queryParams: ['skipHeaders', 'rawHeaders'], + riskLevel: 'write', + description: 'Get browser info', + }, + decodeAndVerifyPost: { + method: 'POST', + path: '/v2/tools/decode-and-verify', + pathParams: [], + riskLevel: 'write', + description: 'Decode and verify object', + }, + encodeAndSignPost: { + method: 'POST', + path: '/v2/tools/encode-and-sign', + pathParams: [], + riskLevel: 'write', + description: 'Encode and sign object', + }, + }, + user: { + get: { + method: 'GET', + path: '/v2/users/{userId}', + pathParams: ['userId'], + riskLevel: 'read', + description: 'Get public user data', + }, + }, + users: { + meGet: { + method: 'GET', + path: '/v2/users/me', + pathParams: [], + riskLevel: 'read', + description: 'Get private user data', + }, + meLimitsGet: { + method: 'GET', + path: '/v2/users/me/limits', + pathParams: [], + riskLevel: 'read', + description: 'Get limits', + }, + meLimitsPut: { + method: 'PUT', + path: '/v2/users/me/limits', + pathParams: [], + riskLevel: 'write', + description: 'Update limits', + }, + meUsageMonthlyGet: { + method: 'GET', + path: '/v2/users/me/usage/monthly', + pathParams: [], + queryParams: ['date'], + riskLevel: 'read', + description: 'Get monthly usage', + }, + }, + webhook: { + delete: { + method: 'DELETE', + path: '/v2/webhooks/{webhookId}', + pathParams: ['webhookId'], + riskLevel: 'destructive', + irreversible: true, + description: 'Delete webhook', + }, + get: { + method: 'GET', + path: '/v2/webhooks/{webhookId}', + pathParams: ['webhookId'], + riskLevel: 'read', + description: 'Get webhook', + }, + put: { + method: 'PUT', + path: '/v2/webhooks/{webhookId}', + pathParams: ['webhookId'], + riskLevel: 'write', + description: 'Update webhook', + }, + testPost: { + method: 'POST', + path: '/v2/webhooks/{webhookId}/test', + pathParams: ['webhookId'], + riskLevel: 'write', + description: 'Test webhook', + }, + webhookDispatchesGet: { + method: 'GET', + path: '/v2/webhooks/{webhookId}/dispatches', + pathParams: ['webhookId'], + riskLevel: 'read', + description: 'Get collection', + }, + }, + webhookDispatch: { + get: { + method: 'GET', + path: '/v2/webhook-dispatches/{dispatchId}', + pathParams: ['dispatchId'], + riskLevel: 'read', + description: 'Get webhook dispatch', + }, + }, + webhookDispatches: { + get: { + method: 'GET', + path: '/v2/webhook-dispatches', + pathParams: [], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get list of webhook dispatches', + }, + }, + webhooks: { + get: { + method: 'GET', + path: '/v2/webhooks', + pathParams: [], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', + description: 'Get list of webhooks', + }, + post: { + method: 'POST', + path: '/v2/webhooks', + pathParams: [], + riskLevel: 'write', + description: 'Create webhook', + }, + }, +} as const satisfies ApifyOperationTree; diff --git a/packages/apify/endpoints/types.ts b/packages/apify/endpoints/types.ts new file mode 100644 index 000000000..d665cf191 --- /dev/null +++ b/packages/apify/endpoints/types.ts @@ -0,0 +1,19 @@ +import { z } from 'zod'; + +export const ApifyOperationInputSchema = z + .object({ + body: z.unknown().optional(), + query: z.record(z.string(), z.unknown()).optional(), + headers: z.record(z.string(), z.unknown()).optional(), + contentType: z.string().optional(), + mediaType: z.string().optional(), + }) + .loose(); + +export const ApifyOperationOutputSchema = z.unknown(); + +export type ApifyOperationInput = z.infer; +export type ApifyOperationOutput = z.infer; + +export type ApifyEndpointInputs = Record; +export type ApifyEndpointOutputs = Record; diff --git a/packages/apify/error-handlers.ts b/packages/apify/error-handlers.ts new file mode 100644 index 000000000..5d04f981d --- /dev/null +++ b/packages/apify/error-handlers.ts @@ -0,0 +1,70 @@ +import type { CorsairErrorHandler } from 'corsair/core'; +import { ApiError } from 'corsair/http'; + +function messageOf(error: Error): string { + if (error instanceof ApiError) { + const body = error.body as + | { error?: { type?: string; message?: string } } + | undefined; + return [ + body?.error?.type, + body?.error?.message, + error.message, + error.statusText, + ] + .filter(Boolean) + .join(' ') + .toLowerCase(); + } + + return error.message.toLowerCase(); +} + +export const errorHandlers = { + RATE_LIMIT_ERROR: { + match: (error: Error) => + error instanceof ApiError + ? error.status === 429 + : messageOf(error).includes('rate-limit'), + handler: async (error: Error) => ({ + maxRetries: 5, + headersRetryAfterMs: + error instanceof ApiError ? error.retryAfter : undefined, + retryStrategy: 'exponential_backoff_jitter', + }), + }, + AUTH_ERROR: { + match: (error: Error) => + error instanceof ApiError + ? error.status === 401 + : messageOf(error).includes('token') || + messageOf(error).includes('unauthorized'), + handler: async () => ({ maxRetries: 0 }), + }, + PERMISSION_ERROR: { + match: (error: Error) => + error instanceof ApiError + ? error.status === 403 + : messageOf(error).includes('permission') || + messageOf(error).includes('forbidden'), + handler: async () => ({ maxRetries: 0 }), + }, + NOT_FOUND_ERROR: { + match: (error: Error) => + error instanceof ApiError + ? error.status === 404 + : messageOf(error).includes('not found'), + handler: async () => ({ maxRetries: 0 }), + }, + BAD_REQUEST_ERROR: { + match: (error: Error) => + error instanceof ApiError + ? error.status === 400 + : messageOf(error).includes('invalid'), + handler: async () => ({ maxRetries: 0 }), + }, + DEFAULT: { + match: () => true, + handler: async () => ({ maxRetries: 0 }), + }, +} satisfies CorsairErrorHandler; diff --git a/packages/apify/index.ts b/packages/apify/index.ts new file mode 100644 index 000000000..41d38e82e --- /dev/null +++ b/packages/apify/index.ts @@ -0,0 +1,123 @@ +import type { + AuthTypes, + BindEndpoints, + BindWebhooks, + CorsairErrorHandler, + CorsairPlugin, + CorsairPluginContext, + KeyBuilderContext, + PickAuth, + PluginAuthConfig, + PluginPermissionsConfig, + RequiredPluginEndpointMeta, + RequiredPluginEndpointSchemas, + RequiredPluginWebhookSchemas, +} from 'corsair/core'; +import { AuthMissingError } from 'corsair/core'; +import { + ApifyEndpoints, + apifyOperations, + buildApifyEndpointMeta, + buildApifyEndpointSchemas, +} from './endpoints'; +import { errorHandlers } from './error-handlers'; +import { ApifySchema } from './schema'; + +const apifyEndpointsNested = ApifyEndpoints; +const apifyWebhooksNested = {} as const; + +export type ApifyPluginOptions = { + authType?: PickAuth<'api_key'>; + key?: string; + hooks?: InternalApifyPlugin['hooks']; + errorHandlers?: CorsairErrorHandler; + permissions?: PluginPermissionsConfig; +}; + +export type ApifyContext = CorsairPluginContext< + typeof ApifySchema, + ApifyPluginOptions +>; + +export type ApifyKeyBuilderContext = KeyBuilderContext; + +export type ApifyBoundEndpoints = BindEndpoints; + +export type ApifyBoundWebhooks = BindWebhooks; + +export const apifyEndpointSchemas = buildApifyEndpointSchemas( + apifyOperations, +) satisfies RequiredPluginEndpointSchemas; + +const apifyWebhookSchemas = {} as const satisfies RequiredPluginWebhookSchemas< + typeof apifyWebhooksNested +>; + +const defaultAuthType: AuthTypes = 'api_key' as const; + +export const apifyAuthConfig = { + api_key: {}, +} as const satisfies PluginAuthConfig; + +const apifyEndpointMeta = buildApifyEndpointMeta( + apifyOperations, +) satisfies RequiredPluginEndpointMeta; + +export type BaseApifyPlugin = CorsairPlugin< + 'apify', + typeof ApifySchema, + typeof apifyEndpointsNested, + typeof apifyWebhooksNested, + T, + typeof defaultAuthType, + typeof apifyAuthConfig +>; + +export type InternalApifyPlugin = BaseApifyPlugin; + +export type ExternalApifyPlugin = + BaseApifyPlugin; + +export function apify( + incomingOptions: ApifyPluginOptions & T = {} as ApifyPluginOptions & T, +): ExternalApifyPlugin { + const options = { + ...incomingOptions, + authType: incomingOptions.authType ?? defaultAuthType, + }; + + return { + id: 'apify', + authConfig: apifyAuthConfig, + schema: ApifySchema, + options, + hooks: options.hooks, + endpoints: apifyEndpointsNested, + webhooks: apifyWebhooksNested, + endpointMeta: apifyEndpointMeta, + endpointSchemas: apifyEndpointSchemas, + webhookSchemas: apifyWebhookSchemas, + pluginWebhookMatcher: () => false, + errorHandlers: { + ...errorHandlers, + ...options.errorHandlers, + }, + keyBuilder: async (ctx: ApifyKeyBuilderContext, source) => { + if (source === 'endpoint' && options.key) return options.key; + + if (source === 'endpoint' && ctx.authType === 'api_key') { + const res = await ctx.keys.get_api_key(); + if (res) return res; + } + + throw new AuthMissingError('apify', 'api_key'); + }, + } satisfies InternalApifyPlugin; +} + +export type { + ApifyEndpointInputs, + ApifyEndpointOutputs, + ApifyOperationInput, + ApifyOperationOutput, +} from './endpoints'; diff --git a/packages/apify/package.json b/packages/apify/package.json new file mode 100644 index 000000000..3694fd598 --- /dev/null +++ b/packages/apify/package.json @@ -0,0 +1,40 @@ +{ + "name": "@corsair-dev/apify", + "version": "0.1.0", + "description": "Apify plugin for Corsair", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "dev-source": "./index.ts", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "scripts": { + "build": "rm -rf dist && tsc --build --force && tsup", + "typecheck": "tsc --noEmit" + }, + "peerDependencies": { + "corsair": ">=0.1.0", + "zod": "^4.1.13" + }, + "devDependencies": { + "corsair": "workspace:*", + "tsup": "^8.0.1", + "typescript": "catalog:", + "zod": "^4.1.13" + }, + "keywords": [ + "corsair", + "apify", + "plugin" + ], + "author": "", + "license": "Apache-2.0", + "files": [ + "dist" + ] +} diff --git a/packages/apify/schema/database.ts b/packages/apify/schema/database.ts new file mode 100644 index 000000000..4c74606a6 --- /dev/null +++ b/packages/apify/schema/database.ts @@ -0,0 +1,147 @@ +import { z } from 'zod'; + +const ApifyAccessLevel = z + .enum(['PRIVATE', 'READ', 'WRITE', 'READ_WRITE']) + .or(z.string()); + +export const ApifyActor = z + .object({ + id: z.string(), + userId: z.string().optional(), + name: z.string().optional(), + username: z.string().optional(), + title: z.string().nullable().optional(), + description: z.string().nullable().optional(), + isPublic: z.boolean().optional(), + isDeprecated: z.boolean().optional(), + notice: z.string().nullable().optional(), + createdAt: z.coerce.date().nullable().optional(), + modifiedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifyActorRun = z + .object({ + id: z.string(), + actId: z.string().optional(), + actorTaskId: z.string().nullable().optional(), + status: z.string(), + statusMessage: z.string().nullable().optional(), + startedAt: z.coerce.date().nullable().optional(), + finishedAt: z.coerce.date().nullable().optional(), + buildId: z.string().nullable().optional(), + buildNumber: z.string().nullable().optional(), + defaultDatasetId: z.string().nullable().optional(), + defaultKeyValueStoreId: z.string().nullable().optional(), + defaultRequestQueueId: z.string().nullable().optional(), + usageTotalUsd: z.number().nullable().optional(), + }) + .loose(); + +export const ApifyActorBuild = z + .object({ + id: z.string(), + actId: z.string().optional(), + userId: z.string().optional(), + status: z.string(), + buildNumber: z.string().optional(), + startedAt: z.coerce.date().nullable().optional(), + finishedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifyActorTask = z + .object({ + id: z.string(), + actId: z.string().optional(), + userId: z.string().optional(), + name: z.string().optional(), + title: z.string().nullable().optional(), + createdAt: z.coerce.date().nullable().optional(), + modifiedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifyDataset = z + .object({ + id: z.string(), + name: z.string().nullable().optional(), + userId: z.string().optional(), + itemCount: z.number().optional(), + access: ApifyAccessLevel.optional(), + createdAt: z.coerce.date().nullable().optional(), + modifiedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifyKeyValueStore = z + .object({ + id: z.string(), + name: z.string().nullable().optional(), + userId: z.string().optional(), + recordCount: z.number().optional(), + access: ApifyAccessLevel.optional(), + createdAt: z.coerce.date().nullable().optional(), + modifiedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifyRequestQueue = z + .object({ + id: z.string(), + name: z.string().nullable().optional(), + userId: z.string().optional(), + totalRequestCount: z.number().optional(), + handledRequestCount: z.number().optional(), + pendingRequestCount: z.number().optional(), + access: ApifyAccessLevel.optional(), + createdAt: z.coerce.date().nullable().optional(), + modifiedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifySchedule = z + .object({ + id: z.string(), + name: z.string().optional(), + userId: z.string().optional(), + isEnabled: z.boolean().optional(), + cronExpression: z.string().optional(), + timezone: z.string().optional(), + createdAt: z.coerce.date().nullable().optional(), + modifiedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifyWebhook = z + .object({ + id: z.string(), + userId: z.string().optional(), + eventTypes: z.array(z.string()).optional(), + requestUrl: z.string().optional(), + isAdHoc: z.boolean().optional(), + createdAt: z.coerce.date().nullable().optional(), + modifiedAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export const ApifyUser = z + .object({ + id: z.string(), + username: z.string().optional(), + email: z.string().email().optional(), + profile: z.record(z.string(), z.unknown()).optional(), + createdAt: z.coerce.date().nullable().optional(), + }) + .loose(); + +export type ApifyActor = z.infer; +export type ApifyActorRun = z.infer; +export type ApifyActorBuild = z.infer; +export type ApifyActorTask = z.infer; +export type ApifyDataset = z.infer; +export type ApifyKeyValueStore = z.infer; +export type ApifyRequestQueue = z.infer; +export type ApifySchedule = z.infer; +export type ApifyWebhook = z.infer; +export type ApifyUser = z.infer; diff --git a/packages/apify/schema/index.ts b/packages/apify/schema/index.ts new file mode 100644 index 000000000..8e35421b6 --- /dev/null +++ b/packages/apify/schema/index.ts @@ -0,0 +1,28 @@ +import { + ApifyActor, + ApifyActorBuild, + ApifyActorRun, + ApifyActorTask, + ApifyDataset, + ApifyKeyValueStore, + ApifyRequestQueue, + ApifySchedule, + ApifyUser, + ApifyWebhook, +} from './database'; + +export const ApifySchema = { + version: '2.0.0', + entities: { + actors: ApifyActor, + actorBuilds: ApifyActorBuild, + actorRuns: ApifyActorRun, + actorTasks: ApifyActorTask, + datasets: ApifyDataset, + keyValueStores: ApifyKeyValueStore, + requestQueues: ApifyRequestQueue, + schedules: ApifySchedule, + webhooks: ApifyWebhook, + users: ApifyUser, + }, +} as const; diff --git a/packages/apify/tsconfig.json b/packages/apify/tsconfig.json new file mode 100644 index 000000000..360eafeaf --- /dev/null +++ b/packages/apify/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["esnext"], + "types": ["node"], + "module": "ESNext", + "moduleResolution": "Bundler", + "outDir": "./dist", + "rootDir": "./", + "composite": true, + "incremental": true, + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "skipLibCheck": true + }, + "include": ["./**/*"], + "exclude": ["dist", "node_modules"], + "references": [] +} diff --git a/packages/apify/tsup.config.ts b/packages/apify/tsup.config.ts new file mode 100644 index 000000000..3ec221e23 --- /dev/null +++ b/packages/apify/tsup.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + clean: false, + dts: false, + format: ['esm'], + target: 'esnext', + platform: 'node', + bundle: true, + splitting: true, + minify: true, + outDir: 'dist', + external: ['corsair', 'zod'], + entry: ['index.ts'], +}); diff --git a/packages/corsair/core/constants.ts b/packages/corsair/core/constants.ts index 9b8edbbe1..b3d0182ff 100644 --- a/packages/corsair/core/constants.ts +++ b/packages/corsair/core/constants.ts @@ -17,6 +17,7 @@ export const BaseProviders = [ 'ahrefs', 'airtable', 'amplitude', + 'apify', 'asana', 'bitwarden', 'bluesky', @@ -42,6 +43,7 @@ export const BaseProviders = [ 'grafana', 'hackernews', 'hubspot', + 'instagram', 'intercom', 'jira', 'linear', @@ -79,7 +81,6 @@ export const BaseProviders = [ 'zendesk', 'zohomail', 'zoom', - 'instagram', ] as const; export const ProviderDisplayNames = { @@ -87,6 +88,7 @@ export const ProviderDisplayNames = { ahrefs: 'Ahrefs', airtable: 'Airtable', amplitude: 'Amplitude', + apify: 'Apify', asana: 'Asana', bitwarden: 'Bitwarden', bluesky: 'Bluesky', @@ -164,6 +166,7 @@ export type AllProviders = | 'ahrefs' | 'airtable' | 'amplitude' + | 'apify' | 'asana' | 'bitwarden' | 'bluesky' @@ -189,6 +192,7 @@ export type AllProviders = | 'grafana' | 'hackernews' | 'hubspot' + | 'instagram' | 'intercom' | 'jira' | 'linear' @@ -226,7 +230,6 @@ export type AllProviders = | 'zendesk' | 'zohomail' | 'zoom' - | 'instagram' | (string & {}); export type AuthTypes = 'oauth_2' | 'api_key' | 'bot_token' | 'managed'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f0c6e6844..158ac2ab5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -364,6 +364,21 @@ importers: specifier: ^4.1.13 version: 4.1.13 + packages/apify: + devDependencies: + corsair: + specifier: workspace:* + version: link:../corsair + tsup: + specifier: ^8.0.1 + version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) + typescript: + specifier: 'catalog:' + version: 5.9.3 + zod: + specifier: ^4.1.13 + version: 4.1.13 + packages/app: dependencies: '@ai-sdk/mcp': From c77dcf2e6cc3d2cadb4d3a9105179e1a1f8a59b0 Mon Sep 17 00:00:00 2001 From: Aman Raj Date: Fri, 3 Jul 2026 22:27:32 +0530 Subject: [PATCH 02/15] test: wire Apify into demo testing --- demo/testing/package.json | 2 ++ demo/testing/src/scripts/test-script.ts | 29 ++++++++++--------------- demo/testing/src/server/corsair.ts | 5 +++++ pnpm-lock.yaml | 3 +++ 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/demo/testing/package.json b/demo/testing/package.json index 3dcf0da17..f2808e2c8 100644 --- a/demo/testing/package.json +++ b/demo/testing/package.json @@ -17,6 +17,7 @@ "dev": "next dev -p 3001", "build": "next build", "start": "next start", + "test": "NODE_OPTIONS=--conditions=dev-source tsx src/scripts/test-script.ts", "test:hub": "tsx src/scripts/test-hub.ts", "test:manual": "tsx src/scripts/test-script.ts", "rebuild:sqlite": "pnpm rebuild better-sqlite3", @@ -26,6 +27,7 @@ "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.0", "@corsair-dev/agentql": "workspace:*", + "@corsair-dev/apify": "workspace:*", "@corsair-dev/bitwarden": "workspace:*", "@corsair-dev/cursor": "workspace:*", "@corsair-dev/firecrawl": "workspace:*", diff --git a/demo/testing/src/scripts/test-script.ts b/demo/testing/src/scripts/test-script.ts index 497559193..51379afcb 100644 --- a/demo/testing/src/scripts/test-script.ts +++ b/demo/testing/src/scripts/test-script.ts @@ -2,26 +2,19 @@ import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); -import { corsair } from '@/server/corsair'; - -async function setInstagramCredentials() { - const { FACEBOOK_APP_ID, FACEBOOK_APP_SECRET, IG_ACCESS_TOKEN } = process.env; - - if (FACEBOOK_APP_ID) { - await corsair.keys.instagram.set_client_id(FACEBOOK_APP_ID); - } - if (FACEBOOK_APP_SECRET) { - await corsair.keys.instagram.set_client_secret(FACEBOOK_APP_SECRET); - } - if (IG_ACCESS_TOKEN) { - await corsair.instagram.keys.set_access_token(IG_ACCESS_TOKEN); +const main = async () => { + if (!process.env.APIFY_API_KEY) { + console.log('Skipping Apify demo test: APIFY_API_KEY is not set.'); + return; } -} -const main = async () => { - const res = await corsair.slack.api.messages.post({ - channel: 'general', - text: 'hello', + const { corsair } = await import('@/server/corsair'); + const result = await corsair.apify.api.users.meGet({}); + const data = result.data as { id?: string; username?: string }; + + console.log('Apify user lookup succeeded', { + id: data.id, + username: data.username, }); }; diff --git a/demo/testing/src/server/corsair.ts b/demo/testing/src/server/corsair.ts index 3755c8b3e..6d3de59de 100644 --- a/demo/testing/src/server/corsair.ts +++ b/demo/testing/src/server/corsair.ts @@ -3,10 +3,12 @@ import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); import { agentql } from '@corsair-dev/agentql'; +import { apify } from '@corsair-dev/apify'; import { gmail } from '@corsair-dev/gmail'; import { googlecalendar } from '@corsair-dev/googlecalendar'; import { googlesheets } from '@corsair-dev/googlesheets'; import { hubspot } from '@corsair-dev/hubspot'; +import { instagram } from '@corsair-dev/instagram'; import { linear } from '@corsair-dev/linear'; import { onedrive } from '@corsair-dev/onedrive'; import { sharepoint } from '@corsair-dev/sharepoint'; @@ -58,6 +60,9 @@ export const corsair = createCorsair({ agentql({ key: process.env.AGENTQL_API_KEY, }), + apify({ + key: process.env.APIFY_API_KEY, + }), twilio(), vapi({ key: process.env.VAPI_API_KEY, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 158ac2ab5..f5e1f67e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,6 +143,9 @@ importers: '@corsair-dev/agentql': specifier: workspace:* version: link:../../packages/agentql + '@corsair-dev/apify': + specifier: workspace:* + version: link:../../packages/apify '@corsair-dev/bitwarden': specifier: workspace:* version: link:../../packages/bitwarden From 9c964657a8febbf358d6890eb35c0662b853723f Mon Sep 17 00:00:00 2001 From: Aman Raj Date: Fri, 3 Jul 2026 22:41:12 +0530 Subject: [PATCH 03/15] fix: address Apify review feedback --- packages/apify/client.ts | 18 +++++++++++------- packages/apify/endpoints/index.ts | 6 ++++++ packages/apify/endpoints/operations.ts | 12 ++++-------- packages/apify/endpoints/types.ts | 4 ++++ packages/apify/schema/database.ts | 1 + 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/apify/client.ts b/packages/apify/client.ts index a188b567e..4a41b8123 100644 --- a/packages/apify/client.ts +++ b/packages/apify/client.ts @@ -26,17 +26,21 @@ const RESERVED_INPUT_KEYS = new Set([ 'mediaType', ]); -function isRecord(value: unknown): value is Record { +// Apify accepts and returns endpoint-specific JSON that the generic client passes through unchanged. +type ApifyJsonValue = unknown; +type ApifyJsonRecord = Record; + +function isRecord(value: ApifyJsonValue): value is ApifyJsonRecord { return value !== null && typeof value === 'object' && !Array.isArray(value); } function pickDefined( input: ApifyOperationInput, keys: readonly string[] | undefined, -): Record | undefined { +): ApifyJsonRecord | undefined { if (!keys?.length) return undefined; - const output: Record = {}; + const output: ApifyJsonRecord = {}; for (const key of keys) { const value = input[key]; if (value !== undefined) output[key] = value; @@ -48,7 +52,7 @@ function pickDefined( function buildQuery( operation: ApifyOperationDefinition, input: ApifyOperationInput, -): Record | undefined { +): ApifyJsonRecord | undefined { const query = { ...(isRecord(input.query) ? input.query : {}), ...(pickDefined(input, operation.queryParams) ?? {}), @@ -60,14 +64,14 @@ function buildQuery( function buildBody( operation: ApifyOperationDefinition, input: ApifyOperationInput, -): unknown { +): ApifyJsonValue { if (input.body !== undefined) return input.body; if (operation.method === 'GET' || operation.method === 'HEAD') return undefined; const queryParams = new Set(operation.queryParams ?? []); const pathParams = new Set(operation.pathParams); - const body: Record = {}; + const body: ApifyJsonRecord = {}; for (const [key, value] of Object.entries(input)) { if ( @@ -118,7 +122,7 @@ export async function makeApifyRequest( }; try { - const response = await request(config, requestOptions); + const response = await request(config, requestOptions); if (response === undefined && operation.method === 'HEAD') { return { exists: true }; } diff --git a/packages/apify/endpoints/index.ts b/packages/apify/endpoints/index.ts index 099d670fe..fdfc285e5 100644 --- a/packages/apify/endpoints/index.ts +++ b/packages/apify/endpoints/index.ts @@ -40,6 +40,7 @@ function buildEndpointTree( tree: T, segments: string[] = [], ): ApifyEndpointTree { + // The recursive builder accumulates heterogeneous endpoint functions before the final typed tree cast. const endpoints: Record = {}; for (const [key, value] of Object.entries(tree)) { @@ -71,8 +72,11 @@ function buildEndpointTree( function createOperationInputSchema(operation: ApifyOperationDefinition) { const shape: Record = { + // Apify operation bodies vary per endpoint and can include arbitrary JSON payloads. body: z.unknown().optional(), + // Query values are endpoint-specific primitives preserved by the generic operation router. query: z.record(z.string(), z.unknown()).optional(), + // Custom headers are passed through to Apify without a stable provider-wide shape. headers: z.record(z.string(), z.unknown()).optional(), contentType: z.string().optional(), mediaType: z.string().optional(), @@ -83,6 +87,7 @@ function createOperationInputSchema(operation: ApifyOperationDefinition) { } for (const param of operation.queryParams ?? []) { + // Generated query metadata names the parameter but does not constrain its provider-specific value type. shape[param] = z.unknown().optional(); } @@ -93,6 +98,7 @@ export function buildApifyEndpointSchemas( tree: T, segments: string[] = [], ): RequiredPluginEndpointSchemas> { + // Schema entries are accumulated by dotted operation path before the typed schema-map cast. const schemas: Record = {}; for (const [key, value] of Object.entries(tree)) { diff --git a/packages/apify/endpoints/operations.ts b/packages/apify/endpoints/operations.ts index 91e008025..28bba3986 100644 --- a/packages/apify/endpoints/operations.ts +++ b/packages/apify/endpoints/operations.ts @@ -406,8 +406,7 @@ export const apifyOperations = { path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}/lock', pathParams: ['actorId', 'requestId'], queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'destructive', - irreversible: true, + riskLevel: 'write', description: "Delete lock on request in last run's default request queue", }, runsLastRequestQueueRequestLockPut: { @@ -1018,8 +1017,7 @@ export const apifyOperations = { path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}/lock', pathParams: ['runId', 'requestId'], queryParams: ['clientKey', 'forefront'], - riskLevel: 'destructive', - irreversible: true, + riskLevel: 'write', description: 'Delete lock on request in default request queue', }, requestQueueRequestLockPut: { @@ -1409,8 +1407,7 @@ export const apifyOperations = { path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}/lock', pathParams: ['actorTaskId', 'requestId'], queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'destructive', - irreversible: true, + riskLevel: 'write', description: "Delete lock on request in last task run's default request queue", }, @@ -1965,8 +1962,7 @@ export const apifyOperations = { path: '/v2/request-queues/{queueId}/requests/{requestId}/lock', pathParams: ['queueId', 'requestId'], queryParams: ['clientKey', 'forefront'], - riskLevel: 'destructive', - irreversible: true, + riskLevel: 'write', description: 'Delete request lock', }, requestLockPut: { diff --git a/packages/apify/endpoints/types.ts b/packages/apify/endpoints/types.ts index d665cf191..400acbe51 100644 --- a/packages/apify/endpoints/types.ts +++ b/packages/apify/endpoints/types.ts @@ -2,14 +2,18 @@ import { z } from 'zod'; export const ApifyOperationInputSchema = z .object({ + // Apify operation bodies vary per endpoint and can include arbitrary JSON payloads. body: z.unknown().optional(), + // Query values are endpoint-specific primitives preserved by the generic operation router. query: z.record(z.string(), z.unknown()).optional(), + // Custom headers are passed through to Apify without a stable provider-wide shape. headers: z.record(z.string(), z.unknown()).optional(), contentType: z.string().optional(), mediaType: z.string().optional(), }) .loose(); +// Apify returns endpoint-specific payloads that this generated passthrough layer does not normalize. export const ApifyOperationOutputSchema = z.unknown(); export type ApifyOperationInput = z.infer; diff --git a/packages/apify/schema/database.ts b/packages/apify/schema/database.ts index 4c74606a6..c2305df68 100644 --- a/packages/apify/schema/database.ts +++ b/packages/apify/schema/database.ts @@ -130,6 +130,7 @@ export const ApifyUser = z id: z.string(), username: z.string().optional(), email: z.string().email().optional(), + // Apify user profile fields are custom account metadata without a stable provider-wide schema. profile: z.record(z.string(), z.unknown()).optional(), createdAt: z.coerce.date().nullable().optional(), }) From 71cbfb1d4467d3b24ff3e45138cb682c147b7020 Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 22:03:03 +0530 Subject: [PATCH 04/15] revert(apify): drop demo/testing wiring out of plugin scope --- demo/testing/package.json | 2 -- demo/testing/src/scripts/test-script.ts | 29 +++++++++++++++---------- demo/testing/src/server/corsair.ts | 5 ----- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/demo/testing/package.json b/demo/testing/package.json index f2808e2c8..3dcf0da17 100644 --- a/demo/testing/package.json +++ b/demo/testing/package.json @@ -17,7 +17,6 @@ "dev": "next dev -p 3001", "build": "next build", "start": "next start", - "test": "NODE_OPTIONS=--conditions=dev-source tsx src/scripts/test-script.ts", "test:hub": "tsx src/scripts/test-hub.ts", "test:manual": "tsx src/scripts/test-script.ts", "rebuild:sqlite": "pnpm rebuild better-sqlite3", @@ -27,7 +26,6 @@ "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.0", "@corsair-dev/agentql": "workspace:*", - "@corsair-dev/apify": "workspace:*", "@corsair-dev/bitwarden": "workspace:*", "@corsair-dev/cursor": "workspace:*", "@corsair-dev/firecrawl": "workspace:*", diff --git a/demo/testing/src/scripts/test-script.ts b/demo/testing/src/scripts/test-script.ts index 51379afcb..497559193 100644 --- a/demo/testing/src/scripts/test-script.ts +++ b/demo/testing/src/scripts/test-script.ts @@ -2,19 +2,26 @@ import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); -const main = async () => { - if (!process.env.APIFY_API_KEY) { - console.log('Skipping Apify demo test: APIFY_API_KEY is not set.'); - return; - } +import { corsair } from '@/server/corsair'; - const { corsair } = await import('@/server/corsair'); - const result = await corsair.apify.api.users.meGet({}); - const data = result.data as { id?: string; username?: string }; +async function setInstagramCredentials() { + const { FACEBOOK_APP_ID, FACEBOOK_APP_SECRET, IG_ACCESS_TOKEN } = process.env; - console.log('Apify user lookup succeeded', { - id: data.id, - username: data.username, + if (FACEBOOK_APP_ID) { + await corsair.keys.instagram.set_client_id(FACEBOOK_APP_ID); + } + if (FACEBOOK_APP_SECRET) { + await corsair.keys.instagram.set_client_secret(FACEBOOK_APP_SECRET); + } + if (IG_ACCESS_TOKEN) { + await corsair.instagram.keys.set_access_token(IG_ACCESS_TOKEN); + } +} + +const main = async () => { + const res = await corsair.slack.api.messages.post({ + channel: 'general', + text: 'hello', }); }; diff --git a/demo/testing/src/server/corsair.ts b/demo/testing/src/server/corsair.ts index 6d3de59de..3755c8b3e 100644 --- a/demo/testing/src/server/corsair.ts +++ b/demo/testing/src/server/corsair.ts @@ -3,12 +3,10 @@ import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); import { agentql } from '@corsair-dev/agentql'; -import { apify } from '@corsair-dev/apify'; import { gmail } from '@corsair-dev/gmail'; import { googlecalendar } from '@corsair-dev/googlecalendar'; import { googlesheets } from '@corsair-dev/googlesheets'; import { hubspot } from '@corsair-dev/hubspot'; -import { instagram } from '@corsair-dev/instagram'; import { linear } from '@corsair-dev/linear'; import { onedrive } from '@corsair-dev/onedrive'; import { sharepoint } from '@corsair-dev/sharepoint'; @@ -60,9 +58,6 @@ export const corsair = createCorsair({ agentql({ key: process.env.AGENTQL_API_KEY, }), - apify({ - key: process.env.APIFY_API_KEY, - }), twilio(), vapi({ key: process.env.VAPI_API_KEY, From 214c95e975e49e5677340576ec2e565232acaa97 Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 22:03:15 +0530 Subject: [PATCH 05/15] fix(apify): correct browserInfoDelete risk metadata --- packages/apify/endpoints/operations.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/apify/endpoints/operations.ts b/packages/apify/endpoints/operations.ts index 28bba3986..c50308814 100644 --- a/packages/apify/endpoints/operations.ts +++ b/packages/apify/endpoints/operations.ts @@ -2122,8 +2122,7 @@ export const apifyOperations = { path: '/v2/browser-info', pathParams: [], queryParams: ['skipHeaders', 'rawHeaders'], - riskLevel: 'destructive', - irreversible: true, + riskLevel: 'write', description: 'Get browser info', }, browserInfoGet: { From 978a97809bafd3c5d89126834918c12d783d19ea Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 22:03:25 +0530 Subject: [PATCH 06/15] fix(apify): export EndpointInputSchemas/EndpointOutputSchemas --- packages/apify/endpoints/types.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/apify/endpoints/types.ts b/packages/apify/endpoints/types.ts index 400acbe51..b3a4b434d 100644 --- a/packages/apify/endpoints/types.ts +++ b/packages/apify/endpoints/types.ts @@ -21,3 +21,10 @@ export type ApifyOperationOutput = z.infer; export type ApifyEndpointInputs = Record; export type ApifyEndpointOutputs = Record; + +// Generic schemas exposed under the conventional names expected by the plugin +// validator. Per-operation schemas are built dynamically in endpoints/index.ts +// (see buildApifyEndpointSchemas); these are the shared shapes every operation +// derives from. +export const EndpointInputSchemas = ApifyOperationInputSchema; +export const EndpointOutputSchemas = ApifyOperationOutputSchema; From cef9becb9ff818ea593b48c71367a7875f6ee4c5 Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 22:03:35 +0530 Subject: [PATCH 07/15] test(apify): add jest wiring and operation suite --- packages/apify/jest.config.cjs | 55 ++++++++++ packages/apify/operations.test.ts | 174 ++++++++++++++++++++++++++++++ packages/apify/package.json | 6 +- packages/apify/tsconfig.json | 2 +- 4 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 packages/apify/jest.config.cjs create mode 100644 packages/apify/operations.test.ts diff --git a/packages/apify/jest.config.cjs b/packages/apify/jest.config.cjs new file mode 100644 index 000000000..8c6218f64 --- /dev/null +++ b/packages/apify/jest.config.cjs @@ -0,0 +1,55 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: [''], + testMatch: [ + '**/*.test.ts', + '**/tests/**/*.test.ts', + '**/plugins/**/*.test.ts', + '**/setup/**/*.test.ts', + ], + collectCoverageFrom: [ + '**/*.ts', + '!**/*.d.ts', + '!**/node_modules/**', + '!**/dist/**', + '!jest.config.ts', + '!tests/**', + ], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], + transform: { + '^.+\\.yaml$': '/../corsair/jest-yaml-transform.cjs', + '^.+\\.ts$': [ + 'ts-jest', + { + useESM: true, + tsconfig: { + esModuleInterop: true, + allowSyntheticDefaultImports: true, + verbatimModuleSyntax: false, + module: 'ESNext', + moduleResolution: 'Bundler', + }, + }, + ], + '.*\\.js$': [ + 'ts-jest', + { + useESM: true, + tsconfig: { + esModuleInterop: true, + allowSyntheticDefaultImports: true, + }, + }, + ], + }, + moduleNameMapper: { + '^corsair/core$': '/../corsair/core.ts', + '^corsair/http$': '/../corsair/http.ts', + '^(\\.\\.?/.*)\\.js$': '$1', + }, + transformIgnorePatterns: ['node_modules/(?!.*uuid.*)'], + extensionsToTreatAsEsm: ['.ts'], + testTimeout: 30000, + verbose: true, +}; diff --git a/packages/apify/operations.test.ts b/packages/apify/operations.test.ts new file mode 100644 index 000000000..2fa0cd85a --- /dev/null +++ b/packages/apify/operations.test.ts @@ -0,0 +1,174 @@ +import type { ApifyOperationDefinition } from './endpoints'; +import { + ApifyEndpoints, + apifyOperations, + buildApifyEndpointMeta, + buildApifyEndpointSchemas, +} from './endpoints'; +import { + ApifyOperationInputSchema, + ApifyOperationOutputSchema, +} from './endpoints/types'; + +type OperationEntry = { path: string; def: ApifyOperationDefinition }; + +// Walks the nested operation tree and yields every leaf operation with its +// dotted path (e.g. "act.buildsGet"). Used to assert over the full registry. +function isDefinition(node: unknown): node is ApifyOperationDefinition { + return ( + typeof node === 'object' && + node !== null && + 'method' in node && + 'path' in node + ); +} + +function flattenOperations(node: unknown, prefix = ''): OperationEntry[] { + const out: OperationEntry[] = []; + if (typeof node !== 'object' || node === null) return out; + for (const [key, value] of Object.entries(node)) { + if (isDefinition(value)) { + out.push({ path: `${prefix}${key}`, def: value }); + } else { + out.push(...flattenOperations(value, `${prefix}${key}.`)); + } + } + return out; +} + +const ALL_OPERATIONS = flattenOperations(apifyOperations); + +describe('apify operation registry', () => { + it('registers a non-empty set of operations', () => { + expect(ALL_OPERATIONS.length).toBeGreaterThan(0); + // Sanity bound: the registry covers many Apify resources, so it is large. + expect(ALL_OPERATIONS.length).toBeGreaterThan(100); + }); + + it('gives every operation a valid HTTP method and absolute path', () => { + const allowedMethods = new Set([ + 'GET', + 'POST', + 'PUT', + 'DELETE', + 'PATCH', + 'HEAD', + ]); + for (const { def } of ALL_OPERATIONS) { + expect(allowedMethods.has(def.method)).toBe(true); + expect(def.path.startsWith('/v2/')).toBe(true); + expect(typeof def.description).toBe('string'); + expect(def.description.length).toBeGreaterThan(0); + } + }); + + it('declares every path param used in the URL template', () => { + for (const { def } of ALL_OPERATIONS) { + const templateParams = (def.path.match(/\{(\w+)\}/g) ?? []).map((t) => + t.slice(1, -1), + ); + for (const param of templateParams) { + expect(def.pathParams).toContain(param); + } + } + }); + + it('marks DELETE operations with the right risk level', () => { + for (const { def } of ALL_OPERATIONS) { + if (def.method !== 'DELETE') continue; + // Two DELETE families are intentionally non-destructive: + // - /lock paths release a temporary request-queue lock (re-acquirable), + // so they are a write, not destructive, and never irreversible. + // - /v2/browser-info is a read-style endpoint the provider exposes + // across all HTTP verbs; the DELETE variant must not be destructive. + const releasesLock = def.path.endsWith('/lock'); + const isBrowserInfo = def.path === '/v2/browser-info'; + if (releasesLock || isBrowserInfo) { + expect(def.riskLevel).not.toBe('destructive'); + expect(def.irreversible).not.toBe(true); + } else { + // Every other DELETE removes a real Apify resource. + expect(def.riskLevel).toBe('destructive'); + } + } + }); +}); + +describe('apify endpoint tree', () => { + it('exposes a callable function for every registered operation', () => { + expect(typeof ApifyEndpoints).toBe('object'); + // Every leaf in the operation tree has a matching endpoint function. + const actNode = (ApifyEndpoints as Record).act; + expect(typeof actNode).toBe('object'); + expect( + typeof (actNode as Record unknown>).get, + ).toBe('function'); + }); +}); + +describe('apify endpoint schemas', () => { + const schemas = buildApifyEndpointSchemas(apifyOperations); + const schemaMap = schemas as unknown as Record< + string, + { + input: { safeParse: (v: unknown) => { success: boolean } }; + output: unknown; + } + >; + + it('builds an input/output schema entry for every operation', () => { + const schemaKeys = Object.keys(schemaMap); + expect(schemaKeys.length).toBe(ALL_OPERATIONS.length); + for (const { path } of ALL_OPERATIONS) { + expect(schemaMap[path]).toBeDefined(); + } + }); + + it('treats each path param as a required string|number input', () => { + const sample = schemaMap['act.get']; + expect(sample).toBeDefined(); + const parsed = sample?.input.safeParse({ actorId: 'abc123' }); + expect(parsed?.success).toBe(true); + }); + + it('rejects inputs missing a required path param', () => { + const sample = schemaMap['act.get']; + expect(sample).toBeDefined(); + const parsed = sample?.input.safeParse({}); + expect(parsed?.success).toBe(false); + }); + + it('preserves optional query/body passthrough fields', () => { + const parsed = ApifyOperationInputSchema.safeParse({ + query: { limit: 10 }, + body: { foo: 'bar' }, + }); + expect(parsed.success).toBe(true); + }); + + it('uses a passthrough output schema', () => { + expect(ApifyOperationOutputSchema.safeParse({ any: 'thing' }).success).toBe( + true, + ); + }); +}); + +describe('apify endpoint meta', () => { + const meta = buildApifyEndpointMeta(apifyOperations); + const metaMap = meta as unknown as Record< + string, + { riskLevel: string; irreversible?: boolean } + >; + + it('captures risk metadata for every operation', () => { + expect(Object.keys(metaMap).length).toBe(ALL_OPERATIONS.length); + for (const { path } of ALL_OPERATIONS) { + expect(metaMap[path]?.riskLevel).toBeDefined(); + } + }); + + it('tags actor delete as irreversible', () => { + expect(metaMap['act.delete']?.riskLevel).toBe('destructive'); + expect(metaMap['act.delete']?.irreversible).toBe(true); + }); +}); diff --git a/packages/apify/package.json b/packages/apify/package.json index 3694fd598..4f96dfd1b 100644 --- a/packages/apify/package.json +++ b/packages/apify/package.json @@ -15,14 +15,18 @@ }, "scripts": { "build": "rm -rf dist && tsc --build --force && tsup", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "test": "jest" }, "peerDependencies": { "corsair": ">=0.1.0", "zod": "^4.1.13" }, "devDependencies": { + "@types/jest": "^29.5.14", "corsair": "workspace:*", + "jest": "^29.7.0", + "ts-jest": "^29.4.9", "tsup": "^8.0.1", "typescript": "catalog:", "zod": "^4.1.13" diff --git a/packages/apify/tsconfig.json b/packages/apify/tsconfig.json index 360eafeaf..15e507a13 100644 --- a/packages/apify/tsconfig.json +++ b/packages/apify/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "lib": ["esnext"], - "types": ["node"], + "types": ["node", "jest"], "module": "ESNext", "moduleResolution": "Bundler", "outDir": "./dist", From 88bc8fb2f7176a6cc4651cfc22dc0c37edcf34dd Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 22:03:43 +0530 Subject: [PATCH 08/15] fix(apify): sync pnpm-lock with main after merge --- pnpm-lock.yaml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1a00440f..8f4d49ec0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -147,9 +147,6 @@ importers: '@corsair-dev/agentql': specifier: workspace:* version: link:../../packages/agentql - '@corsair-dev/apify': - specifier: workspace:* - version: link:../../packages/apify '@corsair-dev/bitwarden': specifier: workspace:* version: link:../../packages/bitwarden @@ -382,9 +379,18 @@ importers: packages/apify: devDependencies: + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 corsair: specifier: workspace:* version: link:../corsair + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + ts-jest: + specifier: ^29.4.9 + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) @@ -392,8 +398,8 @@ importers: specifier: 'catalog:' version: 5.9.3 zod: - specifier: ^4.1.13 - version: 4.1.13 + specifier: 4.4.3 + version: 4.4.3 packages/app: dependencies: From c28c9bfdb03625f4ef9b508275bb6aae51620134 Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 22:46:05 +0530 Subject: [PATCH 09/15] fix(apify): nest charge/resurrect ops under actorRun --- packages/apify/endpoints/operations.ts | 44 +++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apify/endpoints/operations.ts b/packages/apify/endpoints/operations.ts index c50308814..261077212 100644 --- a/packages/apify/endpoints/operations.ts +++ b/packages/apify/endpoints/operations.ts @@ -769,6 +769,13 @@ export const apifyOperations = { riskLevel: 'write', description: 'Abort run', }, + chargePost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/charge', + pathParams: ['runId'], + riskLevel: 'write', + description: 'Charge events in run', + }, datasetDelete: { method: 'DELETE', path: '/v2/actor-runs/{runId}/dataset', @@ -1083,6 +1090,21 @@ export const apifyOperations = { riskLevel: 'write', description: 'Unlock requests in default request queue', }, + resurrectPost: { + method: 'POST', + path: '/v2/actor-runs/{runId}/resurrect', + pathParams: ['runId'], + queryParams: [ + 'build', + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + ], + riskLevel: 'write', + description: 'Resurrect run', + }, }, actorRuns: { get: { @@ -1880,28 +1902,6 @@ export const apifyOperations = { description: 'Get log', }, }, - postChargeRun: { - method: 'POST', - path: '/v2/actor-runs/{runId}/charge', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Charge events in run', - }, - postResurrectRun: { - method: 'POST', - path: '/v2/actor-runs/{runId}/resurrect', - pathParams: ['runId'], - queryParams: [ - 'build', - 'timeout', - 'memory', - 'maxItems', - 'maxTotalChargeUsd', - 'restartOnError', - ], - riskLevel: 'write', - description: 'Resurrect run', - }, requestQueue: { delete: { method: 'DELETE', From 39ab998cf757abee4d4555575ecceae59764277d Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 22:46:15 +0530 Subject: [PATCH 10/15] test(apify): exercise endpoint invocation and request building --- packages/apify/operations.test.ts | 166 ++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/packages/apify/operations.test.ts b/packages/apify/operations.test.ts index 2fa0cd85a..73f7104ae 100644 --- a/packages/apify/operations.test.ts +++ b/packages/apify/operations.test.ts @@ -1,3 +1,4 @@ +import { request } from 'corsair/http'; import type { ApifyOperationDefinition } from './endpoints'; import { ApifyEndpoints, @@ -9,6 +10,21 @@ import { ApifyOperationInputSchema, ApifyOperationOutputSchema, } from './endpoints/types'; +import type { ApifyContext } from './index'; +import { apify } from './index'; + +// Mock the shared HTTP transport so endpoint invocations exercise the full +// request-building path (makeApifyRequest → buildBody/buildQuery/pickDefined) +// without hitting the network. +jest.mock('corsair/http', () => { + const original = jest.requireActual('corsair/http'); + return { + ...original, + request: jest.fn(), + }; +}); + +const mockRequest = request as jest.MockedFunction; type OperationEntry = { path: string; def: ApifyOperationDefinition }; @@ -172,3 +188,153 @@ describe('apify endpoint meta', () => { expect(metaMap['act.delete']?.irreversible).toBe(true); }); }); + +// A minimal context carrying just the fields the endpoint closures read. +// makeApifyRequest consumes ctx.key; logEventFromContext reads ctx for logging. +function makeCtx(key = 'test-token'): ApifyContext { + return { key } as unknown as ApifyContext; +} + +describe('apify endpoint invocation', () => { + beforeEach(() => mockRequest.mockReset()); + + it('routes an endpoint call to makeApifyRequest with the right method, path, and bearer token', async () => { + mockRequest.mockResolvedValue({ id: 'actor-1' }); + + const result = await ( + ApifyEndpoints as unknown as { + act: { get: (ctx: ApifyContext, input: unknown) => Promise }; + } + ).act.get(makeCtx(), { actorId: 'abc123' }); + + expect(mockRequest).toHaveBeenCalledTimes(1); + const [config, requestOptions] = mockRequest.mock.calls[0] ?? []; + expect(config).toMatchObject({ + BASE: 'https://api.apify.com', + TOKEN: 'test-token', + }); + expect(requestOptions).toMatchObject({ + method: 'GET', + url: '/v2/actors/{actorId}', + }); + expect(requestOptions?.path).toEqual({ actorId: 'abc123' }); + // GET requests carry no body. + expect(requestOptions?.body).toBeUndefined(); + expect(result).toEqual({ id: 'actor-1' }); + }); + + it('builds a JSON body from non-reserved input fields on POST', async () => { + mockRequest.mockResolvedValue({ ok: true }); + + await ( + ApifyEndpoints as unknown as { + actorRun: { + chargePost: (ctx: ApifyContext, input: unknown) => Promise; + }; + } + ).actorRun.chargePost(makeCtx(), { runId: 'r1', events: [{ e: 1 }] }); + + const requestOptions = mockRequest.mock.calls[0]?.[1]; + expect(requestOptions).toMatchObject({ + method: 'POST', + url: '/v2/actor-runs/{runId}/charge', + body: { events: [{ e: 1 }] }, + }); + expect(requestOptions?.path).toEqual({ runId: 'r1' }); + }); + + it('passes query params through without polluting the body', async () => { + mockRequest.mockResolvedValue([]); + + await ( + ApifyEndpoints as unknown as { + act: { + buildsGet: (ctx: ApifyContext, input: unknown) => Promise; + }; + } + ).act.buildsGet(makeCtx(), { actorId: 'a1', limit: 5, offset: 10 }); + + const requestOptions = mockRequest.mock.calls[0]?.[1]; + expect(requestOptions?.query).toMatchObject({ limit: 5, offset: 10 }); + // Query/path params are excluded from the body. + expect(requestOptions?.body).toBeUndefined(); + }); + + it('returns { success: true } for an empty response on non-HEAD requests', async () => { + mockRequest.mockResolvedValue(undefined); + + const result = await ( + ApifyEndpoints as unknown as { + actorRun: { + delete: (ctx: ApifyContext, input: unknown) => Promise; + }; + } + ).actorRun.delete(makeCtx(), { runId: 'r1' }); + + expect(result).toEqual({ success: true }); + }); + + it('wraps non-Api errors in ApifyAPIError before surfacing them', async () => { + mockRequest.mockRejectedValue(new Error('network down')); + + await expect( + ( + ApifyEndpoints as unknown as { + act: { get: (ctx: ApifyContext, input: unknown) => Promise }; + } + ).act.get(makeCtx(), { actorId: 'abc123' }), + ).rejects.toThrow('network down'); + }); +}); + +describe('apify plugin factory', () => { + it('routes the inline key through keyBuilder before any request', async () => { + const plugin = apify({ key: 'inline-key' }); + const ctx = { + authType: 'api_key', + keys: { get_api_key: jest.fn().mockResolvedValue('stored-key') }, + }; + const keyBuilder = plugin.keyBuilder as unknown as ( + ctx: { authType: string; keys: { get_api_key: () => Promise } }, + source: string, + ) => Promise; + + const key = await keyBuilder(ctx, 'endpoint'); + expect(key).toBe('inline-key'); + }); + + it('falls back to the key store when no inline key is set', async () => { + const plugin = apify({}); + const getApiKey = jest.fn().mockResolvedValue('stored-key'); + const ctx = { authType: 'api_key', keys: { get_api_key: getApiKey } }; + const keyBuilder = plugin.keyBuilder as unknown as ( + ctx: { authType: string; keys: { get_api_key: () => Promise } }, + source: string, + ) => Promise; + + const key = await keyBuilder(ctx, 'endpoint'); + expect(getApiKey).toHaveBeenCalled(); + expect(key).toBe('stored-key'); + }); + + it('throws AuthMissingError when no key is available', async () => { + const plugin = apify({}); + const ctx = { + authType: 'api_key', + keys: { get_api_key: jest.fn().mockResolvedValue(undefined) }, + }; + const keyBuilder = plugin.keyBuilder as unknown as ( + ctx: { authType: string; keys: { get_api_key: () => Promise } }, + source: string, + ) => Promise; + + await expect(keyBuilder(ctx, 'endpoint')).rejects.toThrow('api_key'); + }); + + it('registers error handlers covering rate-limit and auth errors', () => { + const plugin = apify({}); + expect(plugin.errorHandlers?.RATE_LIMIT_ERROR).toBeDefined(); + expect(plugin.errorHandlers?.AUTH_ERROR).toBeDefined(); + expect(plugin.errorHandlers?.DEFAULT).toBeDefined(); + }); +}); From 600181a29720f5af3834a786801f1a683ace002b Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Wed, 15 Jul 2026 23:04:56 +0530 Subject: [PATCH 11/15] test(apify): cover endpoint invocation across all namespaces --- packages/apify/operations.test.ts | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/packages/apify/operations.test.ts b/packages/apify/operations.test.ts index 73f7104ae..52bed1774 100644 --- a/packages/apify/operations.test.ts +++ b/packages/apify/operations.test.ts @@ -285,8 +285,81 @@ describe('apify endpoint invocation', () => { ).act.get(makeCtx(), { actorId: 'abc123' }), ).rejects.toThrow('network down'); }); + + // Drive one endpoint from EVERY top-level namespace so request-building + // (path/query/body wiring) is exercised across the full registered surface, + // not just act.* and actorRun.*. + it('routes the first operation of every namespace to its declared path and method', async () => { + mockRequest.mockResolvedValue({ ok: true }); + const endpoints = ApifyEndpoints as unknown as Record< + string, + Record Promise> + >; + + for (const sample of sampleOperationPerNamespace()) { + const { namespace, opName, def } = sample; + const nsEndpoints = endpoints[namespace]; + expect(nsEndpoints).toBeDefined(); + const endpointFn = nsEndpoints?.[opName]; + expect(endpointFn).toBeDefined(); + mockRequest.mockClear(); + // Build a deterministic input: a string value for each declared path param. + const input: Record = {}; + for (const param of def.pathParams) { + input[param] = `sample-${param}`; + } + // Invoke the endpoint closure — this exercises makeApifyRequest's + // full request-building path (pickDefined/buildQuery/buildBody). + await endpointFn?.(makeCtx(), input); + + const requestOptions = mockRequest.mock.calls[0]?.[1]; + expect(requestOptions?.method).toBe(def.method); + expect(requestOptions?.url).toBe(def.path); + } + }); }); +// For every top-level namespace, pick its first leaf operation. Returns the +// namespace, the operation name, and the operation definition so the caller can +// build an input and assert the routed request. +function sampleOperationPerNamespace(): Array<{ + namespace: string; + opName: string; + def: ApifyOperationDefinition; +}> { + const out: Array<{ + namespace: string; + opName: string; + def: ApifyOperationDefinition; + }> = []; + const root = apifyOperations as unknown as Record; + for (const [namespace, node] of Object.entries(root)) { + const entry = firstLeaf(node); + if (entry) out.push({ namespace, opName: entry.opName, def: entry.def }); + } + return out; +} + +function firstLeaf( + node: unknown, +): { opName: string; def: ApifyOperationDefinition } | undefined { + if (typeof node !== 'object' || node === null) return undefined; + for (const [key, value] of Object.entries(node as Record)) { + if ( + typeof value === 'object' && + value !== null && + 'method' in value && + 'path' in value + ) { + return { opName: key, def: value as unknown as ApifyOperationDefinition }; + } + // Descend into subtrees. + const nested = firstLeaf(value); + if (nested) return nested; + } + return undefined; +} + describe('apify plugin factory', () => { it('routes the inline key through keyBuilder before any request', async () => { const plugin = apify({ key: 'inline-key' }); From 71ec835caf86eb826d9cf89898d1d0318354f5ea Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Thu, 23 Jul 2026 18:19:45 +0530 Subject: [PATCH 12/15] fix(apify): guard logging failures and keep DEFAULT error handler last --- packages/apify/endpoints/index.ts | 25 ++++++++++++++++--------- packages/apify/index.ts | 14 ++++++++++---- packages/apify/operations.test.ts | 31 ++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/packages/apify/endpoints/index.ts b/packages/apify/endpoints/index.ts index fdfc285e5..2a263c3dd 100644 --- a/packages/apify/endpoints/index.ts +++ b/packages/apify/endpoints/index.ts @@ -51,15 +51,22 @@ function buildEndpointTree( input: ApifyOperationInput, ) => { const response = await makeApifyRequest(value, ctx.key, input ?? {}); - await logEventFromContext( - ctx, - `apify.${operationPath}`, - { - method: value.method, - path: value.path, - }, - 'completed', - ); + // Never let logging failures convert a successful Apify response into + // an error for the caller (logEventFromContext also swallows, but keep + // this defensive so the success path always returns). + try { + await logEventFromContext( + ctx, + `apify.${operationPath}`, + { + method: value.method, + path: value.path, + }, + 'completed', + ); + } catch { + // ignore + } return response; }; } else { diff --git a/packages/apify/index.ts b/packages/apify/index.ts index 41d38e82e..71e451e21 100644 --- a/packages/apify/index.ts +++ b/packages/apify/index.ts @@ -98,10 +98,16 @@ export function apify( endpointSchemas: apifyEndpointSchemas, webhookSchemas: apifyWebhookSchemas, pluginWebhookMatcher: () => false, - errorHandlers: { - ...errorHandlers, - ...options.errorHandlers, - }, + errorHandlers: (() => { + // DEFAULT matches everything (`() => true`), so it must always be + // evaluated last — otherwise caller-supplied handlers become dead code. + const { DEFAULT: defaultHandler, ...specificDefaults } = errorHandlers; + return { + ...specificDefaults, + ...(options.errorHandlers || {}), + DEFAULT: options.errorHandlers?.DEFAULT || defaultHandler, + }; + })(), keyBuilder: async (ctx: ApifyKeyBuilderContext, source) => { if (source === 'endpoint' && options.key) return options.key; diff --git a/packages/apify/operations.test.ts b/packages/apify/operations.test.ts index 52bed1774..0aaf55011 100644 --- a/packages/apify/operations.test.ts +++ b/packages/apify/operations.test.ts @@ -1,3 +1,4 @@ +import { logEventFromContext } from 'corsair/core'; import { request } from 'corsair/http'; import type { ApifyOperationDefinition } from './endpoints'; import { @@ -24,7 +25,18 @@ jest.mock('corsair/http', () => { }; }); +jest.mock('corsair/core', () => { + const original = jest.requireActual('corsair/core'); + return { + ...original, + logEventFromContext: jest.fn().mockResolvedValue(null), + }; +}); + const mockRequest = request as jest.MockedFunction; +const mockLog = logEventFromContext as jest.MockedFunction< + typeof logEventFromContext +>; type OperationEntry = { path: string; def: ApifyOperationDefinition }; @@ -196,7 +208,11 @@ function makeCtx(key = 'test-token'): ApifyContext { } describe('apify endpoint invocation', () => { - beforeEach(() => mockRequest.mockReset()); + beforeEach(() => { + mockRequest.mockReset(); + mockLog.mockReset(); + mockLog.mockResolvedValue(null); + }); it('routes an endpoint call to makeApifyRequest with the right method, path, and bearer token', async () => { mockRequest.mockResolvedValue({ id: 'actor-1' }); @@ -223,6 +239,19 @@ describe('apify endpoint invocation', () => { expect(result).toEqual({ id: 'actor-1' }); }); + it('still returns the Apify response when logging throws', async () => { + mockRequest.mockResolvedValue({ id: 'actor-1' }); + mockLog.mockRejectedValue(new Error('logger down')); + + const result = await ( + ApifyEndpoints as unknown as { + act: { get: (ctx: ApifyContext, input: unknown) => Promise }; + } + ).act.get(makeCtx(), { actorId: 'abc123' }); + + expect(result).toEqual({ id: 'actor-1' }); + }); + it('builds a JSON body from non-reserved input fields on POST', async () => { mockRequest.mockResolvedValue({ ok: true }); From fe5a81f6e842fe232d95fd437182929493f8b10c Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Thu, 23 Jul 2026 18:24:47 +0530 Subject: [PATCH 13/15] fix(apify): repair pnpm-lock after main merge (ts-jest importer) --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 386473f70..f6ccf29c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -432,7 +432,7 @@ importers: version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) ts-jest: specifier: ^29.4.9 - version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@30.4.1)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.27.0)(jest-util@30.4.1)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.0.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) From a106074d98ef573ef0c73d040da4adda6cebe9f8 Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Fri, 24 Jul 2026 07:57:05 +0530 Subject: [PATCH 14/15] fix(apify): trim ops to OSS listing (113) and drop comments --- packages/apify/client.ts | 1 - packages/apify/endpoints/index.ts | 13 +- packages/apify/endpoints/operations.ts | 2578 ++++++++---------------- packages/apify/endpoints/types.ts | 8 - packages/apify/error-handlers.ts | 2 +- packages/apify/index.ts | 2 - packages/apify/operations.test.ts | 131 +- packages/apify/schema/database.ts | 1 - 8 files changed, 960 insertions(+), 1776 deletions(-) diff --git a/packages/apify/client.ts b/packages/apify/client.ts index 4a41b8123..baee04472 100644 --- a/packages/apify/client.ts +++ b/packages/apify/client.ts @@ -26,7 +26,6 @@ const RESERVED_INPUT_KEYS = new Set([ 'mediaType', ]); -// Apify accepts and returns endpoint-specific JSON that the generic client passes through unchanged. type ApifyJsonValue = unknown; type ApifyJsonRecord = Record; diff --git a/packages/apify/endpoints/index.ts b/packages/apify/endpoints/index.ts index 2a263c3dd..1c8a16b14 100644 --- a/packages/apify/endpoints/index.ts +++ b/packages/apify/endpoints/index.ts @@ -40,7 +40,6 @@ function buildEndpointTree( tree: T, segments: string[] = [], ): ApifyEndpointTree { - // The recursive builder accumulates heterogeneous endpoint functions before the final typed tree cast. const endpoints: Record = {}; for (const [key, value] of Object.entries(tree)) { @@ -51,9 +50,6 @@ function buildEndpointTree( input: ApifyOperationInput, ) => { const response = await makeApifyRequest(value, ctx.key, input ?? {}); - // Never let logging failures convert a successful Apify response into - // an error for the caller (logEventFromContext also swallows, but keep - // this defensive so the success path always returns). try { await logEventFromContext( ctx, @@ -64,9 +60,7 @@ function buildEndpointTree( }, 'completed', ); - } catch { - // ignore - } + } catch {} return response; }; } else { @@ -79,11 +73,8 @@ function buildEndpointTree( function createOperationInputSchema(operation: ApifyOperationDefinition) { const shape: Record = { - // Apify operation bodies vary per endpoint and can include arbitrary JSON payloads. body: z.unknown().optional(), - // Query values are endpoint-specific primitives preserved by the generic operation router. query: z.record(z.string(), z.unknown()).optional(), - // Custom headers are passed through to Apify without a stable provider-wide shape. headers: z.record(z.string(), z.unknown()).optional(), contentType: z.string().optional(), mediaType: z.string().optional(), @@ -94,7 +85,6 @@ function createOperationInputSchema(operation: ApifyOperationDefinition) { } for (const param of operation.queryParams ?? []) { - // Generated query metadata names the parameter but does not constrain its provider-specific value type. shape[param] = z.unknown().optional(); } @@ -105,7 +95,6 @@ export function buildApifyEndpointSchemas( tree: T, segments: string[] = [], ): RequiredPluginEndpointSchemas> { - // Schema entries are accumulated by dotted operation path before the typed schema-map cast. const schemas: Record = {}; for (const [key, value] of Object.entries(tree)) { diff --git a/packages/apify/endpoints/operations.ts b/packages/apify/endpoints/operations.ts index 261077212..1225c9840 100644 --- a/packages/apify/endpoints/operations.ts +++ b/packages/apify/endpoints/operations.ts @@ -16,6 +16,7 @@ export type ApifyOperationDefinition = { riskLevel: EndpointRiskLevel; irreversible?: boolean; description: string; + slug: string; }; export type ApifyOperationTree = { @@ -23,117 +24,127 @@ export type ApifyOperationTree = { }; export const apifyOperations = { - act: { - buildAbortPost: { + actorBuilds: { + abortActorBuild: { method: 'POST', - path: '/v2/actors/{actorId}/builds/{buildId}/abort', - pathParams: ['actorId', 'buildId'], + path: '/v2/actor-builds/{buildId}/abort', + pathParams: ['buildId'], riskLevel: 'write', - description: 'Deprecated. Abort build', + description: + 'Tool to abort an Actor build that is starting or running. Use when you need to cancel a build in progress. Builds in terminal states (FINISHED, FAILED, ABORTING, TIMED-OUT) are not affected.', + slug: 'APIFY_ACTOR_BUILD_ABORT_POST', + }, + deleteActorBuild: { + method: 'DELETE', + path: '/v2/actor-builds/{buildId}', + pathParams: ['buildId'], + riskLevel: 'destructive', + irreversible: true, + description: + 'Tool to delete an Actor build permanently. Use when you need to remove a specific build by its ID. The default build for an Actor cannot be deleted. Only users with build permissions can delete builds.', + slug: 'APIFY_ACTOR_BUILD_DELETE', }, - buildDefaultGet: { + getActorBuild: { method: 'GET', - path: '/v2/actors/{actorId}/builds/default', - pathParams: ['actorId'], + path: '/v2/actor-builds/{buildId}', + pathParams: ['buildId'], queryParams: ['waitForFinish'], riskLevel: 'read', - description: 'Get default build', + description: + 'Tool to get detailed information about a specific Actor build. Use when you need to retrieve complete build details by build ID. Optionally wait for the build to finish using the waitForFinish parameter to avoid polling.', + slug: 'APIFY_ACTOR_BUILD_GET', }, - buildGet: { + getActorBuildLog: { method: 'GET', - path: '/v2/actors/{actorId}/builds/{buildId}', - pathParams: ['actorId', 'buildId'], - queryParams: ['waitForFinish'], + path: '/v2/actor-builds/{buildId}/log', + pathParams: ['buildId'], + queryParams: ['stream', 'download'], riskLevel: 'read', - description: 'Deprecated. Get build', + description: + 'Tool to retrieve the log file for a specific Actor build. Use when you need to inspect logs generated during an Actor build process. Only the trailing 5 million characters of the log are stored.', + slug: 'APIFY_ACTOR_BUILD_LOG_GET', }, - buildsGet: { + getUserBuildsList: { method: 'GET', - path: '/v2/actors/{actorId}/builds', - pathParams: ['actorId'], + path: '/v2/actor-builds', + pathParams: [], queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: 'Get list of builds', + description: + 'Tool to get a paginated list of all builds for a user. Use when you need to retrieve build history across all actors. Supports pagination up to 1000 records.', + slug: 'APIFY_ACTOR_BUILDS_GET', }, - buildsPost: { + }, + actorRuns: { + abortActorRun: { method: 'POST', - path: '/v2/actors/{actorId}/builds', - pathParams: ['actorId'], - queryParams: [ - 'version', - 'useCache', - 'betaPackages', - 'tag', - 'waitForFinish', - ], + path: '/v2/actor-runs/{runId}/abort', + pathParams: ['runId'], + queryParams: ['gracefully'], riskLevel: 'write', - description: 'Build Actor', + description: + 'Tool to abort a running or starting Actor run. Use when you need to stop an Actor run that is currently in STARTING or RUNNING status. For runs with status FINISHED, FAILED, ABORTING, and TIMED-OUT this call does nothing.', + slug: 'APIFY_ACTOR_RUN_ABORT_POST', }, - delete: { + deleteActorRun: { method: 'DELETE', - path: '/v2/actors/{actorId}', - pathParams: ['actorId'], + path: '/v2/actor-runs/{runId}', + pathParams: ['runId'], riskLevel: 'destructive', irreversible: true, - description: 'Delete Actor', - }, - get: { - method: 'GET', - path: '/v2/actors/{actorId}', - pathParams: ['actorId'], - riskLevel: 'read', - description: 'Get Actor', + description: + 'Tool to delete a finished Actor run. Use when you need to permanently remove a completed run. Only finished runs can be deleted by the initiating user or organization.', + slug: 'APIFY_ACTOR_RUN_DELETE', }, - openapiJsonGet: { + getActorRun: { method: 'GET', - path: '/v2/actors/{actorId}/builds/{buildId}/openapi.json', - pathParams: ['actorId', 'buildId'], + path: '/v2/actor-runs/{runId}', + pathParams: ['runId'], + queryParams: ['waitForFinish'], riskLevel: 'read', - description: 'Get OpenAPI definition', - }, - put: { - method: 'PUT', - path: '/v2/actors/{actorId}', - pathParams: ['actorId'], - riskLevel: 'write', - description: 'Update Actor', - }, - runAbortPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/{runId}/abort', - pathParams: ['actorId', 'runId'], - queryParams: ['gracefully'], - riskLevel: 'write', - description: 'Deprecated. Abort run', + description: + 'Tool to get details about a specific Actor run. Use when you need to retrieve comprehensive information about a run including its execution status, resource usage, storage IDs, and metadata.', + slug: 'APIFY_ACTOR_RUN_GET', }, - runGet: { + getRunDatasetItems: { method: 'GET', - path: '/v2/actors/{actorId}/runs/{runId}', - pathParams: ['actorId', 'runId'], - queryParams: ['waitForFinish'], + path: '/v2/actor-runs/{runId}/dataset/items', + pathParams: ['runId'], + queryParams: [ + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + 'signature', + ], riskLevel: 'read', - description: 'Deprecated. Get run', - }, - runMetamorphPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/{runId}/metamorph', - pathParams: ['actorId', 'runId'], - queryParams: ['targetActorId', 'build'], - riskLevel: 'write', - description: 'Deprecated. Metamorph run', - }, - runResurrectPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/{runId}/resurrect', - pathParams: ['actorId', 'runId'], - queryParams: ['build', 'timeout', 'memory', 'restartOnError'], - riskLevel: 'write', - description: 'Resurrect run', + description: + 'Tool to get dataset items from a specific Actor run. Use when you need to retrieve the output data from a completed or running Actor run.', + slug: 'APIFY_GET_RUN_DATASET_ITEMS', }, - runsGet: { + listUserActorRuns: { method: 'GET', - path: '/v2/actors/{actorId}/runs', - pathParams: ['actorId'], + path: '/v2/actor-runs', + pathParams: [], queryParams: [ 'offset', 'limit', @@ -143,37 +154,79 @@ export const apifyOperations = { 'startedBefore', ], riskLevel: 'read', - description: 'Get list of runs', + description: + 'Tool to get a paginated list of all Actor runs for the authenticated user. Use when you need to browse all runs across all actors, optionally filtered by status or date range.', + slug: 'APIFY_LIST_USER_RUNS', }, - runsLastAbortPost: { + resurrectRun: { method: 'POST', - path: '/v2/actors/{actorId}/runs/last/abort', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'gracefully'], + path: '/v2/actor-runs/{runId}/resurrect', + pathParams: ['runId'], + queryParams: [ + 'build', + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + ], + riskLevel: 'write', + description: + 'Tool to resurrect a finished Actor run. Use when you need to restart a completed or failed run. Deprecated endpoint; may be removed in future.', + slug: 'APIFY_RESURRECT_RUN', + }, + updateActorRunStatusMessage: { + method: 'PUT', + path: '/v2/actor-runs/{runId}', + pathParams: ['runId'], + riskLevel: 'write', + description: + 'Tool to update the status message of an Actor run. Use when you need to set progress information or status updates that will be displayed in the Apify Console UI during Actor execution.', + slug: 'APIFY_ACTOR_RUN_PUT', + }, + }, + actorTasks: { + createActorTask: { + method: 'POST', + path: '/v2/actor-tasks', + pathParams: [], riskLevel: 'write', - description: "Abort Actor's last run", + description: + 'Tool to create a new Actor task with specified settings. Use when you need to configure or schedule recurring Actor runs programmatically.', + slug: 'APIFY_CREATE_TASK', }, - runsLastDatasetDelete: { + deleteActorTask: { method: 'DELETE', - path: '/v2/actors/{actorId}/runs/last/dataset', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], + path: '/v2/actor-tasks/{actorTaskId}', + pathParams: ['actorTaskId'], riskLevel: 'destructive', irreversible: true, - description: "Delete last run's default dataset", + description: + 'Tool to delete an Actor task permanently. Use when you need to remove a task by its ID or username\\~taskName. Confirm before calling.', + slug: 'APIFY_ACTOR_TASK_DELETE', }, - runsLastDatasetGet: { + getActorTask: { method: 'GET', - path: '/v2/actors/{actorId}/runs/last/dataset', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], + path: '/v2/actor-tasks/{actorTaskId}', + pathParams: ['actorTaskId'], riskLevel: 'read', - description: "Get last run's default dataset", + description: + 'Tool to get complete details about an Actor task. Use when you need to retrieve task configuration, input settings, or metadata by task ID or username\\~task-name.', + slug: 'APIFY_ACTOR_TASK_GET', }, - runsLastDatasetItemsGet: { + getTaskInput: { method: 'GET', - path: '/v2/actors/{actorId}/runs/last/dataset/items', - pathParams: ['actorId'], + path: '/v2/actor-tasks/{actorTaskId}/input', + pathParams: ['actorTaskId'], + riskLevel: 'read', + description: + 'Tool to retrieve the input configuration of a specific task. Use when you need to inspect stored task input before execution or debugging.', + slug: 'APIFY_GET_TASK_INPUT', + }, + getTaskLastRunDatasetItems: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset/items', + pathParams: ['actorTaskId'], queryParams: [ 'status', 'origin', @@ -203,1008 +256,291 @@ export const apifyOperations = { 'signature', ], riskLevel: 'read', - description: "Get last run's dataset items", - }, - runsLastDatasetItemsPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/last/dataset/items', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Store items in last run's dataset", - }, - runsLastDatasetPut: { - method: 'PUT', - path: '/v2/actors/{actorId}/runs/last/dataset', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Update last run's default dataset", - }, - runsLastDatasetStatisticsGet: { - method: 'GET', - path: '/v2/actors/{actorId}/runs/last/dataset/statistics', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'read', - description: "Get last run's dataset statistics", + description: + "Tool to get dataset items from the last run of an Actor task. Use when you need to retrieve data from the most recent task execution. Filter by status (e.g., 'SUCCEEDED') to get items from the last successful run only.", + slug: 'APIFY_GET_TASK_LAST_RUN_DATASET_ITEMS', }, - runsLastGet: { + getLastActorTaskRun: { method: 'GET', - path: '/v2/actors/{actorId}/runs/last', - pathParams: ['actorId'], + path: '/v2/actor-tasks/{actorTaskId}/runs/last', + pathParams: ['actorTaskId'], queryParams: ['status', 'origin', 'waitForFinish'], riskLevel: 'read', - description: 'Get last run', - }, - runsLastKeyValueStoreDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/runs/last/key-value-store', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete last run's default store", + description: + "Tool to get the most recent run of a specific Actor task. Use when you need to retrieve the last execution details. You can filter by status to get only successful runs using status='SUCCEEDED'.", + slug: 'APIFY_ACTOR_TASK_RUNS_LAST_GET', }, - runsLastKeyValueStoreGet: { + getListOfTaskRuns: { method: 'GET', - path: '/v2/actors/{actorId}/runs/last/key-value-store', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], + path: '/v2/actor-tasks/{actorTaskId}/runs', + pathParams: ['actorTaskId'], + queryParams: ['offset', 'limit', 'desc', 'status'], riskLevel: 'read', - description: "Get last run's default store", + description: + 'Tool to get a list of runs for a specific Actor task. Use when you need to paginate through task runs and optionally filter by status.', + slug: 'APIFY_GET_LIST_OF_TASK_RUNS', }, - runsLastKeyValueStoreKeysGet: { + getListOfTaskWebhooks: { method: 'GET', - path: '/v2/actors/{actorId}/runs/last/key-value-store/keys', - pathParams: ['actorId'], - queryParams: [ - 'status', - 'origin', - 'exclusiveStartKey', - 'limit', - 'collection', - 'prefix', - 'signature', - ], + path: '/v2/actor-tasks/{actorTaskId}/webhooks', + pathParams: ['actorTaskId'], + queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: "Get last run's default store's list of keys", - }, - runsLastKeyValueStorePut: { - method: 'PUT', - path: '/v2/actors/{actorId}/runs/last/key-value-store', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Update last run's default store", - }, - runsLastKeyValueStoreRecordDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorId', 'recordKey'], - queryParams: ['status', 'origin'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete last run's default store's record", + description: + 'Tool to get a list of webhooks for a specific Actor task. Use when you need to review or paginate webhooks after creating or updating a task.', + slug: 'APIFY_GET_LIST_OF_TASK_WEBHOOKS', }, - runsLastKeyValueStoreRecordGet: { + getListOfTasks: { method: 'GET', - path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorId', 'recordKey'], - queryParams: ['status', 'origin', 'signature', 'attachment'], + path: '/v2/actor-tasks', + pathParams: [], + queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: "Get last run's default store's record", + description: + 'Tool to fetch a paginated list of tasks belonging to the authenticated user. Use when you need to browse or sort tasks created by the user.', + slug: 'APIFY_GET_LIST_OF_TASKS', }, - runsLastKeyValueStoreRecordPost: { + runTaskAsynchronously: { method: 'POST', - path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorId', 'recordKey'], - queryParams: ['status', 'origin'], + path: '/v2/actor-tasks/{actorTaskId}/runs', + pathParams: ['actorTaskId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'waitForFinish', + 'webhooks', + ], riskLevel: 'write', - description: "Store record in last run's default store (POST)", + description: + 'Tool to run a specific Actor task asynchronously. Use when you need to trigger a task run without waiting for completion and immediately retrieve its run details.', + slug: 'APIFY_RUN_TASK', }, - runsLastKeyValueStoreRecordPut: { - method: 'PUT', - path: '/v2/actors/{actorId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorId', 'recordKey'], - queryParams: ['status', 'origin'], + runTaskSyncGetDatasetItems: { + method: 'GET', + path: '/v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items', + pathParams: ['actorTaskId'], + queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'build', + 'webhooks', + 'format', + 'clean', + 'offset', + 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', + 'desc', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', + ], riskLevel: 'write', - description: "Store record in last run's default store", + description: + 'Tool to run an actor task synchronously and retrieve its dataset items. Use when immediate access to task run results is needed. The run must finish within 300 seconds otherwise the request times out. For large datasets exceeding the timeout, use `limit`/`offset` pagination to retrieve results in smaller batches or switch to an async run pattern with a separate dataset retrieval call.', + slug: 'APIFY_ACTOR_TASK_RUN_SYNC_GET_DATASET_ITEMS_GET', }, - runsLastKeyValueStoreRecordsGet: { + runTaskSyncGet: { method: 'GET', - path: '/v2/actors/{actorId}/runs/last/key-value-store/records', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'collection', 'prefix', 'signature'], - riskLevel: 'read', - description: "Download last run's default store's records", - }, - runsLastLogGet: { - method: 'GET', - path: '/v2/actors/{actorId}/runs/last/log', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'stream', 'download', 'raw'], - riskLevel: 'read', - description: "Get last Actor run's log", - }, - runsLastMetamorphPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/last/metamorph', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'targetActorId', 'build'], - riskLevel: 'write', - description: "Metamorph Actor's last run", - }, - runsLastRebootPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/last/reboot', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Reboot Actor's last run", - }, - runsLastRequestQueueDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/runs/last/request-queue', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete last run's default request queue", - }, - runsLastRequestQueueGet: { - method: 'GET', - path: '/v2/actors/{actorId}/runs/last/request-queue', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'read', - description: "Get last run's default request queue", - }, - runsLastRequestQueueHeadGet: { - method: 'GET', - path: '/v2/actors/{actorId}/runs/last/request-queue/head', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'limit', 'clientKey'], - riskLevel: 'read', - description: "Get last run's default request queue head", - }, - runsLastRequestQueueHeadLockPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/last/request-queue/head/lock', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'lockSecs', 'limit', 'clientKey'], - riskLevel: 'write', - description: "Get and lock last run's default request queue head", - }, - runsLastRequestQueuePut: { - method: 'PUT', - path: '/v2/actors/{actorId}/runs/last/request-queue', - pathParams: ['actorId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Update last run's default request queue", - }, - runsLastRequestQueueRequestDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}', - pathParams: ['actorId', 'requestId'], - queryParams: ['status', 'origin', 'clientKey'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete request from last run's default request queue", - }, - runsLastRequestQueueRequestGet: { - method: 'GET', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}', - pathParams: ['actorId', 'requestId'], - queryParams: ['status', 'origin'], - riskLevel: 'read', - description: "Get request from last run's default request queue", - }, - runsLastRequestQueueRequestLockDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}/lock', - pathParams: ['actorId', 'requestId'], - queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'write', - description: "Delete lock on request in last run's default request queue", - }, - runsLastRequestQueueRequestLockPut: { - method: 'PUT', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}/lock', - pathParams: ['actorId', 'requestId'], - queryParams: ['status', 'origin', 'lockSecs', 'clientKey', 'forefront'], - riskLevel: 'write', - description: - "Prolong lock on request in last run's default request queue", - }, - runsLastRequestQueueRequestPut: { - method: 'PUT', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/{requestId}', - pathParams: ['actorId', 'requestId'], - queryParams: ['status', 'origin', 'forefront', 'clientKey'], - riskLevel: 'write', - description: "Update request in last run's default request queue", - }, - runsLastRequestQueueRequestsBatchDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/batch', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'clientKey'], - riskLevel: 'destructive', - irreversible: true, - description: - "Batch delete requests from last run's default request queue", - }, - runsLastRequestQueueRequestsBatchPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/batch', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'write', - description: "Batch add requests to last run's default request queue", - }, - runsLastRequestQueueRequestsGet: { - method: 'GET', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests', - pathParams: ['actorId'], - queryParams: [ - 'status', - 'origin', - 'clientKey', - 'exclusiveStartId', - 'limit', - 'cursor', - 'filter', - ], - riskLevel: 'read', - description: "List last run's default request queue's requests", - }, - runsLastRequestQueueRequestsPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'write', - description: "Add request to last run's default request queue", - }, - runsLastRequestQueueRequestsUnlockPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs/last/request-queue/requests/unlock', - pathParams: ['actorId'], - queryParams: ['status', 'origin', 'clientKey'], - riskLevel: 'write', - description: "Unlock requests in last run's default request queue", - }, - runsPost: { - method: 'POST', - path: '/v2/actors/{actorId}/runs', - pathParams: ['actorId'], - queryParams: [ - 'timeout', - 'memory', - 'maxItems', - 'maxTotalChargeUsd', - 'restartOnError', - 'build', - 'waitForFinish', - 'webhooks', - 'forcePermissionLevel', - ], - riskLevel: 'write', - description: 'Run Actor', - }, - runSyncGet: { - method: 'GET', - path: '/v2/actors/{actorId}/run-sync', - pathParams: ['actorId'], - queryParams: [ - 'outputRecordKey', - 'timeout', - 'memory', - 'maxItems', - 'maxTotalChargeUsd', - 'restartOnError', - 'build', - 'webhooks', - ], - riskLevel: 'write', - description: 'Run Actor synchronously without input', - }, - runSyncGetDatasetItemsGet: { - method: 'GET', - path: '/v2/actors/{actorId}/run-sync-get-dataset-items', - pathParams: ['actorId'], - queryParams: [ - 'timeout', - 'memory', - 'maxItems', - 'maxTotalChargeUsd', - 'restartOnError', - 'build', - 'webhooks', - 'format', - 'clean', - 'offset', - 'limit', - 'fields', - 'outputFields', - 'omit', - 'unwind', - 'flatten', - 'desc', - 'attachment', - 'delimiter', - 'bom', - 'xmlRoot', - 'xmlRow', - 'skipHeaderRow', - 'skipHidden', - 'skipEmpty', - 'simplified', - 'view', - 'skipFailedPages', - 'feedTitle', - 'feedDescription', - ], - riskLevel: 'write', - description: - 'Run Actor synchronously without input and get dataset items', - }, - runSyncGetDatasetItemsPost: { - method: 'POST', - path: '/v2/actors/{actorId}/run-sync-get-dataset-items', - pathParams: ['actorId'], - queryParams: [ - 'timeout', - 'memory', - 'maxItems', - 'maxTotalChargeUsd', - 'restartOnError', - 'build', - 'webhooks', - 'format', - 'clean', - 'offset', - 'limit', - 'fields', - 'outputFields', - 'omit', - 'unwind', - 'flatten', - 'desc', - 'attachment', - 'delimiter', - 'bom', - 'xmlRoot', - 'xmlRow', - 'skipHeaderRow', - 'skipHidden', - 'skipEmpty', - 'simplified', - 'view', - 'skipFailedPages', - 'feedTitle', - 'feedDescription', - ], - riskLevel: 'write', - description: 'Run Actor synchronously and get dataset items', - }, - runSyncPost: { - method: 'POST', - path: '/v2/actors/{actorId}/run-sync', - pathParams: ['actorId'], + path: '/v2/actor-tasks/{actorTaskId}/run-sync', + pathParams: ['actorTaskId'], queryParams: [ - 'outputRecordKey', 'timeout', - 'memory', - 'maxItems', - 'maxTotalChargeUsd', - 'restartOnError', - 'build', - 'webhooks', - ], - riskLevel: 'write', - description: 'Run Actor synchronously and return key-value store record', - }, - validateInputPost: { - method: 'POST', - path: '/v2/actors/{actorId}/validate-input', - pathParams: ['actorId'], - queryParams: ['build'], - riskLevel: 'write', - description: 'Validate Actor input', - }, - versionDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/versions/{versionNumber}', - pathParams: ['actorId', 'versionNumber'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete version', - }, - versionEnvVarDelete: { - method: 'DELETE', - path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', - pathParams: ['actorId', 'versionNumber', 'envVarName'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete environment variable', - }, - versionEnvVarGet: { - method: 'GET', - path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', - pathParams: ['actorId', 'versionNumber', 'envVarName'], - riskLevel: 'read', - description: 'Get environment variable', - }, - versionEnvVarPost: { - method: 'POST', - path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', - pathParams: ['actorId', 'versionNumber', 'envVarName'], - riskLevel: 'write', - description: 'Update environment variable (POST)', - }, - versionEnvVarPut: { - method: 'PUT', - path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', - pathParams: ['actorId', 'versionNumber', 'envVarName'], - riskLevel: 'write', - description: 'Update environment variable', - }, - versionEnvVarsGet: { - method: 'GET', - path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars', - pathParams: ['actorId', 'versionNumber'], - riskLevel: 'read', - description: 'Get list of environment variables', - }, - versionEnvVarsPost: { - method: 'POST', - path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars', - pathParams: ['actorId', 'versionNumber'], - riskLevel: 'write', - description: 'Create environment variable', - }, - versionGet: { - method: 'GET', - path: '/v2/actors/{actorId}/versions/{versionNumber}', - pathParams: ['actorId', 'versionNumber'], - riskLevel: 'read', - description: 'Get version', - }, - versionPost: { - method: 'POST', - path: '/v2/actors/{actorId}/versions/{versionNumber}', - pathParams: ['actorId', 'versionNumber'], - riskLevel: 'write', - description: 'Update version (POST)', - }, - versionPut: { - method: 'PUT', - path: '/v2/actors/{actorId}/versions/{versionNumber}', - pathParams: ['actorId', 'versionNumber'], - riskLevel: 'write', - description: 'Update version', - }, - versionsGet: { - method: 'GET', - path: '/v2/actors/{actorId}/versions', - pathParams: ['actorId'], - riskLevel: 'read', - description: 'Get list of versions', - }, - versionsPost: { - method: 'POST', - path: '/v2/actors/{actorId}/versions', - pathParams: ['actorId'], - riskLevel: 'write', - description: 'Create version', - }, - webhooksGet: { - method: 'GET', - path: '/v2/actors/{actorId}/webhooks', - pathParams: ['actorId'], - queryParams: ['offset', 'limit', 'desc'], - riskLevel: 'read', - description: 'Get list of webhooks', - }, - }, - actorBuild: { - abortPost: { - method: 'POST', - path: '/v2/actor-builds/{buildId}/abort', - pathParams: ['buildId'], - riskLevel: 'write', - description: 'Abort build', - }, - delete: { - method: 'DELETE', - path: '/v2/actor-builds/{buildId}', - pathParams: ['buildId'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete build', - }, - get: { - method: 'GET', - path: '/v2/actor-builds/{buildId}', - pathParams: ['buildId'], - queryParams: ['waitForFinish'], - riskLevel: 'read', - description: 'Get build', - }, - logGet: { - method: 'GET', - path: '/v2/actor-builds/{buildId}/log', - pathParams: ['buildId'], - queryParams: ['stream', 'download'], - riskLevel: 'read', - description: "Get build's Log", - }, - openapiJsonGet: { - method: 'GET', - path: '/v2/actor-builds/{buildId}/openapi.json', - pathParams: ['buildId'], - riskLevel: 'read', - description: 'Get OpenAPI definition', - }, - }, - actorBuilds: { - get: { - method: 'GET', - path: '/v2/actor-builds', - pathParams: [], - queryParams: ['offset', 'limit', 'desc'], - riskLevel: 'read', - description: 'Get user builds list', - }, - }, - actorRun: { - abortPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/abort', - pathParams: ['runId'], - queryParams: ['gracefully'], - riskLevel: 'write', - description: 'Abort run', - }, - chargePost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/charge', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Charge events in run', - }, - datasetDelete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}/dataset', - pathParams: ['runId'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete default dataset', - }, - datasetGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/dataset', - pathParams: ['runId'], - riskLevel: 'read', - description: 'Get default dataset', - }, - datasetItemsGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/dataset/items', - pathParams: ['runId'], - queryParams: [ - 'format', - 'clean', - 'offset', - 'limit', - 'fields', - 'outputFields', - 'omit', - 'unwind', - 'flatten', - 'desc', - 'attachment', - 'delimiter', - 'bom', - 'xmlRoot', - 'xmlRow', - 'skipHeaderRow', - 'skipHidden', - 'skipEmpty', - 'simplified', - 'view', - 'skipFailedPages', - 'feedTitle', - 'feedDescription', - 'signature', - ], - riskLevel: 'read', - description: 'Get default dataset items', - }, - datasetItemsPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/dataset/items', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Store items', - }, - datasetPut: { - method: 'PUT', - path: '/v2/actor-runs/{runId}/dataset', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Update default dataset', - }, - datasetStatisticsGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/dataset/statistics', - pathParams: ['runId'], - riskLevel: 'read', - description: 'Get default dataset statistics', - }, - delete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}', - pathParams: ['runId'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete run', - }, - get: { - method: 'GET', - path: '/v2/actor-runs/{runId}', - pathParams: ['runId'], - queryParams: ['waitForFinish'], - riskLevel: 'read', - description: 'Get run', - }, - keyValueStoreDelete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}/key-value-store', - pathParams: ['runId'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete default store', - }, - keyValueStoreGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/key-value-store', - pathParams: ['runId'], - riskLevel: 'read', - description: 'Get default store', - }, - keyValueStoreKeysGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/key-value-store/keys', - pathParams: ['runId'], - queryParams: [ - 'exclusiveStartKey', - 'limit', - 'collection', - 'prefix', - 'signature', - ], - riskLevel: 'read', - description: "Get default store's list of keys", - }, - keyValueStorePut: { - method: 'PUT', - path: '/v2/actor-runs/{runId}/key-value-store', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Update default store', - }, - keyValueStoreRecordDelete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', - pathParams: ['runId', 'recordKey'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete default store's record", - }, - keyValueStoreRecordGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', - pathParams: ['runId', 'recordKey'], - queryParams: ['signature', 'attachment'], - riskLevel: 'read', - description: "Get default store's record", - }, - keyValueStoreRecordPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', - pathParams: ['runId', 'recordKey'], - riskLevel: 'write', - description: 'Store record in default store (POST)', - }, - keyValueStoreRecordPut: { - method: 'PUT', - path: '/v2/actor-runs/{runId}/key-value-store/records/{recordKey}', - pathParams: ['runId', 'recordKey'], - riskLevel: 'write', - description: 'Store record in default store', - }, - keyValueStoreRecordsGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/key-value-store/records', - pathParams: ['runId'], - queryParams: ['collection', 'prefix', 'signature'], - riskLevel: 'read', - description: "Download default store's records", - }, - logGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/log', - pathParams: ['runId'], - queryParams: ['stream', 'download', 'raw'], - riskLevel: 'read', - description: "Get run's log", - }, - metamorphPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/metamorph', - pathParams: ['runId'], - queryParams: ['targetActorId', 'build'], - riskLevel: 'write', - description: 'Metamorph run', - }, - put: { - method: 'PUT', - path: '/v2/actor-runs/{runId}', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Update run', - }, - rebootPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/reboot', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Reboot run', - }, - requestQueueDelete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}/request-queue', - pathParams: ['runId'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete default request queue', - }, - requestQueueGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/request-queue', - pathParams: ['runId'], - riskLevel: 'read', - description: 'Get default request queue', - }, - requestQueueHeadGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/request-queue/head', - pathParams: ['runId'], - queryParams: ['limit', 'clientKey'], - riskLevel: 'read', - description: 'Get default request queue head', - }, - requestQueueHeadLockPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/request-queue/head/lock', - pathParams: ['runId'], - queryParams: ['lockSecs', 'limit', 'clientKey'], - riskLevel: 'write', - description: 'Get and lock default request queue head', - }, - requestQueuePut: { - method: 'PUT', - path: '/v2/actor-runs/{runId}/request-queue', - pathParams: ['runId'], - riskLevel: 'write', - description: 'Update default request queue', - }, - requestQueueRequestDelete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}', - pathParams: ['runId', 'requestId'], - queryParams: ['clientKey'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete request from default request queue', - }, - requestQueueRequestGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}', - pathParams: ['runId', 'requestId'], - riskLevel: 'read', - description: 'Get request from default request queue', - }, - requestQueueRequestLockDelete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}/lock', - pathParams: ['runId', 'requestId'], - queryParams: ['clientKey', 'forefront'], - riskLevel: 'write', - description: 'Delete lock on request in default request queue', - }, - requestQueueRequestLockPut: { - method: 'PUT', - path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}/lock', - pathParams: ['runId', 'requestId'], - queryParams: ['lockSecs', 'clientKey', 'forefront'], - riskLevel: 'write', - description: 'Prolong lock on request in default request queue', - }, - requestQueueRequestPut: { - method: 'PUT', - path: '/v2/actor-runs/{runId}/request-queue/requests/{requestId}', - pathParams: ['runId', 'requestId'], - queryParams: ['forefront', 'clientKey'], - riskLevel: 'write', - description: 'Update request in default request queue', - }, - requestQueueRequestsBatchDelete: { - method: 'DELETE', - path: '/v2/actor-runs/{runId}/request-queue/requests/batch', - pathParams: ['runId'], - queryParams: ['clientKey'], - riskLevel: 'destructive', - irreversible: true, - description: 'Batch delete requests from default request queue', - }, - requestQueueRequestsBatchPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/request-queue/requests/batch', - pathParams: ['runId'], - queryParams: ['clientKey', 'forefront'], - riskLevel: 'write', - description: 'Batch add requests to default request queue', - }, - requestQueueRequestsGet: { - method: 'GET', - path: '/v2/actor-runs/{runId}/request-queue/requests', - pathParams: ['runId'], - queryParams: [ - 'clientKey', - 'exclusiveStartId', - 'limit', - 'cursor', - 'filter', - ], - riskLevel: 'read', - description: "List default request queue's requests", - }, - requestQueueRequestsPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/request-queue/requests', - pathParams: ['runId'], - queryParams: ['clientKey', 'forefront'], - riskLevel: 'write', - description: 'Add request to default request queue', - }, - requestQueueRequestsUnlockPost: { - method: 'POST', - path: '/v2/actor-runs/{runId}/request-queue/requests/unlock', - pathParams: ['runId'], - queryParams: ['clientKey'], + 'memory', + 'maxItems', + 'build', + 'outputRecordKey', + 'webhooks', + ], riskLevel: 'write', - description: 'Unlock requests in default request queue', + description: + 'Tool to run a specific task synchronously and return its output. Use when immediate task results are needed with pre-configured settings. The run must finish within 300 seconds otherwise the HTTP request fails with a timeout error.', + slug: 'APIFY_ACTOR_TASK_RUN_SYNC_GET', }, - resurrectPost: { + runTaskSyncPost: { method: 'POST', - path: '/v2/actor-runs/{runId}/resurrect', - pathParams: ['runId'], + path: '/v2/actor-tasks/{actorTaskId}/run-sync', + pathParams: ['actorTaskId'], queryParams: [ - 'build', 'timeout', 'memory', 'maxItems', 'maxTotalChargeUsd', 'restartOnError', + 'build', + 'outputRecordKey', + 'webhooks', ], riskLevel: 'write', - description: 'Resurrect run', + description: + 'Tool to run an Actor task synchronously with input override and return its output. Use when immediate task results are needed with custom input parameters. The run must finish within 300 seconds otherwise the HTTP request fails with a timeout error (though the run continues server-side).', + slug: 'APIFY_ACTOR_TASK_RUN_SYNC_POST', }, - }, - actorRuns: { - get: { - method: 'GET', - path: '/v2/actor-runs', - pathParams: [], + runTaskSyncWithInputOverrideGetDatasetItems: { + method: 'POST', + path: '/v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items', + pathParams: ['actorTaskId'], queryParams: [ + 'timeout', + 'memory', + 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', + 'build', + 'webhooks', + 'format', + 'clean', 'offset', 'limit', + 'fields', + 'outputFields', + 'omit', + 'unwind', + 'flatten', 'desc', - 'status', - 'startedAfter', - 'startedBefore', + 'attachment', + 'delimiter', + 'bom', + 'xmlRoot', + 'xmlRow', + 'skipHeaderRow', + 'skipHidden', + 'skipEmpty', + 'simplified', + 'view', + 'skipFailedPages', + 'feedTitle', + 'feedDescription', ], - riskLevel: 'read', - description: 'Get user runs list', - }, - }, - actorTask: { - delete: { - method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}', - pathParams: ['actorTaskId'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete task', + riskLevel: 'write', + description: + 'Tool to run an actor task synchronously with input overrides and retrieve its dataset items. Use when you need to override task input configuration and get immediate results. The run must finish within 300 seconds otherwise the request times out.', + slug: 'APIFY_ACTOR_TASK_RUN_SYNC_GET_DATASET_ITEMS_POST', }, - get: { - method: 'GET', + updateActorTask: { + method: 'PUT', path: '/v2/actor-tasks/{actorTaskId}', pathParams: ['actorTaskId'], - riskLevel: 'read', - description: 'Get task', - }, - inputGet: { - method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/input', - pathParams: ['actorTaskId'], - riskLevel: 'read', - description: 'Get task input', + riskLevel: 'write', + description: + 'Tool to update Actor task settings using JSON payload. Only specified properties are updated; others remain unchanged. Use when you need to modify task configuration, input, or execution options.', + slug: 'APIFY_ACTOR_TASK_PUT', }, - inputPut: { + updateTaskInput: { method: 'PUT', path: '/v2/actor-tasks/{actorTaskId}/input', pathParams: ['actorTaskId'], riskLevel: 'write', - description: 'Update task input', + description: + 'Tool to update the input configuration of a specific Actor task. Use when you need to modify a scheduled tasks input before execution.', + slug: 'APIFY_UPDATE_TASK_INPUT', }, - lastLogGet: { - method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/log', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'stream', 'download', 'raw'], - riskLevel: 'read', - description: "Get last Actor task run's log", + }, + actors: { + buildActor: { + method: 'POST', + path: '/v2/actors/{actorId}/builds', + pathParams: ['actorId'], + queryParams: [ + 'version', + 'useCache', + 'betaPackages', + 'tag', + 'waitForFinish', + ], + riskLevel: 'write', + description: + "Tool to build an Actor with specified configuration. Use when you need to create a new build of an Actor with a specific version. The build process compiles the Actor's source code into a Docker image.", + slug: 'APIFY_ACT_BUILDS_POST', }, - put: { - method: 'PUT', - path: '/v2/actor-tasks/{actorTaskId}', - pathParams: ['actorTaskId'], + createActor: { + method: 'POST', + path: '/v2/actors', + pathParams: [], riskLevel: 'write', - description: 'Update task', + description: + 'Tool to create a new Actor with specified configuration. Use when you need to initialize a fresh Actor programmatically before publishing or running it.', + slug: 'APIFY_CREATE_ACTOR', }, - runsGet: { - method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs', - pathParams: ['actorTaskId'], - queryParams: ['offset', 'limit', 'desc', 'status'], - riskLevel: 'read', - description: 'Get list of task runs', + createActorVersion: { + method: 'POST', + path: '/v2/actors/{actorId}/versions', + pathParams: ['actorId'], + riskLevel: 'write', + description: + 'Tool to create a new version of an Actor. Use when you need to add a new version with specific source code location and configuration. Requires versionNumber and sourceType parameters, plus conditional parameters based on the sourceType.', + slug: 'APIFY_ACT_VERSIONS_POST', }, - runsLastAbortPost: { + createActorVersionEnvironmentVariable: { method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/abort', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'gracefully'], + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars', + pathParams: ['actorId', 'versionNumber'], riskLevel: 'write', - description: "Abort Actor task's last run", + description: + 'Tool to create an environment variable for a specific Actor version. Use when adding new environment variables to Actor versions. Requires name and value parameters.', + slug: 'APIFY_ACT_VERSION_ENV_VARS_POST', }, - runsLastDatasetDelete: { + deleteActor: { method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], + path: '/v2/actors/{actorId}', + pathParams: ['actorId'], + riskLevel: 'destructive', + irreversible: true, + description: + 'Tool to delete an Actor permanently. Use when you need to remove an Actor by its ID or username\\~actorName. Confirm before calling.', + slug: 'APIFY_DELETE_ACTOR', + }, + deleteActorVersion: { + method: 'DELETE', + path: '/v2/actors/{actorId}/versions/{versionNumber}', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'destructive', + irreversible: true, + description: + "Tool to delete a specific version of an Actor's source code. Use when you need to remove an Actor version by actor ID and version number. Confirm before calling.", + slug: 'APIFY_ACT_VERSION_DELETE', + }, + deleteActorVersionEnvironmentVariable: { + method: 'DELETE', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', + pathParams: ['actorId', 'versionNumber', 'envVarName'], riskLevel: 'destructive', irreversible: true, - description: "Delete last task run's default dataset", + description: + 'Tool to delete an environment variable from a specific Actor version. Use when removing environment variables from Actor versions.', + slug: 'APIFY_ACT_VERSION_ENV_VAR_DELETE', }, - runsLastDatasetGet: { + getActorDetails: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], + path: '/v2/actors/{actorId}', + pathParams: ['actorId'], riskLevel: 'read', - description: "Get last task run's default dataset", + description: + 'Tool to get details of a specific Actor. Use when you need actor metadata by ID or username/actorName. Response includes `isDeprecated` and `notice` fields indicating deprecation status, and `pricingInfos` for per-unit cost details — review both before scheduling runs.', + slug: 'APIFY_GET_ACTOR', }, - runsLastDatasetItemsGet: { + getActorLastRunDatasetItems: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset/items', - pathParams: ['actorTaskId'], + path: '/v2/actors/{actorId}/runs/last/dataset/items', + pathParams: ['actorId'], queryParams: [ 'status', 'origin', @@ -1234,277 +570,126 @@ export const apifyOperations = { 'signature', ], riskLevel: 'read', - description: "Get last task run's dataset items", - }, - runsLastDatasetItemsPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset/items', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Store items in last task run's dataset", - }, - runsLastDatasetPut: { - method: 'PUT', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Update last task run's default dataset", - }, - runsLastDatasetStatisticsGet: { - method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/dataset/statistics', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'read', - description: "Get last task run's dataset statistics", + description: + "Tool to get dataset items from the last run of an Actor. Use when you need to retrieve output data from the most recent Actor execution, optionally filtered by run status (e.g., status='SUCCEEDED' to get items only from the last successful run).", + slug: 'APIFY_GET_ACTOR_LAST_RUN_DATASET_ITEMS', }, - runsLastGet: { + getActorVersionEnvironmentVariable: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'waitForFinish'], + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', + pathParams: ['actorId', 'versionNumber', 'envVarName'], riskLevel: 'read', - description: 'Get last run', - }, - runsLastKeyValueStoreDelete: { - method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete last task run's default store", + description: + 'Tool to get environment variable details for a specific Actor version. Use when retrieving environment variable information from an Actor version. Returns name, value (if not secret), and secret status.', + slug: 'APIFY_ACT_VERSION_ENV_VAR_GET', }, - runsLastKeyValueStoreGet: { + getActorVersion: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], + path: '/v2/actors/{actorId}/versions/{versionNumber}', + pathParams: ['actorId', 'versionNumber'], riskLevel: 'read', - description: "Get last task run's default store", + description: + 'Tool to get details about a specific version of an Actor. Use when you need version metadata including source type, build tag, and configuration details.', + slug: 'APIFY_ACT_VERSION_GET', }, - runsLastKeyValueStoreKeysGet: { + getDefaultBuild: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/keys', - pathParams: ['actorTaskId'], - queryParams: [ - 'status', - 'origin', - 'exclusiveStartKey', - 'limit', - 'collection', - 'prefix', - 'signature', - ], + path: '/v2/actors/{actorId}/builds/default', + pathParams: ['actorId'], + queryParams: ['waitForFinish'], riskLevel: 'read', - description: "Get last task run's default store's list of keys", - }, - runsLastKeyValueStorePut: { - method: 'PUT', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Update last task run's default store", - }, - runsLastKeyValueStoreRecordDelete: { - method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorTaskId', 'recordKey'], - queryParams: ['status', 'origin'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete last task run's default store's record", + description: + 'Tool to get the default build for an Actor. Use after specifying the Actor ID; optionally wait for the build to finish before returning.', + slug: 'APIFY_GET_DEFAULT_BUILD', }, - runsLastKeyValueStoreRecordGet: { + getOpenapiDefinition: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorTaskId', 'recordKey'], - queryParams: ['status', 'origin', 'signature', 'attachment'], + path: '/v2/actors/{actorId}/builds/{buildId}/openapi.json', + pathParams: ['actorId', 'buildId'], riskLevel: 'read', - description: "Get last task run's default store's record", - }, - runsLastKeyValueStoreRecordPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorTaskId', 'recordKey'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Store record in last task run's default store (POST)", - }, - runsLastKeyValueStoreRecordPut: { - method: 'PUT', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records/{recordKey}', - pathParams: ['actorTaskId', 'recordKey'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Store record in last task run's default store", + description: + 'Tool to get the OpenAPI definition for a specific Actor build. Use when you need the API schema for code generation or analysis.', + slug: 'APIFY_GET_OPEN_API_DEFINITION', }, - runsLastKeyValueStoreRecordsGet: { + getLastActorRun: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/key-value-store/records', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'collection', 'prefix', 'signature'], + path: '/v2/actors/{actorId}/runs/last', + pathParams: ['actorId'], + queryParams: ['status', 'origin', 'waitForFinish'], riskLevel: 'read', - description: "Download last task run's default store's records", - }, - runsLastMetamorphPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/metamorph', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'targetActorId', 'build'], - riskLevel: 'write', - description: "Metamorph Actor task's last run", - }, - runsLastRebootPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/reboot', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Reboot Actor task's last run", - }, - runsLastRequestQueueDelete: { - method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete last task run's default request queue", + description: + "Tool to get the most recent run of a specific Actor. Use when you need to retrieve the last execution details of an Actor and optionally filter by status (e.g., status='SUCCEEDED' to get only the last successful run).", + slug: 'APIFY_ACT_RUNS_LAST_GET', }, - runsLastRequestQueueGet: { + getListOfActorVersionEnvironmentVariables: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars', + pathParams: ['actorId', 'versionNumber'], riskLevel: 'read', - description: "Get last task run's default request queue", + description: + 'Tool to get the list of environment variables for a specific Actor version. Use when you need to retrieve environment variable configurations for an Actor version.', + slug: 'APIFY_ACT_VERSION_ENV_VARS_GET', }, - runsLastRequestQueueHeadGet: { + getListOfActorVersions: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/head', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'limit', 'clientKey'], + path: '/v2/actors/{actorId}/versions', + pathParams: ['actorId'], riskLevel: 'read', - description: "Get last task run's default request queue head", - }, - runsLastRequestQueueHeadLockPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/head/lock', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'lockSecs', 'limit', 'clientKey'], - riskLevel: 'write', - description: "Get and lock last task run's default request queue head", - }, - runsLastRequestQueuePut: { - method: 'PUT', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin'], - riskLevel: 'write', - description: "Update last task run's default request queue", - }, - runsLastRequestQueueRequestDelete: { - method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}', - pathParams: ['actorTaskId', 'requestId'], - queryParams: ['status', 'origin', 'clientKey'], - riskLevel: 'destructive', - irreversible: true, - description: "Delete request from last task run's default request queue", + description: + 'Tool to get the list of versions of a specific Actor. Use when you need to retrieve version metadata including source type, version number, and configuration details.', + slug: 'APIFY_ACT_VERSIONS_GET', }, - runsLastRequestQueueRequestGet: { + getListOfActorWebhooks: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}', - pathParams: ['actorTaskId', 'requestId'], - queryParams: ['status', 'origin'], + path: '/v2/actors/{actorId}/webhooks', + pathParams: ['actorId'], + queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: "Get request from last task run's default request queue", - }, - runsLastRequestQueueRequestLockDelete: { - method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}/lock', - pathParams: ['actorTaskId', 'requestId'], - queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'write', - description: - "Delete lock on request in last task run's default request queue", - }, - runsLastRequestQueueRequestLockPut: { - method: 'PUT', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}/lock', - pathParams: ['actorTaskId', 'requestId'], - queryParams: ['status', 'origin', 'lockSecs', 'clientKey', 'forefront'], - riskLevel: 'write', description: - "Prolong lock on request in last task run's default request queue", - }, - runsLastRequestQueueRequestPut: { - method: 'PUT', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/{requestId}', - pathParams: ['actorTaskId', 'requestId'], - queryParams: ['status', 'origin', 'forefront', 'clientKey'], - riskLevel: 'write', - description: "Update request in last task run's default request queue", + 'Tool to get a list of webhooks for a specific Actor. Use when you need to review or manage webhooks configured for an Actor.', + slug: 'APIFY_ACT_WEBHOOKS_GET', }, - runsLastRequestQueueRequestsBatchDelete: { - method: 'DELETE', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/batch', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'clientKey'], - riskLevel: 'destructive', - irreversible: true, + getListOfActors: { + method: 'GET', + path: '/v2/actors', + pathParams: [], + queryParams: ['my', 'offset', 'limit', 'desc', 'sortBy'], + riskLevel: 'read', description: - "Batch delete requests from last task run's default request queue", + 'Tool to get the list of all Actors that the user created or used. Use when you need to enumerate or browse Actors. Add my=1 to get only user-created Actors.', + slug: 'APIFY_ACTS_GET', }, - runsLastRequestQueueRequestsBatchPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/batch', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'write', + getListOfBuilds: { + method: 'GET', + path: '/v2/actors/{actorId}/builds', + pathParams: ['actorId'], + queryParams: ['offset', 'limit', 'desc'], + riskLevel: 'read', description: - "Batch add requests to last task run's default request queue", + 'Tool to get a list of builds for a specific Actor. Use when you need paginated access to an Actor’s build (version) history.', + slug: 'APIFY_GET_LIST_OF_BUILDS', }, - runsLastRequestQueueRequestsGet: { + getListOfRuns: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests', - pathParams: ['actorTaskId'], + path: '/v2/actors/{actorId}/runs', + pathParams: ['actorId'], queryParams: [ - 'status', - 'origin', - 'clientKey', - 'exclusiveStartId', + 'offset', 'limit', - 'cursor', - 'filter', + 'desc', + 'status', + 'startedAfter', + 'startedBefore', ], riskLevel: 'read', - description: "List last task run's default request queue's requests", - }, - runsLastRequestQueueRequestsPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'clientKey', 'forefront'], - riskLevel: 'write', - description: "Add request to last task run's default request queue", - }, - runsLastRequestQueueRequestsUnlockPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs/last/request-queue/requests/unlock', - pathParams: ['actorTaskId'], - queryParams: ['status', 'origin', 'clientKey'], - riskLevel: 'write', - description: "Unlock requests in last task run's default request queue", + description: + 'Tool to get a list of runs for a specific Actor. Use when you need to paginate through runs and optionally filter by status before processing run data.', + slug: 'APIFY_GET_LIST_OF_RUNS', }, - runsPost: { + runActorAsynchronously: { method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/runs', - pathParams: ['actorTaskId'], + path: '/v2/actors/{actorId}/runs', + pathParams: ['actorId'], queryParams: [ 'timeout', 'memory', @@ -1514,33 +699,42 @@ export const apifyOperations = { 'build', 'waitForFinish', 'webhooks', + 'forcePermissionLevel', ], riskLevel: 'write', - description: 'Run task', + description: + 'Tool to run a specific Actor asynchronously. Use when you need to trigger an Actor run without waiting for completion and retrieve its run details immediately.', + slug: 'APIFY_RUN_ACTOR', }, - runSyncGet: { - method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/run-sync', - pathParams: ['actorTaskId'], + runActorSync: { + method: 'POST', + path: '/v2/actors/{actorId}/run-sync', + pathParams: ['actorId'], queryParams: [ + 'outputRecordKey', 'timeout', 'memory', 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', 'build', - 'outputRecordKey', 'webhooks', ], riskLevel: 'write', - description: 'Run task synchronously', + description: + 'Tool to run a specific Actor synchronously with input and return its output record. Use when immediate Actor results are needed; runs may timeout after 300 seconds. To avoid timeouts, scope inputs to specific URLs rather than broad crawls and request only necessary fields (e.g., text or markdown).', + slug: 'APIFY_RUN_ACTOR_SYNC', }, - runSyncGetDatasetItemsGet: { + runActorSyncGetDatasetItems: { method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items', - pathParams: ['actorTaskId'], + path: '/v2/actors/{actorId}/run-sync-get-dataset-items', + pathParams: ['actorId'], queryParams: [ 'timeout', 'memory', 'maxItems', + 'maxTotalChargeUsd', + 'restartOnError', 'build', 'webhooks', 'format', @@ -1568,12 +762,14 @@ export const apifyOperations = { 'feedDescription', ], riskLevel: 'write', - description: 'Run task synchronously and get dataset items', + description: + "Tool to run Actor synchronously and get dataset items. Supports both actors that require input and those that don't. Use when immediate access to Actor results is needed. The run must finish within 300 seconds otherwise the request times out.", + slug: 'APIFY_ACT_RUN_SYNC_GET_DATASET_ITEMS_GET', }, - runSyncGetDatasetItemsPost: { + runActorSyncGetDatasetItemsItems: { method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/run-sync-get-dataset-items', - pathParams: ['actorTaskId'], + path: '/v2/actors/{actorId}/run-sync-get-dataset-items', + pathParams: ['actorId'], queryParams: [ 'timeout', 'memory', @@ -1607,119 +803,98 @@ export const apifyOperations = { 'feedDescription', ], riskLevel: 'write', - description: 'Run task synchronously and get dataset items', + description: + 'Tool to run an Actor synchronously and retrieve its dataset items. Use when immediate access to run results is needed.', + slug: 'APIFY_RUN_ACTOR_SYNC_GET_DATASET_ITEMS', }, - runSyncPost: { - method: 'POST', - path: '/v2/actor-tasks/{actorTaskId}/run-sync', - pathParams: ['actorTaskId'], + runActorSyncWithoutInputGet: { + method: 'GET', + path: '/v2/actors/{actorId}/run-sync', + pathParams: ['actorId'], queryParams: [ + 'outputRecordKey', 'timeout', 'memory', 'maxItems', 'maxTotalChargeUsd', 'restartOnError', 'build', - 'outputRecordKey', 'webhooks', ], riskLevel: 'write', - description: 'Run task synchronously', + description: + 'Tool to run a specific Actor synchronously without input and return its output. Use when immediate Actor results are needed without providing input data; the run must finish within 300 seconds otherwise the HTTP request fails with a timeout error.', + slug: 'APIFY_ACT_RUN_SYNC_GET', }, - webhooksGet: { - method: 'GET', - path: '/v2/actor-tasks/{actorTaskId}/webhooks', - pathParams: ['actorTaskId'], - queryParams: ['offset', 'limit', 'desc'], - riskLevel: 'read', - description: 'Get list of webhooks', + updateActor: { + method: 'PUT', + path: '/v2/actors/{actorId}', + pathParams: ['actorId'], + riskLevel: 'write', + description: + 'Tool to update Actor settings using JSON payload. Only specified fields will be updated. Use when you need to modify Actor configuration, make an Actor public, or update version settings.', + slug: 'APIFY_ACT_PUT', }, - }, - actorTasks: { - get: { - method: 'GET', - path: '/v2/actor-tasks', - pathParams: [], - queryParams: ['offset', 'limit', 'desc'], - riskLevel: 'read', - description: 'Get list of tasks', + updateActorVersion: { + method: 'PUT', + path: '/v2/actors/{actorId}/versions/{versionNumber}', + pathParams: ['actorId', 'versionNumber'], + riskLevel: 'write', + description: + "Tool to update an Actor version's configuration and source code. Use when modifying version properties such as buildTag, sourceType, or environment variables. Only specified properties will be updated.", + slug: 'APIFY_ACT_VERSION_PUT', }, - post: { - method: 'POST', - path: '/v2/actor-tasks', - pathParams: [], + updateActorVersionEnvironmentVariable: { + method: 'PUT', + path: '/v2/actors/{actorId}/versions/{versionNumber}/env-vars/{envVarName}', + pathParams: ['actorId', 'versionNumber', 'envVarName'], riskLevel: 'write', - description: 'Create task', + description: + 'Tool to update environment variable for a specific Actor version using JSON payload. Only specified fields will be updated. Use when modifying existing environment variables in Actor versions.', + slug: 'APIFY_ACT_VERSION_ENV_VAR_PUT', }, }, - acts: { - get: { - method: 'GET', - path: '/v2/actors', - pathParams: [], - queryParams: ['my', 'offset', 'limit', 'desc', 'sortBy'], - riskLevel: 'read', - description: 'Get list of Actors', - }, - post: { + datasets: { + createDataset: { method: 'POST', - path: '/v2/actors', + path: '/v2/datasets', pathParams: [], + queryParams: ['name'], riskLevel: 'write', - description: 'Create Actor', + description: + 'Tool to create a new dataset. Use when you need to initialize or retrieve a dataset by name.', + slug: 'APIFY_CREATE_DATASET', }, - }, - dataset: { - delete: { + deleteDataset: { method: 'DELETE', path: '/v2/datasets/{datasetId}', pathParams: ['datasetId'], riskLevel: 'destructive', irreversible: true, - description: 'Delete dataset', + description: + 'Tool to delete a dataset permanently. Use when you need to remove a dataset by its ID or username\\~dataset-name. Confirm before calling.', + slug: 'APIFY_DATASET_DELETE', }, - get: { + getDataset: { method: 'GET', path: '/v2/datasets/{datasetId}', pathParams: ['datasetId'], riskLevel: 'read', - description: 'Get dataset', + description: + "Tool to retrieve dataset metadata by dataset ID. Use when you need information about a dataset's structure, item counts, or access URLs. This does not return dataset items themselves.", + slug: 'APIFY_DATASET_GET', }, - itemsGet: { + getDatasetStatistics: { method: 'GET', - path: '/v2/datasets/{datasetId}/items', + path: '/v2/datasets/{datasetId}/statistics', pathParams: ['datasetId'], - queryParams: [ - 'format', - 'clean', - 'offset', - 'limit', - 'fields', - 'outputFields', - 'omit', - 'unwind', - 'flatten', - 'desc', - 'attachment', - 'delimiter', - 'bom', - 'xmlRoot', - 'xmlRow', - 'skipHeaderRow', - 'skipHidden', - 'skipEmpty', - 'simplified', - 'view', - 'skipFailedPages', - 'feedTitle', - 'feedDescription', - 'signature', - ], riskLevel: 'read', - description: 'Get dataset items', + description: + 'Tool to get dataset field statistics by dataset ID. Use when you need statistical information about dataset fields including min, max, null count, and empty count. Only provides field statistics when dataset schema is configured.', + slug: 'APIFY_DATASET_STATISTICS_GET', }, - itemsHead: { - method: 'HEAD', + getDatasetItems: { + method: 'GET', path: '/v2/datasets/{datasetId}/items', pathParams: ['datasetId'], queryParams: [ @@ -1749,65 +924,99 @@ export const apifyOperations = { 'signature', ], riskLevel: 'read', - description: 'Get dataset items headers', + description: + 'Tool to retrieve items from a dataset. Use when you need to fetch data from a specified dataset by pagination or filtering. Only JSON format is fully supported. For datasets larger than 1000 items, issue multiple calls incrementing `offset` by `limit` until the response returns fewer items than `limit`.', + slug: 'APIFY_GET_DATASET_ITEMS', + }, + getListOfDatasets: { + method: 'GET', + path: '/v2/datasets', + pathParams: [], + queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], + riskLevel: 'read', + description: + "Tool to get list of datasets for a user. Use when you need to enumerate or browse user's datasets. Supports pagination with up to 1000 items per page.", + slug: 'APIFY_DATASETS_GET', }, - itemsPost: { + storeDataInDataset: { method: 'POST', path: '/v2/datasets/{datasetId}/items', pathParams: ['datasetId'], riskLevel: 'write', - description: 'Store items', + description: + 'Tool to store data items in a dataset. Use after collecting data when you want to batch-append or update items in an existing dataset.', + slug: 'APIFY_STORE_DATA_IN_DATASET', }, - put: { + updateDataset: { method: 'PUT', path: '/v2/datasets/{datasetId}', pathParams: ['datasetId'], riskLevel: 'write', - description: 'Update dataset', - }, - statisticsGet: { - method: 'GET', - path: '/v2/datasets/{datasetId}/statistics', - pathParams: ['datasetId'], - riskLevel: 'read', - description: 'Get dataset statistics', + description: + "Tool to update a dataset's name via JSON payload. Use when you need to rename an existing dataset.", + slug: 'APIFY_DATASET_PUT', }, }, - datasets: { - get: { - method: 'GET', - path: '/v2/datasets', - pathParams: [], - queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], + keyValueStores: { + checkKeyValueStoreRecordExists: { + method: 'HEAD', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], riskLevel: 'read', - description: 'Get list of datasets', + description: + 'Tool to check if a record exists in a key-value store. Use when you need to verify whether a specific key exists in an Apify Key-Value Store without retrieving its content.', + slug: 'APIFY_KEY_VALUE_STORE_RECORD_HEAD', }, - post: { + createKeyValueStore: { method: 'POST', - path: '/v2/datasets', + path: '/v2/key-value-stores', pathParams: [], queryParams: ['name'], riskLevel: 'write', - description: 'Create dataset', + description: + 'Tool to create a new key-value store or retrieve an existing one by name. Use when you need to initialize a store for saving data records or files. If a store with the given name already exists, returns that store instead of creating a duplicate.', + slug: 'APIFY_KEY_VALUE_STORES_POST', }, - }, - keyValueStore: { - delete: { + deleteKeyValueStore: { method: 'DELETE', path: '/v2/key-value-stores/{storeId}', pathParams: ['storeId'], riskLevel: 'destructive', irreversible: true, - description: 'Delete store', + description: + 'Tool to delete a key-value store permanently. Use when you need to remove a key-value store by its ID. Confirm before calling.', + slug: 'APIFY_KEY_VALUE_STORE_DELETE', + }, + deleteKeyValueStoreRecord: { + method: 'DELETE', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], + riskLevel: 'destructive', + irreversible: true, + description: + 'Tool to delete a record from a key-value store. Use when you need to remove a specific record by its key from an Apify Key-Value Store.', + slug: 'APIFY_KEY_VALUE_STORE_RECORD_DELETE', + }, + getKeyValueRecord: { + method: 'GET', + path: '/v2/key-value-stores/{storeId}/records/{recordKey}', + pathParams: ['storeId', 'recordKey'], + queryParams: ['attachment', 'signature'], + riskLevel: 'read', + description: + 'Tool to retrieve a record from a key-value store. Use when you need to fetch a specific value by key from an Apify Key-Value Store.', + slug: 'APIFY_GET_KEY_VALUE_RECORD', }, - get: { + getKeyValueStore: { method: 'GET', path: '/v2/key-value-stores/{storeId}', pathParams: ['storeId'], riskLevel: 'read', - description: 'Get store', + description: + 'Tool to retrieve key-value store metadata by store ID. Use when you need detailed information about a specific key-value store including stats and access URLs.', + slug: 'APIFY_KEY_VALUE_STORE_GET', }, - keysGet: { + getKeyValueStoreKeys: { method: 'GET', path: '/v2/key-value-stores/{storeId}/keys', pathParams: ['storeId'], @@ -1819,186 +1028,173 @@ export const apifyOperations = { 'signature', ], riskLevel: 'read', - description: 'Get list of keys', - }, - put: { - method: 'PUT', - path: '/v2/key-value-stores/{storeId}', - pathParams: ['storeId'], - riskLevel: 'write', - description: 'Update store', - }, - recordDelete: { - method: 'DELETE', - path: '/v2/key-value-stores/{storeId}/records/{recordKey}', - pathParams: ['storeId', 'recordKey'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete record', + description: + 'Tool to retrieve a list of keys from a key-value store. Use when you need to list keys in a store with optional filtering and pagination support.', + slug: 'APIFY_KEY_VALUE_STORE_KEYS_GET', }, - recordGet: { + getListOfKeyValueStores: { method: 'GET', - path: '/v2/key-value-stores/{storeId}/records/{recordKey}', - pathParams: ['storeId', 'recordKey'], - queryParams: ['attachment', 'signature'], - riskLevel: 'read', - description: 'Get record', - }, - recordHead: { - method: 'HEAD', - path: '/v2/key-value-stores/{storeId}/records/{recordKey}', - pathParams: ['storeId', 'recordKey'], + path: '/v2/key-value-stores', + pathParams: [], + queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], riskLevel: 'read', - description: 'Check if a record exists', - }, - recordPost: { - method: 'POST', - path: '/v2/key-value-stores/{storeId}/records/{recordKey}', - pathParams: ['storeId', 'recordKey'], - riskLevel: 'write', - description: 'Store record (POST)', + description: + 'Tool to get the list of key-value stores owned by the user. Use when you need to enumerate or browse available stores. Supports pagination up to 1000 records per request.', + slug: 'APIFY_KEY_VALUE_STORES_GET', }, - recordPut: { + storeDataInKeyValueStore: { method: 'PUT', path: '/v2/key-value-stores/{storeId}/records/{recordKey}', pathParams: ['storeId', 'recordKey'], riskLevel: 'write', - description: 'Store record', + description: + 'Tool to create or update a record in a key-value store. Use after you have the store ID and record key to persist JSON data.', + slug: 'APIFY_STORE_DATA_IN_KEY_VALUE_STORE', }, - recordsGet: { - method: 'GET', - path: '/v2/key-value-stores/{storeId}/records', + updateKeyValueStore: { + method: 'PUT', + path: '/v2/key-value-stores/{storeId}', pathParams: ['storeId'], - queryParams: ['collection', 'prefix', 'signature'], - riskLevel: 'read', - description: 'Download records', - }, - }, - keyValueStores: { - get: { - method: 'GET', - path: '/v2/key-value-stores', - pathParams: [], - queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], - riskLevel: 'read', - description: 'Get list of key-value stores', - }, - post: { - method: 'POST', - path: '/v2/key-value-stores', - pathParams: [], - queryParams: ['name'], riskLevel: 'write', - description: 'Create key-value store', - }, - }, - log: { - get: { - method: 'GET', - path: '/v2/logs/{buildOrRunId}', - pathParams: ['buildOrRunId'], - queryParams: ['stream', 'download', 'raw'], - riskLevel: 'read', - description: 'Get log', - }, - }, - requestQueue: { - delete: { - method: 'DELETE', - path: '/v2/request-queues/{queueId}', - pathParams: ['queueId'], - riskLevel: 'destructive', - irreversible: true, - description: 'Delete request queue', - }, - get: { - method: 'GET', - path: '/v2/request-queues/{queueId}', - pathParams: ['queueId'], - riskLevel: 'read', - description: 'Get request queue', + description: + "Tool to update a key-value store's properties. Use when renaming or changing access or schema version of the store after confirming the store ID.", + slug: 'APIFY_UPDATE_KEY_VALUE_STORE', }, - headGet: { + }, + logs: { + getLog: { method: 'GET', - path: '/v2/request-queues/{queueId}/head', - pathParams: ['queueId'], - queryParams: ['limit', 'clientKey'], + path: '/v2/logs/{buildOrRunId}', + pathParams: ['buildOrRunId'], + queryParams: ['stream', 'download', 'raw'], riskLevel: 'read', - description: 'Get head', + description: + 'Tool to retrieve logs for a specific Actor run or build. Use after a run completes or fails — a run may report success status yet contain only informational messages, making log inspection the only way to confirm actual outcomes. For long runs, log responses can be very large; prioritize error-level entries and recent timestamps to diagnose issues efficiently.', + slug: 'APIFY_GET_LOG', }, - headLockPost: { + }, + requestQueues: { + addRequestToQueue: { method: 'POST', - path: '/v2/request-queues/{queueId}/head/lock', + path: '/v2/request-queues/{queueId}/requests', pathParams: ['queueId'], - queryParams: ['lockSecs', 'limit', 'clientKey'], + queryParams: ['clientKey', 'forefront'], riskLevel: 'write', - description: 'Get head and lock', + description: + 'Tool to add a request to the queue. Use when you need to add a web page URL to a request queue for crawling. If a request with the same uniqueKey was already present in the queue, returns the ID of the existing request.', + slug: 'APIFY_REQUEST_QUEUE_REQUESTS_POST', }, - put: { - method: 'PUT', - path: '/v2/request-queues/{queueId}', + batchAddRequestsToQueue: { + method: 'POST', + path: '/v2/request-queues/{queueId}/requests/batch', pathParams: ['queueId'], + queryParams: ['clientKey', 'forefront'], riskLevel: 'write', - description: 'Update request queue', + description: + 'Tool to batch-add up to 25 requests to a request queue. Use when you need to add multiple requests efficiently. Failed requests due to rate limits should be retried with exponential backoff.', + slug: 'APIFY_REQUEST_QUEUE_REQUESTS_BATCH_POST', }, - requestDelete: { + batchDeleteRequestsFromQueue: { method: 'DELETE', - path: '/v2/request-queues/{queueId}/requests/{requestId}', - pathParams: ['queueId', 'requestId'], + path: '/v2/request-queues/{queueId}/requests/batch', + pathParams: ['queueId'], queryParams: ['clientKey'], riskLevel: 'destructive', irreversible: true, - description: 'Delete request', + description: + 'Tool to batch-delete up to 25 requests from a queue. Use when you need to remove multiple requests efficiently. Failed requests due to rate limits should be retried with exponential backoff.', + slug: 'APIFY_REQUEST_QUEUE_REQUESTS_BATCH_DELETE', }, - requestGet: { - method: 'GET', - path: '/v2/request-queues/{queueId}/requests/{requestId}', - pathParams: ['queueId', 'requestId'], - riskLevel: 'read', - description: 'Get request', + createRequestQueue: { + method: 'POST', + path: '/v2/request-queues', + pathParams: [], + queryParams: ['name'], + riskLevel: 'write', + description: + 'Tool to create a new request queue or retrieve an existing one by name. Use when you need to initialize a queue for storing and managing web scraping requests. If a queue with the given name already exists, returns that queue instead of creating a duplicate. Unnamed queues follow data retention period policies.', + slug: 'APIFY_REQUEST_QUEUES_POST', }, - requestLockDelete: { + deleteRequestLock: { method: 'DELETE', path: '/v2/request-queues/{queueId}/requests/{requestId}/lock', pathParams: ['queueId', 'requestId'], queryParams: ['clientKey', 'forefront'], riskLevel: 'write', - description: 'Delete request lock', + description: + 'Tool to delete a request lock from a request queue. Use when you need to unlock a previously locked request. Only the client that locked the request can delete its lock.', + slug: 'APIFY_REQUEST_QUEUE_REQUEST_LOCK_DELETE', }, - requestLockPut: { - method: 'PUT', - path: '/v2/request-queues/{queueId}/requests/{requestId}/lock', - pathParams: ['queueId', 'requestId'], - queryParams: ['lockSecs', 'clientKey', 'forefront'], - riskLevel: 'write', - description: 'Prolong request lock', + deleteRequestQueue: { + method: 'DELETE', + path: '/v2/request-queues/{queueId}', + pathParams: ['queueId'], + riskLevel: 'destructive', + irreversible: true, + description: + 'Tool to delete a request queue permanently. Use when you need to remove a request queue by its ID.', + slug: 'APIFY_REQUEST_QUEUE_DELETE', }, - requestPut: { - method: 'PUT', + deleteRequestFromQueue: { + method: 'DELETE', path: '/v2/request-queues/{queueId}/requests/{requestId}', pathParams: ['queueId', 'requestId'], - queryParams: ['forefront', 'clientKey'], - riskLevel: 'write', - description: 'Update request', - }, - requestsBatchDelete: { - method: 'DELETE', - path: '/v2/request-queues/{queueId}/requests/batch', - pathParams: ['queueId'], queryParams: ['clientKey'], riskLevel: 'destructive', irreversible: true, - description: 'Delete requests', + description: + 'Tool to delete a specific request from a request queue. Use when you need to remove a request by its ID from an Apify request queue.', + slug: 'APIFY_REQUEST_QUEUE_REQUEST_DELETE', }, - requestsBatchPost: { + getHeadAndLockQueueRequests: { method: 'POST', - path: '/v2/request-queues/{queueId}/requests/batch', + path: '/v2/request-queues/{queueId}/head/lock', pathParams: ['queueId'], - queryParams: ['clientKey', 'forefront'], + queryParams: ['lockSecs', 'limit', 'clientKey'], riskLevel: 'write', - description: 'Add requests', + description: + 'Tool to get and lock head requests from the queue. Returns the given number of first requests from the queue and locks them for the given time, preventing other clients from accessing them during the lock period. Use when you need to process requests exclusively without concurrent access by other clients.', + slug: 'APIFY_REQUEST_QUEUE_HEAD_LOCK_POST', + }, + getRequestQueue: { + method: 'GET', + path: '/v2/request-queues/{queueId}', + pathParams: ['queueId'], + riskLevel: 'read', + description: + 'Tool to retrieve request queue metadata by queue ID. Use when you need information about a specific request queue including its statistics and request counts.', + slug: 'APIFY_REQUEST_QUEUE_GET', + }, + getRequestQueueHead: { + method: 'GET', + path: '/v2/request-queues/{queueId}/head', + pathParams: ['queueId'], + queryParams: ['limit', 'clientKey'], + riskLevel: 'read', + description: + 'Tool to retrieve first requests from the queue for inspection. Use when you need to examine pending requests without locking them.', + slug: 'APIFY_REQUEST_QUEUE_HEAD_GET', + }, + getRequestFromQueue: { + method: 'GET', + path: '/v2/request-queues/{queueId}/requests/{requestId}', + pathParams: ['queueId', 'requestId'], + riskLevel: 'read', + description: + 'Tool to retrieve a specific request from a request queue by its ID. Use when you need to get detailed information about a request in an Apify request queue.', + slug: 'APIFY_REQUEST_QUEUE_REQUEST_GET', + }, + getListOfRequestQueues: { + method: 'GET', + path: '/v2/request-queues', + pathParams: [], + queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], + riskLevel: 'read', + description: + "Tool to get list of request queues for a user. Use when you need to enumerate or browse user's request queues. Supports pagination with up to 1000 items per page.", + slug: 'APIFY_REQUEST_QUEUES_GET', }, - requestsGet: { + listRequestQueueRequests: { method: 'GET', path: '/v2/request-queues/{queueId}/requests', pathParams: ['queueId'], @@ -2010,93 +1206,110 @@ export const apifyOperations = { 'filter', ], riskLevel: 'read', - description: 'List requests', + description: + 'Tool to list requests in a request queue with pagination support. Use when you need to retrieve multiple requests from an Apify request queue.', + slug: 'APIFY_REQUEST_QUEUE_REQUESTS_GET', }, - requestsPost: { - method: 'POST', - path: '/v2/request-queues/{queueId}/requests', - pathParams: ['queueId'], - queryParams: ['clientKey', 'forefront'], + prolongRequestLock: { + method: 'PUT', + path: '/v2/request-queues/{queueId}/requests/{requestId}/lock', + pathParams: ['queueId', 'requestId'], + queryParams: ['lockSecs', 'clientKey', 'forefront'], riskLevel: 'write', - description: 'Add request', + description: + 'Tool to prolong request lock in a request queue. Use when you need to extend the lock duration on a previously locked request. Only the client that locked the request can prolong its lock.', + slug: 'APIFY_REQUEST_QUEUE_REQUEST_LOCK_PUT', }, - requestsUnlockPost: { + unlockQueueRequests: { method: 'POST', path: '/v2/request-queues/{queueId}/requests/unlock', pathParams: ['queueId'], queryParams: ['clientKey'], riskLevel: 'write', - description: 'Unlock requests', + description: + 'Tool to unlock requests in a request queue that are currently locked by the client. If the client is within an Actor run, unlocks all requests locked by that specific run plus all requests locked by the same clientKey. If the client is outside of an Actor run, unlocks all requests locked using the same clientKey.', + slug: 'APIFY_REQUEST_QUEUE_REQUESTS_UNLOCK_POST', }, - }, - requestQueues: { - get: { - method: 'GET', - path: '/v2/request-queues', - pathParams: [], - queryParams: ['offset', 'limit', 'desc', 'unnamed', 'ownership'], - riskLevel: 'read', - description: 'Get list of request queues', + updateRequestQueue: { + method: 'PUT', + path: '/v2/request-queues/{queueId}', + pathParams: ['queueId'], + riskLevel: 'write', + description: + 'Tool to update request queue name using JSON payload. Use when you need to rename an existing request queue.', + slug: 'APIFY_REQUEST_QUEUE_PUT', }, - post: { + updateRequestInQueue: { + method: 'PUT', + path: '/v2/request-queues/{queueId}/requests/{requestId}', + pathParams: ['queueId', 'requestId'], + queryParams: ['forefront', 'clientKey'], + riskLevel: 'write', + description: + 'Tool to update a request in a request queue. Use when you need to modify request properties or mark a request as handled by setting handledAt to the current date/time. If handledAt is set, the request will be removed from the head of the queue and unlocked if applicable.', + slug: 'APIFY_REQUEST_QUEUE_REQUEST_PUT', + }, + }, + schedules: { + createSchedule: { method: 'POST', - path: '/v2/request-queues', + path: '/v2/schedules', pathParams: [], - queryParams: ['name'], riskLevel: 'write', - description: 'Create request queue', + description: + 'Tool to create a new schedule with specified settings. Use when you need to automate Actor or Actor task execution at specific times using cron expressions.', + slug: 'APIFY_SCHEDULES_POST', }, - }, - schedule: { - delete: { + deleteSchedule: { method: 'DELETE', path: '/v2/schedules/{scheduleId}', pathParams: ['scheduleId'], riskLevel: 'destructive', irreversible: true, - description: 'Delete schedule', + description: + 'Tool to delete a schedule by its ID. Use when you need to remove a schedule from the Apify system.', + slug: 'APIFY_SCHEDULE_DELETE', }, - get: { + getSchedule: { method: 'GET', path: '/v2/schedules/{scheduleId}', pathParams: ['scheduleId'], riskLevel: 'read', - description: 'Get schedule', + description: + 'Tool to get schedule details by ID. Use when you need to retrieve comprehensive information about a schedule including cron expression, timezone, actions, and execution times.', + slug: 'APIFY_SCHEDULE_GET', }, - logGet: { + getScheduleLog: { method: 'GET', path: '/v2/schedules/{scheduleId}/log', pathParams: ['scheduleId'], riskLevel: 'read', - description: 'Get schedule log', - }, - put: { - method: 'PUT', - path: '/v2/schedules/{scheduleId}', - pathParams: ['scheduleId'], - riskLevel: 'write', - description: 'Update schedule', + description: + 'Tool to get schedule log by ID. Use when you need to retrieve execution history for a schedule, including invocation timestamps and status messages. Returns up to 1000 invocations.', + slug: 'APIFY_SCHEDULE_LOG_GET', }, - }, - schedules: { - get: { + getListOfSchedules: { method: 'GET', path: '/v2/schedules', pathParams: [], queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: 'Get list of schedules', + description: + "Tool to get list of schedules created by the user. Use when you need to browse or enumerate user's schedules. Supports pagination with up to 1000 items per page.", + slug: 'APIFY_SCHEDULES_GET', }, - post: { - method: 'POST', - path: '/v2/schedules', - pathParams: [], + updateSchedule: { + method: 'PUT', + path: '/v2/schedules/{scheduleId}', + pathParams: ['scheduleId'], riskLevel: 'write', - description: 'Create schedule', + description: + 'Tool to update an existing schedule with new settings. Use when you need to modify schedule properties like cron expression, timezone, enabled status, or actions. Only specified fields are updated; others remain unchanged.', + slug: 'APIFY_SCHEDULE_PUT', }, }, store: { - get: { + getListOfActorsInStore: { method: 'GET', path: '/v2/store', pathParams: [], @@ -2113,169 +1326,146 @@ export const apifyOperations = { 'includeUnrunnableActors', ], riskLevel: 'read', - description: 'Get list of Actors in Store', + description: + 'Tool to get list of public Actors from Apify Store. Use when you need to browse or search public Actors available in the store. Supports searching by title, name, description, username, and readme.', + slug: 'APIFY_STORE_GET', }, }, - tools: { - browserInfoDelete: { - method: 'DELETE', - path: '/v2/browser-info', - pathParams: [], - queryParams: ['skipHeaders', 'rawHeaders'], - riskLevel: 'write', - description: 'Get browser info', - }, - browserInfoGet: { + users: { + getAccountLimits: { method: 'GET', - path: '/v2/browser-info', + path: '/v2/users/me/limits', pathParams: [], - queryParams: ['skipHeaders', 'rawHeaders'], riskLevel: 'read', - description: 'Get browser info', - }, - browserInfoPost: { - method: 'POST', - path: '/v2/browser-info', - pathParams: [], - queryParams: ['skipHeaders', 'rawHeaders'], - riskLevel: 'write', - description: 'Get browser info', - }, - browserInfoPut: { - method: 'PUT', - path: '/v2/browser-info', - pathParams: [], - queryParams: ['skipHeaders', 'rawHeaders'], - riskLevel: 'write', - description: 'Get browser info', - }, - decodeAndVerifyPost: { - method: 'POST', - path: '/v2/tools/decode-and-verify', - pathParams: [], - riskLevel: 'write', - description: 'Decode and verify object', - }, - encodeAndSignPost: { - method: 'POST', - path: '/v2/tools/encode-and-sign', - pathParams: [], - riskLevel: 'write', - description: 'Encode and sign object', + description: + 'Tool to get a complete summary of account limits and usage. Use when you need to retrieve information about usage cycles, spending caps, compute resources, data transfer quotas, and other account limits. This shows the same information as the Limits page in Apify console.', + slug: 'APIFY_USERS_ME_LIMITS_GET', }, - }, - user: { - get: { + getCurrentUserAccountData: { method: 'GET', - path: '/v2/users/{userId}', - pathParams: ['userId'], + path: '/v2/users/me', + pathParams: [], riskLevel: 'read', - description: 'Get public user data', + description: + "Tool to get private user account information. Use when you need to retrieve comprehensive data about the current user identified by the authentication token, including profile, subscription plan, and proxy settings. Note: 'plan', 'email', and 'profile' fields are omitted when accessed from Actor run.", + slug: 'APIFY_USERS_ME_GET', }, - }, - users: { - meGet: { + getMonthlyUsage: { method: 'GET', - path: '/v2/users/me', + path: '/v2/users/me/usage/monthly', pathParams: [], + queryParams: ['date'], riskLevel: 'read', - description: 'Get private user data', + description: + 'Tool to get monthly usage summary with daily breakdown. Use when you need detailed usage information including storage, data transfer, and request queue metrics for the current or a specific billing cycle. This shows the same information as the Billing page in Apify console.', + slug: 'APIFY_USERS_ME_USAGE_MONTHLY_GET', }, - meLimitsGet: { + getPublicUserData: { method: 'GET', - path: '/v2/users/me/limits', - pathParams: [], + path: '/v2/users/{userId}', + pathParams: ['userId'], riskLevel: 'read', - description: 'Get limits', + description: + 'Tool to get public user data. Use when you need to retrieve publicly accessible information about a specific Apify user account, similar to what can be seen on public profile pages. This operation requires no authentication token.', + slug: 'APIFY_USER_GET', }, - meLimitsPut: { + updateAccountLimits: { method: 'PUT', path: '/v2/users/me/limits', pathParams: [], riskLevel: 'write', - description: 'Update limits', + description: + 'Tool to update account limits manageable on the Limits page. Use when you need to set or modify the monthly spending cap (maxMonthlyUsageUsd) or data retention period (dataRetentionDays). At least one limit parameter must be provided.', + slug: 'APIFY_USERS_ME_LIMITS_PUT', }, - meUsageMonthlyGet: { + }, + webhookDispatches: { + getWebhookDispatch: { method: 'GET', - path: '/v2/users/me/usage/monthly', + path: '/v2/webhook-dispatches/{dispatchId}', + pathParams: ['dispatchId'], + riskLevel: 'read', + description: + 'Tool to get webhook dispatch object with all details. Use when you need to retrieve information about a specific webhook dispatch including its status, event data, and call history.', + slug: 'APIFY_WEBHOOK_DISPATCH_GET', + }, + getListOfWebhookDispatches: { + method: 'GET', + path: '/v2/webhook-dispatches', pathParams: [], - queryParams: ['date'], + queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: 'Get monthly usage', + description: + 'Tool to get list of webhook dispatches for the user. Use when you need to retrieve webhook execution history with pagination support.', + slug: 'APIFY_WEBHOOK_DISPATCHES_GET', }, }, - webhook: { - delete: { + webhooks: { + createTaskWebhook: { + method: 'POST', + path: '/v2/webhooks', + pathParams: [], + riskLevel: 'write', + description: + 'Tool to create a webhook for an Actor task. Use when you need external notifications about task run events (e.g., completion or failure) in downstream systems.', + slug: 'APIFY_CREATE_TASK_WEBHOOK', + }, + deleteWebhook: { method: 'DELETE', path: '/v2/webhooks/{webhookId}', pathParams: ['webhookId'], riskLevel: 'destructive', irreversible: true, - description: 'Delete webhook', + description: + 'Tool to delete a webhook by its ID. Use when removing a webhook after confirming the webhook ID.', + slug: 'APIFY_DELETE_WEBHOOK', }, - get: { + getAllWebhooks: { method: 'GET', - path: '/v2/webhooks/{webhookId}', - pathParams: ['webhookId'], + path: '/v2/webhooks', + pathParams: [], + queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: 'Get webhook', + description: + 'Tool to get a list of all webhooks created by the user. Use when you need to enumerate webhooks before filtering or maintenance.', + slug: 'APIFY_GET_ALL_WEBHOOKS', }, - put: { - method: 'PUT', + getWebhook: { + method: 'GET', path: '/v2/webhooks/{webhookId}', pathParams: ['webhookId'], - riskLevel: 'write', - description: 'Update webhook', - }, - testPost: { - method: 'POST', - path: '/v2/webhooks/{webhookId}/test', - pathParams: ['webhookId'], - riskLevel: 'write', - description: 'Test webhook', + riskLevel: 'read', + description: + 'Tool to get webhook object with all details. Use when you need to retrieve complete information about a specific webhook by its ID.', + slug: 'APIFY_WEBHOOK_GET', }, - webhookDispatchesGet: { + getWebhookDispatches: { method: 'GET', path: '/v2/webhooks/{webhookId}/dispatches', pathParams: ['webhookId'], - riskLevel: 'read', - description: 'Get collection', - }, - }, - webhookDispatch: { - get: { - method: 'GET', - path: '/v2/webhook-dispatches/{dispatchId}', - pathParams: ['dispatchId'], - riskLevel: 'read', - description: 'Get webhook dispatch', - }, - }, - webhookDispatches: { - get: { - method: 'GET', - path: '/v2/webhook-dispatches', - pathParams: [], - queryParams: ['offset', 'limit', 'desc'], - riskLevel: 'read', - description: 'Get list of webhook dispatches', - }, - }, - webhooks: { - get: { - method: 'GET', - path: '/v2/webhooks', - pathParams: [], queryParams: ['offset', 'limit', 'desc'], riskLevel: 'read', - description: 'Get list of webhooks', + description: + 'Tool to get list of webhook dispatches for a specific webhook. Use when you need to retrieve dispatch history for a particular webhook with pagination support.', + slug: 'APIFY_WEBHOOK_WEBHOOK_DISPATCHES_GET', }, - post: { + testWebhook: { method: 'POST', - path: '/v2/webhooks', - pathParams: [], + path: '/v2/webhooks/{webhookId}/test', + pathParams: ['webhookId'], + riskLevel: 'write', + description: + 'Tool to test a webhook by creating a test dispatch with a dummy payload. Use when you need to verify webhook configuration before production use.', + slug: 'APIFY_WEBHOOK_TEST_POST', + }, + updateWebhook: { + method: 'PUT', + path: '/v2/webhooks/{webhookId}', + pathParams: ['webhookId'], riskLevel: 'write', - description: 'Create webhook', + description: + 'Tool to update webhook using JSON payload. Only specified properties are updated; others remain unchanged. Use when you need to modify webhook settings like event types, target URL, or other configuration.', + slug: 'APIFY_WEBHOOK_PUT', }, }, } as const satisfies ApifyOperationTree; diff --git a/packages/apify/endpoints/types.ts b/packages/apify/endpoints/types.ts index b3a4b434d..1b9774f30 100644 --- a/packages/apify/endpoints/types.ts +++ b/packages/apify/endpoints/types.ts @@ -2,18 +2,14 @@ import { z } from 'zod'; export const ApifyOperationInputSchema = z .object({ - // Apify operation bodies vary per endpoint and can include arbitrary JSON payloads. body: z.unknown().optional(), - // Query values are endpoint-specific primitives preserved by the generic operation router. query: z.record(z.string(), z.unknown()).optional(), - // Custom headers are passed through to Apify without a stable provider-wide shape. headers: z.record(z.string(), z.unknown()).optional(), contentType: z.string().optional(), mediaType: z.string().optional(), }) .loose(); -// Apify returns endpoint-specific payloads that this generated passthrough layer does not normalize. export const ApifyOperationOutputSchema = z.unknown(); export type ApifyOperationInput = z.infer; @@ -22,9 +18,5 @@ export type ApifyOperationOutput = z.infer; export type ApifyEndpointInputs = Record; export type ApifyEndpointOutputs = Record; -// Generic schemas exposed under the conventional names expected by the plugin -// validator. Per-operation schemas are built dynamically in endpoints/index.ts -// (see buildApifyEndpointSchemas); these are the shared shapes every operation -// derives from. export const EndpointInputSchemas = ApifyOperationInputSchema; export const EndpointOutputSchemas = ApifyOperationOutputSchema; diff --git a/packages/apify/error-handlers.ts b/packages/apify/error-handlers.ts index 5d04f981d..297557c8e 100644 --- a/packages/apify/error-handlers.ts +++ b/packages/apify/error-handlers.ts @@ -27,7 +27,7 @@ export const errorHandlers = { ? error.status === 429 : messageOf(error).includes('rate-limit'), handler: async (error: Error) => ({ - maxRetries: 5, + maxRetries: 0, headersRetryAfterMs: error instanceof ApiError ? error.retryAfter : undefined, retryStrategy: 'exponential_backoff_jitter', diff --git a/packages/apify/index.ts b/packages/apify/index.ts index 71e451e21..723624c6a 100644 --- a/packages/apify/index.ts +++ b/packages/apify/index.ts @@ -99,8 +99,6 @@ export function apify( webhookSchemas: apifyWebhookSchemas, pluginWebhookMatcher: () => false, errorHandlers: (() => { - // DEFAULT matches everything (`() => true`), so it must always be - // evaluated last — otherwise caller-supplied handlers become dead code. const { DEFAULT: defaultHandler, ...specificDefaults } = errorHandlers; return { ...specificDefaults, diff --git a/packages/apify/operations.test.ts b/packages/apify/operations.test.ts index 0aaf55011..e5ba802c1 100644 --- a/packages/apify/operations.test.ts +++ b/packages/apify/operations.test.ts @@ -14,9 +14,6 @@ import { import type { ApifyContext } from './index'; import { apify } from './index'; -// Mock the shared HTTP transport so endpoint invocations exercise the full -// request-building path (makeApifyRequest → buildBody/buildQuery/pickDefined) -// without hitting the network. jest.mock('corsair/http', () => { const original = jest.requireActual('corsair/http'); return { @@ -40,8 +37,6 @@ const mockLog = logEventFromContext as jest.MockedFunction< type OperationEntry = { path: string; def: ApifyOperationDefinition }; -// Walks the nested operation tree and yields every leaf operation with its -// dotted path (e.g. "act.buildsGet"). Used to assert over the full registry. function isDefinition(node: unknown): node is ApifyOperationDefinition { return ( typeof node === 'object' && @@ -67,10 +62,13 @@ function flattenOperations(node: unknown, prefix = ''): OperationEntry[] { const ALL_OPERATIONS = flattenOperations(apifyOperations); describe('apify operation registry', () => { - it('registers a non-empty set of operations', () => { - expect(ALL_OPERATIONS.length).toBeGreaterThan(0); - // Sanity bound: the registry covers many Apify resources, so it is large. - expect(ALL_OPERATIONS.length).toBeGreaterThan(100); + it('registers exactly the 113 OSS listing operations', () => { + expect(ALL_OPERATIONS.length).toBe(113); + const slugs = ALL_OPERATIONS.map(({ def }) => def.slug); + expect(new Set(slugs).size).toBe(113); + for (const slug of slugs) { + expect(slug.startsWith('APIFY_')).toBe(true); + } }); it('gives every operation a valid HTTP method and absolute path', () => { @@ -104,18 +102,11 @@ describe('apify operation registry', () => { it('marks DELETE operations with the right risk level', () => { for (const { def } of ALL_OPERATIONS) { if (def.method !== 'DELETE') continue; - // Two DELETE families are intentionally non-destructive: - // - /lock paths release a temporary request-queue lock (re-acquirable), - // so they are a write, not destructive, and never irreversible. - // - /v2/browser-info is a read-style endpoint the provider exposes - // across all HTTP verbs; the DELETE variant must not be destructive. const releasesLock = def.path.endsWith('/lock'); - const isBrowserInfo = def.path === '/v2/browser-info'; - if (releasesLock || isBrowserInfo) { + if (releasesLock) { expect(def.riskLevel).not.toBe('destructive'); expect(def.irreversible).not.toBe(true); } else { - // Every other DELETE removes a real Apify resource. expect(def.riskLevel).toBe('destructive'); } } @@ -125,11 +116,11 @@ describe('apify operation registry', () => { describe('apify endpoint tree', () => { it('exposes a callable function for every registered operation', () => { expect(typeof ApifyEndpoints).toBe('object'); - // Every leaf in the operation tree has a matching endpoint function. - const actNode = (ApifyEndpoints as Record).act; - expect(typeof actNode).toBe('object'); + const actors = (ApifyEndpoints as Record).actors; + expect(typeof actors).toBe('object'); expect( - typeof (actNode as Record unknown>).get, + typeof (actors as Record unknown>) + .getActorDetails, ).toBe('function'); }); }); @@ -153,14 +144,14 @@ describe('apify endpoint schemas', () => { }); it('treats each path param as a required string|number input', () => { - const sample = schemaMap['act.get']; + const sample = schemaMap['actors.getActorDetails']; expect(sample).toBeDefined(); const parsed = sample?.input.safeParse({ actorId: 'abc123' }); expect(parsed?.success).toBe(true); }); it('rejects inputs missing a required path param', () => { - const sample = schemaMap['act.get']; + const sample = schemaMap['actors.getActorDetails']; expect(sample).toBeDefined(); const parsed = sample?.input.safeParse({}); expect(parsed?.success).toBe(false); @@ -196,13 +187,11 @@ describe('apify endpoint meta', () => { }); it('tags actor delete as irreversible', () => { - expect(metaMap['act.delete']?.riskLevel).toBe('destructive'); - expect(metaMap['act.delete']?.irreversible).toBe(true); + expect(metaMap['actors.deleteActor']?.riskLevel).toBe('destructive'); + expect(metaMap['actors.deleteActor']?.irreversible).toBe(true); }); }); -// A minimal context carrying just the fields the endpoint closures read. -// makeApifyRequest consumes ctx.key; logEventFromContext reads ctx for logging. function makeCtx(key = 'test-token'): ApifyContext { return { key } as unknown as ApifyContext; } @@ -219,9 +208,14 @@ describe('apify endpoint invocation', () => { const result = await ( ApifyEndpoints as unknown as { - act: { get: (ctx: ApifyContext, input: unknown) => Promise }; + actors: { + getActorDetails: ( + ctx: ApifyContext, + input: unknown, + ) => Promise; + }; } - ).act.get(makeCtx(), { actorId: 'abc123' }); + ).actors.getActorDetails(makeCtx(), { actorId: 'abc123' }); expect(mockRequest).toHaveBeenCalledTimes(1); const [config, requestOptions] = mockRequest.mock.calls[0] ?? []; @@ -234,7 +228,6 @@ describe('apify endpoint invocation', () => { url: '/v2/actors/{actorId}', }); expect(requestOptions?.path).toEqual({ actorId: 'abc123' }); - // GET requests carry no body. expect(requestOptions?.body).toBeUndefined(); expect(result).toEqual({ id: 'actor-1' }); }); @@ -245,9 +238,14 @@ describe('apify endpoint invocation', () => { const result = await ( ApifyEndpoints as unknown as { - act: { get: (ctx: ApifyContext, input: unknown) => Promise }; + actors: { + getActorDetails: ( + ctx: ApifyContext, + input: unknown, + ) => Promise; + }; } - ).act.get(makeCtx(), { actorId: 'abc123' }); + ).actors.getActorDetails(makeCtx(), { actorId: 'abc123' }); expect(result).toEqual({ id: 'actor-1' }); }); @@ -257,19 +255,25 @@ describe('apify endpoint invocation', () => { await ( ApifyEndpoints as unknown as { - actorRun: { - chargePost: (ctx: ApifyContext, input: unknown) => Promise; + datasets: { + storeDataInDataset: ( + ctx: ApifyContext, + input: unknown, + ) => Promise; }; } - ).actorRun.chargePost(makeCtx(), { runId: 'r1', events: [{ e: 1 }] }); + ).datasets.storeDataInDataset(makeCtx(), { + datasetId: 'd1', + items: [{ e: 1 }], + }); const requestOptions = mockRequest.mock.calls[0]?.[1]; expect(requestOptions).toMatchObject({ method: 'POST', - url: '/v2/actor-runs/{runId}/charge', - body: { events: [{ e: 1 }] }, + url: '/v2/datasets/{datasetId}/items', + body: { items: [{ e: 1 }] }, }); - expect(requestOptions?.path).toEqual({ runId: 'r1' }); + expect(requestOptions?.path).toEqual({ datasetId: 'd1' }); }); it('passes query params through without polluting the body', async () => { @@ -277,15 +281,21 @@ describe('apify endpoint invocation', () => { await ( ApifyEndpoints as unknown as { - act: { - buildsGet: (ctx: ApifyContext, input: unknown) => Promise; + actors: { + getListOfBuilds: ( + ctx: ApifyContext, + input: unknown, + ) => Promise; }; } - ).act.buildsGet(makeCtx(), { actorId: 'a1', limit: 5, offset: 10 }); + ).actors.getListOfBuilds(makeCtx(), { + actorId: 'a1', + limit: 5, + offset: 10, + }); const requestOptions = mockRequest.mock.calls[0]?.[1]; expect(requestOptions?.query).toMatchObject({ limit: 5, offset: 10 }); - // Query/path params are excluded from the body. expect(requestOptions?.body).toBeUndefined(); }); @@ -294,11 +304,14 @@ describe('apify endpoint invocation', () => { const result = await ( ApifyEndpoints as unknown as { - actorRun: { - delete: (ctx: ApifyContext, input: unknown) => Promise; + actorRuns: { + deleteActorRun: ( + ctx: ApifyContext, + input: unknown, + ) => Promise; }; } - ).actorRun.delete(makeCtx(), { runId: 'r1' }); + ).actorRuns.deleteActorRun(makeCtx(), { runId: 'r1' }); expect(result).toEqual({ success: true }); }); @@ -309,15 +322,17 @@ describe('apify endpoint invocation', () => { await expect( ( ApifyEndpoints as unknown as { - act: { get: (ctx: ApifyContext, input: unknown) => Promise }; + actors: { + getActorDetails: ( + ctx: ApifyContext, + input: unknown, + ) => Promise; + }; } - ).act.get(makeCtx(), { actorId: 'abc123' }), + ).actors.getActorDetails(makeCtx(), { actorId: 'abc123' }), ).rejects.toThrow('network down'); }); - // Drive one endpoint from EVERY top-level namespace so request-building - // (path/query/body wiring) is exercised across the full registered surface, - // not just act.* and actorRun.*. it('routes the first operation of every namespace to its declared path and method', async () => { mockRequest.mockResolvedValue({ ok: true }); const endpoints = ApifyEndpoints as unknown as Record< @@ -332,13 +347,10 @@ describe('apify endpoint invocation', () => { const endpointFn = nsEndpoints?.[opName]; expect(endpointFn).toBeDefined(); mockRequest.mockClear(); - // Build a deterministic input: a string value for each declared path param. const input: Record = {}; for (const param of def.pathParams) { input[param] = `sample-${param}`; } - // Invoke the endpoint closure — this exercises makeApifyRequest's - // full request-building path (pickDefined/buildQuery/buildBody). await endpointFn?.(makeCtx(), input); const requestOptions = mockRequest.mock.calls[0]?.[1]; @@ -348,9 +360,6 @@ describe('apify endpoint invocation', () => { }); }); -// For every top-level namespace, pick its first leaf operation. Returns the -// namespace, the operation name, and the operation definition so the caller can -// build an input and assert the routed request. function sampleOperationPerNamespace(): Array<{ namespace: string; opName: string; @@ -382,7 +391,6 @@ function firstLeaf( ) { return { opName: key, def: value as unknown as ApifyOperationDefinition }; } - // Descend into subtrees. const nested = firstLeaf(value); if (nested) return nested; } @@ -439,4 +447,13 @@ describe('apify plugin factory', () => { expect(plugin.errorHandlers?.AUTH_ERROR).toBeDefined(); expect(plugin.errorHandlers?.DEFAULT).toBeDefined(); }); + + it('exposes only API Key auth to match the OSS listing', () => { + const plugin = apify({}); + expect(plugin.authConfig).toEqual({ api_key: {} }); + expect( + (plugin.options as { authType?: string } | undefined)?.authType, + ).toBe('api_key'); + expect(plugin.webhooks).toEqual({}); + }); }); diff --git a/packages/apify/schema/database.ts b/packages/apify/schema/database.ts index c2305df68..4c74606a6 100644 --- a/packages/apify/schema/database.ts +++ b/packages/apify/schema/database.ts @@ -130,7 +130,6 @@ export const ApifyUser = z id: z.string(), username: z.string().optional(), email: z.string().email().optional(), - // Apify user profile fields are custom account metadata without a stable provider-wide schema. profile: z.record(z.string(), z.unknown()).optional(), createdAt: z.coerce.date().nullable().optional(), }) From 8021afef0bec88ad3d86edc3ccc5184311aa7766 Mon Sep 17 00:00:00 2001 From: ambikeesshh Date: Fri, 24 Jul 2026 08:04:41 +0530 Subject: [PATCH 15/15] fix(apify): restore 429 retries and document unknown types --- packages/apify/client.ts | 1 + packages/apify/endpoints/index.ts | 6 ++++++ packages/apify/endpoints/types.ts | 4 ++++ packages/apify/error-handlers.ts | 2 +- packages/apify/schema/database.ts | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/apify/client.ts b/packages/apify/client.ts index baee04472..341296022 100644 --- a/packages/apify/client.ts +++ b/packages/apify/client.ts @@ -26,6 +26,7 @@ const RESERVED_INPUT_KEYS = new Set([ 'mediaType', ]); +// Apify JSON payloads are endpoint-specific and passed through unchanged. type ApifyJsonValue = unknown; type ApifyJsonRecord = Record; diff --git a/packages/apify/endpoints/index.ts b/packages/apify/endpoints/index.ts index 1c8a16b14..4bee707fb 100644 --- a/packages/apify/endpoints/index.ts +++ b/packages/apify/endpoints/index.ts @@ -40,6 +40,7 @@ function buildEndpointTree( tree: T, segments: string[] = [], ): ApifyEndpointTree { + // Accumulator holds mixed endpoint fns / nested trees before the final cast. const endpoints: Record = {}; for (const [key, value] of Object.entries(tree)) { @@ -73,8 +74,11 @@ function buildEndpointTree( function createOperationInputSchema(operation: ApifyOperationDefinition) { const shape: Record = { + // Apify request bodies differ per endpoint and are passed through as-is. body: z.unknown().optional(), + // Query values are endpoint-specific and not shared across operations. query: z.record(z.string(), z.unknown()).optional(), + // Custom headers are forwarded without a fixed provider-wide shape. headers: z.record(z.string(), z.unknown()).optional(), contentType: z.string().optional(), mediaType: z.string().optional(), @@ -85,6 +89,7 @@ function createOperationInputSchema(operation: ApifyOperationDefinition) { } for (const param of operation.queryParams ?? []) { + // Query metadata names the param but does not constrain its value type. shape[param] = z.unknown().optional(); } @@ -95,6 +100,7 @@ export function buildApifyEndpointSchemas( tree: T, segments: string[] = [], ): RequiredPluginEndpointSchemas> { + // Schema map is keyed by dotted path before the typed cast. const schemas: Record = {}; for (const [key, value] of Object.entries(tree)) { diff --git a/packages/apify/endpoints/types.ts b/packages/apify/endpoints/types.ts index 1b9774f30..84b9e5e8e 100644 --- a/packages/apify/endpoints/types.ts +++ b/packages/apify/endpoints/types.ts @@ -2,14 +2,18 @@ import { z } from 'zod'; export const ApifyOperationInputSchema = z .object({ + // Apify request bodies differ per endpoint and are passed through as-is. body: z.unknown().optional(), + // Query values are endpoint-specific and not shared across operations. query: z.record(z.string(), z.unknown()).optional(), + // Custom headers are forwarded without a fixed provider-wide shape. headers: z.record(z.string(), z.unknown()).optional(), contentType: z.string().optional(), mediaType: z.string().optional(), }) .loose(); +// Apify responses are endpoint-specific and are not normalized here. export const ApifyOperationOutputSchema = z.unknown(); export type ApifyOperationInput = z.infer; diff --git a/packages/apify/error-handlers.ts b/packages/apify/error-handlers.ts index 297557c8e..8061812ea 100644 --- a/packages/apify/error-handlers.ts +++ b/packages/apify/error-handlers.ts @@ -27,7 +27,7 @@ export const errorHandlers = { ? error.status === 429 : messageOf(error).includes('rate-limit'), handler: async (error: Error) => ({ - maxRetries: 0, + maxRetries: 3, headersRetryAfterMs: error instanceof ApiError ? error.retryAfter : undefined, retryStrategy: 'exponential_backoff_jitter', diff --git a/packages/apify/schema/database.ts b/packages/apify/schema/database.ts index 4c74606a6..b31be0e96 100644 --- a/packages/apify/schema/database.ts +++ b/packages/apify/schema/database.ts @@ -130,6 +130,7 @@ export const ApifyUser = z id: z.string(), username: z.string().optional(), email: z.string().email().optional(), + // Profile is free-form account metadata without a stable schema. profile: z.record(z.string(), z.unknown()).optional(), createdAt: z.coerce.date().nullable().optional(), })