@crawlee/core 4.0.0-beta.210 → 4.0.0-beta.212

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.
@@ -245,7 +245,7 @@ export class RequestList {
245
245
  * Loads all remote sources of URLs and potentially starts periodic state persistence.
246
246
  * This function must be called before you can start using the instance in a meaningful way.
247
247
  */
248
- async initialize() {
248
+ async #initialize() {
249
249
  if (this.#isLoading) {
250
250
  throw new Error('RequestList sources are already loading or were loaded.');
251
251
  }
@@ -253,17 +253,17 @@ export class RequestList {
253
253
  await purgeDefaultStorages({ onlyPurgeOnce: true });
254
254
  let persistedRequests;
255
255
  if (this.#persistRequestsKey) {
256
- persistedRequests = await this.getPersistedState(this.#persistRequestsKey);
256
+ persistedRequests = await this.#getPersistedState(this.#persistRequestsKey);
257
257
  if (persistedRequests)
258
258
  this.#log.debug('Loaded requests from key value store using the persistRequestsKey.');
259
259
  }
260
260
  // Add persisted requests / new sources in a memory efficient way because with very
261
261
  // large lists, we were running out of memory.
262
262
  if (persistedRequests) {
263
- await this.addPersistedRequests(persistedRequests);
263
+ await this.#addPersistedRequests(persistedRequests);
264
264
  }
265
265
  else {
266
- await this.addRequestsFromSources();
266
+ await this.#addRequestsFromSources();
267
267
  }
268
268
  // Restores the crawling position - the requests have to be loaded first, as the record is validated
269
269
  // against them. Also starts the periodic state persistence when `persistStateKey` is set.
@@ -272,7 +272,7 @@ export class RequestList {
272
272
  this.#requestsToRetry = [...this.inProgress];
273
273
  this.#isInitialized = true;
274
274
  if (this.#persistRequestsKey && !this.areRequestsPersisted)
275
- await this.persistRequests();
275
+ await this.#persistRequests();
276
276
  return this;
277
277
  }
278
278
  /**
@@ -280,7 +280,7 @@ export class RequestList {
280
280
  * This needs to be done in a memory efficient way. We should update the input
281
281
  * to a Stream once apify-client supports streams.
282
282
  */
283
- async addPersistedRequests(persistedRequests) {
283
+ async #addPersistedRequests(persistedRequests) {
284
284
  // We don't need the sources so we purge them to
285
285
  // prevent them from hanging in memory.
286
286
  for (let i = 0; i < this.#sources.length; i++) {
@@ -291,7 +291,7 @@ export class RequestList {
291
291
  this.areRequestsPersisted = true;
292
292
  const requestStream = createDeserialize(persistedRequests);
293
293
  for await (const request of requestStream) {
294
- this.addRequest(request);
294
+ this.#addRequest(request);
295
295
  }
296
296
  }
297
297
  /**
@@ -300,7 +300,7 @@ export class RequestList {
300
300
  * We need to avoid keeping both sources and requests in memory
301
301
  * to reduce memory footprint with very large sources.
302
302
  */
303
- async addRequestsFromSources() {
303
+ async #addRequestsFromSources() {
304
304
  // We'll load all sources in sequence to ensure that they get loaded in the right order.
305
305
  const sourcesCount = this.#sources.length;
306
306
  for (let i = 0; i < sourcesCount; i++) {
@@ -310,11 +310,11 @@ export class RequestList {
310
310
  // oxlint-disable-next-line typescript/no-array-delete
311
311
  delete this.#sources[i];
312
312
  if (typeof source === 'object' && source.requestsFromUrl) {
313
- const fetchedRequests = await this.fetchRequestsFromUrl(source);
314
- await this.addFetchedRequests(source, fetchedRequests);
313
+ const fetchedRequests = await this.#fetchRequestsFromUrl(source);
314
+ await this.#addFetchedRequests(source, fetchedRequests);
315
315
  }
316
316
  else {
317
- this.addRequest(source);
317
+ this.#addRequest(source);
318
318
  }
319
319
  }
320
320
  // Drop the original array full of empty indexes.
@@ -327,7 +327,7 @@ export class RequestList {
327
327
  const source = sourcesFromFunction[i];
328
328
  // oxlint-disable-next-line typescript/no-array-delete -- intentional, drop the slot so V8 can collect the object
329
329
  delete sourcesFromFunction[i];
330
- this.addRequest(source);
330
+ this.#addRequest(source);
331
331
  }
332
332
  sourcesFromFunction.length = 0;
333
333
  }
@@ -365,7 +365,7 @@ export class RequestList {
365
365
  * are automatically persisted at RequestList initialization (if the persistRequestsKey is set),
366
366
  * but there's no reason to persist it again afterwards, because RequestList is immutable.
367
367
  */
368
- async persistRequests() {
368
+ async #persistRequests() {
369
369
  const serializedRequests = await serializeArray(this.requests);
370
370
  this.#store ??= await KeyValueStore.open();
371
371
  await this.#store.setValue(this.#persistRequestsKey, serializedRequests, { contentType: CONTENT_TYPE_BINARY });
@@ -376,14 +376,14 @@ export class RequestList {
376
376
  * Note that the object's fields can change in future releases.
377
377
  */
378
378
  getState() {
379
- this.ensureIsInitialized();
379
+ this.#ensureIsInitialized();
380
380
  return this.#stateCodec.encode(this.#state.currentValue);
381
381
  }
382
382
  /**
383
383
  * @inheritDoc
384
384
  */
385
385
  async checkReadiness() {
386
- this.ensureIsInitialized();
386
+ this.#ensureIsInitialized();
387
387
  if (this.#requestsToRetry.length > 0 || this.#state.currentValue.nextIndex < this.requests.length) {
388
388
  return { status: 'ready' };
389
389
  }
@@ -394,12 +394,12 @@ export class RequestList {
394
394
  * @inheritDoc
395
395
  */
396
396
  async fetchNextRequest() {
397
- this.ensureIsInitialized();
397
+ this.#ensureIsInitialized();
398
398
  // First re-serve any requests that were interrupted before the last state persist.
399
399
  const uniqueKey = this.#requestsToRetry.shift();
400
400
  if (uniqueKey) {
401
401
  const index = this.#uniqueKeyToIndex[uniqueKey];
402
- return this.ensureRequest(this.requests[index], index);
402
+ return this.#ensureRequest(this.requests[index], index);
403
403
  }
404
404
  // Otherwise return next request.
405
405
  const state = this.#state.currentValue;
@@ -408,7 +408,7 @@ export class RequestList {
408
408
  const request = this.requests[index];
409
409
  state.inProgress.add(request.uniqueKey);
410
410
  state.nextIndex++;
411
- return this.ensureRequest(request, index);
411
+ return this.#ensureRequest(request, index);
412
412
  }
413
413
  return null;
414
414
  }
@@ -423,7 +423,7 @@ export class RequestList {
423
423
  yield req;
424
424
  }
425
425
  }
426
- ensureRequest(requestLike, index) {
426
+ #ensureRequest(requestLike, index) {
427
427
  if (requestLike instanceof Request) {
428
428
  return requestLike;
429
429
  }
@@ -435,18 +435,18 @@ export class RequestList {
435
435
  */
436
436
  async markRequestAsHandled(request) {
437
437
  const { uniqueKey } = request;
438
- this.ensureUniqueKeyValid(uniqueKey);
439
- this.ensureInProgress(uniqueKey);
440
- this.ensureIsInitialized();
438
+ this.#ensureUniqueKeyValid(uniqueKey);
439
+ this.#ensureInProgress(uniqueKey);
440
+ this.#ensureIsInitialized();
441
441
  this.inProgress.delete(uniqueKey);
442
442
  }
443
443
  /**
444
444
  * Adds all fetched requests from a URL from a remote resource.
445
445
  */
446
- async addFetchedRequests(source, fetchedRequests) {
446
+ async #addFetchedRequests(source, fetchedRequests) {
447
447
  const { requestsFromUrl, regex } = source;
448
448
  const originalLength = this.requests.length;
449
- fetchedRequests.forEach((request) => this.addRequest(request));
449
+ fetchedRequests.forEach((request) => this.#addRequest(request));
450
450
  const fetchedCount = fetchedRequests.length;
451
451
  const importedCount = this.requests.length - originalLength;
452
452
  this.#log.info('Fetched and loaded Requests from a remote resource.', {
@@ -458,7 +458,7 @@ export class RequestList {
458
458
  sample: JSON.stringify(fetchedRequests.slice(0, 5)),
459
459
  });
460
460
  }
461
- async getPersistedState(key) {
461
+ async #getPersistedState(key) {
462
462
  this.#store ??= await KeyValueStore.open();
463
463
  const state = await this.#store.getValue(key);
464
464
  return state;
@@ -466,12 +466,12 @@ export class RequestList {
466
466
  /**
467
467
  * Fetches URLs from requestsFromUrl and returns them in format of list of requests
468
468
  */
469
- async fetchRequestsFromUrl(source) {
469
+ async #fetchRequestsFromUrl(source) {
470
470
  const { requestsFromUrl, regex, ...sharedOpts } = source;
471
471
  // Download remote resource and parse URLs.
472
472
  let urlsArr;
473
473
  try {
474
- urlsArr = await this.downloadListOfUrls({
474
+ urlsArr = await this.#downloadListOfUrls({
475
475
  url: requestsFromUrl,
476
476
  urlRegExp: regex,
477
477
  proxyUrl: (await this.#proxyConfiguration?.newProxyInfo())?.url,
@@ -492,7 +492,7 @@ export class RequestList {
492
492
  * If the `source` parameter is a string or plain object and not an instance
493
493
  * of a `Request`, then the function creates a `Request` instance.
494
494
  */
495
- addRequest(source) {
495
+ #addRequest(source) {
496
496
  let request;
497
497
  const type = typeof source;
498
498
  if (type === 'string') {
@@ -514,7 +514,7 @@ export class RequestList {
514
514
  request.uniqueKey += `-${this.requests.length}`;
515
515
  }
516
516
  const { uniqueKey } = request;
517
- this.ensureUniqueKeyValid(uniqueKey);
517
+ this.#ensureUniqueKeyValid(uniqueKey);
518
518
  // Skip requests with duplicate uniqueKey
519
519
  if (!Object.hasOwn(this.#uniqueKeyToIndex, uniqueKey)) {
520
520
  this.#uniqueKeyToIndex[uniqueKey] = this.requests.length;
@@ -528,7 +528,7 @@ export class RequestList {
528
528
  * Helper function that validates unique key.
529
529
  * Throws an error if uniqueKey is not a non-empty string.
530
530
  */
531
- ensureUniqueKeyValid(uniqueKey) {
531
+ #ensureUniqueKeyValid(uniqueKey) {
532
532
  if (typeof uniqueKey !== 'string' || !uniqueKey) {
533
533
  throw new Error("Request object's uniqueKey must be a non-empty string");
534
534
  }
@@ -536,7 +536,7 @@ export class RequestList {
536
536
  /**
537
537
  * Checks that a request is currently being processed and throws an error if not.
538
538
  */
539
- ensureInProgress(uniqueKey) {
539
+ #ensureInProgress(uniqueKey) {
540
540
  if (!this.inProgress.has(uniqueKey)) {
541
541
  throw new Error(`The request is not being processed (uniqueKey: ${uniqueKey})`);
542
542
  }
@@ -544,7 +544,7 @@ export class RequestList {
544
544
  /**
545
545
  * Throws an error if request list wasn't initialized.
546
546
  */
547
- ensureIsInitialized() {
547
+ #ensureIsInitialized() {
548
548
  if (!this.#isInitialized) {
549
549
  throw new Error('RequestList is not initialized; you must call "await requestList.initialize()" before using it!');
550
550
  }
@@ -553,14 +553,14 @@ export class RequestList {
553
553
  * Returns the total number of unique requests present in the `RequestList`.
554
554
  */
555
555
  async getTotalCount() {
556
- this.ensureIsInitialized();
556
+ this.#ensureIsInitialized();
557
557
  return this.requests.length;
558
558
  }
559
559
  /**
560
560
  * Returns the number of pending requests in the `RequestList`.
561
561
  */
562
562
  async getPendingCount() {
563
- this.ensureIsInitialized();
563
+ this.#ensureIsInitialized();
564
564
  return this.requests.length - (this.#state.currentValue.nextIndex - this.inProgress.size);
565
565
  }
566
566
  /**
@@ -578,7 +578,7 @@ export class RequestList {
578
578
  * @inheritDoc
579
579
  */
580
580
  async getHandledCount() {
581
- this.ensureIsInitialized();
581
+ this.#ensureIsInitialized();
582
582
  return this.#state.currentValue.nextIndex - this.inProgress.size;
583
583
  }
584
584
  /**
@@ -638,7 +638,7 @@ export class RequestList {
638
638
  if (listNameOrOptions != null && typeof listNameOrOptions === 'object') {
639
639
  options = { ...listNameOrOptions, ...options };
640
640
  const rl = new RequestList(options);
641
- await rl.initialize();
641
+ await rl.#initialize();
642
642
  return rl;
643
643
  }
644
644
  const listName = listNameOrOptions;
@@ -651,13 +651,13 @@ export class RequestList {
651
651
  persistRequestsKey: listName ? `${listName}-${REQUESTS_PERSISTENCE_KEY}` : options.persistRequestsKey,
652
652
  sources: sources ?? options.sources,
653
653
  });
654
- await rl.initialize();
654
+ await rl.#initialize();
655
655
  return rl;
656
656
  }
657
657
  /**
658
658
  * @internal wraps public utility for mocking purposes
659
659
  */
660
- async downloadListOfUrls(options) {
660
+ async #downloadListOfUrls(options) {
661
661
  return downloadListOfUrls({
662
662
  ...options,
663
663
  httpClient: this.#httpClient,
@@ -17,18 +17,6 @@ export declare class RequestManagerTandem implements IRequestManager {
17
17
  * (e.g. a lazily-opened default {@link RequestQueue}).
18
18
  */
19
19
  constructor(requestLoader: IRequestLoader, requestManager: IRequestManager | (() => IRequestManager | Promise<IRequestManager>));
20
- /**
21
- * Resolves the writable request manager, opening it lazily (via the factory) on first use and memoizing the result.
22
- */
23
- private getRequestManager;
24
- /**
25
- * Transfers a single request from the read-only loader to the writable manager.
26
- * If the transfer fails, the request is dropped (and logged) rather than reclaimed.
27
- *
28
- * @returns `true` if a request was successfully transferred (or there was nothing to transfer), and `false` if a
29
- * transfer was attempted but failed - in which case the caller should not fetch from the manager this round.
30
- */
31
- private transferNextRequestToQueue;
32
20
  /**
33
21
  * Fetches the next request, transferring one from the loader first if the loader still has work.
34
22
  * @inheritdoc
@@ -37,7 +37,7 @@ export class RequestManagerTandem {
37
37
  /**
38
38
  * Resolves the writable request manager, opening it lazily (via the factory) on first use and memoizing the result.
39
39
  */
40
- async getRequestManager() {
40
+ async #getRequestManager() {
41
41
  if (this.#resolvedRequestManager === undefined) {
42
42
  this.#requestManagerPromise ??= Promise.resolve(this.#requestManagerFactory());
43
43
  this.#resolvedRequestManager = await this.#requestManagerPromise;
@@ -55,12 +55,12 @@ export class RequestManagerTandem {
55
55
  * @returns `true` if a request was successfully transferred (or there was nothing to transfer), and `false` if a
56
56
  * transfer was attempted but failed - in which case the caller should not fetch from the manager this round.
57
57
  */
58
- async transferNextRequestToQueue() {
58
+ async #transferNextRequestToQueue() {
59
59
  const request = await this.#requestLoader.fetchNextRequest();
60
60
  if (request === null) {
61
61
  return true;
62
62
  }
63
- const requestManager = await this.getRequestManager();
63
+ const requestManager = await this.#getRequestManager();
64
64
  try {
65
65
  await requestManager.addRequest(request, { forefront: true });
66
66
  return true;
@@ -84,19 +84,19 @@ export class RequestManagerTandem {
84
84
  if ((await this.#requestLoader.checkReadiness()).status === 'ready') {
85
85
  // If the transfer failed, the request was dropped; don't fetch from the manager this round (matching
86
86
  // crawlee-python behaviour). The next `fetchNextRequest()` call will pick up where we left off.
87
- if (!(await this.transferNextRequestToQueue())) {
87
+ if (!(await this.#transferNextRequestToQueue())) {
88
88
  return null;
89
89
  }
90
90
  }
91
91
  // Try to fetch from manager after the transfer
92
- return (await this.getRequestManager()).fetchNextRequest();
92
+ return (await this.#getRequestManager()).fetchNextRequest();
93
93
  }
94
94
  /**
95
95
  * The loader and the manager read as one source.
96
96
  * @inheritdoc
97
97
  */
98
98
  async checkReadiness() {
99
- const requestManager = await this.getRequestManager();
99
+ const requestManager = await this.#getRequestManager();
100
100
  const [loaderStatus, managerStatus] = await Promise.all([
101
101
  this.#requestLoader.checkReadiness(),
102
102
  requestManager.checkReadiness(),
@@ -108,13 +108,13 @@ export class RequestManagerTandem {
108
108
  */
109
109
  async getHandledCount() {
110
110
  // Since one of the stores needs to have priority when both are present, we query the request manager - the request loader will first be dumped into the manager and then left empty.
111
- return (await this.getRequestManager()).getHandledCount();
111
+ return (await this.#getRequestManager()).getHandledCount();
112
112
  }
113
113
  /**
114
114
  * @inheritdoc
115
115
  */
116
116
  async getTotalCount() {
117
- const requestManager = await this.getRequestManager();
117
+ const requestManager = await this.#getRequestManager();
118
118
  const [managerTotal, loaderTotal] = await Promise.all([
119
119
  requestManager.getTotalCount(),
120
120
  // count only pending to avoid double counting, requests marked as "handled" have been moved to requestManager
@@ -126,7 +126,7 @@ export class RequestManagerTandem {
126
126
  * @inheritdoc
127
127
  */
128
128
  async getPendingCount() {
129
- const requestManager = await this.getRequestManager();
129
+ const requestManager = await this.#getRequestManager();
130
130
  const [managerPending, loaderPending] = await Promise.all([
131
131
  requestManager.getPendingCount(),
132
132
  this.#requestLoader.getPendingCount(),
@@ -148,25 +148,25 @@ export class RequestManagerTandem {
148
148
  * @inheritdoc
149
149
  */
150
150
  async markRequestAsHandled(request) {
151
- return (await this.getRequestManager()).markRequestAsHandled(request);
151
+ return (await this.#getRequestManager()).markRequestAsHandled(request);
152
152
  }
153
153
  /**
154
154
  * @inheritdoc
155
155
  */
156
156
  async reclaimRequest(request, options) {
157
- return (await this.getRequestManager()).reclaimRequest(request, options);
157
+ return (await this.#getRequestManager()).reclaimRequest(request, options);
158
158
  }
159
159
  /**
160
160
  * @inheritdoc
161
161
  */
162
162
  async addRequest(requestLike, options) {
163
- return (await this.getRequestManager()).addRequest(requestLike, options);
163
+ return (await this.#getRequestManager()).addRequest(requestLike, options);
164
164
  }
165
165
  /**
166
166
  * @inheritdoc
167
167
  */
168
168
  async addRequestsBatched(requests, options) {
169
- return (await this.getRequestManager()).addRequestsBatched(requests, options);
169
+ return (await this.#getRequestManager()).addRequestsBatched(requests, options);
170
170
  }
171
171
  /**
172
172
  * Purges the writable request manager so the tandem can be reused (e.g. across repeated `crawler.run()` calls).
@@ -174,7 +174,7 @@ export class RequestManagerTandem {
174
174
  * @inheritdoc
175
175
  */
176
176
  async purge() {
177
- await (await this.getRequestManager()).purge?.();
177
+ await (await this.#getRequestManager()).purge?.();
178
178
  }
179
179
  /**
180
180
  * Forwards the hint to the writable request manager — that is where requests are fetched from and
@@ -195,6 +195,6 @@ export class RequestManagerTandem {
195
195
  return this.#resolvedRequestManager?.recordPacingSignal(signal) ?? false;
196
196
  }
197
197
  async extendRequestProcessingTimeSecs(request, secs) {
198
- return (await this.getRequestManager()).extendRequestProcessingTimeSecs?.(request, secs) ?? false;
198
+ return (await this.#getRequestManager()).extendRequestProcessingTimeSecs?.(request, secs) ?? false;
199
199
  }
200
200
  }
@@ -86,22 +86,6 @@ export declare class RequestQueue implements IStorage, IRequestManager {
86
86
  * @param [options] Request queue operation options.
87
87
  */
88
88
  addRequest(requestLike: Source, options?: RequestQueueOperationOptions): Promise<RequestQueueOperationInfo>;
89
- /**
90
- * Journals an addition for introspection only; these entries are never replayed. A no-op unless the
91
- * transaction is open, so detached and outliving writers stay out of the journal.
92
- */
93
- private recordRequestJournalEntry;
94
- /**
95
- * The requests buffered by the given transaction for this queue, keyed by `uniqueKey` — a dedup
96
- * index derived from the transaction journal.
97
- */
98
- private bufferedRequests;
99
- /**
100
- * Adds a request under the `deferred` policy: journaled now, really added by the commit replay.
101
- * A new request's `requestId` is the local `uniqueKey` hash and is **provisional** — never write it
102
- * to `request.id` or the dedup caches. Dedup is cheapest-first: buffer, caches, then a backend probe.
103
- */
104
- private addRequestDeferred;
105
89
  /** @internal */
106
90
  commitJournalEntries(entries: JournalEntry[]): Promise<void>;
107
91
  /**
@@ -201,10 +185,6 @@ export declare class RequestQueue implements IStorage, IRequestManager {
201
185
  * this only touches the one request it is given.
202
186
  */
203
187
  extendRequestProcessingTimeSecs(request: Request, secs: number): Promise<boolean>;
204
- /**
205
- * Caches information about request to beware of unneeded addRequest() calls.
206
- */
207
- private cacheRequest;
208
188
  /**
209
189
  * Removes the queue either from the Apify Cloud storage or from the local database,
210
190
  * depending on the mode of operation.
@@ -250,18 +230,6 @@ export declare class RequestQueue implements IStorage, IRequestManager {
250
230
  * @throws If the underlying storage no longer exists (e.g. it was deleted externally).
251
231
  */
252
232
  getInfo(): Promise<RequestQueueInfo>;
253
- /**
254
- * Fetches URLs from requestsFromUrl and returns them in format of list of requests
255
- */
256
- private fetchRequestsFromUrl;
257
- /**
258
- * Adds all fetched requests from a URL from a remote resource.
259
- */
260
- private addFetchedRequests;
261
- /**
262
- * @internal wraps public utility for mocking purposes
263
- */
264
- private downloadListOfUrls;
265
233
  /**
266
234
  * Opens a request queue and returns a promise resolving to an instance
267
235
  * of the {@link RequestQueue} class.