Skip to content

Commit

Permalink
feat: validate crawlee versions in Actor.init (#301)
Browse files Browse the repository at this point in the history
* feat: validate crawlee versions in `Actor.init`

The SDK depends on `@crawlee/core`, but if the user installs an incompatible version of crawlee, they might end up with two installations of the `@crawlee/core` which means multiple static registers like the one for the global configuration, which breaks the integration, since the SDK will only touch the global config it sees, but it's a different one than the explicitly installed package.

Closes #237

* normalize paths and declare missing dependency

* add more details to the error message

* support pnpm and yarn pnp
  • Loading branch information
B4nan authored May 23, 2024
1 parent f499ed2 commit 66ff6a9
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 2 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/apify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@
"@crawlee/types": "^3.9.0",
"@crawlee/utils": "^3.9.0",
"apify-client": "^2.9.0",
"fs-extra": "^11.2.0",
"ow": "^0.28.2",
"semver": "^7.5.4",
"tslib": "^2.6.2",
"ws": "^7.5.9"
}
}
}
3 changes: 2 additions & 1 deletion packages/apify/src/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { KeyValueStore } from './key_value_store';
import { PlatformEventManager } from './platform_event_manager';
import type { ProxyConfigurationOptions } from './proxy_configuration';
import { ProxyConfiguration } from './proxy_configuration';
import { logSystemInfo, printOutdatedSdkWarning } from './utils';
import { checkCrawleeVersion, logSystemInfo, printOutdatedSdkWarning } from './utils';

/**
* `Actor` class serves as an alternative approach to the static helpers exported from the package. It allows to pass configuration
Expand Down Expand Up @@ -193,6 +193,7 @@ export class Actor<Data extends Dictionary = Dictionary> {

this.initialized = true;

checkCrawleeVersion();
logSystemInfo();
printOutdatedSdkWarning();

Expand Down
38 changes: 38 additions & 0 deletions packages/apify/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { type } from 'node:os';
import { normalize } from 'node:path';

import { APIFY_ENV_VARS } from '@apify/consts';
import log from '@apify/log';
// @ts-expect-error if we enable resolveJsonModule, we end up with `src` folder in `dist`
import { version as crawleeVersion } from '@crawlee/core/package.json';
// @ts-expect-error if we enable resolveJsonModule, we end up with `src` folder in `dist`
import { version as apifyClientVersion } from 'apify-client/package.json';
import { pathExistsSync, readJSONSync } from 'fs-extra';
import semver from 'semver';

// @ts-expect-error if we enable resolveJsonModule, we end up with `src` folder in `dist`
Expand All @@ -25,6 +27,42 @@ export function logSystemInfo() {
});
}

/**
* Logs info about system, node version and apify package version.
* @internal
*/
export function checkCrawleeVersion() {
const paths = [
// when users install `crawlee` package, we need to check its core dependency
normalize(`${process.cwd()}/node_modules/crawlee/node_modules/@crawlee/core/package.json`),
// when users install `@crawlee/cheerio` or other crawler package, we need to check the dependency under basic crawler package
normalize(`${process.cwd()}/node_modules/@crawlee/basic/node_modules/@crawlee/core/package.json`),
// also check paths via `require.resolve` to support pnpm
require.resolve('crawlee/package.json'),
require.resolve('@crawlee/basic/package.json'),
];

for (const path of paths) {
if (!pathExistsSync(path)) {
continue;
}

let version;

try {
version = readJSONSync(path).version;
} catch {
//
}

if (version != null && version !== crawleeVersion) {
const details = `User installed version (${version}) found in ${path}.\nSDK uses ${crawleeVersion} from ${require.resolve('@crawlee/core')}`;
// eslint-disable-next-line max-len
throw new Error(`Detected incompatible Crawlee version used by the SDK. User installed ${version} but the SDK uses ${crawleeVersion}.\n\n${details}`);
}
}
}

/**
* Prints a warning if this version of Apify SDK is outdated.
* @ignore
Expand Down

0 comments on commit 66ff6a9

Please sign in to comment.