apify 4.0.0-beta.34 → 4.0.0-beta.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actor.d.ts +0 -16
- package/dist/actor.js +36 -34
- package/dist/apify_storage_backend.d.ts +1 -2
- package/dist/configuration.d.ts +3 -3
- package/dist/configuration.js +14 -3
- package/dist/smart_apify_storage_backend.d.ts +52 -0
- package/dist/smart_apify_storage_backend.js +73 -0
- package/package.json +1 -1
package/dist/actor.d.ts
CHANGED
|
@@ -1381,22 +1381,6 @@ export declare class Actor<Data extends Dictionary = Dictionary> {
|
|
|
1381
1381
|
* @internal
|
|
1382
1382
|
*/
|
|
1383
1383
|
static setDefaultInstance(instance?: Actor): void;
|
|
1384
|
-
/**
|
|
1385
|
-
* The backend the Actor installs: the caller's, the platform's, or crawlee's local default.
|
|
1386
|
-
*
|
|
1387
|
-
* Only the last two are wrapped for dataset-item charging. The platform counts an
|
|
1388
|
-
* `apify-default-dataset-item` per item written to the run's default dataset through Apify
|
|
1389
|
-
* storage, so a caller-supplied backend is billed nothing and must not be accounted for -
|
|
1390
|
-
* charging for it would spend a budget nobody is consuming and trim the caller's items to fit
|
|
1391
|
-
* it. crawlee's local default stands in for Apify storage, so it is wrapped to keep local
|
|
1392
|
-
* pay-per-event testing faithful.
|
|
1393
|
-
*
|
|
1394
|
-
* Wrapping means owning the instance, which is why the local default is constructed here
|
|
1395
|
-
* rather than left to be created lazily on first use.
|
|
1396
|
-
*/
|
|
1397
|
-
private createStorageBackend;
|
|
1398
|
-
/** Wrapped here rather than at the `init()` call site so that `forceCloud` storages are charged too. */
|
|
1399
|
-
private createApifyStorageBackend;
|
|
1400
1384
|
/**
|
|
1401
1385
|
* crawlee's service locator is set-once, so a backend registered before `init()` wins and the
|
|
1402
1386
|
* Actor cannot install its own over it. Replaces the resulting `ServiceConflictError` with the
|
package/dist/actor.js
CHANGED
|
@@ -15,6 +15,7 @@ import { Configuration } from './configuration.js';
|
|
|
15
15
|
import { getDefaultsFromInputSchema, noActorInputSchemaDefinedMarker, readInputSchema } from './input-schemas.js';
|
|
16
16
|
import { PlatformEventManager } from './platform_event_manager.js';
|
|
17
17
|
import { ProxyConfiguration } from './proxy_configuration.js';
|
|
18
|
+
import { SmartApifyStorageBackend } from './smart_apify_storage_backend.js';
|
|
18
19
|
import { checkCrawleeVersion, getSystemInfo, isNonEmptyObject, printOutdatedSdkWarning, snakeCaseToCamelCase, } from './utils.js';
|
|
19
20
|
/**
|
|
20
21
|
* Exit codes for the Actor process.
|
|
@@ -78,6 +79,8 @@ export class Actor {
|
|
|
78
79
|
#chargingManager;
|
|
79
80
|
/** How Apify platform request queues are consumed; set from {@link InitOptions.requestQueueAccess}. */
|
|
80
81
|
#requestQueueAccess = 'single';
|
|
82
|
+
/** Lazily built by the `#storageBackend` getter. */
|
|
83
|
+
#cachedStorageBackend;
|
|
81
84
|
constructor(options = {}) {
|
|
82
85
|
const { configuration, ...configOptions } = options;
|
|
83
86
|
if (configuration) {
|
|
@@ -212,7 +215,7 @@ export class Actor {
|
|
|
212
215
|
serviceLocator.setEventManager(this.eventManager);
|
|
213
216
|
}
|
|
214
217
|
if (!serviceLocator.getServicesIfSet().storageBackend) {
|
|
215
|
-
this.installStorageBackend(
|
|
218
|
+
this.installStorageBackend(options.storage ?? this.#storageBackend);
|
|
216
219
|
}
|
|
217
220
|
else if (options.storage) {
|
|
218
221
|
this.installStorageBackend(options.storage);
|
|
@@ -255,8 +258,7 @@ export class Actor {
|
|
|
255
258
|
log.debug(`ChargingManager initialized`, this.#chargingManager.getPricingInfo());
|
|
256
259
|
// Only knowable once the pricing is loaded. Reachable with a caller-supplied backend or one
|
|
257
260
|
// registered with crawlee directly; the storages the Actor installs itself are wrapped.
|
|
258
|
-
if (this.#chargingManager.isPayPerEvent &&
|
|
259
|
-
!(serviceLocator.getStorageBackend() instanceof ChargingStorageBackend)) {
|
|
261
|
+
if (this.#chargingManager.isPayPerEvent && !this.#chargesDefaultDatasetItems()) {
|
|
260
262
|
log.warning('Items pushed to the default dataset will not be charged for, because this run does not use Apify ' +
|
|
261
263
|
'storage - the platform only counts items it stores itself.');
|
|
262
264
|
}
|
|
@@ -721,7 +723,9 @@ export class Actor {
|
|
|
721
723
|
parseArgument(options, z.object({ forceCloud: z.boolean().optional() }).strict());
|
|
722
724
|
this.ensureActorInit('openDataset');
|
|
723
725
|
return Dataset.open(datasetIdOrName ?? null, {
|
|
724
|
-
storageBackend: options.forceCloud
|
|
726
|
+
storageBackend: options.forceCloud
|
|
727
|
+
? this.#storageBackend.getSuitableStorageBackend({ forceCloud: true })
|
|
728
|
+
: undefined,
|
|
725
729
|
});
|
|
726
730
|
}
|
|
727
731
|
/**
|
|
@@ -871,7 +875,9 @@ export class Actor {
|
|
|
871
875
|
parseArgument(options, z.object({ forceCloud: z.boolean().optional() }).strict());
|
|
872
876
|
this.ensureActorInit('openKeyValueStore');
|
|
873
877
|
return KeyValueStore.open(storeIdOrName ?? null, {
|
|
874
|
-
storageBackend: options.forceCloud
|
|
878
|
+
storageBackend: options.forceCloud
|
|
879
|
+
? this.#storageBackend.getSuitableStorageBackend({ forceCloud: true })
|
|
880
|
+
: undefined,
|
|
875
881
|
});
|
|
876
882
|
}
|
|
877
883
|
/**
|
|
@@ -897,7 +903,9 @@ export class Actor {
|
|
|
897
903
|
parseArgument(options, z.object({ forceCloud: z.boolean().optional() }).strict());
|
|
898
904
|
this.ensureActorInit('openRequestQueue');
|
|
899
905
|
return RequestQueue.open(queueIdOrName ?? null, {
|
|
900
|
-
storageBackend: options.forceCloud
|
|
906
|
+
storageBackend: options.forceCloud
|
|
907
|
+
? this.#storageBackend.getSuitableStorageBackend({ forceCloud: true })
|
|
908
|
+
: undefined,
|
|
901
909
|
});
|
|
902
910
|
}
|
|
903
911
|
/**
|
|
@@ -1646,40 +1654,34 @@ export class Actor {
|
|
|
1646
1654
|
Actor.#instance = instance;
|
|
1647
1655
|
}
|
|
1648
1656
|
/**
|
|
1649
|
-
* The backend the Actor installs
|
|
1657
|
+
* The backend the Actor installs unless the caller brings one: Apify platform storage on the
|
|
1658
|
+
* platform, crawlee's local default outside of it.
|
|
1650
1659
|
*
|
|
1651
|
-
*
|
|
1652
|
-
*
|
|
1653
|
-
* storage
|
|
1654
|
-
* charging for it would spend a budget nobody is consuming and trim the caller's items to fit
|
|
1655
|
-
* it. crawlee's local default stands in for Apify storage, so it is wrapped to keep local
|
|
1656
|
-
* pay-per-event testing faithful.
|
|
1660
|
+
* Both sides are wrapped for dataset-item charging - crawlee's local default stands in for
|
|
1661
|
+
* Apify storage, so local pay-per-event testing stays faithful. A caller-supplied backend
|
|
1662
|
+
* (`Actor.init({ storage })`) is billed nothing and is installed unwrapped, in place of this.
|
|
1657
1663
|
*
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1664
|
+
* One instance per Actor: a second platform backend would mint unnamed storages of its own for
|
|
1665
|
+
* aliases this one has already resolved.
|
|
1660
1666
|
*/
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
return storage;
|
|
1664
|
-
}
|
|
1665
|
-
if (this.isAtHome()) {
|
|
1666
|
-
return this.createApifyStorageBackend();
|
|
1667
|
-
}
|
|
1668
|
-
return new ChargingStorageBackend(new ServiceLocator(this.configuration).getStorageBackend(), {
|
|
1667
|
+
get #storageBackend() {
|
|
1668
|
+
const charging = {
|
|
1669
1669
|
configuration: this.configuration,
|
|
1670
1670
|
getChargingManager: () => this.#chargingManager,
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1671
|
+
};
|
|
1672
|
+
return (this.#cachedStorageBackend ??= new SmartApifyStorageBackend({
|
|
1673
|
+
cloudStorageBackend: new ChargingStorageBackend(new ApifyStorageBackend(this.apifyClient, {
|
|
1674
|
+
configuration: this.configuration,
|
|
1675
|
+
requestQueueAccess: this.#requestQueueAccess,
|
|
1676
|
+
}), charging),
|
|
1677
|
+
localStorageBackend: new ChargingStorageBackend(new ServiceLocator(this.configuration).getStorageBackend(), charging),
|
|
1676
1678
|
configuration: this.configuration,
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1679
|
+
}));
|
|
1680
|
+
}
|
|
1681
|
+
/** Whether items reaching the run's default dataset are counted for pay-per-event charging. */
|
|
1682
|
+
#chargesDefaultDatasetItems() {
|
|
1683
|
+
const installed = serviceLocator.getStorageBackend();
|
|
1684
|
+
return installed instanceof SmartApifyStorageBackend || installed instanceof ChargingStorageBackend;
|
|
1683
1685
|
}
|
|
1684
1686
|
/**
|
|
1685
1687
|
* crawlee's service locator is set-once, so a backend registered before `init()` wins and the
|
|
@@ -2,7 +2,7 @@ import type { DatasetBackend, KeyValueStoreBackend, RequestQueueBackend, Storage
|
|
|
2
2
|
import type { ApifyClient } from 'apify-client';
|
|
3
3
|
import { type RequestQueueAccessMode } from './apify_request_queue_backend.js';
|
|
4
4
|
import type { Configuration } from './configuration.js';
|
|
5
|
-
type StorageType = 'Dataset' | 'KeyValueStore' | 'RequestQueue';
|
|
5
|
+
export type StorageType = 'Dataset' | 'KeyValueStore' | 'RequestQueue';
|
|
6
6
|
/** The reserved alias crawlee uses for the default (unnamed) storage. */
|
|
7
7
|
export declare const DEFAULT_STORAGE_ALIAS = "__default__";
|
|
8
8
|
export interface ApifyStorageBackendOptions {
|
|
@@ -88,4 +88,3 @@ export declare class ApifyStorageBackend implements StorageBackend {
|
|
|
88
88
|
private resourceClient;
|
|
89
89
|
private collectionClient;
|
|
90
90
|
}
|
|
91
|
-
export {};
|
package/dist/configuration.d.ts
CHANGED
|
@@ -9,9 +9,6 @@ export declare const apifyConfigFields: {
|
|
|
9
9
|
persistStorage: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>>;
|
|
10
10
|
storageDir: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
11
11
|
containerized: ConfigField<z.ZodOptional<z.ZodPreprocess<z.ZodBoolean>>>;
|
|
12
|
-
defaultDatasetId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
13
|
-
defaultKeyValueStoreId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
14
|
-
defaultRequestQueueId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
15
12
|
inputKey: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
16
13
|
memoryMbytes: ConfigField<z.ZodOptional<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
17
14
|
availableMemoryRatio: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
@@ -22,6 +19,9 @@ export declare const apifyConfigFields: {
|
|
|
22
19
|
chromeExecutablePath: ConfigField<z.ZodOptional<z.ZodString>>;
|
|
23
20
|
defaultBrowserPath: ConfigField<z.ZodOptional<z.ZodString>>;
|
|
24
21
|
purgeOnStart: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodBoolean, unknown>>>;
|
|
22
|
+
defaultDatasetId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
23
|
+
defaultKeyValueStoreId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
24
|
+
defaultRequestQueueId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
25
25
|
metamorphAfterSleepMillis: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
26
26
|
actorEventsWsUrl: ConfigField<z.ZodOptional<z.ZodString>>;
|
|
27
27
|
token: ConfigField<z.ZodOptional<z.ZodString>>;
|
package/dist/configuration.js
CHANGED
|
@@ -20,9 +20,6 @@ export const apifyConfigFields = {
|
|
|
20
20
|
// take precedence; crawlee's own CRAWLEE_* var is reused as the fallback,
|
|
21
21
|
// never re-typed). A schema is passed only where the SDK needs a different
|
|
22
22
|
// default than crawlee's.
|
|
23
|
-
defaultDatasetId: withApifyEnv(crawleeConfigFields.defaultDatasetId, [ACTOR_ENV_VARS.DEFAULT_DATASET_ID, APIFY_ENV_VARS.DEFAULT_DATASET_ID], z.string().default(LOCAL_ACTOR_ENV_VARS[ACTOR_ENV_VARS.DEFAULT_DATASET_ID])),
|
|
24
|
-
defaultKeyValueStoreId: withApifyEnv(crawleeConfigFields.defaultKeyValueStoreId, [ACTOR_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID, APIFY_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID], z.string().default(LOCAL_ACTOR_ENV_VARS[ACTOR_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID])),
|
|
25
|
-
defaultRequestQueueId: withApifyEnv(crawleeConfigFields.defaultRequestQueueId, [ACTOR_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID, APIFY_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID], z.string().default(LOCAL_ACTOR_ENV_VARS[ACTOR_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID])),
|
|
26
23
|
inputKey: withApifyEnv(crawleeConfigFields.inputKey, [ACTOR_ENV_VARS.INPUT_KEY, APIFY_ENV_VARS.INPUT_KEY]),
|
|
27
24
|
memoryMbytes: withApifyEnv(crawleeConfigFields.memoryMbytes, [
|
|
28
25
|
ACTOR_ENV_VARS.MEMORY_MBYTES,
|
|
@@ -39,6 +36,20 @@ export const apifyConfigFields = {
|
|
|
39
36
|
chromeExecutablePath: withApifyEnv(crawleeConfigFields.chromeExecutablePath, APIFY_ENV_VARS.CHROME_EXECUTABLE_PATH),
|
|
40
37
|
defaultBrowserPath: withApifyEnv(crawleeConfigFields.defaultBrowserPath, 'APIFY_DEFAULT_BROWSER_PATH'),
|
|
41
38
|
purgeOnStart: withApifyEnv(crawleeConfigFields.purgeOnStart, APIFY_ENV_VARS.PURGE_ON_START),
|
|
39
|
+
// Crawlee addresses the default storage by a reserved alias; on the platform
|
|
40
|
+
// each run gets real storage IDs, which the API calls need.
|
|
41
|
+
defaultDatasetId: field(z.string().default(LOCAL_ACTOR_ENV_VARS[ACTOR_ENV_VARS.DEFAULT_DATASET_ID]), [
|
|
42
|
+
ACTOR_ENV_VARS.DEFAULT_DATASET_ID,
|
|
43
|
+
APIFY_ENV_VARS.DEFAULT_DATASET_ID,
|
|
44
|
+
]),
|
|
45
|
+
defaultKeyValueStoreId: field(z.string().default(LOCAL_ACTOR_ENV_VARS[ACTOR_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID]), [
|
|
46
|
+
ACTOR_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID,
|
|
47
|
+
APIFY_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID,
|
|
48
|
+
]),
|
|
49
|
+
defaultRequestQueueId: field(z.string().default(LOCAL_ACTOR_ENV_VARS[ACTOR_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID]), [
|
|
50
|
+
ACTOR_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID,
|
|
51
|
+
APIFY_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID,
|
|
52
|
+
]),
|
|
42
53
|
// Apify-specific fields
|
|
43
54
|
metamorphAfterSleepMillis: field(coerceNumber.default(300_000), APIFY_ENV_VARS.METAMORPH_AFTER_SLEEP_MILLIS),
|
|
44
55
|
actorEventsWsUrl: field(z.string().optional(), [
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DatasetBackend, KeyValueStoreBackend, RequestQueueBackend, StorageBackend, StorageIdentifier } from '@crawlee/types';
|
|
2
|
+
import type { StorageType } from './apify_storage_backend.js';
|
|
3
|
+
import type { Configuration } from './configuration.js';
|
|
4
|
+
import type { OpenStorageOptions } from './storage.js';
|
|
5
|
+
export interface SmartApifyStorageBackendOptions {
|
|
6
|
+
/** Used on the Apify platform, and locally for `forceCloud` storages. */
|
|
7
|
+
cloudStorageBackend: StorageBackend;
|
|
8
|
+
/** Used outside of the Apify platform, except for `forceCloud` storages. */
|
|
9
|
+
localStorageBackend: StorageBackend;
|
|
10
|
+
/** Supplies `isAtHome` and the token that cloud storage needs. */
|
|
11
|
+
configuration: Configuration;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Routes storages to Apify cloud storage or to a local one, depending on where the Actor runs.
|
|
15
|
+
*
|
|
16
|
+
* On the Apify platform (detected through the `APIFY_IS_AT_HOME` environment variable) storages are
|
|
17
|
+
* opened in the cloud; locally they are opened through `localStorageBackend`, unless `forceCloud`
|
|
18
|
+
* asks for the cloud one. `Actor` installs it; callers who want storages of their own pass a
|
|
19
|
+
* backend to `Actor.init({ storage })` instead.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export declare class SmartApifyStorageBackend implements StorageBackend {
|
|
24
|
+
#private;
|
|
25
|
+
constructor(options: SmartApifyStorageBackendOptions);
|
|
26
|
+
/**
|
|
27
|
+
* The backend a storage is opened through: the cloud one on the platform or with `forceCloud`,
|
|
28
|
+
* the local one otherwise.
|
|
29
|
+
*
|
|
30
|
+
* Exposed so that `forceCloud` storages can be opened through the very same cloud backend
|
|
31
|
+
* instance this one delegates to — two instances would resolve run-scoped aliases to two
|
|
32
|
+
* separate storages.
|
|
33
|
+
*/
|
|
34
|
+
getSuitableStorageBackend(options?: OpenStorageOptions): StorageBackend;
|
|
35
|
+
get stats(): {
|
|
36
|
+
rateLimitErrors: number[];
|
|
37
|
+
} | undefined;
|
|
38
|
+
/** Repeats crawlee's own fallback, so that routing a backend does not change how storages are cached. */
|
|
39
|
+
getStorageBackendCacheKey(): string;
|
|
40
|
+
createDatasetBackend(options?: StorageIdentifier): Promise<DatasetBackend>;
|
|
41
|
+
createKeyValueStoreBackend(options?: StorageIdentifier): Promise<KeyValueStoreBackend>;
|
|
42
|
+
createRequestQueueBackend(options?: StorageIdentifier): Promise<RequestQueueBackend>;
|
|
43
|
+
/**
|
|
44
|
+
* Declared unconditionally, unlike on the backends this one delegates to: crawlee branches on
|
|
45
|
+
* the presence of the three methods below, and delegating to a backend that lacks one is
|
|
46
|
+
* indistinguishable from not having it — a `false` from `storageExists` means the same as its
|
|
47
|
+
* absence (crawlee falls through to a name lookup), and the other two have no return value.
|
|
48
|
+
*/
|
|
49
|
+
storageExists(id: string, type: StorageType): Promise<boolean>;
|
|
50
|
+
purge(): Promise<void>;
|
|
51
|
+
teardown(): Promise<void>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routes storages to Apify cloud storage or to a local one, depending on where the Actor runs.
|
|
3
|
+
*
|
|
4
|
+
* On the Apify platform (detected through the `APIFY_IS_AT_HOME` environment variable) storages are
|
|
5
|
+
* opened in the cloud; locally they are opened through `localStorageBackend`, unless `forceCloud`
|
|
6
|
+
* asks for the cloud one. `Actor` installs it; callers who want storages of their own pass a
|
|
7
|
+
* backend to `Actor.init({ storage })` instead.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export class SmartApifyStorageBackend {
|
|
12
|
+
#cloudStorageBackend;
|
|
13
|
+
#localStorageBackend;
|
|
14
|
+
#configuration;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.#cloudStorageBackend = options.cloudStorageBackend;
|
|
17
|
+
this.#localStorageBackend = options.localStorageBackend;
|
|
18
|
+
this.#configuration = options.configuration;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The backend a storage is opened through: the cloud one on the platform or with `forceCloud`,
|
|
22
|
+
* the local one otherwise.
|
|
23
|
+
*
|
|
24
|
+
* Exposed so that `forceCloud` storages can be opened through the very same cloud backend
|
|
25
|
+
* instance this one delegates to — two instances would resolve run-scoped aliases to two
|
|
26
|
+
* separate storages.
|
|
27
|
+
*/
|
|
28
|
+
getSuitableStorageBackend(options = {}) {
|
|
29
|
+
if (this.#configuration.isAtHome) {
|
|
30
|
+
return this.#cloudStorageBackend;
|
|
31
|
+
}
|
|
32
|
+
if (!options.forceCloud) {
|
|
33
|
+
return this.#localStorageBackend;
|
|
34
|
+
}
|
|
35
|
+
if (!this.#configuration.token) {
|
|
36
|
+
throw new Error('In order to use the Apify cloud storage from your computer, you need to provide an Apify token ' +
|
|
37
|
+
'using the APIFY_TOKEN environment variable.');
|
|
38
|
+
}
|
|
39
|
+
return this.#cloudStorageBackend;
|
|
40
|
+
}
|
|
41
|
+
get stats() {
|
|
42
|
+
return this.getSuitableStorageBackend().stats;
|
|
43
|
+
}
|
|
44
|
+
/** Repeats crawlee's own fallback, so that routing a backend does not change how storages are cached. */
|
|
45
|
+
getStorageBackendCacheKey() {
|
|
46
|
+
const backend = this.getSuitableStorageBackend();
|
|
47
|
+
return backend.getStorageBackendCacheKey?.() ?? backend.constructor.name;
|
|
48
|
+
}
|
|
49
|
+
async createDatasetBackend(options) {
|
|
50
|
+
return await this.getSuitableStorageBackend().createDatasetBackend(options);
|
|
51
|
+
}
|
|
52
|
+
async createKeyValueStoreBackend(options) {
|
|
53
|
+
return await this.getSuitableStorageBackend().createKeyValueStoreBackend(options);
|
|
54
|
+
}
|
|
55
|
+
async createRequestQueueBackend(options) {
|
|
56
|
+
return await this.getSuitableStorageBackend().createRequestQueueBackend(options);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Declared unconditionally, unlike on the backends this one delegates to: crawlee branches on
|
|
60
|
+
* the presence of the three methods below, and delegating to a backend that lacks one is
|
|
61
|
+
* indistinguishable from not having it — a `false` from `storageExists` means the same as its
|
|
62
|
+
* absence (crawlee falls through to a name lookup), and the other two have no return value.
|
|
63
|
+
*/
|
|
64
|
+
async storageExists(id, type) {
|
|
65
|
+
return (await this.getSuitableStorageBackend().storageExists?.(id, type)) ?? false;
|
|
66
|
+
}
|
|
67
|
+
async purge() {
|
|
68
|
+
await this.getSuitableStorageBackend().purge?.();
|
|
69
|
+
}
|
|
70
|
+
async teardown() {
|
|
71
|
+
await this.getSuitableStorageBackend().teardown?.();
|
|
72
|
+
}
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apify",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.36",
|
|
4
4
|
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|