├── .editorconfig ├── .eslintrc.json ├── .github ├── CODEOWNERS ├── scripts │ └── before-beta-release.js └── workflows │ ├── check.yaml │ ├── docs.yaml │ └── release.yaml ├── .gitignore ├── .markdownlint.json ├── .markdownlintignore ├── .npmrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── .gitignore ├── examples │ └── index.md ├── features.md ├── index.md └── usage_concepts.md ├── jest.config.js ├── package-lock.json ├── package.json ├── renovate.json ├── src ├── apify_api_error.ts ├── apify_client.ts ├── base │ ├── api_client.ts │ ├── resource_client.ts │ └── resource_collection_client.ts ├── body_parser.ts ├── http_client.ts ├── index.ts ├── interceptors.ts ├── resource_clients │ ├── actor.ts │ ├── actor_collection.ts │ ├── actor_env_var.ts │ ├── actor_env_var_collection.ts │ ├── actor_version.ts │ ├── actor_version_collection.ts │ ├── build.ts │ ├── build_collection.ts │ ├── dataset.ts │ ├── dataset_collection.ts │ ├── key_value_store.ts │ ├── key_value_store_collection.ts │ ├── log.ts │ ├── request_queue.ts │ ├── request_queue_collection.ts │ ├── run.ts │ ├── run_collection.ts │ ├── schedule.ts │ ├── schedule_collection.ts │ ├── store_collection.ts │ ├── task.ts │ ├── task_collection.ts │ ├── user.ts │ ├── webhook.ts │ ├── webhook_collection.ts │ ├── webhook_dispatch.ts │ └── webhook_dispatch_collection.ts ├── statistics.ts ├── timezones.ts └── utils.ts ├── test ├── _helper.js ├── actors.test.js ├── apify_api_error.test.js ├── builds.test.js ├── datasets.test.js ├── http_client.test.js ├── index.test.js ├── key_value_stores.test.js ├── logs.test.js ├── mock_server │ ├── routes │ │ ├── actors.js │ │ ├── add_routes.js │ │ ├── builds.js │ │ ├── datasets.js │ │ ├── external.js │ │ ├── key_value_stores.js │ │ ├── logs.js │ │ ├── request_queues.js │ │ ├── runs.js │ │ ├── schedules.js │ │ ├── store.ts │ │ ├── tasks.js │ │ ├── users.js │ │ ├── webhook_dispatches.js │ │ └── webhooks.js │ └── server.js ├── request_queues.test.js ├── runs.test.js ├── schedules.test.js ├── statistics.test.ts ├── store.test.ts ├── tasks.test.js ├── tsconfig.json ├── users.test.js ├── utils.test.js ├── webhook_dispatches.test.js └── webhooks.test.js ├── tsconfig.eslint.json ├── tsconfig.json ├── webpack.config.js └── website ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .markdownlint.json ├── .markdownlintignore ├── babel.config.js ├── docusaurus.config.js ├── i18n └── en │ ├── code.json │ ├── docusaurus-plugin-content-blog │ └── options.json │ ├── docusaurus-plugin-content-docs │ ├── current.json │ ├── version-0.22.4.json │ ├── version-1.0.0.json │ ├── version-1.0.1.json │ ├── version-1.0.2.json │ ├── version-1.1.0.json │ ├── version-1.1.2.json │ ├── version-1.2.0.json │ ├── version-1.3.1.json │ ├── version-2.0.1.json │ └── version-2.0.6.json │ └── docusaurus-theme-classic │ ├── footer.json │ └── navbar.json ├── package-lock.json ├── package.json ├── sidebars.js ├── sitePlugin.js ├── src ├── components │ └── ApiLink.jsx ├── pages │ ├── index.js │ ├── index.module.css │ └── versions.js └── theme │ └── NavbarItem │ └── DocsVersionDropdownNavbarItem.js ├── static └── .nojekyll ├── tools └── utils │ ├── createHref.js │ └── externalLink.js ├── tsconfig.eslint.json ├── versioned_docs ├── version-2.6 │ ├── api-packages.json │ ├── api-typedoc.json │ ├── examples │ │ └── index.md │ ├── features.md │ ├── index.md │ └── usage_concepts.md ├── version-2.7 │ ├── .gitignore │ ├── api-packages.json │ ├── api-typedoc.json │ ├── examples │ │ └── index.md │ ├── features.md │ ├── index.md │ └── usage_concepts.md ├── version-2.8 │ ├── .gitignore │ ├── api-packages.json │ ├── api-typedoc.json │ ├── examples │ │ └── index.md │ ├── features.md │ ├── index.md │ └── usage_concepts.md └── version-2.9 │ ├── .gitignore │ ├── api-packages.json │ ├── api-typedoc.json │ ├── examples │ └── index.md │ ├── features.md │ ├── index.md │ └── usage_concepts.md ├── versioned_sidebars ├── version-2.6-sidebars.json ├── version-2.7-sidebars.json ├── version-2.8-sidebars.json └── version-2.9-sidebars.json └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | end_of_line = lf 10 | # editorconfig-tools is unable to ignore longs strings or urls 11 | max_line_length = null 12 | quote_type = single 13 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@apify/ts" 4 | ], 5 | "parserOptions": { 6 | "project": "tsconfig.eslint.json" 7 | }, 8 | "overrides": [ 9 | { 10 | "files": [ 11 | "test/**/*.js" 12 | ], 13 | "env": { 14 | "jest": true 15 | } 16 | } 17 | ], 18 | "rules": { 19 | "@typescript-eslint/no-explicit-any": "off", 20 | "no-void": 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Documentation codeowner 2 | 3 | /docs/*.md @TC-MO 4 | /docs/*.mdx @TC-MO 5 | -------------------------------------------------------------------------------- /.github/scripts/before-beta-release.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const { execSync } = require('child_process'); 4 | 5 | const PKG_JSON_PATH = path.join(__dirname, '..', '..', 'package.json'); 6 | 7 | const pkgJson = require(PKG_JSON_PATH); 8 | 9 | const PACKAGE_NAME = pkgJson.name; 10 | const VERSION = pkgJson.version; 11 | 12 | const nextVersion = getNextVersion(VERSION); 13 | console.log(`before-deploy: Setting version to ${nextVersion}`); 14 | pkgJson.version = nextVersion; 15 | 16 | fs.writeFileSync(PKG_JSON_PATH, JSON.stringify(pkgJson, null, 2) + '\n'); 17 | 18 | function getNextVersion(version) { 19 | const versionString = execSync(`npm show ${PACKAGE_NAME} versions --json`, { encoding: 'utf8'}); 20 | const versions = JSON.parse(versionString); 21 | 22 | if (versions.some(v => v === VERSION)) { 23 | console.error(`before-deploy: A release with version ${VERSION} already exists. Please increment version accordingly.`); 24 | process.exit(1); 25 | } 26 | 27 | const prereleaseNumbers = versions 28 | .filter(v => (v.startsWith(VERSION) && v.includes('-'))) 29 | .map(v => Number(v.match(/\.(\d+)$/)[1])); 30 | const lastPrereleaseNumber = Math.max(-1, ...prereleaseNumbers); 31 | return `${version}-beta.${lastPrereleaseNumber + 1}` 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | # This workflow runs for every pull request to lint and test the proposed changes. 2 | 3 | name: Check 4 | 5 | on: 6 | pull_request: 7 | 8 | jobs: 9 | build_and_test: 10 | name: Build & Test 11 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | node-version: [ 16, 18, 20 ] 18 | 19 | steps: 20 | - name: Cancel Workflow Action 21 | uses: styfle/cancel-workflow-action@0.12.1 22 | with: 23 | access_token: ${{ github.token }} 24 | 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | 28 | - name: Use Node.js ${{ matrix.node-version }} 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | cache: 'npm' 33 | cache-dependency-path: 'package-lock.json' 34 | 35 | - name: Install Dependencies 36 | run: npm ci 37 | 38 | - name: Run Tests 39 | run: npm test 40 | 41 | lint: 42 | name: Lint 43 | runs-on: ubuntu-latest 44 | 45 | steps: 46 | - uses: actions/checkout@v4 47 | - name: Use Node.js 18 48 | uses: actions/setup-node@v4 49 | with: 50 | node-version: 18 51 | cache: 'npm' 52 | cache-dependency-path: 'package-lock.json' 53 | - name: Install Dependencies 54 | run: npm ci 55 | - run: npm run lint 56 | 57 | docs: 58 | name: Docs build 59 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 60 | runs-on: ubuntu-latest 61 | steps: 62 | - name: Checkout Source code 63 | uses: actions/checkout@v4 64 | 65 | - name: Use Node.js 18 66 | uses: actions/setup-node@v4 67 | with: 68 | node-version: 18 69 | cache: 'npm' 70 | cache-dependency-path: 'package-lock.json' 71 | - name: Install Dependencies 72 | run: npm ci 73 | 74 | - name: Install & build & deploy docs 75 | run: | 76 | npm ci --force 77 | cd website 78 | npm ci --force 79 | npm run lint 80 | npm run build 81 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 12 | environment: 13 | name: github-pages 14 | permissions: 15 | contents: write 16 | pages: write 17 | id-token: write 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} 24 | 25 | - name: Use Node.js 16 26 | uses: actions/setup-node@v2-beta 27 | with: 28 | node-version: 16 29 | cache: npm 30 | cache-dependency-path: website/package-lock.json 31 | 32 | - name: Set git identity 33 | run: | 34 | git config user.name 'GitHub Actions' 35 | git config user.email 'github-actions[bot]@users.noreply.github.com' 36 | 37 | - name: Install Node.js dependencies 38 | run: | 39 | npm install 40 | cd website 41 | npm install 42 | npm update @apify/docs-theme 43 | 44 | # We do this as early as possible to prevent conflicts if someone else would push something in the meantime 45 | - name: Commit the updated package.json and lockfile 46 | run: | 47 | git config user.name 'GitHub Actions' 48 | git config user.email 'github-actions[bot]@users.noreply.github.com' 49 | git add website/package.json 50 | git add website/package-lock.json 51 | git diff-index --quiet HEAD || git commit -m 'chore: Automatic theme updating workflow [skip ci]' || true 52 | git push 53 | 54 | - name: Build Docusaurus docs 55 | run: npm run build 56 | working-directory: ./website 57 | 58 | - name: Set up GitHub Pages 59 | uses: actions/configure-pages@v4 60 | 61 | - name: Upload GitHub Pages artifact 62 | uses: actions/upload-pages-artifact@v3 63 | with: 64 | path: ./website/build 65 | 66 | - name: Deploy artifact to GitHub Pages 67 | uses: actions/deploy-pages@v4 68 | 69 | - name: Invalidate CloudFront cache 70 | run: gh workflow run invalidate.yaml --repo apify/apify-docs-private 71 | env: 72 | GITHUB_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }} 73 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Check & Release Beta 2 | 3 | on: 4 | # Push to master will deploy a beta version 5 | push: 6 | branches: 7 | - master 8 | # This will allow releasing beta versions from non-master releases. 9 | # TODO: We need to release this version with other tags than beta. It can mess up the beta version as it will override it with older code. 10 | - version/** 11 | # A release via GitHub releases will deploy a latest version 12 | release: 13 | types: [ published ] 14 | 15 | jobs: 16 | build_and_test: 17 | name: Build & Test 18 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 19 | runs-on: ubuntu-latest 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | node-version: [ 16, 18, 20 ] 25 | 26 | steps: 27 | - name: Cancel Workflow Action 28 | uses: styfle/cancel-workflow-action@0.12.1 29 | with: 30 | access_token: ${{ github.token }} 31 | 32 | - name: Checkout repository 33 | uses: actions/checkout@v4 34 | 35 | - name: Use Node.js ${{ matrix.node-version }} 36 | uses: actions/setup-node@v4 37 | with: 38 | node-version: ${{ matrix.node-version }} 39 | cache: 'npm' 40 | cache-dependency-path: 'package-lock.json' 41 | 42 | - name: Install Dependencies 43 | run: npm ci 44 | 45 | - name: Run Tests 46 | run: npm test 47 | 48 | lint: 49 | name: Lint 50 | runs-on: ubuntu-latest 51 | 52 | steps: 53 | - uses: actions/checkout@v4 54 | - name: Use Node.js 20 55 | uses: actions/setup-node@v4 56 | with: 57 | node-version: ${{ matrix.node-version }} 58 | cache: 'npm' 59 | cache-dependency-path: 'package-lock.json' 60 | - run: npm ci 61 | - run: npm run lint 62 | 63 | 64 | # The deploy job is long but there are only 2 important parts. NPM publish 65 | # and triggering of docker image builds in the apify-actor-docker repo. 66 | deploy: 67 | name: Publish to NPM 68 | needs: [ build_and_test, lint ] 69 | runs-on: ubuntu-latest 70 | steps: 71 | - uses: actions/checkout@v4 72 | - name: Use Node.js 20 73 | uses: actions/setup-node@v4 74 | with: 75 | node-version: ${{ matrix.node-version }} 76 | cache: 'npm' 77 | cache-dependency-path: 'package-lock.json' 78 | - name: Install dependencies 79 | run: | 80 | echo "access=public" >> .npmrc 81 | echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> .npmrc 82 | npm ci 83 | - # Determine if this is a beta or latest release 84 | name: Set Release Tag 85 | run: echo "RELEASE_TAG=$(if [ ${{ github.event_name }} = release ]; then echo latest; else echo beta; fi)" >> $GITHUB_ENV 86 | - # Check version consistency and increment pre-release version number for beta only. 87 | name: Bump pre-release version 88 | if: env.RELEASE_TAG == 'beta' 89 | run: node ./.github/scripts/before-beta-release.js 90 | - name: Build module 91 | run: npm run build 92 | - name: Publish to NPM 93 | run: npm publish --tag ${{ env.RELEASE_TAG }} 94 | - # Latest version is tagged by the release process so we only tag beta here. 95 | name: Tag Version 96 | if: env.RELEASE_TAG == 'beta' 97 | run: | 98 | git_tag=v`node -p "require('./package.json').version"` 99 | git tag $git_tag 100 | git push origin $git_tag 101 | 102 | env: 103 | NODE_AUTH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_NPM_TOKEN }} 104 | NPM_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_NPM_TOKEN }} 105 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | build-docs 4 | node_modules 5 | *.log 6 | *.pid 7 | *.seed 8 | .DS_Store 9 | lib 10 | coverage 11 | .nyc_output 12 | logs 13 | pids 14 | .idea 15 | .vscode 16 | yarn.lock 17 | tmp 18 | jsconfig.json 19 | types 20 | docs/api 21 | docs/typedefs 22 | .history 23 | .docusaurus 24 | tsconfig.tsbuildinfo 25 | apify_storage 26 | crawlee_storage 27 | storage 28 | .turbo 29 | changelog.md 30 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "single-title": false, 3 | "line-length": false, 4 | "code-block-style": { 5 | "style": "fenced" 6 | }, 7 | "no-inline-html": false, 8 | "no-trailing-punctuation": { 9 | "punctuation": ".,;:。,;:" 10 | }, 11 | "no-multiple-blanks": { 12 | "maximum": 2 13 | }, 14 | "no-space-in-emphasis": false, 15 | "link-fragments": false 16 | } 17 | -------------------------------------------------------------------------------- /.markdownlintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | changelog.md 2 | -------------------------------------------------------------------------------- /docs/examples/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic usage 3 | sidebar_label: Basic usage 4 | --- 5 | 6 | This section contains examples of how to use Apify Client for Javascript. 7 | 8 | There is nothing here yet. 9 | -------------------------------------------------------------------------------- /docs/features.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Features' 3 | --- 4 | 5 | # Features 6 | 7 | Besides greatly simplifying the process of querying the Apify API, the client provides other useful features. 8 | 9 | ## Automatic parsing and error handling 10 | 11 | Based on the endpoint, the client automatically extracts the relevant data and returns it in the 12 | expected format. Date strings are automatically converted to `Date` objects. For exceptions, 13 | we throw an `ApifyApiError`, which wraps the plain JSON errors returned by API and enriches 14 | them with other context for easier debugging. 15 | 16 | ## Retries with exponential backoff 17 | 18 | Network communication sometimes fails, that's a given. The client will automatically retry requests that 19 | failed due to a network error, an internal error of the Apify API (HTTP 500+) or rate limit error (HTTP 429). 20 | By default, it will retry up to 8 times. First retry will be attempted after ~500ms, second after ~1000ms 21 | and so on. You can configure those parameters using the `maxRetries` and `minDelayBetweenRetriesMillis` 22 | options of the `ApifyClient` constructor. 23 | 24 | ## Convenience functions and options 25 | 26 | Some actions can't be performed by the API itself, such as indefinite waiting for an actor run to finish 27 | (because of network timeouts). The client provides convenient `call()` and `waitForFinish()` functions that do that. 28 | Key-value store records can be retrieved as objects, buffers or streams via the respective options, dataset items 29 | can be fetched as individual objects or serialized data and we plan to add better stream support and async iterators. 30 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Quick start' 3 | title: 'Quick start' 4 | --- 5 | 6 | # Apify API client for JavaScript 7 | 8 | `apify-client` is the official library to access [Apify API](https://docs.apify.com/api/v2) from your 9 | JavaScript applications. It runs both in Node.js and browser and provides useful features like 10 | automatic retries and convenience functions that improve the experience of using the Apify API. 11 | 12 | You can install the client via the [npm package](https://www.npmjs.com/package/apify-client). To do that, simply run `npm i apify-client`. 13 | 14 | ## Quick Start 15 | 16 | ```js 17 | const { ApifyClient } = require('apify-client'); 18 | 19 | const client = new ApifyClient({ 20 | token: 'MY-APIFY-TOKEN', 21 | }); 22 | 23 | // Starts an actor and waits for it to finish. 24 | const { defaultDatasetId } = await client.actor('john-doe/my-cool-actor').call(); 25 | // Fetches results from the actor's dataset. 26 | const { items } = await client.dataset(defaultDatasetId).listItems(); 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/usage_concepts.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Usage concepts' 3 | --- 4 | 5 | # Usage concepts 6 | 7 | The `ApifyClient` interface follows a generic pattern that is applicable to all of its components. By calling individual methods of `ApifyClient`, specific clients which target individual API resources are created. There are two types of those clients. A client for management of a single resource and a client for a collection of resources. 8 | 9 | ```js 10 | const { ApifyClient } = require('apify-client'); 11 | const apifyClient = new ApifyClient({ token: 'my-token' }); 12 | 13 | // Collection clients do not require a parameter. 14 | const actorCollectionClient = apifyClient.actors(); 15 | // Creates an actor with the name: my-actor. 16 | const myActor = await actorCollectionClient.create({ name: 'my-actor' }); 17 | // Lists all of your actors. 18 | const { items } = await actorCollectionClient.list(); 19 | ``` 20 | 21 | ```js 22 | // Collection clients do not require a parameter. 23 | const datasetCollectionClient = apifyClient.datasets(); 24 | // Gets (or creates, if it doesn't exist) a dataset with the name of my-dataset. 25 | const myDataset = await datasetCollectionClient.getOrCreate('my-dataset'); 26 | ``` 27 | 28 | ```js 29 | // Resource clients accept an ID of the resource. 30 | const actorClient = apifyClient.actor('john-doe/my-actor'); 31 | // Fetches the john-doe/my-actor object from the API. 32 | const myActor = await actorClient.get(); 33 | // Starts the run of john-doe/my-actor and returns the Run object. 34 | const myActorRun = await actorClient.start(); 35 | ``` 36 | 37 | ```js 38 | // Resource clients accept an ID of the resource. 39 | const datasetClient = apifyClient.dataset('john-doe/my-dataset'); 40 | // Appends items to the end of john-doe/my-dataset. 41 | await datasetClient.pushItems([{ foo: 1 }, { bar: 2 }]); 42 | ``` 43 | 44 | > The ID of the resource can be either the `id` of the said resource, or a combination of your `username/resource-name`. 45 | 46 | This is really all you need to remember, because all resource clients follow the pattern you see above. 47 | 48 | ## Nested clients 49 | 50 | Sometimes clients return other clients. That's to simplify working with nested collections, such as runs of a given actor. 51 | 52 | ```js 53 | const actorClient = apifyClient.actor('john-doe/hello-world'); 54 | const runsClient = actorClient.runs(); 55 | // Lists the last 10 runs of the john-doe/hello-world actor. 56 | const { items } = await runsClient.list({ 57 | limit: 10, 58 | desc: true 59 | }) 60 | 61 | // Selects the last run of the john-doe/hello-world actor that finished 62 | // with a SUCCEEDED status. 63 | const lastSucceededRunClient = actorClient.lastRun({ status: 'SUCCEEDED' }); 64 | // Fetches items from the run's dataset. 65 | const { items } = await lastSucceededRunClient.dataset() 66 | .listItems(); 67 | ``` 68 | 69 | > The quick access to `dataset` and other storages directly from the run client can now only be used with the `lastRun()` method, but the feature will be available to all runs in the future. 70 | 71 | ## Pagination 72 | 73 | Most methods named `list` or `listSomething` return a [`Promise`](/reference/interface/PaginatedList). There are some exceptions though, like `listKeys` or `listHead` which paginate differently. The results you're looking for are always stored under `items` and you can use the `limit` property to get only a subset of results. Other props are also available, depending on the method. 74 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | verbose: true, 3 | preset: 'ts-jest', 4 | testEnvironment: 'node', 5 | transform: { 6 | '^.+\\.tsx?$': ['ts-jest', { 7 | tsconfig: 'test/tsconfig.json', 8 | isolatedModules: true, 9 | }], 10 | }, 11 | testTimeout: 20_000, 12 | collectCoverage: true, 13 | collectCoverageFrom: [ 14 | '/src/**/*.[jt]s', 15 | ], 16 | maxWorkers: 3, 17 | }; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apify-client", 3 | "version": "2.9.4", 4 | "description": "Apify API client for JavaScript", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "browser": "dist/bundle.js", 9 | "unpkg": "dist/bundle.js", 10 | "exports": { 11 | "./package.json": "./package.json", 12 | ".": { 13 | "import": "./dist/index.mjs", 14 | "require": "./dist/index.js", 15 | "types": "./dist/index.d.ts", 16 | "browser": "./dist/bundle.js" 17 | } 18 | }, 19 | "keywords": [ 20 | "apify", 21 | "api", 22 | "apifier", 23 | "crawler", 24 | "scraper" 25 | ], 26 | "author": { 27 | "name": "Apify", 28 | "email": "support@apify.com", 29 | "url": "https://apify.com" 30 | }, 31 | "contributors": [ 32 | "Jan Curn ", 33 | "Marek Trunkát ", 34 | "Ondra Urban ", 35 | "Jakub Drobník " 36 | ], 37 | "license": "Apache-2.0", 38 | "repository": { 39 | "type": "git", 40 | "url": "git+https://github.com/apify/apify-client-js" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/apify/apify-client-js/issues" 44 | }, 45 | "homepage": "https://docs.apify.com/api/client/js/", 46 | "files": [ 47 | "dist", 48 | "!dist/*.tsbuildinfo" 49 | ], 50 | "scripts": { 51 | "build": "npm run clean && npm run build:node && npm run build:browser", 52 | "postbuild": "gen-esm-wrapper dist/index.js dist/index.mjs", 53 | "prepublishOnly": "(test $CI || (echo \"Publishing is reserved to CI!\"; exit 1))", 54 | "clean": "rimraf dist", 55 | "test": "npm run build && jest", 56 | "lint": "eslint src test --ext js,jsx,mjs,ts", 57 | "lint:fix": "eslint src test --ext js,jsx,mjs,ts --fix", 58 | "build:node": "tsc", 59 | "build:browser": "webpack" 60 | }, 61 | "dependencies": { 62 | "@apify/consts": "^2.25.0", 63 | "@apify/log": "^2.2.6", 64 | "@crawlee/types": "^3.3.0", 65 | "agentkeepalive": "^4.2.1", 66 | "async-retry": "^1.3.3", 67 | "axios": "^1.6.7", 68 | "content-type": "^1.0.5", 69 | "ow": "^0.28.2", 70 | "tslib": "^2.5.0", 71 | "type-fest": "^4.0.0" 72 | }, 73 | "devDependencies": { 74 | "@apify/eslint-config-ts": "^0.4.0", 75 | "@apify/tsconfig": "^0.1.0", 76 | "@babel/cli": "^7.21.0", 77 | "@babel/core": "^7.21.0", 78 | "@babel/preset-env": "^7.20.2", 79 | "@babel/register": "^7.21.0", 80 | "@crawlee/puppeteer": "^3.2.2", 81 | "@types/async-retry": "^1.4.5", 82 | "@types/content-type": "^1.1.5", 83 | "@types/express": "^4.17.17", 84 | "@types/fs-extra": "^11.0.1", 85 | "@types/jest": "^29.4.0", 86 | "@types/node": "^20.0.0", 87 | "@typescript-eslint/eslint-plugin": "^7.0.0", 88 | "@typescript-eslint/parser": "^7.0.0", 89 | "babel-loader": "^9.1.2", 90 | "body-parser": "^1.19.0", 91 | "compression": "^1.7.4", 92 | "eslint": "^8.45.0", 93 | "express": "^4.18.2", 94 | "fs-extra": "^11.1.0", 95 | "gen-esm-wrapper": "^1.1.2", 96 | "jest": "^29.4.3", 97 | "process": "^0.11.10", 98 | "puppeteer": "^22.0.0", 99 | "rimraf": "^5.0.0", 100 | "terser-webpack-plugin": "^5.3.6", 101 | "ts-jest": "^29.0.5", 102 | "ts-loader": "^9.4.2", 103 | "ts-node": "^10.9.1", 104 | "typescript": "^5.0.0", 105 | "webpack": "^5.75.0", 106 | "webpack-cli": "^5.0.1" 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":semanticCommitTypeAll(chore)" 5 | ], 6 | "pinVersions": false, 7 | "separateMajorMinor": false, 8 | "dependencyDashboard": false, 9 | "semanticCommits": "enabled", 10 | "lockFileMaintenance": { 11 | "enabled": true, 12 | "schedule": [ 13 | "before 2am" 14 | ], 15 | "automerge": true, 16 | "automergeType": "branch" 17 | }, 18 | "constraints": { 19 | "npm": "^8.0.0" 20 | }, 21 | "packageRules": [ 22 | { 23 | "matchUpdateTypes": [ 24 | "patch", 25 | "minor" 26 | ], 27 | "matchCurrentVersion": "!/^0/", 28 | "groupName": "patch/minor dependencies", 29 | "groupSlug": "all-non-major", 30 | "automerge": true, 31 | "automergeType": "branch" 32 | } 33 | ], 34 | "schedule": [ 35 | "every weekday" 36 | ], 37 | "ignoreDeps": [] 38 | } 39 | -------------------------------------------------------------------------------- /src/base/api_client.ts: -------------------------------------------------------------------------------- 1 | import { ApifyClient } from '../apify_client'; 2 | import { HttpClient } from '../http_client'; 3 | 4 | /** @private */ 5 | export interface ApiClientOptions { 6 | baseUrl: string; 7 | resourcePath: string; 8 | apifyClient: ApifyClient; 9 | httpClient: HttpClient; 10 | id?: string; 11 | params?: Record; 12 | } 13 | 14 | export interface ApiClientOptionsWithOptionalResourcePath extends Omit { 15 | resourcePath?: string; 16 | } 17 | 18 | export type ApiClientSubResourceOptions = Omit; 19 | 20 | /** @private */ 21 | export abstract class ApiClient { 22 | id?: string; 23 | 24 | safeId?: string; 25 | 26 | baseUrl: string; 27 | 28 | resourcePath: string; 29 | 30 | url: string; 31 | 32 | apifyClient: ApifyClient; 33 | 34 | httpClient: HttpClient; 35 | 36 | params?: Record; 37 | 38 | constructor(options: ApiClientOptions) { 39 | const { 40 | baseUrl, 41 | apifyClient, 42 | httpClient, 43 | resourcePath, 44 | id, 45 | params = {}, 46 | } = options; 47 | 48 | this.id = id; 49 | this.safeId = id && this._toSafeId(id); 50 | this.baseUrl = baseUrl; 51 | this.resourcePath = resourcePath; 52 | this.url = id 53 | ? `${baseUrl}/${resourcePath}/${this.safeId}` 54 | : `${baseUrl}/${resourcePath}`; 55 | this.apifyClient = apifyClient; 56 | this.httpClient = httpClient; 57 | this.params = params; 58 | } 59 | 60 | protected _subResourceOptions(moreOptions?: T): BaseOptions & T { 61 | const baseOptions: BaseOptions = { 62 | baseUrl: this._url(), 63 | apifyClient: this.apifyClient, 64 | httpClient: this.httpClient, 65 | params: this._params(), 66 | }; 67 | return { ...baseOptions, ...moreOptions } as BaseOptions & T; 68 | } 69 | 70 | protected _url(path?: string): string { 71 | return path ? `${this.url}/${path}` : this.url; 72 | } 73 | 74 | protected _params(endpointParams?: T): Record { 75 | return { ...this.params, ...endpointParams }; 76 | } 77 | 78 | protected _toSafeId(id: string): string { 79 | // The id has the format `username/actor-name`, so we only need to replace the first `/`. 80 | return id.replace('/', '~'); 81 | } 82 | } 83 | 84 | export interface BaseOptions { 85 | baseUrl: string; 86 | apifyClient: ApifyClient; 87 | httpClient: HttpClient; 88 | params: Record; 89 | } 90 | -------------------------------------------------------------------------------- /src/base/resource_client.ts: -------------------------------------------------------------------------------- 1 | import { ACT_JOB_STATUSES, ACT_JOB_TERMINAL_STATUSES } from '@apify/consts'; 2 | 3 | import { ApiClient } from './api_client'; 4 | import { ApifyApiError } from '../apify_api_error'; 5 | import { ApifyRequestConfig } from '../http_client'; 6 | import { 7 | pluckData, 8 | parseDateFields, 9 | catchNotFoundOrThrow, 10 | } from '../utils'; 11 | 12 | /** 13 | * We need to supply some number for the API, 14 | * because it would not accept "Infinity". 15 | * 999999 seconds is more than 10 days. 16 | */ 17 | const MAX_WAIT_FOR_FINISH = 999999; 18 | 19 | /** 20 | * Resource client. 21 | * @private 22 | */ 23 | export class ResourceClient extends ApiClient { 24 | protected async _get(options: T = {} as T): Promise { 25 | const requestOpts: ApifyRequestConfig = { 26 | url: this._url(), 27 | method: 'GET', 28 | params: this._params(options), 29 | }; 30 | try { 31 | const response = await this.httpClient.call(requestOpts); 32 | return parseDateFields(pluckData(response.data)) as R; 33 | } catch (err) { 34 | catchNotFoundOrThrow(err as ApifyApiError); 35 | } 36 | 37 | return undefined; 38 | } 39 | 40 | protected async _update(newFields: T): Promise { 41 | const response = await this.httpClient.call({ 42 | url: this._url(), 43 | method: 'PUT', 44 | params: this._params(), 45 | data: newFields, 46 | }); 47 | return parseDateFields(pluckData(response.data)) as R; 48 | } 49 | 50 | protected async _delete(): Promise { 51 | try { 52 | await this.httpClient.call({ 53 | url: this._url(), 54 | method: 'DELETE', 55 | params: this._params(), 56 | }); 57 | } catch (err) { 58 | catchNotFoundOrThrow(err as ApifyApiError); 59 | } 60 | } 61 | 62 | /** 63 | * This function is used in Build and Run endpoints so it's kept 64 | * here to stay DRY. 65 | */ 66 | protected async _waitForFinish< 67 | R extends { status: typeof ACT_JOB_STATUSES[keyof typeof ACT_JOB_STATUSES]; }, 68 | >(options: WaitForFinishOptions = {}): Promise { 69 | const { 70 | waitSecs = MAX_WAIT_FOR_FINISH, 71 | } = options; 72 | const waitMillis = waitSecs * 1000; 73 | let job: R | undefined; 74 | 75 | const startedAt = Date.now(); 76 | const shouldRepeat = () => { 77 | const millisSinceStart = Date.now() - startedAt; 78 | if (millisSinceStart >= waitMillis) return false; 79 | const hasJobEnded = job && ACT_JOB_TERMINAL_STATUSES.includes(job.status as typeof ACT_JOB_TERMINAL_STATUSES[number]); 80 | return !hasJobEnded; 81 | }; 82 | 83 | do { 84 | const millisSinceStart = Date.now() - startedAt; 85 | const remainingWaitSeconds = Math.round((waitMillis - millisSinceStart) / 1000); 86 | const waitForFinish = Math.max(0, remainingWaitSeconds); 87 | 88 | const requestOpts: ApifyRequestConfig = { 89 | url: this._url(), 90 | method: 'GET', 91 | params: this._params({ waitForFinish }), 92 | }; 93 | try { 94 | const response = await this.httpClient.call(requestOpts); 95 | job = parseDateFields(pluckData(response.data)) as R; 96 | } catch (err) { 97 | catchNotFoundOrThrow(err as ApifyApiError); 98 | job = undefined; 99 | } 100 | 101 | // It might take some time for database replicas to get up-to-date, 102 | // so getRun() might return null. Wait a little bit and try it again. 103 | if (!job) await new Promise((resolve) => setTimeout(resolve, 250)); 104 | } while (shouldRepeat()); 105 | 106 | if (!job) { 107 | const constructorName = this.constructor.name; 108 | const jobName = constructorName.match(/(\w+)Client/)![1].toLowerCase(); 109 | throw new Error(`Waiting for ${jobName} to finish failed. Cannot fetch actor ${jobName} details from the server.`); 110 | } 111 | 112 | return job; 113 | } 114 | } 115 | 116 | export interface WaitForFinishOptions { 117 | waitSecs?: number; 118 | } 119 | -------------------------------------------------------------------------------- /src/base/resource_collection_client.ts: -------------------------------------------------------------------------------- 1 | import { ApiClient } from './api_client'; 2 | import { 3 | pluckData, 4 | parseDateFields, 5 | } from '../utils'; 6 | 7 | /** 8 | * Resource collection client. 9 | * @private 10 | */ 11 | export class ResourceCollectionClient extends ApiClient { 12 | /** 13 | * @private 14 | */ 15 | protected async _list(options: T = {} as T): Promise { 16 | const response = await this.httpClient.call({ 17 | url: this._url(), 18 | method: 'GET', 19 | params: this._params(options), 20 | }); 21 | return parseDateFields(pluckData(response.data)) as R; 22 | } 23 | 24 | protected async _create(resource: D): Promise { 25 | const response = await this.httpClient.call({ 26 | url: this._url(), 27 | method: 'POST', 28 | params: this._params(), 29 | data: resource, 30 | }); 31 | return parseDateFields(pluckData(response.data)) as R; 32 | } 33 | 34 | protected async _getOrCreate(name?: string, resource?: D): Promise { 35 | const response = await this.httpClient.call({ 36 | url: this._url(), 37 | method: 'POST', 38 | params: this._params({ name }), 39 | data: resource, 40 | }); 41 | return parseDateFields(pluckData(response.data)) as R; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/body_parser.ts: -------------------------------------------------------------------------------- 1 | import contentTypeParser from 'content-type'; 2 | import { JsonArray, JsonObject } from 'type-fest'; 3 | 4 | import { isNode } from './utils'; 5 | 6 | const CONTENT_TYPE_JSON = 'application/json'; 7 | const STRINGIFIABLE_CONTENT_TYPE_RXS = [ 8 | new RegExp(`^${CONTENT_TYPE_JSON}`, 'i'), 9 | /^application\/.*xml$/i, 10 | /^text\//i, 11 | ]; 12 | 13 | /** 14 | * Parses a Buffer or ArrayBuffer using the provided content type header. 15 | * 16 | * - application/json is returned as a parsed object. 17 | * - application/*xml and text/* are returned as strings. 18 | * - everything else is returned as original body. 19 | * 20 | * If the header includes a charset, the body will be stringified only 21 | * if the charset represents a known encoding to Node.js or Browser. 22 | */ 23 | export function maybeParseBody(body: Buffer | ArrayBuffer, contentTypeHeader: string): string | Buffer | ArrayBuffer | JsonObject | JsonArray { 24 | let contentType; 25 | let charset: BufferEncoding; 26 | try { 27 | const result = contentTypeParser.parse(contentTypeHeader); 28 | contentType = result.type; 29 | charset = result.parameters.charset as BufferEncoding; 30 | } catch { 31 | // can't parse, keep original body 32 | return body; 33 | } 34 | 35 | // If we can't successfully parse it, we return 36 | // the original buffer rather than a mangled string. 37 | if (!areDataStringifiable(contentType, charset)) return body; 38 | const dataString = isomorphicBufferToString(body, charset); 39 | 40 | return contentType === CONTENT_TYPE_JSON 41 | ? JSON.parse(dataString) 42 | : dataString; 43 | } 44 | 45 | export function isomorphicBufferToString(buffer: Buffer | ArrayBuffer, encoding: BufferEncoding): string { 46 | if (buffer.constructor.name !== ArrayBuffer.name) { 47 | return buffer.toString(encoding); 48 | } 49 | 50 | // Browser decoding only works with UTF-8. 51 | const utf8decoder = new TextDecoder(); 52 | return utf8decoder.decode(new Uint8Array(buffer)); 53 | } 54 | 55 | function isCharsetStringifiable(charset: string) { 56 | if (!charset) return true; // hope that it's utf-8 57 | if (isNode()) return Buffer.isEncoding(charset); 58 | const normalizedCharset = charset.toLowerCase().replace('-', ''); 59 | // Browsers only support decoding utf-8 buffers. 60 | return normalizedCharset === 'utf8'; 61 | } 62 | 63 | function isContentTypeStringifiable(contentType: string) { 64 | if (!contentType) return false; // keep buffer 65 | return STRINGIFIABLE_CONTENT_TYPE_RXS.some((rx) => rx.test(contentType)); 66 | } 67 | 68 | function areDataStringifiable(contentType: string, charset: string) { 69 | return isContentTypeStringifiable(contentType) && isCharsetStringifiable(charset); 70 | } 71 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './apify_client'; 2 | export * from './resource_clients/actor'; 3 | export * from './resource_clients/actor_collection'; 4 | export * from './resource_clients/build'; 5 | export * from './resource_clients/build_collection'; 6 | export * from './resource_clients/dataset'; 7 | export * from './resource_clients/dataset_collection'; 8 | export * from './resource_clients/key_value_store'; 9 | export * from './resource_clients/key_value_store_collection'; 10 | export * from './resource_clients/log'; 11 | export * from './resource_clients/request_queue'; 12 | export * from './resource_clients/request_queue_collection'; 13 | export * from './resource_clients/run'; 14 | export * from './resource_clients/run_collection'; 15 | export * from './resource_clients/schedule'; 16 | export * from './resource_clients/schedule_collection'; 17 | export * from './resource_clients/task'; 18 | export * from './resource_clients/task_collection'; 19 | export * from './resource_clients/user'; 20 | export * from './resource_clients/webhook'; 21 | export * from './resource_clients/webhook_collection'; 22 | export * from './resource_clients/webhook_dispatch'; 23 | export * from './resource_clients/webhook_dispatch_collection'; 24 | export * from './resource_clients/store_collection'; 25 | export { ApifyApiError } from './apify_api_error'; 26 | export { InvalidResponseBodyError } from './interceptors'; 27 | export { PaginatedList, Dictionary } from './utils'; 28 | -------------------------------------------------------------------------------- /src/resource_clients/actor_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { Actor, ActorDefaultRunOptions, ActorExampleRunInput } from './actor'; 4 | import { ActorVersion } from './actor_version'; 5 | import { ApiClientSubResourceOptions } from '../base/api_client'; 6 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 7 | import { PaginatedList } from '../utils'; 8 | 9 | export class ActorCollectionClient extends ResourceCollectionClient { 10 | /** 11 | * @hidden 12 | */ 13 | constructor(options: ApiClientSubResourceOptions) { 14 | super({ 15 | resourcePath: 'acts', 16 | ...options, 17 | }); 18 | } 19 | 20 | /** 21 | * https://docs.apify.com/api/v2#/reference/actors/actor-collection/get-list-of-actors 22 | */ 23 | async list(options: ActorCollectionListOptions = {}): Promise { 24 | ow(options, ow.object.exactShape({ 25 | my: ow.optional.boolean, 26 | limit: ow.optional.number, 27 | offset: ow.optional.number, 28 | desc: ow.optional.boolean, 29 | })); 30 | 31 | return this._list(options); 32 | } 33 | 34 | /** 35 | * https://docs.apify.com/api/v2#/reference/actors/actor-collection/create-actor 36 | */ 37 | async create(actor: ActorCollectionCreateOptions): Promise { 38 | ow(actor, ow.optional.object); 39 | 40 | return this._create(actor); 41 | } 42 | } 43 | 44 | export interface ActorCollectionListOptions { 45 | my?: boolean; 46 | limit?: number; 47 | offset?: number; 48 | desc?: boolean; 49 | } 50 | 51 | export interface ActorCollectionListItem { 52 | id: string; 53 | createdAt: Date; 54 | modifiedAt: Date; 55 | name: string; 56 | username: string; 57 | } 58 | 59 | export type ActorCollectionListResult = PaginatedList; 60 | 61 | export interface ActorCollectionCreateOptions { 62 | categories?: string[]; 63 | defaultRunOptions?: ActorDefaultRunOptions; 64 | description?: string; 65 | exampleRunInput?: ActorExampleRunInput; 66 | isDeprecated?: boolean; 67 | isPublic?: boolean; 68 | name?: string; 69 | restartOnError?: boolean; 70 | seoTitle?: string; 71 | seoDescription?: string; 72 | title?: string; 73 | versions?: ActorVersion[]; 74 | } 75 | -------------------------------------------------------------------------------- /src/resource_clients/actor_env_var.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { ActorEnvironmentVariable } from './actor_version'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceClient } from '../base/resource_client'; 6 | 7 | export class ActorEnvVarClient extends ResourceClient { 8 | /** 9 | * @hidden 10 | */ 11 | constructor(options: ApiClientSubResourceOptions) { 12 | super({ 13 | resourcePath: 'env-vars', 14 | ...options, 15 | }); 16 | } 17 | 18 | /** 19 | * https://docs.apify.com/api/v2#/reference/actors/environment-variable-object/get-environment-variable 20 | */ 21 | async get(): Promise { 22 | return this._get(); 23 | } 24 | 25 | /** 26 | * https://docs.apify.com/api/v2#/reference/actors/environment-variable-object/update-environment-variable 27 | */ 28 | async update(actorEnvVar: ActorEnvironmentVariable): Promise { 29 | ow(actorEnvVar, ow.object); 30 | return this._update(actorEnvVar); 31 | } 32 | 33 | /** 34 | * https://docs.apify.com/api/v2#/reference/actors/environment-variable-object/delete-environment-variable 35 | */ 36 | async delete(): Promise { 37 | return this._delete(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/resource_clients/actor_env_var_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { ActorEnvironmentVariable } from './actor_version'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class ActorEnvVarCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'env-vars', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/actors/environment-variable-collection/get-list-of-environment-variables 21 | */ 22 | async list(options: ActorEnvVarCollectionListOptions = {}): Promise { 23 | ow(options, ow.object.exactShape({ 24 | limit: ow.optional.number, 25 | offset: ow.optional.number, 26 | desc: ow.optional.boolean, 27 | })); 28 | return this._list(options); 29 | } 30 | 31 | /** 32 | * https://docs.apify.com/api/v2#/reference/actors/environment-variable-collection/create-environment-variable 33 | */ 34 | async create(actorEnvVar: ActorEnvironmentVariable): Promise { 35 | ow(actorEnvVar, ow.optional.object); 36 | return this._create(actorEnvVar); 37 | } 38 | } 39 | 40 | export interface ActorEnvVarCollectionListOptions { 41 | limit?: number; 42 | offset?: number; 43 | desc?: boolean; 44 | } 45 | 46 | export type ActorEnvVarListResult = Pick, 'total' | 'items'> 47 | -------------------------------------------------------------------------------- /src/resource_clients/actor_version.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { ActorEnvVarClient } from './actor_env_var'; 4 | import { ActorEnvVarCollectionClient } from './actor_env_var_collection'; 5 | import { ApiClientSubResourceOptions } from '../base/api_client'; 6 | import { ResourceClient } from '../base/resource_client'; 7 | 8 | export class ActorVersionClient extends ResourceClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'versions', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/actors/version-object/get-version 21 | */ 22 | async get(): Promise { 23 | return this._get(); 24 | } 25 | 26 | /** 27 | * https://docs.apify.com/api/v2#/reference/actors/version-object/update-version 28 | */ 29 | async update(newFields: ActorVersion): Promise { 30 | ow(newFields, ow.object); 31 | 32 | return this._update(newFields); 33 | } 34 | 35 | /** 36 | * https://docs.apify.com/api/v2#/reference/actors/version-object/delete-version 37 | */ 38 | async delete(): Promise { 39 | return this._delete(); 40 | } 41 | 42 | /** 43 | * TODO: https://docs.apify.com/api/v2#/reference/actors/env-var-object 44 | */ 45 | envVar(envVarName: string): ActorEnvVarClient { 46 | ow(envVarName, ow.string); 47 | return new ActorEnvVarClient(this._subResourceOptions({ 48 | id: envVarName, 49 | })); 50 | } 51 | 52 | /** 53 | * TODO: https://docs.apify.com/api/v2#/reference/actors/env-var-collection 54 | * @return {ActorVersionCollectionClient} 55 | */ 56 | envVars(): ActorEnvVarCollectionClient { 57 | return new ActorEnvVarCollectionClient(this._subResourceOptions()); 58 | } 59 | } 60 | 61 | export interface BaseActorVersion { 62 | versionNumber?: string; 63 | sourceType: SourceType; 64 | envVars?: ActorEnvironmentVariable[]; 65 | applyEnvVarsToBuild?: boolean; 66 | buildTag?: string; 67 | } 68 | 69 | export interface ActorVersionSourceFiles extends BaseActorVersion { 70 | sourceFiles: ActorVersionSourceFile[]; 71 | } 72 | 73 | export interface ActorVersionSourceFile { 74 | name: string; 75 | format: 'TEXT' | 'BASE64'; 76 | content: string; 77 | } 78 | 79 | export interface ActorVersionGitRepo extends BaseActorVersion { 80 | gitRepoUrl: string; 81 | } 82 | 83 | export interface ActorVersionTarball extends BaseActorVersion { 84 | tarballUrl: string; 85 | } 86 | 87 | export interface ActorVersionGitHubGist extends BaseActorVersion { 88 | gitHubGistUrl: string; 89 | } 90 | 91 | export enum ActorSourceType { 92 | SourceFiles = 'SOURCE_FILES', 93 | GitRepo = 'GIT_REPO', 94 | Tarball = 'TARBALL', 95 | GitHubGist = 'GITHUB_GIST', 96 | } 97 | 98 | export interface ActorEnvironmentVariable { 99 | name?: string; 100 | value?: string; 101 | isSecret?: boolean; 102 | } 103 | 104 | export type ActorVersion = 105 | | ActorVersionSourceFiles 106 | | ActorVersionGitRepo 107 | | ActorVersionTarball 108 | | ActorVersionGitHubGist; 109 | 110 | export type FinalActorVersion = ActorVersion & Required>; 111 | -------------------------------------------------------------------------------- /src/resource_clients/actor_version_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { ActorVersion, FinalActorVersion } from './actor_version'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class ActorVersionCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'versions', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/actors/version-collection/get-list-of-versions 21 | */ 22 | async list(options: ActorVersionCollectionListOptions = {}): Promise { 23 | ow(options, ow.object.exactShape({ 24 | limit: ow.optional.number, 25 | offset: ow.optional.number, 26 | desc: ow.optional.boolean, 27 | })); 28 | 29 | return this._list(options); 30 | } 31 | 32 | /** 33 | * https://docs.apify.com/api/v2#/reference/actors/version-collection/create-version 34 | */ 35 | async create(actorVersion: ActorVersion): Promise { 36 | ow(actorVersion, ow.optional.object); 37 | 38 | return this._create(actorVersion); 39 | } 40 | } 41 | 42 | export interface ActorVersionCollectionListOptions { 43 | limit?: number; 44 | offset?: number; 45 | desc?: boolean; 46 | } 47 | 48 | export type ActorVersionListResult = Pick, 'total' | 'items'> 49 | -------------------------------------------------------------------------------- /src/resource_clients/build.ts: -------------------------------------------------------------------------------- 1 | import { ACT_JOB_TERMINAL_STATUSES } from '@apify/consts'; 2 | import ow from 'ow'; 3 | 4 | import { LogClient } from './log'; 5 | import { ApiClientSubResourceOptions } from '../base/api_client'; 6 | import { ResourceClient } from '../base/resource_client'; 7 | import { 8 | cast, 9 | parseDateFields, 10 | pluckData, 11 | } from '../utils'; 12 | 13 | export class BuildClient extends ResourceClient { 14 | /** 15 | * @hidden 16 | */ 17 | constructor(options: ApiClientSubResourceOptions) { 18 | super({ 19 | resourcePath: 'actor-builds', 20 | ...options, 21 | }); 22 | } 23 | 24 | /** 25 | * https://docs.apify.com/api/v2#/reference/actor-builds/build-object/get-build 26 | */ 27 | async get(options: BuildClientGetOptions = {}): Promise { 28 | ow(options, ow.object.exactShape({ 29 | waitForFinish: ow.optional.number, 30 | })); 31 | 32 | return this._get(options); 33 | } 34 | 35 | /** 36 | * https://docs.apify.com/api/v2#/reference/actor-builds/abort-build/abort-build 37 | */ 38 | async abort(): Promise { 39 | const response = await this.httpClient.call({ 40 | url: this._url('abort'), 41 | method: 'POST', 42 | params: this._params(), 43 | }); 44 | 45 | return cast(parseDateFields(pluckData(response.data))); 46 | } 47 | 48 | /** 49 | * https://docs.apify.com/api/v2#/reference/actor-builds/delete-build/delete-build 50 | */ 51 | async delete(): Promise { 52 | return this._delete(); 53 | } 54 | 55 | /** 56 | * Returns a promise that resolves with the finished Build object when the provided actor build finishes 57 | * or with the unfinished Build object when the `waitSecs` timeout lapses. The promise is NOT rejected 58 | * based on run status. You can inspect the `status` property of the Build object to find out its status. 59 | * 60 | * The difference between this function and the `waitForFinish` parameter of the `get` method 61 | * is the fact that this function can wait indefinitely. Its use is preferable to the 62 | * `waitForFinish` parameter alone, which it uses internally. 63 | * 64 | * This is useful when you need to immediately start a run after a build finishes. 65 | */ 66 | async waitForFinish(options: BuildClientWaitForFinishOptions = {}): Promise { 67 | ow(options, ow.object.exactShape({ 68 | waitSecs: ow.optional.number, 69 | })); 70 | 71 | return this._waitForFinish(options); 72 | } 73 | 74 | /** 75 | * https://docs.apify.com/api/v2#/reference/actor-builds/build-log 76 | */ 77 | log(): LogClient { 78 | return new LogClient(this._subResourceOptions({ 79 | resourcePath: 'log', 80 | })); 81 | } 82 | } 83 | 84 | export interface BuildClientGetOptions { 85 | waitForFinish?: number 86 | } 87 | 88 | export interface BuildClientWaitForFinishOptions { 89 | /** 90 | * Maximum time to wait for the build to finish, in seconds. 91 | * If the limit is reached, the returned promise is resolved to a build object that will have 92 | * status `READY` or `RUNNING`. If `waitSecs` omitted, the function waits indefinitely. 93 | */ 94 | waitSecs?: number; 95 | } 96 | 97 | export interface BuildMeta { 98 | origin: string; 99 | clientIp: string; 100 | userAgent: string; 101 | } 102 | 103 | export interface Build { 104 | id: string; 105 | actId: string; 106 | userId: string; 107 | startedAt: Date; 108 | finishedAt?: Date; 109 | status: typeof ACT_JOB_TERMINAL_STATUSES[number]; 110 | meta: BuildMeta; 111 | stats?: BuildStats; 112 | options?: BuildOptions; 113 | inputSchema?: string; 114 | readme?: string; 115 | buildNumber: string; 116 | usage?: BuildUsage; 117 | usageTotalUsd?: number; 118 | usageUsd?: BuildUsage; 119 | } 120 | 121 | export interface BuildUsage { 122 | ACTOR_COMPUTE_UNITS?: number; 123 | } 124 | 125 | export interface BuildStats { 126 | durationMillis: number; 127 | runTimeSecs: number; 128 | computeUnits: number; 129 | } 130 | 131 | export interface BuildOptions { 132 | useCache?: boolean; 133 | betaPackages?: boolean; 134 | memoryMbytes?: number; 135 | diskMbytes?: number; 136 | } 137 | -------------------------------------------------------------------------------- /src/resource_clients/build_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { Build } from './build'; 4 | import { ApiClientOptionsWithOptionalResourcePath } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class BuildCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientOptionsWithOptionalResourcePath) { 13 | super({ 14 | ...options, 15 | resourcePath: options.resourcePath || 'actor-builds', 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/actors/build-collection/get-list-of-builds 21 | */ 22 | async list(options: BuildCollectionClientListOptions = {}): Promise { 23 | ow(options, ow.object.exactShape({ 24 | limit: ow.optional.number, 25 | offset: ow.optional.number, 26 | desc: ow.optional.boolean, 27 | })); 28 | 29 | return this._list(options); 30 | } 31 | } 32 | 33 | export interface BuildCollectionClientListOptions { 34 | limit?: number; 35 | offset?: number; 36 | desc?: boolean; 37 | } 38 | 39 | export type BuildCollectionClientListItem = Required> & Partial> 40 | 41 | export type BuildCollectionClientListResult = PaginatedList; 42 | -------------------------------------------------------------------------------- /src/resource_clients/dataset_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { Dataset } from './dataset'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class DatasetCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'datasets', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/datasets/dataset-collection/get-list-of-datasets 21 | */ 22 | async list(options: DatasetCollectionClientListOptions = {}): Promise { 23 | ow(options, ow.object.exactShape({ 24 | unnamed: ow.optional.boolean, 25 | limit: ow.optional.number, 26 | offset: ow.optional.number, 27 | desc: ow.optional.boolean, 28 | })); 29 | 30 | return this._list(options); 31 | } 32 | 33 | /** 34 | * https://docs.apify.com/api/v2#/reference/datasets/dataset-collection/create-dataset 35 | */ 36 | async getOrCreate(name?: string, options?: DatasetCollectionClientGetOrCreateOptions): Promise { 37 | ow(name, ow.optional.string); 38 | ow(options?.schema, ow.optional.object); // TODO: Add schema validatioon 39 | 40 | return this._getOrCreate(name, options); 41 | } 42 | } 43 | 44 | export interface DatasetCollectionClientListOptions { 45 | unnamed?: boolean; 46 | limit?: number; 47 | offset?: number; 48 | desc?: boolean; 49 | } 50 | 51 | export interface DatasetCollectionClientGetOrCreateOptions { 52 | schema?: Record; 53 | } 54 | 55 | export type DatasetCollectionClientListResult = PaginatedList 56 | -------------------------------------------------------------------------------- /src/resource_clients/key_value_store_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { KeyValueStore } from './key_value_store'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class KeyValueStoreCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'key-value-stores', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/key-value-stores/store-collection/get-list-of-key-value-stores 21 | */ 22 | async list(options: KeyValueStoreCollectionClientListOptions = {}): Promise> { 23 | ow(options, ow.object.exactShape({ 24 | unnamed: ow.optional.boolean, 25 | limit: ow.optional.number, 26 | offset: ow.optional.number, 27 | desc: ow.optional.boolean, 28 | })); 29 | 30 | return this._list(options); 31 | } 32 | 33 | /** 34 | * https://docs.apify.com/api/v2#/reference/key-value-stores/store-collection/create-key-value-store 35 | */ 36 | async getOrCreate(name?: string, options?: KeyValueStoreCollectionClientGetOrCreateOptions): Promise { 37 | ow(name, ow.optional.string); 38 | ow(options?.schema, ow.optional.object); // TODO: Add schema validatioon 39 | 40 | return this._getOrCreate(name, options); 41 | } 42 | } 43 | 44 | export interface KeyValueStoreCollectionClientListOptions { 45 | unnamed?: boolean; 46 | limit?: number; 47 | offset?: number; 48 | desc?: boolean; 49 | } 50 | 51 | export interface KeyValueStoreCollectionClientGetOrCreateOptions { 52 | schema?: Record; 53 | } 54 | 55 | export type KeyValueStoreCollectionListResult = Omit & { username?: string; }; 56 | -------------------------------------------------------------------------------- /src/resource_clients/log.ts: -------------------------------------------------------------------------------- 1 | import type { Readable } from 'node:stream'; 2 | 3 | import { ApifyApiError } from '../apify_api_error'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceClient } from '../base/resource_client'; 6 | import { ApifyRequestConfig } from '../http_client'; 7 | import { 8 | cast, 9 | catchNotFoundOrThrow, 10 | } from '../utils'; 11 | 12 | export class LogClient extends ResourceClient { 13 | /** 14 | * @hidden 15 | */ 16 | constructor(options: ApiClientSubResourceOptions) { 17 | super({ 18 | resourcePath: 'logs', 19 | ...options, 20 | }); 21 | } 22 | 23 | /** 24 | * https://docs.apify.com/api/v2#/reference/logs/log/get-log 25 | */ 26 | async get(): Promise { 27 | const requestOpts: ApifyRequestConfig = { 28 | url: this._url(), 29 | method: 'GET', 30 | params: this._params(), 31 | }; 32 | 33 | try { 34 | const response = await this.httpClient.call(requestOpts); 35 | return cast(response.data); 36 | } catch (err) { 37 | catchNotFoundOrThrow(err as ApifyApiError); 38 | } 39 | 40 | return undefined; 41 | } 42 | 43 | /** 44 | * Gets the log in a Readable stream format. Only works in Node.js. 45 | * https://docs.apify.com/api/v2#/reference/logs/log/get-log 46 | */ 47 | async stream(): Promise { 48 | const params = { 49 | stream: true, 50 | }; 51 | 52 | const requestOpts: ApifyRequestConfig = { 53 | url: this._url(), 54 | method: 'GET', 55 | params: this._params(params), 56 | responseType: 'stream', 57 | }; 58 | 59 | try { 60 | const response = await this.httpClient.call(requestOpts); 61 | return cast(response.data); 62 | } catch (err) { 63 | catchNotFoundOrThrow(err as ApifyApiError); 64 | } 65 | 66 | return undefined; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/resource_clients/request_queue_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { RequestQueue } from './request_queue'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class RequestQueueCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'request-queues', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/request-queues/queue-collection/get-list-of-request-queues 21 | */ 22 | async list(options: RequestQueueCollectionListOptions = {}): Promise { 23 | ow(options, ow.object.exactShape({ 24 | unnamed: ow.optional.boolean, 25 | limit: ow.optional.number, 26 | offset: ow.optional.number, 27 | desc: ow.optional.boolean, 28 | })); 29 | 30 | return this._list(options); 31 | } 32 | 33 | /** 34 | * https://docs.apify.com/api/v2#/reference/request-queues/queue-collection/create-request-queue 35 | */ 36 | async getOrCreate(name?: string): Promise { 37 | ow(name, ow.optional.string); 38 | 39 | return this._getOrCreate(name); 40 | } 41 | } 42 | 43 | export interface RequestQueueCollectionListOptions { 44 | unnamed?: boolean; 45 | limit?: number; 46 | offset?: number; 47 | desc?: boolean; 48 | } 49 | 50 | export type RequestQueueCollectionListResult = PaginatedList & { unnamed: boolean; } 51 | -------------------------------------------------------------------------------- /src/resource_clients/run_collection.ts: -------------------------------------------------------------------------------- 1 | import { ACT_JOB_STATUSES } from '@apify/consts'; 2 | import ow from 'ow'; 3 | 4 | import { ActorRunListItem } from './actor'; 5 | import { ApiClientOptionsWithOptionalResourcePath } from '../base/api_client'; 6 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 7 | import { PaginatedList } from '../utils'; 8 | 9 | export class RunCollectionClient extends ResourceCollectionClient { 10 | /** 11 | * @hidden 12 | */ 13 | constructor(options: ApiClientOptionsWithOptionalResourcePath) { 14 | super({ 15 | resourcePath: 'runs', 16 | ...options, 17 | }); 18 | } 19 | 20 | /** 21 | * https://docs.apify.com/api/v2#/reference/actors/run-collection/get-list-of-runs 22 | */ 23 | async list(options: RunCollectionListOptions = {}): Promise> { 24 | ow(options, ow.object.exactShape({ 25 | limit: ow.optional.number, 26 | offset: ow.optional.number, 27 | desc: ow.optional.boolean, 28 | status: ow.optional.string.oneOf(Object.values(ACT_JOB_STATUSES)), 29 | })); 30 | 31 | return this._list(options); 32 | } 33 | } 34 | 35 | export interface RunCollectionListOptions { 36 | limit?: number; 37 | offset?: number; 38 | desc?: boolean; 39 | status?: keyof typeof ACT_JOB_STATUSES; 40 | } 41 | -------------------------------------------------------------------------------- /src/resource_clients/schedule.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { ApifyApiError } from '../apify_api_error'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceClient } from '../base/resource_client'; 6 | import { ApifyRequestConfig } from '../http_client'; 7 | import { Timezone } from '../timezones'; 8 | import { 9 | pluckData, 10 | parseDateFields, 11 | catchNotFoundOrThrow, 12 | cast, 13 | DistributiveOptional, 14 | } from '../utils'; 15 | 16 | export class ScheduleClient extends ResourceClient { 17 | /** 18 | * @hidden 19 | */ 20 | constructor(options: ApiClientSubResourceOptions) { 21 | super({ 22 | resourcePath: 'schedules', 23 | ...options, 24 | }); 25 | } 26 | 27 | /** 28 | * https://docs.apify.com/api/v2#/reference/schedules/schedule-object/get-schedule 29 | */ 30 | async get(): Promise { 31 | return this._get(); 32 | } 33 | 34 | /** 35 | * https://docs.apify.com/api/v2#/reference/schedules/schedule-object/update-schedule 36 | */ 37 | async update(newFields: ScheduleCreateOrUpdateData): Promise { 38 | ow(newFields, ow.object); 39 | return this._update(newFields); 40 | } 41 | 42 | /** 43 | * https://docs.apify.com/api/v2#/reference/schedules/schedule-object/delete-schedule 44 | */ 45 | async delete(): Promise { 46 | return this._delete(); 47 | } 48 | 49 | /** 50 | * https://docs.apify.com/api/v2#/reference/schedules/schedule-log/get-schedule-log 51 | */ 52 | async getLog(): Promise { 53 | const requestOpts: ApifyRequestConfig = { 54 | url: this._url('log'), 55 | method: 'GET', 56 | params: this._params(), 57 | }; 58 | try { 59 | const response = await this.httpClient.call(requestOpts); 60 | return cast(parseDateFields(pluckData(response.data))); 61 | } catch (err) { 62 | catchNotFoundOrThrow(err as ApifyApiError); 63 | } 64 | 65 | return undefined; 66 | } 67 | } 68 | 69 | export interface Schedule { 70 | id: string; 71 | userId: string; 72 | name: string; 73 | title?: string; 74 | cronExpression: string; 75 | timezone: Timezone; 76 | isEnabled: boolean; 77 | isExclusive: boolean; 78 | description?: string; 79 | createdAt: Date; 80 | modifiedAt: Date; 81 | nextRunAt: string; 82 | lastRunAt: string; 83 | actions: ScheduleAction[]; 84 | } 85 | 86 | export type ScheduleCreateOrUpdateData = Partial< 87 | Pick< 88 | Schedule, 89 | | 'name' 90 | | 'title' 91 | | 'cronExpression' 92 | | 'timezone' 93 | | 'isEnabled' 94 | | 'isExclusive' 95 | | 'description' 96 | > & { 97 | actions: DistributiveOptional[] 98 | } 99 | >; 100 | 101 | export enum ScheduleActions { 102 | RunActor = 'RUN_ACTOR', 103 | RunActorTask = 'RUN_ACTOR_TASK', 104 | } 105 | 106 | interface BaseScheduleAction { 107 | id: string; 108 | type: Type; 109 | } 110 | 111 | export type ScheduleAction = ScheduleActionRunActor | ScheduleActionRunActorTask; 112 | 113 | export interface ScheduleActionRunActor extends BaseScheduleAction { 114 | actorId: string; 115 | runInput?: ScheduledActorRunInput; 116 | runOptions?: ScheduledActorRunOptions; 117 | } 118 | 119 | export interface ScheduledActorRunInput { 120 | body: string; 121 | contentType: string; 122 | } 123 | 124 | export interface ScheduledActorRunOptions { 125 | build: string; 126 | timeoutSecs: number; 127 | memoryMbytes: number; 128 | } 129 | 130 | export interface ScheduleActionRunActorTask extends BaseScheduleAction { 131 | actorTaskId: string; 132 | input?: string; 133 | } 134 | -------------------------------------------------------------------------------- /src/resource_clients/schedule_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { Schedule, ScheduleCreateOrUpdateData } from './schedule'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class ScheduleCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'schedules', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/schedules/schedules-collection/get-list-of-schedules 21 | */ 22 | async list(options: ScheduleCollectionListOptions = {}): Promise> { 23 | ow(options, ow.object.exactShape({ 24 | limit: ow.optional.number, 25 | offset: ow.optional.number, 26 | desc: ow.optional.boolean, 27 | })); 28 | 29 | return this._list(options); 30 | } 31 | 32 | /** 33 | * https://docs.apify.com/api/v2#/reference/schedules/schedules-collection/create-schedule 34 | */ 35 | async create(schedule?: ScheduleCreateOrUpdateData): Promise { 36 | ow(schedule, ow.optional.object); 37 | 38 | return this._create(schedule); 39 | } 40 | } 41 | 42 | export interface ScheduleCollectionListOptions { 43 | limit?: number; 44 | offset?: number; 45 | desc?: boolean; 46 | } 47 | -------------------------------------------------------------------------------- /src/resource_clients/store_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { ActorStats } from './actor'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class StoreCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'store', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2/#/reference/store/store-actors-collection/get-list-of-actors-in-store 21 | */ 22 | async list(options: StoreCollectionListOptions = {}): Promise> { 23 | ow(options, ow.object.exactShape({ 24 | limit: ow.optional.number, 25 | offset: ow.optional.number, 26 | search: ow.optional.string, 27 | sortBy: ow.optional.string, 28 | category: ow.optional.string, 29 | username: ow.optional.string, 30 | pricingModel: ow.optional.string, 31 | })); 32 | 33 | return this._list(options); 34 | } 35 | } 36 | 37 | export interface PricingInfo { 38 | pricingModel: string; 39 | } 40 | 41 | export interface ActorStoreList { 42 | id: string; 43 | name: string; 44 | username: string; 45 | title?: string; 46 | description?: string; 47 | stats: ActorStats; 48 | currentPricingInfo: PricingInfo; 49 | pictureUrl?: string; 50 | userPictureUrl?: string; 51 | url: string; 52 | } 53 | 54 | export interface StoreCollectionListOptions { 55 | limit?: number; 56 | offset?: number; 57 | search?: string; 58 | sortBy?: string; 59 | category?: string; 60 | username?: string; 61 | pricingModel?: string; 62 | } 63 | -------------------------------------------------------------------------------- /src/resource_clients/task_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { Task, TaskUpdateData } from './task'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class TaskCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'actor-tasks', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/actor-tasks/task-collection/get-list-of-tasks 21 | * @param {object} [options] 22 | * @param {number} [options.limit] 23 | * @param {number} [options.offset] 24 | * @param {boolean} [options.desc] 25 | * @return {Promise} 26 | */ 27 | async list(options: TaskCollectionListOptions = {}): Promise> { 28 | ow(options, ow.object.exactShape({ 29 | limit: ow.optional.number, 30 | offset: ow.optional.number, 31 | desc: ow.optional.boolean, 32 | })); 33 | 34 | return this._list(options); 35 | } 36 | 37 | /** 38 | * https://docs.apify.com/api/v2#/reference/actor-tasks/task-collection/create-task 39 | */ 40 | async create(task: TaskCreateData): Promise { 41 | ow(task, ow.object); 42 | 43 | return this._create(task); 44 | } 45 | } 46 | 47 | export interface TaskCollectionListOptions { 48 | limit?: number; 49 | offset?: number; 50 | desc?: boolean; 51 | } 52 | 53 | export type TaskList = Omit; 54 | 55 | export interface TaskCreateData extends TaskUpdateData { 56 | actId: string; 57 | } 58 | -------------------------------------------------------------------------------- /src/resource_clients/webhook.ts: -------------------------------------------------------------------------------- 1 | import { WEBHOOK_EVENT_TYPES } from '@apify/consts'; 2 | import ow from 'ow'; 3 | 4 | import { WebhookDispatch } from './webhook_dispatch'; 5 | import { WebhookDispatchCollectionClient } from './webhook_dispatch_collection'; 6 | import { ApifyApiError } from '../apify_api_error'; 7 | import { ApiClientSubResourceOptions } from '../base/api_client'; 8 | import { ResourceClient } from '../base/resource_client'; 9 | import { ApifyRequestConfig } from '../http_client'; 10 | import { 11 | pluckData, 12 | parseDateFields, 13 | catchNotFoundOrThrow, 14 | cast, 15 | } from '../utils'; 16 | 17 | export class WebhookClient extends ResourceClient { 18 | /** 19 | * @hidden 20 | */ 21 | constructor(options: ApiClientSubResourceOptions) { 22 | super({ 23 | resourcePath: 'webhooks', 24 | ...options, 25 | }); 26 | } 27 | 28 | /** 29 | * https://docs.apify.com/api/v2#/reference/webhooks/webhook-object/get-webhook 30 | */ 31 | async get(): Promise { 32 | return this._get(); 33 | } 34 | 35 | /** 36 | * https://docs.apify.com/api/v2#/reference/webhooks/webhook-object/update-webhook 37 | */ 38 | async update(newFields: WebhookUpdateData): Promise { 39 | ow(newFields, ow.object); 40 | 41 | return this._update(newFields); 42 | } 43 | 44 | /** 45 | * https://docs.apify.com/api/v2#/reference/webhooks/webhook-object/delete-webhook 46 | */ 47 | async delete(): Promise { 48 | return this._delete(); 49 | } 50 | 51 | /** 52 | * https://docs.apify.com/api/v2#/reference/webhooks/webhook-test/test-webhook 53 | */ 54 | async test(): Promise { 55 | const request: ApifyRequestConfig = { 56 | url: this._url('test'), 57 | method: 'POST', 58 | params: this._params(), 59 | }; 60 | 61 | try { 62 | const response = await this.httpClient.call(request); 63 | return cast(parseDateFields(pluckData(response.data))); 64 | } catch (err) { 65 | catchNotFoundOrThrow(err as ApifyApiError); 66 | } 67 | 68 | return undefined; 69 | } 70 | 71 | /** 72 | * https://docs.apify.com/api/v2#/reference/webhooks/dispatches-collection 73 | */ 74 | dispatches(): WebhookDispatchCollectionClient { 75 | return new WebhookDispatchCollectionClient(this._subResourceOptions({ 76 | resourcePath: 'dispatches', 77 | })); 78 | } 79 | } 80 | 81 | export interface Webhook { 82 | id: string; 83 | userId: string; 84 | createdAt: Date; 85 | modifiedAt: Date; 86 | isAdHoc: boolean; 87 | eventTypes: WebhookEventType[]; 88 | condition: WebhookCondition; 89 | ignoreSslErrors: boolean; 90 | doNotRetry: boolean; 91 | requestUrl: string; 92 | payloadTemplate: string; 93 | lastDispatch: string; 94 | stats: WebhookStats; 95 | shouldInterpolateStrings: boolean; 96 | isApifyIntegration?: boolean; 97 | headersTemplate?: string; 98 | description?: string; 99 | } 100 | 101 | export interface WebhookIdempotencyKey { 102 | idempotencyKey?: string; 103 | } 104 | 105 | export type WebhookUpdateData = Partial< 106 | Pick< 107 | Webhook, 108 | | 'isAdHoc' 109 | | 'eventTypes' 110 | | 'condition' 111 | | 'ignoreSslErrors' 112 | | 'doNotRetry' 113 | | 'requestUrl' 114 | | 'payloadTemplate' 115 | | 'shouldInterpolateStrings' 116 | | 'isApifyIntegration' 117 | | 'headersTemplate' 118 | | 'description' 119 | > 120 | > & WebhookIdempotencyKey; 121 | 122 | export interface WebhookStats { 123 | totalDispatches: number; 124 | } 125 | 126 | export type WebhookEventType = typeof WEBHOOK_EVENT_TYPES[keyof typeof WEBHOOK_EVENT_TYPES]; 127 | 128 | export type WebhookCondition = WebhookAnyRunOfActorCondition | WebhookAnyRunOfActorTaskCondition | WebhookCertainRunCondition; 129 | 130 | export interface WebhookAnyRunOfActorCondition { 131 | actorId: string; 132 | } 133 | 134 | export interface WebhookAnyRunOfActorTaskCondition { 135 | actorTaskId: string; 136 | } 137 | 138 | export interface WebhookCertainRunCondition { 139 | actorRunId: string; 140 | } 141 | -------------------------------------------------------------------------------- /src/resource_clients/webhook_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { Webhook, WebhookUpdateData } from './webhook'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class WebhookCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'webhooks', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/webhooks/webhook-collection/get-list-of-webhooks 21 | */ 22 | async list(options: WebhookCollectionListOptions = {}): Promise>> { 23 | ow(options, ow.object.exactShape({ 24 | limit: ow.optional.number, 25 | offset: ow.optional.number, 26 | desc: ow.optional.boolean, 27 | })); 28 | 29 | return this._list(options); 30 | } 31 | 32 | /** 33 | * https://docs.apify.com/api/v2#/reference/webhooks/webhook-collection/create-webhook 34 | */ 35 | async create(webhook?: WebhookUpdateData): Promise { 36 | ow(webhook, ow.optional.object); 37 | 38 | return this._create(webhook); 39 | } 40 | } 41 | 42 | export interface WebhookCollectionListOptions { 43 | limit?: number; 44 | offset?: number; 45 | desc?: boolean; 46 | } 47 | -------------------------------------------------------------------------------- /src/resource_clients/webhook_dispatch.ts: -------------------------------------------------------------------------------- 1 | import { Webhook, WebhookEventType } from './webhook'; 2 | import { ApiClientSubResourceOptions } from '../base/api_client'; 3 | import { ResourceClient } from '../base/resource_client'; 4 | 5 | export class WebhookDispatchClient extends ResourceClient { 6 | /** 7 | * @hidden 8 | */ 9 | constructor(options: ApiClientSubResourceOptions) { 10 | super({ 11 | resourcePath: 'webhook-dispatches', 12 | ...options, 13 | }); 14 | } 15 | 16 | /** 17 | * https://docs.apify.com/api/v2#/reference/webhook-dispatches/webhook-dispatch-object/get-webhook-dispatch 18 | */ 19 | async get(): Promise { 20 | return this._get(); 21 | } 22 | } 23 | 24 | export interface WebhookDispatch { 25 | id: string; 26 | userId: string; 27 | webhookId: string; 28 | createdAt: Date; 29 | status: WebhookDispatchStatus; 30 | eventType: WebhookEventType; 31 | calls: WebhookDispatchCall[]; 32 | webhook: Pick; 33 | } 34 | 35 | export enum WebhookDispatchStatus { 36 | Active = 'ACTIVE', 37 | Succeeded = 'SUCCEEDED', 38 | Failed = 'FAILED', 39 | } 40 | 41 | export interface WebhookDispatchCall { 42 | startedAt: Date; 43 | finishedAt: Date; 44 | errorMessage: string | null; 45 | responseStatus: number | null; 46 | responseBody: string | null; 47 | } 48 | -------------------------------------------------------------------------------- /src/resource_clients/webhook_dispatch_collection.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | import { WebhookDispatch } from './webhook_dispatch'; 4 | import { ApiClientSubResourceOptions } from '../base/api_client'; 5 | import { ResourceCollectionClient } from '../base/resource_collection_client'; 6 | import { PaginatedList } from '../utils'; 7 | 8 | export class WebhookDispatchCollectionClient extends ResourceCollectionClient { 9 | /** 10 | * @hidden 11 | */ 12 | constructor(options: ApiClientSubResourceOptions) { 13 | super({ 14 | resourcePath: 'webhook-dispatches', 15 | ...options, 16 | }); 17 | } 18 | 19 | /** 20 | * https://docs.apify.com/api/v2#/reference/webhook-dispatches/webhook-dispatches-collection/get-list-of-webhook-dispatches 21 | */ 22 | async list(options: WebhookDispatchCollectionListOptions = {}): Promise> { 23 | ow(options, ow.object.exactShape({ 24 | limit: ow.optional.number, 25 | offset: ow.optional.number, 26 | desc: ow.optional.boolean, 27 | })); 28 | 29 | return this._list(options); 30 | } 31 | } 32 | 33 | export interface WebhookDispatchCollectionListOptions { 34 | limit?: number; 35 | offset?: number; 36 | desc?: boolean; 37 | } 38 | -------------------------------------------------------------------------------- /src/statistics.ts: -------------------------------------------------------------------------------- 1 | import ow from 'ow'; 2 | 3 | export class Statistics { 4 | /** 5 | * Number of Apify client function calls 6 | */ 7 | calls = 0; 8 | 9 | /** 10 | * Number of Apify API requests 11 | */ 12 | requests = 0; 13 | 14 | /** 15 | * Number of times the API returned 429 error. Errors on first attempt are 16 | * counted at index 0. First retry error counts are on index 1 and so on. 17 | */ 18 | rateLimitErrors: number[] = []; 19 | 20 | addRateLimitError(attempt: number): void { 21 | ow(attempt, ow.number.greaterThan(0)); 22 | // attempt is never 0, 23 | // but we don't want index 0 empty 24 | const index = attempt - 1; 25 | this._fillBlanksWithZeroes(index); 26 | this.rateLimitErrors[index]++; 27 | } 28 | 29 | /** 30 | * Removes the necessity to pre-initialize array with correct 31 | * number of zeroes by dynamically filling the empty indexes 32 | * when necessary. 33 | */ 34 | private _fillBlanksWithZeroes(inclusiveIndex: number) { 35 | if (this.rateLimitErrors.length <= inclusiveIndex) { 36 | for (let k = 0; k <= inclusiveIndex; k++) { 37 | if (typeof this.rateLimitErrors[k] !== 'number') { 38 | this.rateLimitErrors[k] = 0; 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/_helper.js: -------------------------------------------------------------------------------- 1 | const { launchPuppeteer, puppeteerUtils } = require('@crawlee/puppeteer'); 2 | 3 | const mockServer = require('./mock_server/server'); 4 | 5 | class Browser { 6 | async start() { 7 | this.browser = await launchPuppeteer({ 8 | launchOptions: { headless: true, args: ['--disable-web-security'] }, 9 | }); 10 | return this.browser; 11 | } 12 | 13 | async getInjectedPage(baseUrl, DEFAULT_OPTIONS) { 14 | const page = await this.browser.newPage(); 15 | await puppeteerUtils.injectFile(page, `${__dirname}/../dist/bundle.js`); 16 | 17 | // eslint-disable-next-line no-console 18 | page.on('console', (msg) => console.log(msg.text())); 19 | await page.evaluate((url, defaultQuery) => { 20 | window.client = new window.Apify.ApifyClient({ 21 | baseUrl: url, 22 | maxRetries: 0, 23 | ...defaultQuery, 24 | }); 25 | }, baseUrl, DEFAULT_OPTIONS); 26 | return page; 27 | } 28 | 29 | async cleanUpBrowser() { 30 | return this.browser.close.call(this.browser); 31 | } 32 | } 33 | 34 | const DEFAULT_OPTIONS = { 35 | token: 'default-token', 36 | }; 37 | 38 | const getExpectedQuery = (callQuery = {}) => { 39 | const query = optsToQuery(callQuery); 40 | return { 41 | ...query, 42 | }; 43 | }; 44 | 45 | function optsToQuery(params) { 46 | return Object 47 | .entries(params) 48 | .filter(([k, v]) => v !== false) // eslint-disable-line no-unused-vars 49 | .map(([k, v]) => { 50 | if (v === true) v = '1'; 51 | else if (Array.isArray(v)) v = v.join(','); 52 | else if (typeof v === 'number') v = v.toString(); 53 | return [k, v]; 54 | }) 55 | .reduce((newObj, [k, v]) => { 56 | newObj[k] = v; 57 | return newObj; 58 | }, {}); 59 | } 60 | 61 | const validateRequest = (query = {}, params = {}, body = {}, additionalHeaders = {}) => { 62 | const headers = { 63 | authorization: `Bearer ${DEFAULT_OPTIONS.token}`, 64 | ...additionalHeaders, 65 | }; 66 | const request = mockServer.getLastRequest(); 67 | const expectedQuery = getExpectedQuery(query); 68 | if (query !== false) expect(request.query).toEqual(expectedQuery); 69 | if (params !== false) expect(request.params).toEqual(params); 70 | if (body !== false) expect(request.body).toEqual(body); 71 | Object.entries(headers).forEach(([key, value]) => { 72 | // Browsers tend to send headers "a bit differently". 73 | expect(request.headers).toHaveProperty(key); 74 | const expectedHeaderValue = value.toLowerCase().replace(/\s/g, ''); 75 | const actualHeaderValue = request.headers[key].toLowerCase().replace(/\s/g, ''); 76 | expect(actualHeaderValue).toBe(expectedHeaderValue); 77 | }); 78 | }; 79 | 80 | module.exports = { 81 | validateRequest, 82 | DEFAULT_OPTIONS, 83 | Browser, 84 | }; 85 | -------------------------------------------------------------------------------- /test/apify_api_error.test.js: -------------------------------------------------------------------------------- 1 | const { Browser } = require('./_helper'); 2 | const { ApifyClient } = require('../src/index'); 3 | 4 | describe('ApifyApiError', () => { 5 | const browser = new Browser(); 6 | 7 | beforeAll(async () => { 8 | await browser.start(); 9 | }); 10 | 11 | afterAll(async () => { 12 | await browser.cleanUpBrowser(); 13 | }); 14 | 15 | test('should carry all the information', async () => { 16 | const client = new ApifyClient(); 17 | const actorCollectionClient = client.actors(); 18 | const method = 'list'; 19 | try { 20 | await actorCollectionClient[method](); 21 | throw new Error('wrong error'); 22 | } catch (err) { 23 | expect(err.name).toEqual('ApifyApiError'); 24 | // This does not work in v10 and lower, but we want to be able to run tests for v10, 25 | // because some people might still use it. They will just see clientMethod: undefined. 26 | if (!process.version.startsWith('v10')) { 27 | expect(err.clientMethod).toBe(`${actorCollectionClient.constructor.name}.${method}`); 28 | } 29 | expect(err.type).toEqual('token-not-provided'); 30 | expect(err.message).toEqual('Authentication token was not provided'); 31 | expect(err.statusCode).toEqual(401); 32 | expect(err.path).toMatch(`/v2/${actorCollectionClient.resourcePath}`); 33 | expect(err.httpMethod).toEqual('get'); 34 | expect(err.attempt).toEqual(1); 35 | } 36 | }); 37 | 38 | test('should carry all the information in browser', async () => { 39 | const page = await browser.getInjectedPage(); 40 | const method = 'list'; 41 | const error = await page.evaluate(async (m) => { 42 | const client = new window.Apify.ApifyClient(); 43 | const actorCollectionClient = client.actors(); 44 | try { 45 | await actorCollectionClient[m](); 46 | throw new Error('wrong error'); 47 | } catch (err) { 48 | const serializableErr = {}; 49 | Object.getOwnPropertyNames(err).forEach((prop) => { 50 | serializableErr[prop] = err[prop]; 51 | }); 52 | serializableErr.resourcePath = actorCollectionClient.resourcePath; 53 | return serializableErr; 54 | } 55 | }, method); 56 | expect(error.name).toEqual('ApifyApiError'); 57 | expect(error.clientMethod).toBe(`ActorCollectionClient.${method}`); 58 | expect(error.type).toEqual('token-not-provided'); 59 | expect(error.message).toEqual('Authentication token was not provided'); 60 | expect(error.statusCode).toEqual(401); 61 | expect(error.path).toMatch(`/v2/${error.resourcePath}`); 62 | expect(error.httpMethod).toEqual('get'); 63 | expect(error.attempt).toEqual(1); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/builds.test.js: -------------------------------------------------------------------------------- 1 | const { Browser, validateRequest, DEFAULT_OPTIONS } = require('./_helper'); 2 | const mockServer = require('./mock_server/server'); 3 | const { ApifyClient } = require('../src'); 4 | 5 | describe('Build methods', () => { 6 | let baseUrl; 7 | const browser = new Browser(); 8 | 9 | beforeAll(async () => { 10 | const server = await mockServer.start(); 11 | await browser.start(); 12 | baseUrl = `http://localhost:${server.address().port}`; 13 | }); 14 | 15 | afterAll(async () => { 16 | await Promise.all([ 17 | mockServer.close(), 18 | browser.cleanUpBrowser(), 19 | ]); 20 | }); 21 | 22 | let client; 23 | let page; 24 | beforeEach(async () => { 25 | page = await browser.getInjectedPage(baseUrl, DEFAULT_OPTIONS); 26 | client = new ApifyClient({ 27 | baseUrl, 28 | maxRetries: 0, 29 | ...DEFAULT_OPTIONS, 30 | }); 31 | }); 32 | afterEach(async () => { 33 | client = null; 34 | page.close().catch(() => {}); 35 | }); 36 | 37 | describe('builds()', () => { 38 | test('list() works', async () => { 39 | const query = { 40 | limit: 5, 41 | offset: 3, 42 | desc: true, 43 | }; 44 | 45 | const res = await client.builds().list(query); 46 | expect(res.id).toEqual('list-builds'); 47 | validateRequest(query); 48 | 49 | const browserRes = await page.evaluate((opts) => client.builds().list(opts), query); 50 | expect(browserRes).toEqual(res); 51 | validateRequest(query); 52 | }); 53 | }); 54 | 55 | describe('build()', () => { 56 | test('get() works', async () => { 57 | const buildId = 'some-build-id'; 58 | 59 | const res = await client.build(buildId).get(); 60 | expect(res.id).toEqual('get-build'); 61 | validateRequest({}, { buildId }); 62 | 63 | const browserRes = await page.evaluate((bId) => client.build(bId).get(), buildId); 64 | expect(browserRes).toEqual(res); 65 | validateRequest({}, { buildId }); 66 | }); 67 | 68 | test('get() returns undefined on 404 status code (RECORD_NOT_FOUND)', async () => { 69 | const buildId = '404'; 70 | 71 | const res = await client.build(buildId).get(); 72 | expect(res).toBeUndefined(); 73 | validateRequest({}, { buildId }); 74 | 75 | const browserRes = await page.evaluate((bId) => client.build(bId).get(), buildId); 76 | expect(browserRes).toEqual(res); 77 | validateRequest({}, { buildId }); 78 | }); 79 | 80 | test('abort() works', async () => { 81 | const buildId = 'some-build-id'; 82 | 83 | const res = await client.build(buildId).abort(); 84 | expect(res.id).toEqual('abort-build'); 85 | validateRequest({}, { buildId }); 86 | 87 | const browserRes = await page.evaluate((bId) => client.build(bId).abort(), buildId); 88 | expect(browserRes).toEqual(res); 89 | validateRequest({}, { buildId }); 90 | }); 91 | 92 | test('waitForFinish() works', async () => { 93 | const buildId = 'some-build-id'; 94 | const waitSecs = 0.1; 95 | const data = { status: 'SUCCEEDED' }; 96 | const body = { data }; 97 | 98 | setTimeout(() => mockServer.setResponse({ body }), (waitSecs * 1000) / 2); 99 | const res = await client.build(buildId).waitForFinish({ waitSecs }); 100 | expect(res).toEqual(data); 101 | validateRequest({ waitForFinish: 0 }, { buildId }); 102 | 103 | const browserRes = await page.evaluate( 104 | (bId, ws) => client.build(bId).waitForFinish({ waitSecs: ws }), 105 | buildId, 106 | waitSecs, 107 | ); 108 | expect(browserRes).toEqual(res); 109 | validateRequest({ waitForFinish: 0 }, { buildId }); 110 | }); 111 | 112 | test('log().get() works', async () => { 113 | const buildId = 'some-build-id'; 114 | 115 | const resource = await client.build(buildId).log().get(); 116 | expect(resource).toEqual('build-log'); 117 | validateRequest({}, { buildId }); 118 | 119 | const browserRes = await page.evaluate((id) => client.build(id).log().get(), buildId); 120 | expect(browserRes).toEqual('build-log'); 121 | validateRequest({}, { buildId }); 122 | }); 123 | }); 124 | }); 125 | -------------------------------------------------------------------------------- /test/http_client.test.js: -------------------------------------------------------------------------------- 1 | const { Browser } = require('./_helper'); 2 | const mockServer = require('./mock_server/server'); 3 | const { ApifyClient } = require('../src/index'); 4 | 5 | describe('HttpClient', () => { 6 | let baseUrl; 7 | const browser = new Browser(); 8 | 9 | beforeAll(async () => { 10 | const server = await mockServer.start(); 11 | await browser.start(); 12 | baseUrl = `http://localhost:${server.address().port}`; 13 | }); 14 | 15 | afterAll(async () => { 16 | await Promise.all([ 17 | mockServer.close(), 18 | browser.cleanUpBrowser(), 19 | ]); 20 | }); 21 | 22 | let client; 23 | let page; 24 | beforeEach(async () => { 25 | page = await browser.getInjectedPage(baseUrl, { timeoutSecs: 1 }); 26 | client = new ApifyClient({ 27 | baseUrl, 28 | timeoutSecs: 1, 29 | maxRetries: 0, 30 | requestInterceptors: [(config) => { 31 | config.headers = {}; 32 | return config; 33 | }], 34 | }); 35 | }); 36 | afterEach(async () => { 37 | client = null; 38 | page.close().catch(() => {}); 39 | }); 40 | test('requests timeout after timeoutSecs', async () => { 41 | const context = { delayMillis: 3000 }; 42 | const resourceId = Buffer.from(JSON.stringify(context)).toString('hex'); 43 | 44 | expect.assertions(2); 45 | try { 46 | await client.actor(resourceId).get(); 47 | } catch (err) { 48 | expect(err.message).toMatch('timeout of 1000ms exceeded'); 49 | } 50 | 51 | try { 52 | const r = await page.evaluate((rId) => client.task(rId).get(), resourceId); 53 | expect(r).toBeDefined(); 54 | } catch (err) { 55 | expect(err).toBeInstanceOf(Error); 56 | // this is failing after axios upgrade, the error is returned with a wrong name and message 57 | // expect(err.message).toMatch('timeout of 1000ms exceeded'); 58 | } 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | const { ApifyClient } = require('../src/index'); 2 | 3 | describe('ApifyClient', () => { 4 | test('default baseUrl is correctly set', () => { 5 | const client = new ApifyClient(); 6 | expect(client.baseUrl).toBe('https://api.apify.com/v2'); 7 | }); 8 | test('baseUrl correctly strips trailing slash', () => { 9 | const exampleUrl = 'https://example.com'; 10 | let client = new ApifyClient({ baseUrl: exampleUrl }); 11 | expect(client.baseUrl).toBe(`${exampleUrl}/v2`); 12 | client = new ApifyClient({ baseUrl: `${exampleUrl}/` }); 13 | expect(client.baseUrl).toBe(`${exampleUrl}/v2`); 14 | }); 15 | test('token correctly set', () => { 16 | const token = 'myToken'; 17 | const client = new ApifyClient({ token }); 18 | expect(client.token).toBe(token); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/logs.test.js: -------------------------------------------------------------------------------- 1 | const { Browser, validateRequest, DEFAULT_OPTIONS } = require('./_helper'); 2 | const mockServer = require('./mock_server/server'); 3 | const { ApifyClient } = require('../src'); 4 | 5 | describe('Log methods', () => { 6 | let baseUrl; 7 | const browser = new Browser(); 8 | 9 | beforeAll(async () => { 10 | const server = await mockServer.start(); 11 | await browser.start(); 12 | baseUrl = `http://localhost:${server.address().port}`; 13 | }); 14 | 15 | afterAll(async () => { 16 | await Promise.all([ 17 | mockServer.close(), 18 | browser.cleanUpBrowser(), 19 | ]); 20 | }); 21 | 22 | let client; 23 | let page; 24 | beforeEach(async () => { 25 | page = await browser.getInjectedPage(baseUrl, DEFAULT_OPTIONS); 26 | client = new ApifyClient({ 27 | baseUrl, 28 | maxRetries: 0, 29 | ...DEFAULT_OPTIONS, 30 | }); 31 | }); 32 | afterEach(async () => { 33 | client = null; 34 | page.close().catch(() => {}); 35 | }); 36 | 37 | describe('log(buildOrRunId)', () => { 38 | test('get() works', async () => { 39 | const logId = 'some-id'; 40 | 41 | const res = await client.log(logId).get(); 42 | expect(res).toBe('get-log'); 43 | validateRequest({}, { logId }); 44 | 45 | const browserRes = await page.evaluate((id) => client.log(id).get(), logId); 46 | expect(browserRes).toEqual(res); 47 | validateRequest({}, { logId }); 48 | }); 49 | 50 | test('stream() works', async () => { 51 | const logId = 'some-id'; 52 | 53 | const res = await client.log(logId).stream(); 54 | const chunks = []; 55 | for await (const chunk of res) { 56 | chunks.push(chunk); 57 | } 58 | const id = Buffer.concat(chunks).toString(); 59 | expect(id).toBe('get-log'); 60 | validateRequest({ stream: true }, { logId }); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/mock_server/routes/actors.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const actors = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'list-actors', method: 'GET', path: '/' }, 9 | { id: 'create-actor', method: 'POST', path: '/' }, 10 | { id: 'update-actor', method: 'PUT', path: '/:actorId' }, 11 | { id: 'delete-actor', method: 'DELETE', path: '/:actorId' }, 12 | { id: 'get-actor', method: 'GET', path: '/:actorId' }, 13 | { id: 'list-runs', method: 'GET', path: '/:actorId/runs' }, 14 | { id: 'run-actor', method: 'POST', path: '/:actorId/runs', type: 'responseJsonMock' }, 15 | { id: 'last-run-get', method: 'GET', path: '/:actorId/runs/last' }, 16 | { id: 'last-run-dataset', method: 'GET', path: '/:actorId/runs/last/dataset' }, 17 | { id: 'last-run-keyValueStore', method: 'GET', path: '/:actorId/runs/last/key-value-store' }, 18 | { id: 'last-run-requestQueue', method: 'GET', path: '/:actorId/runs/last/request-queue' }, 19 | { id: 'last-run-log', method: 'GET', path: '/:actorId/runs/last/log', type: 'text' }, 20 | { id: 'get-run', method: 'GET', path: '/:actorId/runs/:runId', type: 'responseJsonMock' }, 21 | { id: 'abort-run', method: 'POST', path: '/:actorId/runs/:runId/abort' }, 22 | { id: 'metamorph-run', method: 'POST', path: '/:actorId/runs/:runId/metamorph' }, 23 | { id: 'resurrect-run', method: 'POST', path: '/:actorId/runs/:runId/resurrect' }, 24 | { id: 'list-builds', method: 'GET', path: '/:actorId/builds' }, 25 | { id: 'build-actor', method: 'POST', path: '/:actorId/builds' }, 26 | { id: 'get-build', method: 'GET', path: '/:actorId/builds/:buildId', type: 'responseJsonMock' }, 27 | { id: 'abort-build', method: 'POST', path: '/:actorId/builds/:buildId/abort' }, 28 | { id: 'list-actor-versions', method: 'GET', path: '/:actorId/versions' }, 29 | { id: 'create-actor-version', method: 'POST', path: '/:actorId/versions' }, 30 | { id: 'get-actor-version', method: 'GET', path: '/:actorId/versions/:versionNumber' }, 31 | { id: 'update-actor-version', method: 'PUT', path: '/:actorId/versions/:versionNumber' }, 32 | { id: 'delete-actor-version', method: 'DELETE', path: '/:actorId/versions/:versionNumber' }, 33 | { id: 'list-actor-env-vars', method: 'GET', path: '/:actorId/versions/:versionNumber/env-vars' }, 34 | { id: 'create-actor-env-var', method: 'POST', path: '/:actorId/versions/:versionNumber/env-vars' }, 35 | { id: 'get-actor-env-var', method: 'GET', path: '/:actorId/versions/:versionNumber/env-vars/:envVarName' }, 36 | { id: 'update-actor-env-var', method: 'PUT', path: '/:actorId/versions/:versionNumber/env-vars/:envVarName' }, 37 | { id: 'delete-actor-env-var', method: 'DELETE', path: '/:actorId/versions/:versionNumber/env-vars/:envVarName' }, 38 | { id: 'list-webhooks', method: 'GET', path: '/:actorId/webhooks' }, 39 | ]; 40 | 41 | addRoutes(actors, ROUTES); 42 | 43 | module.exports = actors; 44 | -------------------------------------------------------------------------------- /test/mock_server/routes/add_routes.js: -------------------------------------------------------------------------------- 1 | function maybeParseContextFromResourceId(resourceId) { 2 | if (typeof resourceId !== 'string') return; 3 | const hexBuffer = Buffer.from(resourceId, 'hex'); 4 | const json = hexBuffer.toString('utf-8'); 5 | try { 6 | return JSON.parse(json); 7 | } catch (err) { 8 | return undefined; 9 | } 10 | } 11 | 12 | const HANDLERS = { 13 | text(id) { 14 | return (req, res) => { 15 | const [resourceId] = Object.values(req.params); 16 | const responseStatusCode = Number(resourceId) || 200; 17 | let payload; 18 | if (responseStatusCode === 200) payload = id; 19 | else if (responseStatusCode === 204) payload = null; 20 | else if (responseStatusCode === 404) { 21 | payload = { 22 | error: { 23 | type: 'record-not-found', 24 | message: 'Record with this name was not found', 25 | }, 26 | }; 27 | } 28 | 29 | const context = maybeParseContextFromResourceId(resourceId); 30 | const delayMillis = context && context.delayMillis; 31 | setTimeout(() => { 32 | res.send(payload); 33 | }, delayMillis || 0); 34 | }; 35 | }, 36 | json(id) { 37 | return (req, res) => { 38 | const [resourceId] = Object.values(req.params); 39 | const responseStatusCode = Number(resourceId) || 200; 40 | let payload = {}; 41 | if (responseStatusCode === 200) payload = { data: { id } }; 42 | else if (responseStatusCode === 204) payload = null; 43 | else if (responseStatusCode === 404) { 44 | payload = { 45 | error: { 46 | type: 'record-not-found', 47 | message: 'Record with this name was not found', 48 | }, 49 | }; 50 | } 51 | 52 | const context = maybeParseContextFromResourceId(resourceId); 53 | const delayMillis = context && context.delayMillis; 54 | setTimeout(() => { 55 | res 56 | .status(responseStatusCode) 57 | .json(payload); 58 | }, delayMillis || 0); 59 | }; 60 | }, 61 | dummyBatchOperation() { 62 | return (req, res) => { 63 | res.status(200).json({ data: { unprocessedRequests: [], processedRequests: req.body } }); 64 | }; 65 | }, 66 | responseJsonMock(id) { 67 | return (req, res) => { 68 | const [resourceId] = Object.values(req.params); 69 | const responseStatusCode = Number(resourceId) || 200; 70 | 71 | const mockServer = req.app.get('mockServer'); 72 | let body = { data: { id } }; 73 | let headers; 74 | let statusCode = responseStatusCode; 75 | 76 | if (mockServer.response) { 77 | body = mockServer.response.body; 78 | headers = mockServer.response.headers; 79 | statusCode = mockServer.response.statusCode || 200; 80 | } 81 | 82 | let payload; 83 | if (statusCode === 200) payload = body; 84 | else if (statusCode === 204) payload = null; 85 | else if (statusCode === 404) { 86 | payload = { 87 | error: { 88 | type: 'record-not-found', 89 | message: 'Record with this name was not found', 90 | }, 91 | }; 92 | } 93 | 94 | const context = maybeParseContextFromResourceId(resourceId); 95 | const delayMillis = context && context.delayMillis; 96 | setTimeout(() => { 97 | res 98 | .status(statusCode) 99 | .set(headers) 100 | .send(payload); 101 | }, delayMillis || 0); 102 | }; 103 | }, 104 | }; 105 | 106 | exports.addRoutes = (router, routes) => { 107 | routes.forEach((route) => { 108 | const type = route.type ? route.type : 'json'; 109 | const handler = HANDLERS[type]; 110 | const method = route.method.toLowerCase(); 111 | router[method](route.path, handler(route.id)); 112 | }); 113 | }; 114 | -------------------------------------------------------------------------------- /test/mock_server/routes/builds.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const builds = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'list-builds', method: 'GET', path: '/' }, 9 | { id: 'get-build', method: 'GET', path: '/:buildId', type: 'responseJsonMock' }, 10 | { id: 'abort-build', method: 'POST', path: '/:buildId/abort' }, 11 | { id: 'build-log', method: 'GET', path: '/:buildId/log', type: 'text' }, 12 | ]; 13 | 14 | addRoutes(builds, ROUTES); 15 | 16 | module.exports = builds; 17 | -------------------------------------------------------------------------------- /test/mock_server/routes/datasets.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const datasets = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'get-or-create-dataset', method: 'POST', path: '/' }, 9 | { id: 'list-datasets', method: 'GET', path: '/' }, 10 | { id: 'get-dataset', method: 'GET', path: '/:datasetId' }, 11 | { id: 'delete-dataset', method: 'DELETE', path: '/:datasetId' }, 12 | { id: 'update-dataset', method: 'PUT', path: '/:datasetId' }, 13 | { id: 'list-items', method: 'GET', path: '/:datasetId/items', type: 'responseJsonMock' }, 14 | { id: 'push-items', method: 'POST', path: '/:datasetId/items' }, 15 | ]; 16 | 17 | addRoutes(datasets, ROUTES); 18 | 19 | module.exports = datasets; 20 | -------------------------------------------------------------------------------- /test/mock_server/routes/external.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const external = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'signed-url', method: 'PUT', path: '/signed-url/:code', type: 'responseJsonMock' }, 9 | ]; 10 | 11 | addRoutes(external, ROUTES); 12 | 13 | module.exports = external; 14 | -------------------------------------------------------------------------------- /test/mock_server/routes/key_value_stores.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const keyValueStores = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'list-stores', method: 'GET', path: '/' }, 9 | { id: 'get-or-create-store', method: 'POST', path: '/' }, 10 | { id: 'get-store', method: 'GET', path: '/:storeId' }, 11 | { id: 'delete-store', method: 'DELETE', path: '/:storeId' }, 12 | { id: 'update-store', method: 'PUT', path: '/:storeId' }, 13 | { id: 'get-record', method: 'GET', path: '/:storeId/records/:key', type: 'responseJsonMock' }, 14 | { id: 'put-record', method: 'PUT', path: '/:storeId/records/:key' }, 15 | { id: 'direct-upload-url', method: 'GET', path: '/:storeId/records/:key/direct-upload-url', type: 'responseJsonMock' }, 16 | { id: 'delete-record', method: 'DELETE', path: '/:storeId/records/:key' }, 17 | { id: 'list-keys', method: 'GET', path: '/:storeId/keys' }, 18 | ]; 19 | 20 | addRoutes(keyValueStores, ROUTES); 21 | 22 | module.exports = keyValueStores; 23 | -------------------------------------------------------------------------------- /test/mock_server/routes/logs.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const logs = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'get-log', method: 'GET', path: '/:logId', type: 'text' }, 9 | ]; 10 | 11 | addRoutes(logs, ROUTES); 12 | 13 | module.exports = logs; 14 | -------------------------------------------------------------------------------- /test/mock_server/routes/request_queues.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const requestQueues = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'get-or-create-queue', method: 'POST', path: '/' }, 9 | { id: 'list-queues', method: 'GET', path: '/' }, 10 | { id: 'get-queue', method: 'GET', path: '/:queueId' }, 11 | { id: 'delete-queue', method: 'DELETE', path: '/:queueId' }, 12 | { id: 'update-queue', method: 'PUT', path: '/:queueId' }, 13 | { id: 'add-request', method: 'POST', path: '/:queueId/requests/' }, 14 | { id: 'list-requests', method: 'GET', path: '/:queueId/requests/', type: 'responseJsonMock' }, 15 | { id: 'update-request', method: 'PUT', path: '/:queueId/requests/:requestId' }, 16 | { id: 'put-lock-request', method: 'PUT', path: '/:queueId/requests/:requestId/lock' }, 17 | { id: 'delete-lock-request', method: 'DELETE', path: '/:queueId/requests/:requestId/lock' }, 18 | { id: 'batch-insert', method: 'POST', path: '/:queueId/requests/batch', type: 'dummyBatchOperation' }, 19 | { id: 'batch-delete', method: 'DELETE', path: '/:queueId/requests/batch', type: 'dummyBatchOperation' }, 20 | { id: 'get-request', method: 'GET', path: '/:queueId/requests/:requestId' }, 21 | { id: 'delete-request', method: 'DELETE', path: '/:queueId/requests/:requestId' }, 22 | { id: 'get-head', method: 'GET', path: '/:queueId/head' }, 23 | { id: 'post-lock-head', method: 'POST', path: '/:queueId/head/lock' }, 24 | ]; 25 | 26 | addRoutes(requestQueues, ROUTES); 27 | 28 | module.exports = requestQueues; 29 | -------------------------------------------------------------------------------- /test/mock_server/routes/runs.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const runs = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'list-runs', method: 'GET', path: '/' }, 9 | { id: 'get-run', method: 'GET', path: '/:runId', type: 'responseJsonMock' }, 10 | { id: 'abort-run', method: 'POST', path: '/:runId/abort' }, 11 | { id: 'metamorph-run', method: 'POST', path: '/:runId/metamorph' }, 12 | { id: 'reboot-run', method: 'POST', path: '/:runId/reboot' }, 13 | { id: 'resurrect-run', method: 'POST', path: '/:runId/resurrect' }, 14 | { id: 'run-dataset', method: 'GET', path: '/:runId/dataset' }, 15 | { id: 'run-keyValueStore', method: 'GET', path: '/:runId/key-value-store' }, 16 | { id: 'run-requestQueue', method: 'GET', path: '/:runId/request-queue' }, 17 | { id: 'run-log', method: 'GET', path: '/:runId/log', type: 'text' }, 18 | ]; 19 | 20 | addRoutes(runs, ROUTES); 21 | 22 | module.exports = runs; 23 | -------------------------------------------------------------------------------- /test/mock_server/routes/schedules.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const schedules = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'create-schedule', method: 'POST', path: '/' }, 9 | { id: 'list-schedules', method: 'GET', path: '/' }, 10 | { id: 'get-schedule', method: 'GET', path: '/:scheduleId' }, 11 | { id: 'update-schedule', method: 'PUT', path: '/:scheduleId' }, 12 | { id: 'delete-schedule', method: 'DELETE', path: '/:scheduleId' }, 13 | { id: 'get-log', method: 'GET', path: '/:scheduleId/log' }, 14 | ]; 15 | 16 | addRoutes(schedules, ROUTES); 17 | 18 | module.exports = schedules; 19 | -------------------------------------------------------------------------------- /test/mock_server/routes/store.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | import { addRoutes } from './add_routes'; 4 | 5 | const store = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'store-list', method: 'GET', path: '/' }, 9 | ]; 10 | 11 | addRoutes(store, ROUTES); 12 | 13 | module.exports = store; 14 | -------------------------------------------------------------------------------- /test/mock_server/routes/tasks.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const tasks = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'list-tasks', method: 'GET', path: '/' }, 9 | { id: 'create-task', method: 'POST', path: '/' }, 10 | { id: 'update-task', method: 'PUT', path: '/:taskId' }, 11 | { id: 'delete-task', method: 'DELETE', path: '/:taskId' }, 12 | { id: 'get-task', method: 'GET', path: '/:taskId' }, 13 | { id: 'list-runs', method: 'GET', path: '/:taskId/runs' }, 14 | { id: 'run-task', method: 'POST', path: '/:taskId/runs', type: 'responseJsonMock' }, 15 | { id: 'list-webhooks', method: 'GET', path: '/:taskId/webhooks' }, 16 | { id: 'get-input', method: 'GET', path: '/:taskId/input' }, 17 | { id: 'update-input', method: 'PUT', path: '/:taskId/input' }, 18 | ]; 19 | 20 | addRoutes(tasks, ROUTES); 21 | 22 | module.exports = tasks; 23 | -------------------------------------------------------------------------------- /test/mock_server/routes/users.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const users = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'get-user', method: 'GET', path: '/:userId' }, 9 | { id: 'get-monthly-usage', method: 'GET', path: '/:userId/usage/monthly' }, 10 | { id: 'get-limits', method: 'GET', path: '/:userId/limits' }, 11 | ]; 12 | 13 | addRoutes(users, ROUTES); 14 | 15 | module.exports = users; 16 | -------------------------------------------------------------------------------- /test/mock_server/routes/webhook_dispatches.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const webhookDispatches = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'list-dispatches', method: 'GET', path: '/' }, 9 | { id: 'get-dispatch', method: 'GET', path: '/:webhookDispatchId' }, 10 | 11 | ]; 12 | 13 | addRoutes(webhookDispatches, ROUTES); 14 | 15 | module.exports = webhookDispatches; 16 | -------------------------------------------------------------------------------- /test/mock_server/routes/webhooks.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const { addRoutes } = require('./add_routes'); 4 | 5 | const webhooks = express.Router(); 6 | 7 | const ROUTES = [ 8 | { id: 'create-webhook', method: 'POST', path: '/' }, 9 | { id: 'list-webhooks', method: 'GET', path: '/' }, 10 | { id: 'get-webhook', method: 'GET', path: '/:webhookId' }, 11 | { id: 'update-webhook', method: 'PUT', path: '/:webhookId' }, 12 | { id: 'delete-webhook', method: 'DELETE', path: '/:webhookId' }, 13 | { id: 'test-webhook', method: 'POST', path: '/:webhookId/test' }, 14 | { id: 'list-dispatches', method: 'GET', path: '/:webhookId/dispatches' }, 15 | 16 | ]; 17 | 18 | addRoutes(webhooks, ROUTES); 19 | 20 | module.exports = webhooks; 21 | -------------------------------------------------------------------------------- /test/mock_server/server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const path = require('path'); 3 | 4 | const bodyParser = require('body-parser'); 5 | const compression = require('compression'); 6 | const express = require('express'); 7 | 8 | // Routers 9 | const actorRouter = require('./routes/actors'); 10 | const buildRouter = require('./routes/builds'); 11 | const datasetRouter = require('./routes/datasets'); 12 | const external = require('./routes/external'); 13 | const keyValueStores = require('./routes/key_value_stores'); 14 | const logRouter = require('./routes/logs'); 15 | const requestQueues = require('./routes/request_queues'); 16 | const runRouter = require('./routes/runs'); 17 | const schedules = require('./routes/schedules'); 18 | const store = require('./routes/store'); 19 | const taskRouter = require('./routes/tasks'); 20 | const userRouter = require('./routes/users'); 21 | const webhookDispatches = require('./routes/webhook_dispatches'); 22 | const webhooks = require('./routes/webhooks'); 23 | 24 | const app = express(); 25 | const v2Router = express.Router(); 26 | const mockServer = { 27 | requests: [], 28 | response: null, 29 | async start(port = 0) { 30 | this.server = http.createServer(app); 31 | return new Promise((resolve, reject) => { 32 | this.server.on('error', reject); 33 | this.server.on('listening', () => resolve(this.server)); 34 | this.server.listen(port); 35 | }); 36 | }, 37 | async close() { 38 | return new Promise((resolve, reject) => { 39 | if (this.server) { 40 | this.server.close((err) => { 41 | if (err) reject(err); 42 | resolve(); 43 | }); 44 | } 45 | }); 46 | }, 47 | getLastRequest() { 48 | return this.requests.pop(); 49 | }, 50 | getLastRequests(length = 1) { 51 | return this.requests.slice(-length); 52 | }, 53 | setResponse(response) { 54 | this.response = response; 55 | }, 56 | }; 57 | 58 | // Debugging middleware 59 | app.use((req, res, next) => { 60 | next(); 61 | }); 62 | app.use(express.text()); 63 | app.use(express.json({ limit: '9mb' })); 64 | app.use(express.urlencoded({ extended: false })); 65 | app.use(bodyParser.raw()); 66 | app.use(express.static(path.join(__dirname, 'public'))); 67 | app.use(compression()); 68 | 69 | app.use('/', (req, res, next) => { 70 | mockServer.requests.push(req); 71 | next(); 72 | }); 73 | app.set('mockServer', mockServer); 74 | app.use('/v2', v2Router); 75 | app.use('/external', external); 76 | 77 | // Attaching V2 routers 78 | v2Router.use('/acts', actorRouter); 79 | v2Router.use('/actor-builds', buildRouter); 80 | v2Router.use('/actor-runs', runRouter); 81 | v2Router.use('/actor-tasks', taskRouter); 82 | v2Router.use('/users', userRouter); 83 | v2Router.use('/logs', logRouter); 84 | v2Router.use('/datasets', datasetRouter); 85 | v2Router.use('/key-value-stores', keyValueStores); 86 | v2Router.use('/request-queues', requestQueues); 87 | v2Router.use('/webhooks', webhooks); 88 | v2Router.use('/schedules', schedules); 89 | v2Router.use('/webhook-dispatches', webhookDispatches); 90 | v2Router.use('/store', store); 91 | 92 | // Debugging middleware 93 | app.use((err, req, res, next) => { // eslint-disable-line 94 | res.status(500).json({ error: { message: err.message } }); 95 | }); 96 | 97 | app.use((req, res) => { 98 | res.status(404).json({ 99 | error: { 100 | type: 'page-not-found', 101 | message: 'Nothing to do here.', 102 | }, 103 | }); 104 | }); 105 | 106 | module.exports = mockServer; 107 | -------------------------------------------------------------------------------- /test/statistics.test.ts: -------------------------------------------------------------------------------- 1 | import { Statistics } from '../src/statistics'; 2 | 3 | describe('Statistics', () => { 4 | test.each([ 5 | [[1], [1]], 6 | [[1, 5], [1, 0, 0, 0, 1]], 7 | [[5, 1], [1, 0, 0, 0, 1]], 8 | [[3, 5, 1], [1, 0, 1, 0, 1]], 9 | [[1, 5, 3], [1, 0, 1, 0, 1]], 10 | [[2, 1, 2, 1, 5, 2, 1], [3, 3, 0, 0, 1]], 11 | ])('addRateLimitError() works with %s', (attempts, errors) => { 12 | const stats = new Statistics(); 13 | attempts.forEach((a) => stats.addRateLimitError(a)); 14 | expect(stats.rateLimitErrors).toEqual(errors); 15 | }); 16 | 17 | test('addRateLimitError() throws with 0', () => { 18 | const stats = new Statistics(); 19 | expect(() => stats.addRateLimitError(0)).toThrow(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/store.test.ts: -------------------------------------------------------------------------------- 1 | import { Browser, DEFAULT_OPTIONS, validateRequest } from './_helper'; 2 | import mockServer from './mock_server/server'; 3 | import { ApifyClient, StoreCollectionListOptions } from '../src'; 4 | 5 | describe('Store', () => { 6 | let baseUrl: string | undefined; 7 | const browser = new Browser(); 8 | 9 | beforeAll(async () => { 10 | const server = await mockServer.start(); 11 | await browser.start(); 12 | baseUrl = `http://localhost:${server.address().port}`; 13 | }); 14 | 15 | afterAll(async () => { 16 | await Promise.all([ 17 | mockServer.close(), 18 | browser.cleanUpBrowser(), 19 | ]); 20 | }); 21 | 22 | let client: ApifyClient | undefined; 23 | let page: any; 24 | beforeEach(async () => { 25 | page = await browser.getInjectedPage(baseUrl, DEFAULT_OPTIONS); 26 | client = new ApifyClient({ 27 | baseUrl, 28 | maxRetries: 0, 29 | ...DEFAULT_OPTIONS, 30 | }); 31 | }); 32 | afterEach(async () => { 33 | client = undefined; 34 | page.close().catch(() => {}); 35 | }); 36 | 37 | test('list() works', async () => { 38 | const opts = { 39 | limit: 5, 40 | offset: 3, 41 | search: 'my search', 42 | sortBy: 'my sort', 43 | category: 'my category', 44 | username: 'my username', 45 | pricingModel: 'my pricing model', 46 | }; 47 | 48 | const res: any = client && await client.store().list(opts); 49 | expect(res.id).toEqual('store-list'); 50 | validateRequest(opts); 51 | 52 | const browserRes: any = await page.evaluate(async (options: StoreCollectionListOptions) => client && client.store().list(options), opts); 53 | expect(browserRes.id).toEqual('store-list'); 54 | expect(browserRes).toEqual(res); 55 | validateRequest(opts); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./", 5 | "noEmit": true, 6 | "allowJs": true 7 | }, 8 | "include": [ 9 | ".", 10 | "../src/**/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /test/users.test.js: -------------------------------------------------------------------------------- 1 | const { ME_USER_NAME_PLACEHOLDER } = require('@apify/consts'); 2 | 3 | const { Browser, validateRequest, DEFAULT_OPTIONS } = require('./_helper'); 4 | const mockServer = require('./mock_server/server'); 5 | const { ApifyClient } = require('../src'); 6 | 7 | describe('User methods', () => { 8 | let baseUrl; 9 | const browser = new Browser(); 10 | 11 | beforeAll(async () => { 12 | const server = await mockServer.start(); 13 | await browser.start(); 14 | baseUrl = `http://localhost:${server.address().port}`; 15 | }); 16 | 17 | afterAll(async () => { 18 | await Promise.all([ 19 | mockServer.close(), 20 | browser.cleanUpBrowser(), 21 | ]); 22 | }); 23 | 24 | let client; 25 | let page; 26 | beforeEach(async () => { 27 | page = await browser.getInjectedPage(baseUrl, DEFAULT_OPTIONS); 28 | client = new ApifyClient({ 29 | baseUrl, 30 | maxRetries: 0, 31 | ...DEFAULT_OPTIONS, 32 | }); 33 | }); 34 | afterEach(async () => { 35 | client = null; 36 | page.close().catch(() => {}); 37 | }); 38 | 39 | describe('user(id)', () => { 40 | test('get() works', async () => { 41 | const userId = 'some-id'; 42 | 43 | const res = await client.user(userId).get(); 44 | expect(res.id).toEqual('get-user'); 45 | validateRequest({}, { userId }); 46 | 47 | const browserRes = await page.evaluate((id) => client.user(id).get(), userId); 48 | expect(browserRes).toEqual(res); 49 | validateRequest({}, { userId }); 50 | }); 51 | 52 | test('get() with no userId', async () => { 53 | const res = await client.user().get(); 54 | expect(res.id).toEqual('get-user'); 55 | validateRequest({}, { userId: ME_USER_NAME_PLACEHOLDER }); 56 | 57 | const browserRes = await page.evaluate((id) => client.user(id).get()); 58 | expect(browserRes).toEqual(res); 59 | validateRequest({}, { userId: ME_USER_NAME_PLACEHOLDER }); 60 | }); 61 | 62 | test('monthlyUsage() works', async () => { 63 | const userId = 'some-id'; 64 | 65 | const res = await client.user(userId).monthlyUsage(); 66 | expect(res.id).toEqual('get-monthly-usage'); 67 | validateRequest({}, { userId }); 68 | 69 | const browserRes = await page.evaluate((id) => client.user(id).monthlyUsage(), userId); 70 | expect(browserRes).toEqual(res); 71 | validateRequest({}, { userId }); 72 | }); 73 | 74 | test('limits() works', async () => { 75 | const userId = 'some-id'; 76 | 77 | const res = await client.user(userId).limits(); 78 | expect(res.id).toEqual('get-limits'); 79 | validateRequest({}, { userId }); 80 | 81 | const browserRes = await page.evaluate((id) => client.user(id).limits(), userId); 82 | expect(browserRes).toEqual(res); 83 | validateRequest({}, { userId }); 84 | }); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /test/webhook_dispatches.test.js: -------------------------------------------------------------------------------- 1 | const { Browser, validateRequest, DEFAULT_OPTIONS } = require('./_helper'); 2 | const mockServer = require('./mock_server/server'); 3 | const { ApifyClient } = require('../src'); 4 | 5 | describe('Webhook Dispatch methods', () => { 6 | let baseUrl; 7 | const browser = new Browser(); 8 | 9 | beforeAll(async () => { 10 | const server = await mockServer.start(); 11 | await browser.start(); 12 | baseUrl = `http://localhost:${server.address().port}`; 13 | }); 14 | 15 | afterAll(async () => { 16 | await Promise.all([ 17 | mockServer.close(), 18 | browser.cleanUpBrowser(), 19 | ]); 20 | }); 21 | 22 | let client; 23 | let page; 24 | beforeEach(async () => { 25 | page = await browser.getInjectedPage(baseUrl, DEFAULT_OPTIONS); 26 | client = new ApifyClient({ 27 | baseUrl, 28 | maxRetries: 0, 29 | ...DEFAULT_OPTIONS, 30 | }); 31 | }); 32 | afterEach(async () => { 33 | client = null; 34 | page.close().catch(() => {}); 35 | }); 36 | 37 | describe('webhookDispatches()', () => { 38 | test('list() works', async () => { 39 | const opts = { 40 | limit: 5, 41 | offset: 3, 42 | desc: true, 43 | }; 44 | 45 | const res = await client.webhookDispatches().list(opts); 46 | expect(res.id).toEqual('list-dispatches'); 47 | validateRequest(opts); 48 | 49 | const browserRes = await page.evaluate((options) => client.webhookDispatches().list(options), opts); 50 | expect(browserRes).toEqual(res); 51 | validateRequest(opts); 52 | }); 53 | }); 54 | 55 | describe('webhookDispatch(id)', () => { 56 | test('get() works', async () => { 57 | const webhookDispatchId = 'some-id'; 58 | 59 | const res = await client.webhookDispatch(webhookDispatchId).get(); 60 | expect(res.id).toEqual('get-dispatch'); 61 | validateRequest({}, { webhookDispatchId }); 62 | 63 | const browserRes = await page.evaluate((id) => client.webhookDispatch(id).get(), webhookDispatchId); 64 | expect(browserRes).toEqual(res); 65 | validateRequest({}, { webhookDispatchId }); 66 | }); 67 | 68 | test('get() 404 works', async () => { 69 | const webhookDispatchId = '404'; 70 | 71 | const res = await client.webhookDispatch(webhookDispatchId).get(); 72 | expect(res).toBeUndefined(); 73 | validateRequest({}, { webhookDispatchId }); 74 | 75 | const browserRes = await page.evaluate((id) => client.webhookDispatch(id).get(), webhookDispatchId); 76 | expect(browserRes).toEqual(res); 77 | validateRequest({}, { webhookDispatchId }); 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | "src/**/*", 5 | "test", 6 | "jest.config.ts", 7 | "webpack.config.js" 8 | ], 9 | "compilerOptions": { 10 | "allowJs": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@apify/tsconfig", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "lib": ["ESNext", "DOM"], 6 | "outDir": "dist", 7 | "skipLibCheck": true 8 | }, 9 | "include": [ 10 | "./src/**/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const { ProvidePlugin, DefinePlugin } = require('webpack'); 2 | const TerserPlugin = require('terser-webpack-plugin'); 3 | 4 | const Package = require('./package.json'); 5 | 6 | /** @type {import('webpack').Configuration} */ 7 | module.exports = { 8 | entry: './src/index.ts', 9 | target: 'web', 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.(js)$/, 14 | exclude: /node_modules/, 15 | use: { 16 | loader: 'babel-loader', 17 | }, 18 | }, 19 | { 20 | test: /\.(ts)$/, 21 | exclude: /node_modules/, 22 | use: { 23 | loader: 'ts-loader', 24 | }, 25 | }, 26 | ], 27 | }, 28 | resolve: { 29 | mainFields: ['browser', 'main', 'module'], 30 | extensions: ['*', '.js', '.ts'], 31 | fallback: { 32 | fs: false, 33 | os: false, 34 | stream: false, 35 | util: false, 36 | zlib: false, 37 | }, 38 | }, 39 | node: { 40 | global: false, 41 | }, 42 | output: { 43 | path: `${__dirname}/dist`, 44 | filename: 'bundle.js', 45 | libraryTarget: 'umd', 46 | library: 'Apify', 47 | }, 48 | mode: 'production', 49 | plugins: [ 50 | new ProvidePlugin({ 51 | process: require.resolve('process/browser'), 52 | }), 53 | new DefinePlugin({ 54 | VERSION: JSON.stringify(Package.version), 55 | BROWSER_BUILD: true, 56 | }), 57 | ], 58 | optimization: { 59 | minimizer: [ 60 | new TerserPlugin({ 61 | terserOptions: { 62 | keep_classnames: true, 63 | }, 64 | }), 65 | ], 66 | }, 67 | }; 68 | -------------------------------------------------------------------------------- /website/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | end_of_line = lf 10 | # editorconfig-tools is unable to ignore longs strings or urls 11 | max_line_length = null 12 | quote_type = single 13 | -------------------------------------------------------------------------------- /website/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | -------------------------------------------------------------------------------- /website/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@apify/eslint-config-ts", 4 | "plugin:react/recommended", 5 | "plugin:react-hooks/recommended" 6 | ], 7 | "parserOptions": { 8 | "files": ["*.js", "*.jsx", "*.ts", "*.tsx"], 9 | "project": "./tsconfig.eslint.json", 10 | "ecmaFeatures": { 11 | "jsx": true 12 | }, 13 | "ecmaVersion": 2020 14 | }, 15 | "env": { 16 | "browser": true 17 | }, 18 | "settings": { 19 | "react": { 20 | "version": "detect" 21 | } 22 | }, 23 | "root": true, 24 | "rules": { 25 | "quote-props": ["error", "consistent"], 26 | "react/prop-types": ["off"] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /website/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "single-title": false, 3 | "line-length": false, 4 | "code-block-style": { 5 | "style": "fenced" 6 | }, 7 | "no-inline-html": false, 8 | "no-trailing-punctuation": { 9 | "punctuation": ".,;:。,;:" 10 | }, 11 | "no-multiple-blanks": { 12 | "maximum": 2 13 | }, 14 | "no-space-in-emphasis": false, 15 | "link-fragments": false 16 | } 17 | -------------------------------------------------------------------------------- /website/.markdownlintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require,import/no-extraneous-dependencies */ 2 | const { config } = require('@apify/docs-theme'); 3 | const { externalLinkProcessor } = require('./tools/utils/externalLink'); 4 | const versions = require('./versions.json'); 5 | 6 | const { absoluteUrl } = config; 7 | /** @type {Partial} */ 8 | module.exports = { 9 | title: 'API client for JavaScript | Apify Documentation', 10 | url: absoluteUrl, 11 | baseUrl: '/api/client/js', 12 | trailingSlash: false, 13 | organizationName: 'apify', 14 | projectName: 'apify-client-js', 15 | favicon: 'img/favicon.ico', 16 | onBrokenLinks: 17 | /** @type {import('@docusaurus/types').ReportingSeverity} */ ('throw'), 18 | onBrokenMarkdownLinks: 19 | /** @type {import('@docusaurus/types').ReportingSeverity} */ ('throw'), 20 | themes: [ 21 | [ 22 | '@apify/docs-theme', 23 | /** @type { import('@apify/docs-theme/types').ThemeOptions } */ 24 | { 25 | subNavbar: { 26 | title: 'API client for JavaScript', 27 | items: [ 28 | { 29 | to: 'docs', 30 | label: 'Docs', 31 | activeBaseRegex: '/docs(?!/changelog|/examples)', 32 | }, 33 | // { 34 | // to: 'docs/examples', 35 | // label: 'Examples', 36 | // activeBaseRegex: '/docs/examples', 37 | // }, 38 | { 39 | to: 'reference', 40 | label: 'Reference', 41 | activeBaseRegex: '/reference', 42 | }, 43 | { 44 | to: 'docs/changelog', 45 | label: 'Changelog', 46 | activeBaseRegex: '/changelog', 47 | }, 48 | { 49 | href: 'https://github.com/apify/apify-client-js', 50 | label: 'GitHub', 51 | }, 52 | { 53 | 'type': 'docsVersionDropdown', 54 | 'position': 'left', 55 | 'className': 'navbar__item', // fixes margin around dropdown - hackish, should be fixed in theme 56 | 'data-api-links': JSON.stringify([ 57 | 'reference/next', 58 | ...versions.map((version, i) => (i === 0 ? 'reference' : `reference/${version}`)), 59 | ]), 60 | 'dropdownItemsBefore': [], 61 | 'dropdownItemsAfter': [], 62 | }, 63 | ], 64 | }, 65 | }, 66 | ], 67 | ], 68 | presets: /** @type {import('@docusaurus/types').PresetConfig[]} */ ([ 69 | [ 70 | '@docusaurus/preset-classic', 71 | /** @type {import('@docusaurus/preset-classic').Options} */ 72 | ({ 73 | docs: { 74 | path: '../docs', 75 | sidebarPath: './sidebars.js', 76 | rehypePlugins: [externalLinkProcessor], 77 | editUrl: 'https://github.com/apify/apify-client-js/edit/master/website/', 78 | }, 79 | }), 80 | ], 81 | ]), 82 | plugins: [ 83 | [ 84 | 'docusaurus-plugin-typedoc-api', 85 | { 86 | projectRoot: `${__dirname}/..`, 87 | changelogs: false, 88 | readmes: false, 89 | packages: [{ path: '.' }], 90 | typedocOptions: { 91 | excludeExternals: false, 92 | }, 93 | routeBasePath: '/reference', 94 | }, 95 | ], 96 | ...config.plugins, 97 | ], 98 | themeConfig: { ...config.themeConfig, versions }, 99 | staticDirectories: ['node_modules/@apify/docs-theme/static', 'static'], 100 | }; 101 | -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-blog/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": { 3 | "message": "Blog", 4 | "description": "The title for the blog used in SEO" 5 | }, 6 | "description": { 7 | "message": "Blog", 8 | "description": "The description for the blog used in SEO" 9 | }, 10 | "sidebar.title": { 11 | "message": "Recent posts", 12 | "description": "The label for the left sidebar" 13 | } 14 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/current.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "Next", 4 | "description": "The label for version current" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-0.22.4.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "0.22.4", 4 | "description": "The label for version 0.22.4" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "1.0.0", 4 | "description": "The label for version 1.0.0" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-1.0.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "1.0.1", 4 | "description": "The label for version 1.0.1" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-1.0.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "1.0.2", 4 | "description": "The label for version 1.0.2" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-1.1.0.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "1.1.0", 4 | "description": "The label for version 1.1.0" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-1.1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "1.1.2", 4 | "description": "The label for version 1.1.2" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-1.2.0.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "1.2.0", 4 | "description": "The label for version 1.2.0" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-1.3.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "1.3.1", 4 | "description": "The label for version 1.3.1" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-2.0.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "2.0.1", 4 | "description": "The label for version 2.0.1" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-plugin-content-docs/version-2.0.6.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "2.0.6", 4 | "description": "The label for version 2.0.6" 5 | }, 6 | "sidebar.docs.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar docs" 9 | }, 10 | "sidebar.docs.category.Examples": { 11 | "message": "Examples", 12 | "description": "The label for category Examples in sidebar docs" 13 | }, 14 | "sidebar.docs.category.API Reference": { 15 | "message": "API Reference", 16 | "description": "The label for category API Reference in sidebar docs" 17 | }, 18 | "sidebar.docs.category.Crawlers": { 19 | "message": "Crawlers", 20 | "description": "The label for category Crawlers in sidebar docs" 21 | }, 22 | "sidebar.docs.category.Result Stores": { 23 | "message": "Result Stores", 24 | "description": "The label for category Result Stores in sidebar docs" 25 | }, 26 | "sidebar.docs.category.Scaling": { 27 | "message": "Scaling", 28 | "description": "The label for category Scaling in sidebar docs" 29 | }, 30 | "sidebar.docs.category.Sources": { 31 | "message": "Sources", 32 | "description": "The label for category Sources in sidebar docs" 33 | }, 34 | "sidebar.docs.category.Utilities": { 35 | "message": "Utilities", 36 | "description": "The label for category Utilities in sidebar docs" 37 | }, 38 | "sidebar.docs.category.Type Definitions": { 39 | "message": "Type Definitions", 40 | "description": "The label for category Type Definitions in sidebar docs" 41 | }, 42 | "sidebar.docs.category.Constructor Options": { 43 | "message": "Constructor Options", 44 | "description": "The label for category Constructor Options in sidebar docs" 45 | }, 46 | "sidebar.docs.category.Functions - Crawlers": { 47 | "message": "Functions - Crawlers", 48 | "description": "The label for category Functions - Crawlers in sidebar docs" 49 | }, 50 | "sidebar.docs.category.Functions - Dataset": { 51 | "message": "Functions - Dataset", 52 | "description": "The label for category Functions - Dataset in sidebar docs" 53 | }, 54 | "sidebar.docs.category.Functions - KeyValueStore": { 55 | "message": "Functions - KeyValueStore", 56 | "description": "The label for category Functions - KeyValueStore in sidebar docs" 57 | }, 58 | "sidebar.docs.category.Functions - Sessions": { 59 | "message": "Functions - Sessions", 60 | "description": "The label for category Functions - Sessions in sidebar docs" 61 | }, 62 | "sidebar.docs.category.Functions - Utilities": { 63 | "message": "Functions - Utilities", 64 | "description": "The label for category Functions - Utilities in sidebar docs" 65 | }, 66 | "sidebar.docs.category.Return Types": { 67 | "message": "Return Types", 68 | "description": "The label for category Return Types in sidebar docs" 69 | } 70 | } -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-theme-classic/footer.json: -------------------------------------------------------------------------------- 1 | { 2 | "copyright": { 3 | "message": "Copyright © 2021 Apify Technologies s.r.o.", 4 | "description": "The footer copyright" 5 | }, 6 | "link.title.Docs": { 7 | "message": "Docs", 8 | "description": "The title of the footer links column with title=Docs in the footer" 9 | }, 10 | "link.title.Community": { 11 | "message": "Community", 12 | "description": "The title of the footer links column with title=Community in the footer" 13 | }, 14 | "link.title.More": { 15 | "message": "More", 16 | "description": "The title of the footer links column with title=More in the footer" 17 | }, 18 | "link.item.label.Guide": { 19 | "message": "Guide", 20 | "description": "The label of footer link with label=Guide linking to docs/" 21 | }, 22 | "link.item.label.Examples": { 23 | "message": "Examples", 24 | "description": "The label of footer link with label=Examples linking to docs/examples/crawl-multiple-urls" 25 | }, 26 | "link.item.label.API Reference": { 27 | "message": "API Reference", 28 | "description": "The label of footer link with label=API Reference linking to docs/api/apify" 29 | }, 30 | "link.item.label.Stack Overflow": { 31 | "message": "Stack Overflow", 32 | "description": "The label of footer link with label=Stack Overflow linking to https://stackoverflow.com/questions/tagged/apify" 33 | }, 34 | "link.item.label.Twitter": { 35 | "message": "Twitter", 36 | "description": "The label of footer link with label=Twitter linking to https://twitter.com/apify" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /website/i18n/en/docusaurus-theme-classic/navbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": { 3 | "message": "Apify SDK", 4 | "description": "The title in the navbar" 5 | }, 6 | "item.label.Guide": { 7 | "message": "Guide", 8 | "description": "Navbar item with label Guide" 9 | }, 10 | "item.label.Examples": { 11 | "message": "Examples", 12 | "description": "Navbar item with label Examples" 13 | }, 14 | "item.label.API Reference": { 15 | "message": "API Reference", 16 | "description": "Navbar item with label API Reference" 17 | }, 18 | "item.label.GitHub": { 19 | "message": "GitHub", 20 | "description": "Navbar item with label GitHub" 21 | }, 22 | "item.label.Version": { 23 | "message": "Version", 24 | "description": "Navbar item with label Version" 25 | }, 26 | "item.label.2.0.6": { 27 | "message": "2.0.6", 28 | "description": "Navbar item with label 2.0.6" 29 | }, 30 | "item.label.2.0.1": { 31 | "message": "2.0.1", 32 | "description": "Navbar item with label 2.0.1" 33 | }, 34 | "item.label.1.3.1": { 35 | "message": "1.3.1", 36 | "description": "Navbar item with label 1.3.1" 37 | }, 38 | "item.label.1.2.0": { 39 | "message": "1.2.0", 40 | "description": "Navbar item with label 1.2.0" 41 | }, 42 | "item.label.1.1.2": { 43 | "message": "1.1.2", 44 | "description": "Navbar item with label 1.1.2" 45 | }, 46 | "item.label.1.1.0": { 47 | "message": "1.1.0", 48 | "description": "Navbar item with label 1.1.0" 49 | }, 50 | "item.label.1.0.2": { 51 | "message": "1.0.2", 52 | "description": "Navbar item with label 1.0.2" 53 | }, 54 | "item.label.1.0.1": { 55 | "message": "1.0.1", 56 | "description": "Navbar item with label 1.0.1" 57 | }, 58 | "item.label.1.0.0": { 59 | "message": "1.0.0", 60 | "description": "Navbar item with label 1.0.0" 61 | }, 62 | "item.label.0.22.4": { 63 | "message": "0.22.4", 64 | "description": "Navbar item with label 0.22.4" 65 | }, 66 | "item.label.Main/Unreleased": { 67 | "message": "Main/Unreleased", 68 | "description": "Navbar item with label Main/Unreleased" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "examples": "docusaurus-examples", 4 | "start": "rimraf .docusaurus && LOCAL=1 docusaurus start", 5 | "build": "rimraf .docusaurus && docusaurus build", 6 | "publish-gh-pages": "docusaurus-publish", 7 | "write-translations": "docusaurus write-translations", 8 | "version": "docusaurus version", 9 | "rename-version": "docusaurus rename-version", 10 | "swizzle": "docusaurus swizzle", 11 | "deploy": "rimraf .docusaurus && docusaurus deploy", 12 | "docusaurus": "docusaurus", 13 | "lint": "npm run lint:md", 14 | "lint:fix": "npm run lint:md:fix && npm run lint:code:fix", 15 | "lint:md": "cd .. && markdownlint 'website/**/*.md' 'docs/**/*.md' && cd website", 16 | "lint:md:fix": "cd .. && markdownlint 'website/**/*.md' 'docs/**/*.md' --fix && cd website" 17 | }, 18 | "devDependencies": { 19 | "@apify/eslint-config-ts": "^0.4.0", 20 | "@apify/tsconfig": "^0.1.0", 21 | "@types/react": "^17.0.39", 22 | "@typescript-eslint/eslint-plugin": "^7.0.0", 23 | "@typescript-eslint/parser": "^7.0.0", 24 | "eslint": "^8.35.0", 25 | "eslint-plugin-react": "^7.32.2", 26 | "eslint-plugin-react-hooks": "^4.6.0", 27 | "fs-extra": "^11.1.0", 28 | "globby": "^13.1.3", 29 | "markdownlint": "^0.33.0", 30 | "markdownlint-cli": "^0.39.0", 31 | "path-browserify": "^1.0.1", 32 | "rimraf": "^5.0.0" 33 | }, 34 | "dependencies": { 35 | "@apify/docs-theme": "^1.0.61", 36 | "@docusaurus/core": "^2.3.1", 37 | "@docusaurus/plugin-client-redirects": "^2.3.1", 38 | "@docusaurus/preset-classic": "^2.3.1", 39 | "clsx": "^2.0.0", 40 | "docusaurus-gtm-plugin": "^0.0.2", 41 | "docusaurus-plugin-typedoc-api": "3.0.0", 42 | "prop-types": "^15.8.1", 43 | "raw-loader": "^4.0.2", 44 | "react": "^17.0.2", 45 | "react-dom": "^17.0.2", 46 | "unist-util-visit": "^5.0.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | module.exports = [[ 2 | { 3 | type: 'category', 4 | label: 'API Client', 5 | items: [ 6 | 'index', 7 | 'features', 8 | 'usage_concepts', 9 | ], 10 | }, 11 | // { 12 | // type: 'category', 13 | // label: 'Examples', 14 | // items: [ 15 | // { 16 | // type: 'autogenerated', 17 | // dirName: 'examples', 18 | // }, 19 | // ], 20 | // }, 21 | { 22 | type: 'doc', 23 | id: 'changelog', 24 | }, 25 | ]]; 26 | -------------------------------------------------------------------------------- /website/sitePlugin.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return { 3 | name: 'custom-docusaurus-plugin', 4 | // eslint-disable-next-line 5 | configureWebpack(config, isServer, utils) { 6 | return { 7 | resolve: { 8 | alias: { 9 | path: require.resolve('path-browserify'), 10 | }, 11 | fallback: { 12 | fs: false, 13 | }, 14 | }, 15 | }; 16 | }, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /website/src/components/ApiLink.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Link from '@docusaurus/Link'; 3 | // eslint-disable-next-line import/no-extraneous-dependencies 4 | import { useDocsVersion } from '@docusaurus/theme-common/internal'; 5 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 6 | 7 | const ApiLink = ({ to, children }) => { 8 | const { version, isLast } = useDocsVersion(); 9 | const { siteConfig } = useDocusaurusContext(); 10 | 11 | if (siteConfig.presets[0][1].docs.disableVersioning) { 12 | return ( 13 | {children} 14 | ); 15 | } 16 | 17 | let versionSlug = `${version}/`; 18 | 19 | if (version === 'current') { 20 | versionSlug = 'next/'; 21 | } else if (isLast) { 22 | versionSlug = ''; 23 | } 24 | 25 | return ( 26 | {children} 27 | ); 28 | }; 29 | 30 | export default ApiLink; 31 | -------------------------------------------------------------------------------- /website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import Layout from '@theme/Layout'; 4 | import Link from '@docusaurus/Link'; 5 | import CodeBlock from '@theme/CodeBlock'; 6 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 7 | import styles from './index.module.css'; 8 | 9 | function Hero() { 10 | return ( 11 |
12 |
13 |
14 |
15 |
16 |

17 | Apify API client for JavaScript 18 |

19 |

20 | {/* eslint-disable-next-line max-len */} 21 | Apify API client for JavaScript 22 |

23 |
24 |
25 |
26 |
27 |

28 |

29 | The official library to interact with Apify API from a web browser, Node.js, JavaScript, 30 | or TypeScript applications, providing convenience functions and automatic retries on errors. 31 |

32 |
33 |
34 |
35 |
36 |
37 | Get Started 38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 | 49 | npm install apify-client 50 | 51 |
52 |
53 |
54 |
55 | ); 56 | } 57 | 58 | export default function Home() { 59 | const { siteConfig } = useDocusaurusContext(); 60 | return ( 61 | 63 | 64 |
65 |
66 |
67 |
68 |

69 | Easily run Actors, await them to finish using the convenient .call() method, 70 | and retrieve results from the resulting dataset. 71 |

72 |
73 |
74 | {`const { ApifyClient } = require('apify-client'); 75 | 76 | const client = new ApifyClient({ 77 | token: 'MY-APIFY-TOKEN', 78 | }); 79 | 80 | // Starts an actor and waits for it to finish. 81 | const { defaultDatasetId } = await client.actor('john-doe/my-cool-actor').call(); 82 | 83 | // Fetches results from the actor's dataset. 84 | const { items } = await client.dataset(defaultDatasetId).listItems();`} 85 |
86 |
87 |
88 |
89 |
90 | ); 91 | } 92 | -------------------------------------------------------------------------------- /website/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | useVersions, 4 | useActiveDocContext, 5 | } from '@docusaurus/plugin-content-docs/client'; 6 | import { useDocsPreferredVersion } from '@docusaurus/theme-common'; 7 | import { useDocsVersionCandidates } from '@docusaurus/theme-common/internal'; 8 | import { translate } from '@docusaurus/Translate'; 9 | import { useLocation } from '@docusaurus/router'; 10 | import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; 11 | import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem'; 12 | 13 | const getVersionMainDoc = (version) => version.docs.find((doc) => doc.id === version.mainDocId); 14 | 15 | function getApiLinks(props, pathname) { 16 | if (!pathname.startsWith('/api/client/js/reference')) { 17 | return []; 18 | } 19 | 20 | try { 21 | return JSON.parse(props['data-api-links']); 22 | } catch { 23 | return []; 24 | } 25 | } 26 | 27 | /* eslint-disable react/prop-types */ 28 | export default function DocsVersionDropdownNavbarItem({ 29 | mobile, 30 | docsPluginId, 31 | dropdownActiveClassDisabled, 32 | dropdownItemsBefore, 33 | dropdownItemsAfter, 34 | ...props 35 | }) { 36 | const { 37 | search, 38 | hash, 39 | pathname 40 | } = useLocation(); 41 | const apiLinks = getApiLinks(props, pathname); 42 | 43 | const activeDocContext = useActiveDocContext(docsPluginId); 44 | const versions = useVersions(docsPluginId); 45 | const { savePreferredVersionName } = useDocsPreferredVersion(docsPluginId); 46 | const versionLinks = versions.map((version, idx) => { 47 | // We try to link to the same doc, in another version 48 | // When not possible, fallback to the "main doc" of the version 49 | const versionDoc = activeDocContext.alternateDocVersions[version.name] 50 | ?? getVersionMainDoc(version); 51 | return { 52 | label: version.label, 53 | // preserve ?search#hash suffix on version switches 54 | to: `${apiLinks[idx] ?? versionDoc.path}${search}${hash}`, 55 | isActive: () => version === activeDocContext.activeVersion, 56 | onClick: () => savePreferredVersionName(version.name), 57 | }; 58 | }); 59 | const items = [ 60 | ...dropdownItemsBefore, 61 | ...versionLinks, 62 | ...dropdownItemsAfter, 63 | ]; 64 | const dropdownVersion = useDocsVersionCandidates(docsPluginId)[0]; 65 | // Mobile dropdown is handled a bit differently 66 | const dropdownLabel = mobile && items.length > 1 67 | ? translate({ 68 | id: 'theme.navbar.mobileVersionsDropdown.label', 69 | message: 'Versions', 70 | description: 71 | 'The label for the navbar versions dropdown on mobile view', 72 | }) 73 | : dropdownVersion.label; 74 | let dropdownTo = mobile && items.length > 1 75 | ? undefined 76 | : getVersionMainDoc(dropdownVersion).path; 77 | 78 | if (dropdownTo && pathname.startsWith('/api/client/js/reference')) { 79 | dropdownTo = versionLinks.find((v) => v.label === dropdownVersion.label)?.to; 80 | } 81 | 82 | // We don't want to render a version dropdown with 0 or 1 item. If we build 83 | // the site with a single docs version (onlyIncludeVersions: ['1.0.0']), 84 | // We'd rather render a button instead of a dropdown 85 | if (items.length <= 1) { 86 | return ( 87 | false : undefined} 93 | /> 94 | ); 95 | } 96 | return ( 97 | false : undefined} 104 | /> 105 | ); 106 | } 107 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redtomato0129/apify-client-js/a14e7eb4dbed39071112b9a5df91865afa394aec/website/static/.nojekyll -------------------------------------------------------------------------------- /website/tools/utils/createHref.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | /** 3 | * Copyright (c) Facebook, Inc. and its affiliates. 4 | * 5 | * The SVG used below is used from docusaurus, which is licensed under the MIT license found in the 6 | * LICENSE file located at: https://github.com/facebook/docusaurus 7 | */ 8 | 9 | exports.createHref = (url, label) => { 10 | return ` 11 | 12 | ${label} 13 | 23 | 24 | `; 25 | }; 26 | -------------------------------------------------------------------------------- /website/tools/utils/externalLink.js: -------------------------------------------------------------------------------- 1 | const { parse } = require('url'); 2 | 3 | const visit = import('unist-util-visit').then((m) => m.visit); 4 | 5 | const internalUrls = ['sdk.apify.com']; 6 | 7 | /** 8 | * @param {import('url').UrlWithStringQuery} href 9 | */ 10 | function isInternal(href) { 11 | return internalUrls.some( 12 | (internalUrl) => href.host === internalUrl 13 | || (!href.protocol && !href.host && (href.pathname || href.hash)), 14 | ); 15 | } 16 | 17 | /** 18 | * @type {import('unified').Plugin} 19 | */ 20 | exports.externalLinkProcessor = () => { 21 | return async (tree) => { 22 | (await visit)(tree, 'element', (node) => { 23 | if ( 24 | node.tagName === 'a' 25 | && node.properties 26 | && typeof node.properties.href === 'string' 27 | ) { 28 | const href = parse(node.properties.href); 29 | 30 | if (!isInternal(href)) { 31 | node.properties.target = '_blank'; 32 | node.properties.rel = 'noopener'; 33 | } else { 34 | node.properties.target = null; 35 | node.properties.rel = null; 36 | } 37 | } 38 | }); 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /website/tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@apify/tsconfig", 3 | "compilerOptions": { 4 | "jsx": "preserve" 5 | }, 6 | "include": [ 7 | "src/**/*.js", 8 | "src/**/*.ts", 9 | "src/**/*.jsx", 10 | "src/**/*.tsx" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.6/api-packages.json: -------------------------------------------------------------------------------- 1 | [{"entryPoints":{"index":{"label":"Index","path":"src/index.ts"}},"packagePath":".","packageSlug":".","packageName":"apify-client","packageVersion":"2.6.2"}] -------------------------------------------------------------------------------- /website/versioned_docs/version-2.6/examples/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic usage 3 | sidebar_label: Basic usage 4 | --- 5 | 6 | This section contains examples of how to use Apify Client for Javascript. 7 | 8 | There is nothing here yet. 9 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.6/features.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Features' 3 | --- 4 | 5 | # Features 6 | 7 | Besides greatly simplifying the process of querying the Apify API, the client provides other useful features. 8 | 9 | ## Automatic parsing and error handling 10 | 11 | Based on the endpoint, the client automatically extracts the relevant data and returns it in the 12 | expected format. Date strings are automatically converted to `Date` objects. For exceptions, 13 | we throw an `ApifyApiError`, which wraps the plain JSON errors returned by API and enriches 14 | them with other context for easier debugging. 15 | 16 | ## Retries with exponential backoff 17 | 18 | Network communication sometimes fails, that's a given. The client will automatically retry requests that 19 | failed due to a network error, an internal error of the Apify API (HTTP 500+) or rate limit error (HTTP 429). 20 | By default, it will retry up to 8 times. First retry will be attempted after ~500ms, second after ~1000ms 21 | and so on. You can configure those parameters using the `maxRetries` and `minDelayBetweenRetriesMillis` 22 | options of the `ApifyClient` constructor. 23 | 24 | ## Convenience functions and options 25 | 26 | Some actions can't be performed by the API itself, such as indefinite waiting for an actor run to finish 27 | (because of network timeouts). The client provides convenient `call()` and `waitForFinish()` functions that do that. 28 | Key-value store records can be retrieved as objects, buffers or streams via the respective options, dataset items 29 | can be fetched as individual objects or serialized data and we plan to add better stream support and async iterators. 30 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.6/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Quick start' 3 | title: 'Quick start' 4 | --- 5 | 6 | # Apify API client for JavaScript 7 | 8 | `apify-client` is the official library to access [Apify API](https://docs.apify.com/api/v2) from your 9 | JavaScript applications. It runs both in Node.js and browser and provides useful features like 10 | automatic retries and convenience functions that improve the experience of using the Apify API. 11 | 12 | ## Quick Start 13 | 14 | ```js 15 | const { ApifyClient } = require('apify-client'); 16 | 17 | const client = new ApifyClient({ 18 | token: 'MY-APIFY-TOKEN', 19 | }); 20 | 21 | // Starts an actor and waits for it to finish. 22 | const { defaultDatasetId } = await client.actor('john-doe/my-cool-actor').call(); 23 | // Fetches results from the actor's dataset. 24 | const { items } = await client.dataset(defaultDatasetId).listItems(); 25 | ``` 26 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.6/usage_concepts.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Usage concepts' 3 | --- 4 | 5 | # Usage concepts 6 | 7 | The `ApifyClient` interface follows a generic pattern that is applicable to all of its components. By calling individual methods of `ApifyClient`, specific clients which target individual API resources are created. There are two types of those clients. A client for management of a single resource and a client for a collection of resources. 8 | 9 | ```js 10 | const { ApifyClient } = require('apify-client'); 11 | const apifyClient = new ApifyClient({ token: 'my-token' }); 12 | 13 | // Collection clients do not require a parameter. 14 | const actorCollectionClient = apifyClient.actors(); 15 | // Creates an actor with the name: my-actor. 16 | const myActor = await actorCollectionClient.create({ name: 'my-actor' }); 17 | // Lists all of your actors. 18 | const { items } = await actorCollectionClient.list(); 19 | ``` 20 | 21 | ```js 22 | // Collection clients do not require a parameter. 23 | const datasetCollectionClient = apifyClient.datasets(); 24 | // Gets (or creates, if it doesn't exist) a dataset with the name of my-dataset. 25 | const myDataset = await datasetCollectionClient.getOrCreate('my-dataset'); 26 | ``` 27 | 28 | ```js 29 | // Resource clients accept an ID of the resource. 30 | const actorClient = apifyClient.actor('john-doe/my-actor'); 31 | // Fetches the john-doe/my-actor object from the API. 32 | const myActor = await actorClient.get(); 33 | // Starts the run of john-doe/my-actor and returns the Run object. 34 | const myActorRun = await actorClient.start(); 35 | ``` 36 | 37 | ```js 38 | // Resource clients accept an ID of the resource. 39 | const datasetClient = apifyClient.dataset('john-doe/my-dataset'); 40 | // Appends items to the end of john-doe/my-dataset. 41 | await datasetClient.pushItems([{ foo: 1 }, { bar: 2 }]); 42 | ``` 43 | 44 | > The ID of the resource can be either the `id` of the said resource, or a combination of your `username/resource-name`. 45 | 46 | This is really all you need to remember, because all resource clients follow the pattern you see above. 47 | 48 | ## Nested clients 49 | 50 | Sometimes clients return other clients. That's to simplify working with nested collections, such as runs of a given actor. 51 | 52 | ```js 53 | const actorClient = apifyClient.actor('john-doe/hello-world'); 54 | const runsClient = actorClient.runs(); 55 | // Lists the last 10 runs of the john-doe/hello-world actor. 56 | const { items } = await runsClient.list({ 57 | limit: 10, 58 | desc: true 59 | }) 60 | 61 | // Selects the last run of the john-doe/hello-world actor that finished 62 | // with a SUCCEEDED status. 63 | const lastSucceededRunClient = actorClient.lastRun({ status: 'SUCCEEDED' }); 64 | // Fetches items from the run's dataset. 65 | const { items } = await lastSucceededRunClient.dataset() 66 | .listItems(); 67 | ``` 68 | 69 | > The quick access to `dataset` and other storages directly from the run client can now only be used with the `lastRun()` method, but the feature will be available to all runs in the future. 70 | 71 | ## Pagination 72 | 73 | Most methods named `list` or `listSomething` return a [`Promise`](/reference/interface/PaginatedList). There are some exceptions though, like `listKeys` or `listHead` which paginate differently. The results you're looking for are always stored under `items` and you can use the `limit` property to get only a subset of results. Other props are also available, depending on the method. 74 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.7/.gitignore: -------------------------------------------------------------------------------- 1 | changelog.md 2 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.7/api-packages.json: -------------------------------------------------------------------------------- 1 | [{"entryPoints":{"index":{"label":"Index","path":"src/index.ts"}},"packagePath":".","packageSlug":".","packageName":"apify-client","packageVersion":"2.7.2"}] -------------------------------------------------------------------------------- /website/versioned_docs/version-2.7/examples/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic usage 3 | sidebar_label: Basic usage 4 | --- 5 | 6 | This section contains examples of how to use Apify Client for Javascript. 7 | 8 | There is nothing here yet. 9 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.7/features.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Features' 3 | --- 4 | 5 | # Features 6 | 7 | Besides greatly simplifying the process of querying the Apify API, the client provides other useful features. 8 | 9 | ## Automatic parsing and error handling 10 | 11 | Based on the endpoint, the client automatically extracts the relevant data and returns it in the 12 | expected format. Date strings are automatically converted to `Date` objects. For exceptions, 13 | we throw an `ApifyApiError`, which wraps the plain JSON errors returned by API and enriches 14 | them with other context for easier debugging. 15 | 16 | ## Retries with exponential backoff 17 | 18 | Network communication sometimes fails, that's a given. The client will automatically retry requests that 19 | failed due to a network error, an internal error of the Apify API (HTTP 500+) or rate limit error (HTTP 429). 20 | By default, it will retry up to 8 times. First retry will be attempted after ~500ms, second after ~1000ms 21 | and so on. You can configure those parameters using the `maxRetries` and `minDelayBetweenRetriesMillis` 22 | options of the `ApifyClient` constructor. 23 | 24 | ## Convenience functions and options 25 | 26 | Some actions can't be performed by the API itself, such as indefinite waiting for an actor run to finish 27 | (because of network timeouts). The client provides convenient `call()` and `waitForFinish()` functions that do that. 28 | Key-value store records can be retrieved as objects, buffers or streams via the respective options, dataset items 29 | can be fetched as individual objects or serialized data and we plan to add better stream support and async iterators. 30 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.7/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Quick start' 3 | title: 'Quick start' 4 | --- 5 | 6 | # Apify API client for JavaScript 7 | 8 | `apify-client` is the official library to access [Apify API](https://docs.apify.com/api/v2) from your 9 | JavaScript applications. It runs both in Node.js and browser and provides useful features like 10 | automatic retries and convenience functions that improve the experience of using the Apify API. 11 | 12 | ## Quick Start 13 | 14 | ```js 15 | const { ApifyClient } = require('apify-client'); 16 | 17 | const client = new ApifyClient({ 18 | token: 'MY-APIFY-TOKEN', 19 | }); 20 | 21 | // Starts an actor and waits for it to finish. 22 | const { defaultDatasetId } = await client.actor('john-doe/my-cool-actor').call(); 23 | // Fetches results from the actor's dataset. 24 | const { items } = await client.dataset(defaultDatasetId).listItems(); 25 | ``` 26 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.7/usage_concepts.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Usage concepts' 3 | --- 4 | 5 | # Usage concepts 6 | 7 | The `ApifyClient` interface follows a generic pattern that is applicable to all of its components. By calling individual methods of `ApifyClient`, specific clients which target individual API resources are created. There are two types of those clients. A client for management of a single resource and a client for a collection of resources. 8 | 9 | ```js 10 | const { ApifyClient } = require('apify-client'); 11 | const apifyClient = new ApifyClient({ token: 'my-token' }); 12 | 13 | // Collection clients do not require a parameter. 14 | const actorCollectionClient = apifyClient.actors(); 15 | // Creates an actor with the name: my-actor. 16 | const myActor = await actorCollectionClient.create({ name: 'my-actor' }); 17 | // Lists all of your actors. 18 | const { items } = await actorCollectionClient.list(); 19 | ``` 20 | 21 | ```js 22 | // Collection clients do not require a parameter. 23 | const datasetCollectionClient = apifyClient.datasets(); 24 | // Gets (or creates, if it doesn't exist) a dataset with the name of my-dataset. 25 | const myDataset = await datasetCollectionClient.getOrCreate('my-dataset'); 26 | ``` 27 | 28 | ```js 29 | // Resource clients accept an ID of the resource. 30 | const actorClient = apifyClient.actor('john-doe/my-actor'); 31 | // Fetches the john-doe/my-actor object from the API. 32 | const myActor = await actorClient.get(); 33 | // Starts the run of john-doe/my-actor and returns the Run object. 34 | const myActorRun = await actorClient.start(); 35 | ``` 36 | 37 | ```js 38 | // Resource clients accept an ID of the resource. 39 | const datasetClient = apifyClient.dataset('john-doe/my-dataset'); 40 | // Appends items to the end of john-doe/my-dataset. 41 | await datasetClient.pushItems([{ foo: 1 }, { bar: 2 }]); 42 | ``` 43 | 44 | > The ID of the resource can be either the `id` of the said resource, or a combination of your `username/resource-name`. 45 | 46 | This is really all you need to remember, because all resource clients follow the pattern you see above. 47 | 48 | ## Nested clients 49 | 50 | Sometimes clients return other clients. That's to simplify working with nested collections, such as runs of a given actor. 51 | 52 | ```js 53 | const actorClient = apifyClient.actor('john-doe/hello-world'); 54 | const runsClient = actorClient.runs(); 55 | // Lists the last 10 runs of the john-doe/hello-world actor. 56 | const { items } = await runsClient.list({ 57 | limit: 10, 58 | desc: true 59 | }) 60 | 61 | // Selects the last run of the john-doe/hello-world actor that finished 62 | // with a SUCCEEDED status. 63 | const lastSucceededRunClient = actorClient.lastRun({ status: 'SUCCEEDED' }); 64 | // Fetches items from the run's dataset. 65 | const { items } = await lastSucceededRunClient.dataset() 66 | .listItems(); 67 | ``` 68 | 69 | > The quick access to `dataset` and other storages directly from the run client can now only be used with the `lastRun()` method, but the feature will be available to all runs in the future. 70 | 71 | ## Pagination 72 | 73 | Most methods named `list` or `listSomething` return a [`Promise`](/reference/interface/PaginatedList). There are some exceptions though, like `listKeys` or `listHead` which paginate differently. The results you're looking for are always stored under `items` and you can use the `limit` property to get only a subset of results. Other props are also available, depending on the method. 74 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.8/.gitignore: -------------------------------------------------------------------------------- 1 | changelog.md 2 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.8/api-packages.json: -------------------------------------------------------------------------------- 1 | [{"entryPoints":{"index":{"label":"Index","path":"src/index.ts"}},"packagePath":".","packageSlug":".","packageName":"apify-client","packageVersion":"2.8.1"}] -------------------------------------------------------------------------------- /website/versioned_docs/version-2.8/examples/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic usage 3 | sidebar_label: Basic usage 4 | --- 5 | 6 | This section contains examples of how to use Apify Client for Javascript. 7 | 8 | There is nothing here yet. 9 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.8/features.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Features' 3 | --- 4 | 5 | # Features 6 | 7 | Besides greatly simplifying the process of querying the Apify API, the client provides other useful features. 8 | 9 | ## Automatic parsing and error handling 10 | 11 | Based on the endpoint, the client automatically extracts the relevant data and returns it in the 12 | expected format. Date strings are automatically converted to `Date` objects. For exceptions, 13 | we throw an `ApifyApiError`, which wraps the plain JSON errors returned by API and enriches 14 | them with other context for easier debugging. 15 | 16 | ## Retries with exponential backoff 17 | 18 | Network communication sometimes fails, that's a given. The client will automatically retry requests that 19 | failed due to a network error, an internal error of the Apify API (HTTP 500+) or rate limit error (HTTP 429). 20 | By default, it will retry up to 8 times. First retry will be attempted after ~500ms, second after ~1000ms 21 | and so on. You can configure those parameters using the `maxRetries` and `minDelayBetweenRetriesMillis` 22 | options of the `ApifyClient` constructor. 23 | 24 | ## Convenience functions and options 25 | 26 | Some actions can't be performed by the API itself, such as indefinite waiting for an actor run to finish 27 | (because of network timeouts). The client provides convenient `call()` and `waitForFinish()` functions that do that. 28 | Key-value store records can be retrieved as objects, buffers or streams via the respective options, dataset items 29 | can be fetched as individual objects or serialized data and we plan to add better stream support and async iterators. 30 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.8/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Quick start' 3 | title: 'Quick start' 4 | --- 5 | 6 | # Apify API client for JavaScript 7 | 8 | `apify-client` is the official library to access [Apify API](https://docs.apify.com/api/v2) from your 9 | JavaScript applications. It runs both in Node.js and browser and provides useful features like 10 | automatic retries and convenience functions that improve the experience of using the Apify API. 11 | 12 | You can install the client via the [npm package](https://www.npmjs.com/package/apify-client). To do that, simply run `npm i apify-client`. 13 | 14 | ## Quick Start 15 | 16 | ```js 17 | const { ApifyClient } = require('apify-client'); 18 | 19 | const client = new ApifyClient({ 20 | token: 'MY-APIFY-TOKEN', 21 | }); 22 | 23 | // Starts an actor and waits for it to finish. 24 | const { defaultDatasetId } = await client.actor('john-doe/my-cool-actor').call(); 25 | // Fetches results from the actor's dataset. 26 | const { items } = await client.dataset(defaultDatasetId).listItems(); 27 | ``` 28 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.8/usage_concepts.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Usage concepts' 3 | --- 4 | 5 | # Usage concepts 6 | 7 | The `ApifyClient` interface follows a generic pattern that is applicable to all of its components. By calling individual methods of `ApifyClient`, specific clients which target individual API resources are created. There are two types of those clients. A client for management of a single resource and a client for a collection of resources. 8 | 9 | ```js 10 | const { ApifyClient } = require('apify-client'); 11 | const apifyClient = new ApifyClient({ token: 'my-token' }); 12 | 13 | // Collection clients do not require a parameter. 14 | const actorCollectionClient = apifyClient.actors(); 15 | // Creates an actor with the name: my-actor. 16 | const myActor = await actorCollectionClient.create({ name: 'my-actor' }); 17 | // Lists all of your actors. 18 | const { items } = await actorCollectionClient.list(); 19 | ``` 20 | 21 | ```js 22 | // Collection clients do not require a parameter. 23 | const datasetCollectionClient = apifyClient.datasets(); 24 | // Gets (or creates, if it doesn't exist) a dataset with the name of my-dataset. 25 | const myDataset = await datasetCollectionClient.getOrCreate('my-dataset'); 26 | ``` 27 | 28 | ```js 29 | // Resource clients accept an ID of the resource. 30 | const actorClient = apifyClient.actor('john-doe/my-actor'); 31 | // Fetches the john-doe/my-actor object from the API. 32 | const myActor = await actorClient.get(); 33 | // Starts the run of john-doe/my-actor and returns the Run object. 34 | const myActorRun = await actorClient.start(); 35 | ``` 36 | 37 | ```js 38 | // Resource clients accept an ID of the resource. 39 | const datasetClient = apifyClient.dataset('john-doe/my-dataset'); 40 | // Appends items to the end of john-doe/my-dataset. 41 | await datasetClient.pushItems([{ foo: 1 }, { bar: 2 }]); 42 | ``` 43 | 44 | > The ID of the resource can be either the `id` of the said resource, or a combination of your `username/resource-name`. 45 | 46 | This is really all you need to remember, because all resource clients follow the pattern you see above. 47 | 48 | ## Nested clients 49 | 50 | Sometimes clients return other clients. That's to simplify working with nested collections, such as runs of a given actor. 51 | 52 | ```js 53 | const actorClient = apifyClient.actor('john-doe/hello-world'); 54 | const runsClient = actorClient.runs(); 55 | // Lists the last 10 runs of the john-doe/hello-world actor. 56 | const { items } = await runsClient.list({ 57 | limit: 10, 58 | desc: true 59 | }) 60 | 61 | // Selects the last run of the john-doe/hello-world actor that finished 62 | // with a SUCCEEDED status. 63 | const lastSucceededRunClient = actorClient.lastRun({ status: 'SUCCEEDED' }); 64 | // Fetches items from the run's dataset. 65 | const { items } = await lastSucceededRunClient.dataset() 66 | .listItems(); 67 | ``` 68 | 69 | > The quick access to `dataset` and other storages directly from the run client can now only be used with the `lastRun()` method, but the feature will be available to all runs in the future. 70 | 71 | ## Pagination 72 | 73 | Most methods named `list` or `listSomething` return a [`Promise`](/reference/interface/PaginatedList). There are some exceptions though, like `listKeys` or `listHead` which paginate differently. The results you're looking for are always stored under `items` and you can use the `limit` property to get only a subset of results. Other props are also available, depending on the method. 74 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.9/.gitignore: -------------------------------------------------------------------------------- 1 | changelog.md 2 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.9/api-packages.json: -------------------------------------------------------------------------------- 1 | [{"entryPoints":{"index":{"label":"Index","path":"src/index.ts"}},"packagePath":".","packageSlug":".","packageName":"apify-client","packageVersion":"2.9.0"}] -------------------------------------------------------------------------------- /website/versioned_docs/version-2.9/examples/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic usage 3 | sidebar_label: Basic usage 4 | --- 5 | 6 | This section contains examples of how to use Apify Client for Javascript. 7 | 8 | There is nothing here yet. 9 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.9/features.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Features' 3 | --- 4 | 5 | # Features 6 | 7 | Besides greatly simplifying the process of querying the Apify API, the client provides other useful features. 8 | 9 | ## Automatic parsing and error handling 10 | 11 | Based on the endpoint, the client automatically extracts the relevant data and returns it in the 12 | expected format. Date strings are automatically converted to `Date` objects. For exceptions, 13 | we throw an `ApifyApiError`, which wraps the plain JSON errors returned by API and enriches 14 | them with other context for easier debugging. 15 | 16 | ## Retries with exponential backoff 17 | 18 | Network communication sometimes fails, that's a given. The client will automatically retry requests that 19 | failed due to a network error, an internal error of the Apify API (HTTP 500+) or rate limit error (HTTP 429). 20 | By default, it will retry up to 8 times. First retry will be attempted after ~500ms, second after ~1000ms 21 | and so on. You can configure those parameters using the `maxRetries` and `minDelayBetweenRetriesMillis` 22 | options of the `ApifyClient` constructor. 23 | 24 | ## Convenience functions and options 25 | 26 | Some actions can't be performed by the API itself, such as indefinite waiting for an actor run to finish 27 | (because of network timeouts). The client provides convenient `call()` and `waitForFinish()` functions that do that. 28 | Key-value store records can be retrieved as objects, buffers or streams via the respective options, dataset items 29 | can be fetched as individual objects or serialized data and we plan to add better stream support and async iterators. 30 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.9/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Quick start' 3 | title: 'Quick start' 4 | --- 5 | 6 | # Apify API client for JavaScript 7 | 8 | `apify-client` is the official library to access [Apify API](https://docs.apify.com/api/v2) from your 9 | JavaScript applications. It runs both in Node.js and browser and provides useful features like 10 | automatic retries and convenience functions that improve the experience of using the Apify API. 11 | 12 | You can install the client via the [npm package](https://www.npmjs.com/package/apify-client). To do that, simply run `npm i apify-client`. 13 | 14 | ## Quick Start 15 | 16 | ```js 17 | const { ApifyClient } = require('apify-client'); 18 | 19 | const client = new ApifyClient({ 20 | token: 'MY-APIFY-TOKEN', 21 | }); 22 | 23 | // Starts an actor and waits for it to finish. 24 | const { defaultDatasetId } = await client.actor('john-doe/my-cool-actor').call(); 25 | // Fetches results from the actor's dataset. 26 | const { items } = await client.dataset(defaultDatasetId).listItems(); 27 | ``` 28 | -------------------------------------------------------------------------------- /website/versioned_docs/version-2.9/usage_concepts.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_label: 'Usage concepts' 3 | --- 4 | 5 | # Usage concepts 6 | 7 | The `ApifyClient` interface follows a generic pattern that is applicable to all of its components. By calling individual methods of `ApifyClient`, specific clients which target individual API resources are created. There are two types of those clients. A client for management of a single resource and a client for a collection of resources. 8 | 9 | ```js 10 | const { ApifyClient } = require('apify-client'); 11 | const apifyClient = new ApifyClient({ token: 'my-token' }); 12 | 13 | // Collection clients do not require a parameter. 14 | const actorCollectionClient = apifyClient.actors(); 15 | // Creates an actor with the name: my-actor. 16 | const myActor = await actorCollectionClient.create({ name: 'my-actor' }); 17 | // Lists all of your actors. 18 | const { items } = await actorCollectionClient.list(); 19 | ``` 20 | 21 | ```js 22 | // Collection clients do not require a parameter. 23 | const datasetCollectionClient = apifyClient.datasets(); 24 | // Gets (or creates, if it doesn't exist) a dataset with the name of my-dataset. 25 | const myDataset = await datasetCollectionClient.getOrCreate('my-dataset'); 26 | ``` 27 | 28 | ```js 29 | // Resource clients accept an ID of the resource. 30 | const actorClient = apifyClient.actor('john-doe/my-actor'); 31 | // Fetches the john-doe/my-actor object from the API. 32 | const myActor = await actorClient.get(); 33 | // Starts the run of john-doe/my-actor and returns the Run object. 34 | const myActorRun = await actorClient.start(); 35 | ``` 36 | 37 | ```js 38 | // Resource clients accept an ID of the resource. 39 | const datasetClient = apifyClient.dataset('john-doe/my-dataset'); 40 | // Appends items to the end of john-doe/my-dataset. 41 | await datasetClient.pushItems([{ foo: 1 }, { bar: 2 }]); 42 | ``` 43 | 44 | > The ID of the resource can be either the `id` of the said resource, or a combination of your `username/resource-name`. 45 | 46 | This is really all you need to remember, because all resource clients follow the pattern you see above. 47 | 48 | ## Nested clients 49 | 50 | Sometimes clients return other clients. That's to simplify working with nested collections, such as runs of a given actor. 51 | 52 | ```js 53 | const actorClient = apifyClient.actor('john-doe/hello-world'); 54 | const runsClient = actorClient.runs(); 55 | // Lists the last 10 runs of the john-doe/hello-world actor. 56 | const { items } = await runsClient.list({ 57 | limit: 10, 58 | desc: true 59 | }) 60 | 61 | // Selects the last run of the john-doe/hello-world actor that finished 62 | // with a SUCCEEDED status. 63 | const lastSucceededRunClient = actorClient.lastRun({ status: 'SUCCEEDED' }); 64 | // Fetches items from the run's dataset. 65 | const { items } = await lastSucceededRunClient.dataset() 66 | .listItems(); 67 | ``` 68 | 69 | > The quick access to `dataset` and other storages directly from the run client can now only be used with the `lastRun()` method, but the feature will be available to all runs in the future. 70 | 71 | ## Pagination 72 | 73 | Most methods named `list` or `listSomething` return a [`Promise`](/reference/interface/PaginatedList). There are some exceptions though, like `listKeys` or `listHead` which paginate differently. The results you're looking for are always stored under `items` and you can use the `limit` property to get only a subset of results. Other props are also available, depending on the method. 74 | -------------------------------------------------------------------------------- /website/versioned_sidebars/version-2.6-sidebars.json: -------------------------------------------------------------------------------- 1 | [[ 2 | { 3 | "type": "category", 4 | "label": "API Client", 5 | "items": [ 6 | "index", 7 | "features", 8 | "usage_concepts" 9 | ] 10 | }, 11 | { 12 | "type": "doc", 13 | "id": "changelog" 14 | } 15 | ]] 16 | -------------------------------------------------------------------------------- /website/versioned_sidebars/version-2.7-sidebars.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | { 4 | "type": "category", 5 | "label": "API Client", 6 | "items": [ 7 | "index", 8 | "features", 9 | "usage_concepts" 10 | ] 11 | }, 12 | { 13 | "type": "doc", 14 | "id": "changelog" 15 | } 16 | ] 17 | ] 18 | -------------------------------------------------------------------------------- /website/versioned_sidebars/version-2.8-sidebars.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | { 4 | "type": "category", 5 | "label": "API Client", 6 | "items": [ 7 | "index", 8 | "features", 9 | "usage_concepts" 10 | ] 11 | }, 12 | { 13 | "type": "doc", 14 | "id": "changelog" 15 | } 16 | ] 17 | ] 18 | -------------------------------------------------------------------------------- /website/versioned_sidebars/version-2.9-sidebars.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | { 4 | "type": "category", 5 | "label": "API Client", 6 | "items": [ 7 | "index", 8 | "features", 9 | "usage_concepts" 10 | ] 11 | }, 12 | { 13 | "type": "doc", 14 | "id": "changelog" 15 | } 16 | ] 17 | ] 18 | -------------------------------------------------------------------------------- /website/versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | "2.9", 3 | "2.8", 4 | "2.7", 5 | "2.6" 6 | ] 7 | --------------------------------------------------------------------------------