@crawlee/core 4.0.0-beta.8 → 4.0.0-beta.80
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/README.md +17 -13
- package/autoscaling/autoscaled_pool.d.ts +5 -6
- package/autoscaling/autoscaled_pool.js +12 -11
- package/autoscaling/client_load_signal.d.ts +25 -0
- package/autoscaling/client_load_signal.js +36 -0
- package/autoscaling/cpu_load_signal.d.ts +28 -0
- package/autoscaling/cpu_load_signal.js +24 -0
- package/autoscaling/event_loop_load_signal.d.ts +23 -0
- package/autoscaling/event_loop_load_signal.js +35 -0
- package/autoscaling/index.d.ts +5 -1
- package/autoscaling/index.js +5 -1
- package/autoscaling/load_signal.d.ts +99 -0
- package/autoscaling/load_signal.js +135 -0
- package/autoscaling/memory_load_signal.d.ts +43 -0
- package/autoscaling/memory_load_signal.js +102 -0
- package/autoscaling/snapshotter.d.ts +35 -72
- package/autoscaling/snapshotter.js +78 -181
- package/autoscaling/system_status.d.ts +21 -36
- package/autoscaling/system_status.js +46 -84
- package/configuration.d.ts +88 -228
- package/configuration.js +162 -224
- package/cookie_utils.d.ts +4 -3
- package/cookie_utils.js +20 -13
- package/crawlers/context_pipeline.d.ts +70 -0
- package/crawlers/context_pipeline.js +122 -0
- package/crawlers/crawler_commons.d.ts +20 -30
- package/crawlers/crawler_commons.js +12 -21
- package/crawlers/crawler_utils.d.ts +2 -3
- package/crawlers/crawler_utils.js +1 -2
- package/crawlers/error_snapshotter.d.ts +3 -3
- package/crawlers/error_snapshotter.js +2 -3
- package/crawlers/error_tracker.d.ts +2 -2
- package/crawlers/error_tracker.js +0 -1
- package/crawlers/index.d.ts +1 -2
- package/crawlers/index.js +1 -2
- package/crawlers/internals/types.d.ts +7 -0
- package/crawlers/internals/types.js +1 -0
- package/crawlers/statistics.d.ts +22 -17
- package/crawlers/statistics.js +30 -26
- package/enqueue_links/enqueue_links.d.ts +44 -22
- package/enqueue_links/enqueue_links.js +51 -30
- package/enqueue_links/index.d.ts +0 -1
- package/enqueue_links/index.js +0 -1
- package/enqueue_links/shared.d.ts +25 -9
- package/enqueue_links/shared.js +69 -38
- package/errors.d.ts +53 -4
- package/errors.js +70 -5
- package/events/event_manager.d.ts +34 -8
- package/events/event_manager.js +8 -10
- package/events/index.d.ts +0 -1
- package/events/index.js +0 -1
- package/events/local_event_manager.d.ts +15 -5
- package/events/local_event_manager.js +37 -40
- package/index.d.ts +4 -3
- package/index.js +3 -2
- package/log.d.ts +82 -3
- package/log.js +102 -1
- package/memory-storage/consts.d.ts +4 -0
- package/memory-storage/consts.js +4 -0
- package/memory-storage/index.d.ts +1 -0
- package/memory-storage/index.js +1 -0
- package/memory-storage/memory-storage.d.ts +46 -0
- package/memory-storage/memory-storage.js +136 -0
- package/memory-storage/resource-clients/common/base-client.d.ts +4 -0
- package/memory-storage/resource-clients/common/base-client.js +6 -0
- package/memory-storage/resource-clients/dataset.d.ts +40 -0
- package/memory-storage/resource-clients/dataset.js +113 -0
- package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
- package/memory-storage/resource-clients/key-value-store.js +203 -0
- package/memory-storage/resource-clients/request-queue.d.ts +96 -0
- package/memory-storage/resource-clients/request-queue.js +421 -0
- package/memory-storage/utils.d.ts +17 -0
- package/memory-storage/utils.js +42 -0
- package/package.json +12 -10
- package/proxy_configuration.d.ts +14 -149
- package/proxy_configuration.js +19 -168
- package/recoverable_state.d.ts +120 -0
- package/recoverable_state.js +141 -0
- package/request.d.ts +84 -13
- package/request.js +107 -28
- package/router.d.ts +117 -15
- package/router.js +124 -30
- package/serialization.d.ts +0 -1
- package/serialization.js +1 -2
- package/service_locator.d.ts +156 -0
- package/service_locator.js +238 -0
- package/session_pool/consts.d.ts +1 -2
- package/session_pool/consts.js +1 -2
- package/session_pool/errors.d.ts +0 -1
- package/session_pool/errors.js +0 -1
- package/session_pool/fingerprint.d.ts +9 -0
- package/session_pool/fingerprint.js +30 -0
- package/session_pool/index.d.ts +0 -2
- package/session_pool/index.js +0 -2
- package/session_pool/session.d.ts +35 -73
- package/session_pool/session.js +46 -99
- package/session_pool/session_pool.d.ts +71 -72
- package/session_pool/session_pool.js +111 -100
- package/storages/access_checking.d.ts +0 -1
- package/storages/access_checking.js +5 -2
- package/storages/dataset.d.ts +101 -51
- package/storages/dataset.js +168 -126
- package/storages/index.d.ts +8 -7
- package/storages/index.js +6 -7
- package/storages/key_value_store.d.ts +165 -36
- package/storages/key_value_store.js +269 -122
- package/storages/key_value_store_codec.d.ts +32 -0
- package/storages/key_value_store_codec.js +113 -0
- package/storages/request_dedup_cache.d.ts +23 -0
- package/storages/request_dedup_cache.js +48 -0
- package/storages/request_list.d.ts +38 -82
- package/storages/request_list.js +65 -41
- package/storages/request_loader.d.ts +96 -0
- package/storages/request_loader.js +1 -0
- package/storages/request_manager.d.ts +33 -0
- package/storages/request_manager.js +1 -0
- package/storages/request_manager_tandem.d.ts +106 -0
- package/storages/request_manager_tandem.js +197 -0
- package/storages/request_queue.d.ts +303 -46
- package/storages/request_queue.js +629 -214
- package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +28 -24
- package/storages/{sitemap_request_list.js → sitemap_request_loader.js} +49 -46
- package/storages/storage_instance_manager.d.ts +91 -0
- package/storages/storage_instance_manager.js +258 -0
- package/storages/storage_stats.d.ts +48 -0
- package/storages/storage_stats.js +29 -0
- package/storages/utils.d.ts +51 -6
- package/storages/utils.js +60 -9
- package/system-info/cpu-info.d.ts +67 -0
- package/system-info/cpu-info.js +216 -0
- package/system-info/memory-info.d.ts +31 -0
- package/system-info/memory-info.js +115 -0
- package/system-info/ps-tree.d.ts +17 -0
- package/system-info/ps-tree.js +144 -0
- package/system-info/runtime.d.ts +14 -0
- package/system-info/runtime.js +80 -0
- package/typedefs.d.ts +1 -2
- package/typedefs.js +0 -1
- package/validators.d.ts +8 -1
- package/validators.js +8 -1
- package/autoscaling/autoscaled_pool.d.ts.map +0 -1
- package/autoscaling/autoscaled_pool.js.map +0 -1
- package/autoscaling/index.d.ts.map +0 -1
- package/autoscaling/index.js.map +0 -1
- package/autoscaling/snapshotter.d.ts.map +0 -1
- package/autoscaling/snapshotter.js.map +0 -1
- package/autoscaling/system_status.d.ts.map +0 -1
- package/autoscaling/system_status.js.map +0 -1
- package/configuration.d.ts.map +0 -1
- package/configuration.js.map +0 -1
- package/cookie_utils.d.ts.map +0 -1
- package/cookie_utils.js.map +0 -1
- package/crawlers/crawler_commons.d.ts.map +0 -1
- package/crawlers/crawler_commons.js.map +0 -1
- package/crawlers/crawler_extension.d.ts +0 -12
- package/crawlers/crawler_extension.d.ts.map +0 -1
- package/crawlers/crawler_extension.js +0 -14
- package/crawlers/crawler_extension.js.map +0 -1
- package/crawlers/crawler_utils.d.ts.map +0 -1
- package/crawlers/crawler_utils.js.map +0 -1
- package/crawlers/error_snapshotter.d.ts.map +0 -1
- package/crawlers/error_snapshotter.js.map +0 -1
- package/crawlers/error_tracker.d.ts.map +0 -1
- package/crawlers/error_tracker.js.map +0 -1
- package/crawlers/index.d.ts.map +0 -1
- package/crawlers/index.js.map +0 -1
- package/crawlers/statistics.d.ts.map +0 -1
- package/crawlers/statistics.js.map +0 -1
- package/enqueue_links/enqueue_links.d.ts.map +0 -1
- package/enqueue_links/enqueue_links.js.map +0 -1
- package/enqueue_links/index.d.ts.map +0 -1
- package/enqueue_links/index.js.map +0 -1
- package/enqueue_links/shared.d.ts.map +0 -1
- package/enqueue_links/shared.js.map +0 -1
- package/errors.d.ts.map +0 -1
- package/errors.js.map +0 -1
- package/events/event_manager.d.ts.map +0 -1
- package/events/event_manager.js.map +0 -1
- package/events/index.d.ts.map +0 -1
- package/events/index.js.map +0 -1
- package/events/local_event_manager.d.ts.map +0 -1
- package/events/local_event_manager.js.map +0 -1
- package/http_clients/base-http-client.d.ts +0 -134
- package/http_clients/base-http-client.d.ts.map +0 -1
- package/http_clients/base-http-client.js +0 -33
- package/http_clients/base-http-client.js.map +0 -1
- package/http_clients/form-data-like.d.ts +0 -67
- package/http_clients/form-data-like.d.ts.map +0 -1
- package/http_clients/form-data-like.js +0 -5
- package/http_clients/form-data-like.js.map +0 -1
- package/http_clients/got-scraping-http-client.d.ts +0 -15
- package/http_clients/got-scraping-http-client.d.ts.map +0 -1
- package/http_clients/got-scraping-http-client.js +0 -69
- package/http_clients/got-scraping-http-client.js.map +0 -1
- package/http_clients/index.d.ts +0 -3
- package/http_clients/index.d.ts.map +0 -1
- package/http_clients/index.js +0 -3
- package/http_clients/index.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/log.d.ts.map +0 -1
- package/log.js.map +0 -1
- package/proxy_configuration.d.ts.map +0 -1
- package/proxy_configuration.js.map +0 -1
- package/request.d.ts.map +0 -1
- package/request.js.map +0 -1
- package/router.d.ts.map +0 -1
- package/router.js.map +0 -1
- package/serialization.d.ts.map +0 -1
- package/serialization.js.map +0 -1
- package/session_pool/consts.d.ts.map +0 -1
- package/session_pool/consts.js.map +0 -1
- package/session_pool/errors.d.ts.map +0 -1
- package/session_pool/errors.js.map +0 -1
- package/session_pool/events.d.ts +0 -3
- package/session_pool/events.d.ts.map +0 -1
- package/session_pool/events.js +0 -3
- package/session_pool/events.js.map +0 -1
- package/session_pool/index.d.ts.map +0 -1
- package/session_pool/index.js.map +0 -1
- package/session_pool/session.d.ts.map +0 -1
- package/session_pool/session.js.map +0 -1
- package/session_pool/session_pool.d.ts.map +0 -1
- package/session_pool/session_pool.js.map +0 -1
- package/storages/access_checking.d.ts.map +0 -1
- package/storages/access_checking.js.map +0 -1
- package/storages/dataset.d.ts.map +0 -1
- package/storages/dataset.js.map +0 -1
- package/storages/index.d.ts.map +0 -1
- package/storages/index.js.map +0 -1
- package/storages/key_value_store.d.ts.map +0 -1
- package/storages/key_value_store.js.map +0 -1
- package/storages/request_list.d.ts.map +0 -1
- package/storages/request_list.js.map +0 -1
- package/storages/request_provider.d.ts +0 -307
- package/storages/request_provider.d.ts.map +0 -1
- package/storages/request_provider.js +0 -555
- package/storages/request_provider.js.map +0 -1
- package/storages/request_queue.d.ts.map +0 -1
- package/storages/request_queue.js.map +0 -1
- package/storages/request_queue_v2.d.ts +0 -87
- package/storages/request_queue_v2.d.ts.map +0 -1
- package/storages/request_queue_v2.js +0 -438
- package/storages/request_queue_v2.js.map +0 -1
- package/storages/sitemap_request_list.d.ts.map +0 -1
- package/storages/sitemap_request_list.js.map +0 -1
- package/storages/storage_manager.d.ts +0 -58
- package/storages/storage_manager.d.ts.map +0 -1
- package/storages/storage_manager.js +0 -105
- package/storages/storage_manager.js.map +0 -1
- package/storages/utils.d.ts.map +0 -1
- package/storages/utils.js.map +0 -1
- package/tsconfig.build.tsbuildinfo +0 -1
- package/typedefs.d.ts.map +0 -1
- package/typedefs.js.map +0 -1
- package/validators.d.ts.map +0 -1
- package/validators.js.map +0 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { FileSystemStorageBackend } from '@crawlee/fs-storage';
|
|
3
|
+
import log from '@apify/log';
|
|
4
|
+
import { Configuration } from './configuration.js';
|
|
5
|
+
import { ServiceConflictError } from './errors.js';
|
|
6
|
+
import { LocalEventManager } from './events/local_event_manager.js';
|
|
7
|
+
import { ApifyLogAdapter } from './log.js';
|
|
8
|
+
import { MemoryStorageBackend } from './memory-storage/index.js';
|
|
9
|
+
import { StorageInstanceManager } from './storages/storage_instance_manager.js';
|
|
10
|
+
/**
|
|
11
|
+
* Service locator for managing the services used by Crawlee.
|
|
12
|
+
*
|
|
13
|
+
* All services are initialized to their default value lazily.
|
|
14
|
+
*
|
|
15
|
+
* There are two primary usage patterns:
|
|
16
|
+
*
|
|
17
|
+
* **1. Global service locator (for default services):**
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { serviceLocator, BasicCrawler } from 'crawlee';
|
|
20
|
+
*
|
|
21
|
+
* // Optionally configure global services before creating crawlers
|
|
22
|
+
* serviceLocator.setStorageBackend(myCustomClient);
|
|
23
|
+
*
|
|
24
|
+
* // Crawler uses global services
|
|
25
|
+
* const crawler = new BasicCrawler({ ... });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* **2. Per-crawler services (recommended for isolation):**
|
|
29
|
+
* ```typescript
|
|
30
|
+
* import { BasicCrawler, Configuration, LocalEventManager, MemoryStorageBackend } from 'crawlee';
|
|
31
|
+
*
|
|
32
|
+
* const crawler = new BasicCrawler({
|
|
33
|
+
* requestHandler: async ({ request }) => { ... },
|
|
34
|
+
* configuration: new Configuration({ ... }), // custom config
|
|
35
|
+
* storageBackend: new MemoryStorageBackend(), // custom storage
|
|
36
|
+
* eventManager: LocalEventManager.fromConfig(), // custom events
|
|
37
|
+
* });
|
|
38
|
+
* // Crawler has its own isolated ServiceLocator instance
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class ServiceLocator {
|
|
42
|
+
configuration;
|
|
43
|
+
eventManager;
|
|
44
|
+
storageBackend;
|
|
45
|
+
logger;
|
|
46
|
+
/**
|
|
47
|
+
* Unified storage instance manager for Dataset, KeyValueStore, and RequestQueue.
|
|
48
|
+
* Shared across all ServiceLocator instances (global singleton), matching crawlee-python.
|
|
49
|
+
* Per-crawler isolation is achieved via `clientCacheKey`, not separate manager instances.
|
|
50
|
+
*/
|
|
51
|
+
static storageInstanceManager;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new ServiceLocator instance.
|
|
54
|
+
*
|
|
55
|
+
* @param configuration Optional configuration instance to use
|
|
56
|
+
* @param eventManager Optional event manager instance to use
|
|
57
|
+
* @param storageBackend Optional storage backend instance to use
|
|
58
|
+
* @param logger Optional logger instance to use
|
|
59
|
+
*/
|
|
60
|
+
constructor(configuration, eventManager, storageBackend, logger) {
|
|
61
|
+
this.configuration = configuration;
|
|
62
|
+
this.eventManager = eventManager;
|
|
63
|
+
this.storageBackend = storageBackend;
|
|
64
|
+
this.logger = logger;
|
|
65
|
+
}
|
|
66
|
+
getConfiguration() {
|
|
67
|
+
if (!this.configuration) {
|
|
68
|
+
this.getLogger().debug('No configuration set, implicitly creating and using default Configuration.');
|
|
69
|
+
this.configuration = new Configuration();
|
|
70
|
+
}
|
|
71
|
+
return this.configuration;
|
|
72
|
+
}
|
|
73
|
+
setConfiguration(configuration) {
|
|
74
|
+
// Same instance, no need to do anything
|
|
75
|
+
if (this.configuration === configuration) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Already have a different configuration that was retrieved
|
|
79
|
+
if (this.configuration) {
|
|
80
|
+
throw new ServiceConflictError('Configuration', configuration, this.configuration);
|
|
81
|
+
}
|
|
82
|
+
this.configuration = configuration;
|
|
83
|
+
}
|
|
84
|
+
getEventManager() {
|
|
85
|
+
if (!this.eventManager) {
|
|
86
|
+
this.getLogger().debug('No event manager set, implicitly creating and using default LocalEventManager.');
|
|
87
|
+
if (!this.configuration) {
|
|
88
|
+
this.getLogger().warning('Implicit creation of event manager will implicitly set configuration as side effect. ' +
|
|
89
|
+
'It is advised to explicitly first set the configuration instead.');
|
|
90
|
+
}
|
|
91
|
+
this.eventManager = LocalEventManager.fromConfig(this.getConfiguration());
|
|
92
|
+
}
|
|
93
|
+
return this.eventManager;
|
|
94
|
+
}
|
|
95
|
+
setEventManager(eventManager) {
|
|
96
|
+
// Same instance, no need to do anything
|
|
97
|
+
if (this.eventManager === eventManager) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Already have a different event manager that was retrieved
|
|
101
|
+
if (this.eventManager) {
|
|
102
|
+
throw new ServiceConflictError('EventManager', eventManager, this.eventManager);
|
|
103
|
+
}
|
|
104
|
+
this.eventManager = eventManager;
|
|
105
|
+
}
|
|
106
|
+
getStorageBackend() {
|
|
107
|
+
if (!this.storageBackend) {
|
|
108
|
+
this.getLogger().debug('No storage backend set, implicitly creating and using the default storage backend ' +
|
|
109
|
+
'(FileSystemStorageBackend when persistStorage is enabled, MemoryStorageBackend otherwise).');
|
|
110
|
+
if (!this.configuration) {
|
|
111
|
+
this.getLogger().warning('Implicit creation of storage backend will implicitly set configuration as side effect. ' +
|
|
112
|
+
'It is advised to explicitly first set the configuration instead.');
|
|
113
|
+
}
|
|
114
|
+
const config = this.getConfiguration();
|
|
115
|
+
this.storageBackend = config.persistStorage
|
|
116
|
+
? new FileSystemStorageBackend({
|
|
117
|
+
localDataDirectory: config.storageDir,
|
|
118
|
+
logger: this.getLogger().child({ prefix: 'FileSystemStorageBackend' }),
|
|
119
|
+
})
|
|
120
|
+
: new MemoryStorageBackend({
|
|
121
|
+
logger: this.getLogger().child({ prefix: 'MemoryStorageBackend' }),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return this.storageBackend;
|
|
125
|
+
}
|
|
126
|
+
setStorageBackend(storageBackend) {
|
|
127
|
+
// Same instance, no need to do anything
|
|
128
|
+
if (this.storageBackend === storageBackend) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// Already have a different storage backend that was retrieved
|
|
132
|
+
if (this.storageBackend) {
|
|
133
|
+
throw new ServiceConflictError('StorageBackend', storageBackend, this.storageBackend);
|
|
134
|
+
}
|
|
135
|
+
this.storageBackend = storageBackend;
|
|
136
|
+
}
|
|
137
|
+
getLogger() {
|
|
138
|
+
if (!this.logger) {
|
|
139
|
+
this.logger = new ApifyLogAdapter(log);
|
|
140
|
+
}
|
|
141
|
+
return this.logger;
|
|
142
|
+
}
|
|
143
|
+
setLogger(logger) {
|
|
144
|
+
if (this.logger === logger) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (this.logger) {
|
|
148
|
+
throw new ServiceConflictError('Logger', logger, this.logger);
|
|
149
|
+
}
|
|
150
|
+
this.logger = logger;
|
|
151
|
+
}
|
|
152
|
+
getChildLog(prefix) {
|
|
153
|
+
return this.getLogger().child({ prefix });
|
|
154
|
+
}
|
|
155
|
+
getStorageInstanceManager() {
|
|
156
|
+
if (!ServiceLocator.storageInstanceManager) {
|
|
157
|
+
ServiceLocator.storageInstanceManager = new StorageInstanceManager();
|
|
158
|
+
}
|
|
159
|
+
return ServiceLocator.storageInstanceManager;
|
|
160
|
+
}
|
|
161
|
+
reset() {
|
|
162
|
+
this.configuration = undefined;
|
|
163
|
+
this.eventManager = undefined;
|
|
164
|
+
this.storageBackend = undefined;
|
|
165
|
+
this.logger = undefined;
|
|
166
|
+
ServiceLocator.storageInstanceManager?.clearCache();
|
|
167
|
+
ServiceLocator.storageInstanceManager = undefined;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Used as the default service provider when crawlers don't specify custom services.
|
|
172
|
+
*/
|
|
173
|
+
const globalServiceLocator = new ServiceLocator();
|
|
174
|
+
const serviceLocatorStorage = new AsyncLocalStorage();
|
|
175
|
+
/**
|
|
176
|
+
* Wraps all methods on `target` so that any code they invoke will see the given
|
|
177
|
+
* `serviceLocator` via `AsyncLocalStorage`, rather than the global one.
|
|
178
|
+
*
|
|
179
|
+
* Walks the prototype chain and replaces each method on the *instance* (not the prototype)
|
|
180
|
+
* with a wrapper that calls `serviceLocatorStorage.run(serviceLocator, originalMethod)`.
|
|
181
|
+
*
|
|
182
|
+
* The `AsyncLocalStorage` context propagates through the entire sync/async call tree of each
|
|
183
|
+
* wrapped method — including `super` calls, since the prototype methods execute within the
|
|
184
|
+
* context established by the instance-level wrapper.
|
|
185
|
+
*
|
|
186
|
+
* @internal
|
|
187
|
+
* @returns Scope control functions: `run` executes a callback within the scoped context,
|
|
188
|
+
* `enterScope`/`exitScope` allow entering/leaving the scope imperatively (e.g., for constructor bodies).
|
|
189
|
+
*/
|
|
190
|
+
export function bindMethodsToServiceLocator(serviceLocator, target) {
|
|
191
|
+
let proto = Object.getPrototypeOf(target);
|
|
192
|
+
while (proto !== null && proto !== Object.prototype) {
|
|
193
|
+
const propertyKeys = [...Object.getOwnPropertyNames(proto), ...Object.getOwnPropertySymbols(proto)];
|
|
194
|
+
for (const propertyKey of propertyKeys) {
|
|
195
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
|
|
196
|
+
// We use property descriptors rather than accessing target[propertyKey] directly,
|
|
197
|
+
// because that would trigger getters and cause unwanted side effects.
|
|
198
|
+
// Skip getters, setters, and constructors — only wrap regular methods.
|
|
199
|
+
if (propertyKey === 'constructor' ||
|
|
200
|
+
!descriptor ||
|
|
201
|
+
descriptor.get ||
|
|
202
|
+
descriptor.set ||
|
|
203
|
+
typeof descriptor.value !== 'function')
|
|
204
|
+
continue;
|
|
205
|
+
const original = descriptor.value;
|
|
206
|
+
target[propertyKey] = (...args) => {
|
|
207
|
+
return serviceLocatorStorage.run(serviceLocator, () => {
|
|
208
|
+
return original.apply(target, args);
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
proto = Object.getPrototypeOf(proto);
|
|
213
|
+
}
|
|
214
|
+
let previousStore;
|
|
215
|
+
return {
|
|
216
|
+
run: (fn) => serviceLocatorStorage.run(serviceLocator, fn),
|
|
217
|
+
enterScope: () => {
|
|
218
|
+
previousStore = serviceLocatorStorage.getStore();
|
|
219
|
+
serviceLocatorStorage.enterWith(serviceLocator);
|
|
220
|
+
},
|
|
221
|
+
exitScope: () => {
|
|
222
|
+
serviceLocatorStorage.enterWith(previousStore); // casting to any so that `undefined` is accepted - this "unsets" the AsyncLocalStorage
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
export const serviceLocator = new Proxy({}, {
|
|
227
|
+
get(_target, prop) {
|
|
228
|
+
const active = serviceLocatorStorage.getStore() ?? globalServiceLocator;
|
|
229
|
+
const value = Reflect.get(active, prop, active);
|
|
230
|
+
if (typeof value === 'function') {
|
|
231
|
+
return value.bind(active);
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
},
|
|
235
|
+
set(_target, prop) {
|
|
236
|
+
throw new TypeError(`Cannot set property '${String(prop)}' on serviceLocator directly. Use the setter methods (e.g. setConfiguration(), setStorageBackend()) instead.`);
|
|
237
|
+
},
|
|
238
|
+
});
|
package/session_pool/consts.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
export declare const BLOCKED_STATUS_CODES: number[];
|
|
2
|
-
export declare const PERSIST_STATE_KEY = "
|
|
2
|
+
export declare const PERSIST_STATE_KEY = "CRAWLEE_SESSION_POOL_STATE";
|
|
3
3
|
export declare const MAX_POOL_SIZE = 1000;
|
|
4
|
-
//# sourceMappingURL=consts.d.ts.map
|
package/session_pool/consts.js
CHANGED
package/session_pool/errors.d.ts
CHANGED
package/session_pool/errors.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SessionFingerprint } from '@crawlee/types';
|
|
2
|
+
/**
|
|
3
|
+
* Build a {@link SessionFingerprint} whose `platform` matches the host OS
|
|
4
|
+
* and whose `browser`/`device` are randomized within the realistic profiles for
|
|
5
|
+
* that platform. Used by {@link SessionPool} as the default fingerprint for
|
|
6
|
+
* freshly created sessions; callers can override by passing their own
|
|
7
|
+
* `fingerprint` in `sessionOptions`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createDefaultSessionFingerprint(): SessionFingerprint;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (browser, platform, device) combinations that correspond to setups people
|
|
3
|
+
* actually run. Anything not listed here (e.g. `edge` on android, `safari` on
|
|
4
|
+
* windows, `desktop` mobile platforms) is left out so a randomized default
|
|
5
|
+
* never produces a fingerprint that would itself be a giveaway.
|
|
6
|
+
*/
|
|
7
|
+
const PROFILES_BY_PLATFORM = [
|
|
8
|
+
{ browser: 'chrome', platform: 'windows', device: 'desktop' },
|
|
9
|
+
{ browser: 'firefox', platform: 'windows', device: 'desktop' },
|
|
10
|
+
{ browser: 'edge', platform: 'windows', device: 'desktop' },
|
|
11
|
+
{ browser: 'chrome', platform: 'macos', device: 'desktop' },
|
|
12
|
+
{ browser: 'firefox', platform: 'macos', device: 'desktop' },
|
|
13
|
+
{ browser: 'safari', platform: 'macos', device: 'desktop' },
|
|
14
|
+
{ browser: 'edge', platform: 'macos', device: 'desktop' },
|
|
15
|
+
{ browser: 'chrome', platform: 'linux', device: 'desktop' },
|
|
16
|
+
{ browser: 'firefox', platform: 'linux', device: 'desktop' },
|
|
17
|
+
{ browser: 'chrome', platform: 'android', device: 'mobile' },
|
|
18
|
+
{ browser: 'firefox', platform: 'android', device: 'mobile' },
|
|
19
|
+
{ browser: 'safari', platform: 'ios', device: 'mobile' },
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Build a {@link SessionFingerprint} whose `platform` matches the host OS
|
|
23
|
+
* and whose `browser`/`device` are randomized within the realistic profiles for
|
|
24
|
+
* that platform. Used by {@link SessionPool} as the default fingerprint for
|
|
25
|
+
* freshly created sessions; callers can override by passing their own
|
|
26
|
+
* `fingerprint` in `sessionOptions`.
|
|
27
|
+
*/
|
|
28
|
+
export function createDefaultSessionFingerprint() {
|
|
29
|
+
return { ...PROFILES_BY_PLATFORM[Math.floor(Math.random() * PROFILES_BY_PLATFORM.length)] };
|
|
30
|
+
}
|
package/session_pool/index.d.ts
CHANGED
package/session_pool/index.js
CHANGED
|
@@ -1,23 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Cookie, SerializedCookieJar } from 'tough-cookie';
|
|
1
|
+
import type { Dictionary, ISession, ProxyInfo, SessionFingerprint, SessionState } from '@crawlee/types';
|
|
3
2
|
import { CookieJar } from 'tough-cookie';
|
|
4
|
-
import type {
|
|
5
|
-
import type { ResponseLike } from '../cookie_utils.js';
|
|
6
|
-
/**
|
|
7
|
-
* Persistable {@link Session} state.
|
|
8
|
-
*/
|
|
9
|
-
export interface SessionState {
|
|
10
|
-
id: string;
|
|
11
|
-
cookieJar: SerializedCookieJar;
|
|
12
|
-
userData: object;
|
|
13
|
-
errorScore: number;
|
|
14
|
-
maxErrorScore: number;
|
|
15
|
-
errorScoreDecrement: number;
|
|
16
|
-
usageCount: number;
|
|
17
|
-
maxUsageCount: number;
|
|
18
|
-
expiresAt: string;
|
|
19
|
-
createdAt: string;
|
|
20
|
-
}
|
|
3
|
+
import type { CrawleeLogger } from '../log.js';
|
|
21
4
|
export interface SessionOptions {
|
|
22
5
|
/** Id of session used for generating fingerprints. It is used as proxy session name. */
|
|
23
6
|
id?: string;
|
|
@@ -58,11 +41,22 @@ export interface SessionOptions {
|
|
|
58
41
|
* @default 50
|
|
59
42
|
*/
|
|
60
43
|
maxUsageCount?: number;
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Marks the session as already retired. Used when restoring a previously persisted session
|
|
46
|
+
* so that `isUsable()` reflects the terminal state regardless of error score or usage count.
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
retired?: boolean;
|
|
50
|
+
log?: CrawleeLogger;
|
|
64
51
|
errorScore?: number;
|
|
65
52
|
cookieJar?: CookieJar;
|
|
53
|
+
proxyInfo?: ProxyInfo;
|
|
54
|
+
/**
|
|
55
|
+
* Browser / HTTP client fingerprint tied to this session. Backends use this to make
|
|
56
|
+
* repeated requests with the same session look consistent (same user-agent, headers,
|
|
57
|
+
* TLS profile). See {@link SessionFingerprint}.
|
|
58
|
+
*/
|
|
59
|
+
fingerprint?: SessionFingerprint;
|
|
66
60
|
}
|
|
67
61
|
/**
|
|
68
62
|
* Sessions are used to store information such as cookies and can be used for generating fingerprints and proxy sessions.
|
|
@@ -70,9 +64,8 @@ export interface SessionOptions {
|
|
|
70
64
|
* Session internal state can be enriched with custom user data for example some authorization tokens and specific headers in general.
|
|
71
65
|
* @category Scaling
|
|
72
66
|
*/
|
|
73
|
-
export declare class Session {
|
|
67
|
+
export declare class Session implements ISession {
|
|
74
68
|
readonly id: string;
|
|
75
|
-
private maxAgeSecs;
|
|
76
69
|
userData: Dictionary;
|
|
77
70
|
private _maxErrorScore;
|
|
78
71
|
private _errorScoreDecrement;
|
|
@@ -80,9 +73,11 @@ export declare class Session {
|
|
|
80
73
|
private _expiresAt;
|
|
81
74
|
private _usageCount;
|
|
82
75
|
private _maxUsageCount;
|
|
83
|
-
private sessionPool;
|
|
84
76
|
private _errorScore;
|
|
77
|
+
private _retired;
|
|
78
|
+
private _proxyInfo?;
|
|
85
79
|
private _cookieJar;
|
|
80
|
+
private _fingerprint?;
|
|
86
81
|
private log;
|
|
87
82
|
get errorScore(): number;
|
|
88
83
|
get usageCount(): number;
|
|
@@ -92,10 +87,18 @@ export declare class Session {
|
|
|
92
87
|
get createdAt(): Date;
|
|
93
88
|
get maxUsageCount(): number;
|
|
94
89
|
get cookieJar(): CookieJar;
|
|
90
|
+
get proxyInfo(): ProxyInfo | undefined;
|
|
91
|
+
get fingerprint(): SessionFingerprint | undefined;
|
|
92
|
+
set fingerprint(fingerprint: SessionFingerprint | undefined);
|
|
93
|
+
/**
|
|
94
|
+
* `true` once {@link Session.retire|`retire()`} has been called. Retirement is terminal:
|
|
95
|
+
* a retired session is never picked by the pool and cannot be revived via `markGood()`.
|
|
96
|
+
*/
|
|
97
|
+
get retired(): boolean;
|
|
95
98
|
/**
|
|
96
99
|
* Session configuration.
|
|
97
100
|
*/
|
|
98
|
-
constructor(options
|
|
101
|
+
constructor(options?: SessionOptions);
|
|
99
102
|
/**
|
|
100
103
|
* Indicates whether the session is blocked.
|
|
101
104
|
* Session is blocked once it reaches the `maxErrorScore`.
|
|
@@ -114,7 +117,7 @@ export declare class Session {
|
|
|
114
117
|
isMaxUsageCountReached(): boolean;
|
|
115
118
|
/**
|
|
116
119
|
* Indicates whether the session can be used for next requests.
|
|
117
|
-
* Session is usable when it is not expired, not blocked and the maximum usage count has not be reached.
|
|
120
|
+
* Session is usable when it is not retired, not expired, not blocked and the maximum usage count has not be reached.
|
|
118
121
|
*/
|
|
119
122
|
isUsable(): boolean;
|
|
120
123
|
/**
|
|
@@ -128,11 +131,11 @@ export declare class Session {
|
|
|
128
131
|
*/
|
|
129
132
|
getState(): SessionState;
|
|
130
133
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
134
|
+
* Permanently retires the session — `isUsable()` will return `false` from here on,
|
|
135
|
+
* and no `markGood()` / `markBad()` can revive it. Calling `retire()` again is a no-op.
|
|
136
|
+
*
|
|
137
|
+
* Use this when you're confident the session itself is the problem (e.g. a `403` response).
|
|
138
|
+
* For transient external failures (such as `5XX` responses), use `markBad()` instead.
|
|
136
139
|
*/
|
|
137
140
|
retire(): void;
|
|
138
141
|
/**
|
|
@@ -140,42 +143,6 @@ export declare class Session {
|
|
|
140
143
|
* Should be used when the session has been used unsuccessfully. For example because of timeouts.
|
|
141
144
|
*/
|
|
142
145
|
markBad(): void;
|
|
143
|
-
/**
|
|
144
|
-
* With certain status codes: `401`, `403` or `429` we can be certain
|
|
145
|
-
* that the target website is blocking us. This function helps to do this conveniently
|
|
146
|
-
* by retiring the session when such code is received. Optionally, the default status
|
|
147
|
-
* codes can be extended in the second parameter.
|
|
148
|
-
* @param statusCode HTTP status code.
|
|
149
|
-
* @returns Whether the session was retired.
|
|
150
|
-
*/
|
|
151
|
-
retireOnBlockedStatusCodes(statusCode: number): boolean;
|
|
152
|
-
/**
|
|
153
|
-
* Saves cookies from an HTTP response to be used with the session.
|
|
154
|
-
* It expects an object with a `headers` property that's either an `Object`
|
|
155
|
-
* (typical Node.js responses) or a `Function` (Puppeteer Response).
|
|
156
|
-
*
|
|
157
|
-
* It then parses and saves the cookies from the `set-cookie` header, if available.
|
|
158
|
-
*/
|
|
159
|
-
setCookiesFromResponse(response: ResponseLike): void;
|
|
160
|
-
/**
|
|
161
|
-
* Saves an array with cookie objects to be used with the session.
|
|
162
|
-
* The objects should be in the format that
|
|
163
|
-
* [Puppeteer uses](https://pptr.dev/#?product=Puppeteer&version=v2.0.0&show=api-pagecookiesurls),
|
|
164
|
-
* but you can also use this function to set cookies manually:
|
|
165
|
-
*
|
|
166
|
-
* ```
|
|
167
|
-
* [
|
|
168
|
-
* { name: 'cookie1', value: 'my-cookie' },
|
|
169
|
-
* { name: 'cookie2', value: 'your-cookie' }
|
|
170
|
-
* ]
|
|
171
|
-
* ```
|
|
172
|
-
*/
|
|
173
|
-
setCookies(cookies: CookieObject[], url: string): void;
|
|
174
|
-
/**
|
|
175
|
-
* Returns cookies in a format compatible with puppeteer/playwright and ready to be used with `page.setCookie`.
|
|
176
|
-
* @param url website url. Only cookies stored for this url will be returned
|
|
177
|
-
*/
|
|
178
|
-
getCookies(url: string): CookieObject[];
|
|
179
146
|
/**
|
|
180
147
|
* Returns cookies saved with the session in the typical
|
|
181
148
|
* key1=value1; key2=value2 format, ready to be used in
|
|
@@ -187,13 +154,8 @@ export declare class Session {
|
|
|
187
154
|
* Sets a cookie within this session for the specific URL.
|
|
188
155
|
*/
|
|
189
156
|
setCookie(rawCookie: string, url: string): void;
|
|
190
|
-
/**
|
|
191
|
-
* Sets cookies.
|
|
192
|
-
*/
|
|
193
|
-
protected _setCookies(cookies: Cookie[], url: string): void;
|
|
194
157
|
/**
|
|
195
158
|
* Checks if session is not usable. if it is not retires the session.
|
|
196
159
|
*/
|
|
197
160
|
protected _maybeSelfRetire(): void;
|
|
198
161
|
}
|
|
199
|
-
//# sourceMappingURL=session.d.ts.map
|