@crawlee/core 4.0.0-beta.105 → 4.0.0-beta.106

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.
Files changed (75) hide show
  1. package/autoscaling/autoscaled_pool.d.ts +3 -21
  2. package/autoscaling/autoscaled_pool.js +85 -85
  3. package/autoscaling/client_load_signal.d.ts +1 -5
  4. package/autoscaling/client_load_signal.js +20 -20
  5. package/autoscaling/concurrency_system.d.ts +5 -20
  6. package/autoscaling/concurrency_system.js +81 -80
  7. package/autoscaling/cpu_load_signal.d.ts +1 -2
  8. package/autoscaling/cpu_load_signal.js +10 -10
  9. package/autoscaling/event_loop_load_signal.d.ts +1 -4
  10. package/autoscaling/event_loop_load_signal.js +18 -18
  11. package/autoscaling/load_signal.d.ts +1 -1
  12. package/autoscaling/load_signal.js +12 -11
  13. package/autoscaling/memory_load_signal.d.ts +3 -12
  14. package/autoscaling/memory_load_signal.js +40 -41
  15. package/autoscaling/snapshotter.d.ts +1 -4
  16. package/autoscaling/snapshotter.js +12 -12
  17. package/autoscaling/system_status.d.ts +1 -3
  18. package/autoscaling/system_status.js +11 -11
  19. package/configuration.d.ts +1 -1
  20. package/configuration.js +3 -3
  21. package/crawlers/context_pipeline.js +6 -6
  22. package/crawlers/statistics.d.ts +1 -8
  23. package/crawlers/statistics.js +45 -44
  24. package/events/event_manager.d.ts +1 -1
  25. package/events/event_manager.js +3 -3
  26. package/events/local_event_manager.d.ts +1 -1
  27. package/events/local_event_manager.js +3 -3
  28. package/log.js +5 -1
  29. package/memory-storage/memory-storage.d.ts +1 -5
  30. package/memory-storage/memory-storage.js +2 -2
  31. package/memory-storage/resource-clients/dataset.d.ts +1 -1
  32. package/memory-storage/resource-clients/dataset.js +6 -5
  33. package/memory-storage/resource-clients/key-value-store.d.ts +1 -1
  34. package/memory-storage/resource-clients/key-value-store.js +13 -12
  35. package/memory-storage/resource-clients/request-queue.d.ts +4 -23
  36. package/memory-storage/resource-clients/request-queue.js +59 -58
  37. package/owned_or_injected.d.ts +1 -3
  38. package/owned_or_injected.js +17 -17
  39. package/package.json +5 -5
  40. package/proxy_configuration.d.ts +1 -3
  41. package/proxy_configuration.js +8 -8
  42. package/recoverable_state.d.ts +1 -10
  43. package/recoverable_state.js +41 -41
  44. package/request.d.ts +1 -2
  45. package/request.js +10 -13
  46. package/router.d.ts +1 -4
  47. package/router.js +23 -23
  48. package/serialization.js +8 -9
  49. package/service_locator.d.ts +1 -10
  50. package/service_locator.js +48 -48
  51. package/session_pool/session.d.ts +1 -12
  52. package/session_pool/session.js +50 -50
  53. package/session_pool/session_pool.d.ts +2 -11
  54. package/session_pool/session_pool.js +59 -58
  55. package/storages/dataset.d.ts +1 -1
  56. package/storages/dataset.js +5 -5
  57. package/storages/key_value_store.d.ts +1 -4
  58. package/storages/key_value_store.js +21 -20
  59. package/storages/request_dedup_cache.d.ts +1 -2
  60. package/storages/request_dedup_cache.js +9 -9
  61. package/storages/request_list.d.ts +2 -22
  62. package/storages/request_list.js +74 -73
  63. package/storages/request_manager_tandem.d.ts +1 -10
  64. package/storages/request_manager_tandem.js +27 -27
  65. package/storages/request_queue.d.ts +2 -18
  66. package/storages/request_queue.js +37 -35
  67. package/storages/sitemap_request_loader.d.ts +1 -44
  68. package/storages/sitemap_request_loader.js +87 -87
  69. package/storages/storage_instance_manager.d.ts +1 -2
  70. package/storages/storage_instance_manager.js +17 -17
  71. package/storages/storage_stats.d.ts +1 -1
  72. package/storages/storage_stats.js +4 -4
  73. package/storages/transaction.d.ts +1 -3
  74. package/storages/transaction.js +17 -17
  75. package/system-info/runtime.js +7 -7
@@ -60,24 +60,25 @@ const SESSION_REUSE_STRATEGIES = ['random', 'round-robin', 'use-until-failure'];
60
60
  * @category Scaling
61
61
  */
62
62
  export class SessionPool {
63
- static nextId = 0;
63
+ static #nextId = 0;
64
64
  id;
65
- log;
65
+ #log;
66
+ #sessions = [];
67
+ // kept as TS-private: session_pool tests read/override the members below directly
66
68
  maxPoolSize;
67
69
  createSessionFunction;
68
70
  keyValueStore;
69
- sessions = [];
70
71
  sessionMap = new Map();
71
72
  sessionOptions;
72
73
  persistStateKeyValueStoreId;
73
74
  persistStateKey;
74
- listener;
75
- events;
76
- persistenceOptions;
77
- sessionReuseStrategy;
78
- initPromise;
79
- queue = new AsyncQueue();
80
- roundRobinIndex = 0;
75
+ #listener;
76
+ #events;
77
+ #persistenceOptions;
78
+ #sessionReuseStrategy;
79
+ #initPromise;
80
+ #queue = new AsyncQueue();
81
+ #roundRobinIndex = 0;
81
82
  constructor(options = {}) {
82
83
  ow(options, ow.object.exactShape({
83
84
  id: ow.optional.any(ow.number, ow.string),
@@ -93,20 +94,20 @@ export class SessionPool {
93
94
  const { id, maxPoolSize = MAX_POOL_SIZE, persistStateKeyValueStoreId, persistStateKey, createSessionFunction, sessionOptions = {}, log = serviceLocator.getLogger(), persistenceOptions = {
94
95
  enable: true,
95
96
  }, sessionReuseStrategy = 'random', } = options;
96
- this.id = id != null ? String(id) : String(SessionPool.nextId++);
97
- this.sessionReuseStrategy = sessionReuseStrategy;
98
- this.events = serviceLocator.getEventManager();
99
- this.log = log.child({ prefix: 'SessionPool' });
100
- this.persistenceOptions = persistenceOptions;
97
+ this.id = id != null ? String(id) : String(SessionPool.#nextId++);
98
+ this.#sessionReuseStrategy = sessionReuseStrategy;
99
+ this.#events = serviceLocator.getEventManager();
100
+ this.#log = log.child({ prefix: 'SessionPool' });
101
+ this.#persistenceOptions = persistenceOptions;
101
102
  // Pool Configuration
102
103
  this.maxPoolSize = maxPoolSize;
103
104
  this.createSessionFunction = createSessionFunction || this.defaultCreateSessionFunction;
104
105
  // Session configuration. The pool-scoped logger is merged into per-call sessionOptions inside
105
- // `_invokeCreateSessionFunction`, so every Session inherits it without custom createSessionFunctions
106
+ // `invokeCreateSessionFunction`, so every Session inherits it without custom createSessionFunctions
106
107
  // having to know about it.
107
108
  this.sessionOptions = {
108
109
  ...sessionOptions,
109
- log: this.log,
110
+ log: this.#log,
110
111
  };
111
112
  // Session keyValueStore
112
113
  this.persistStateKeyValueStoreId = persistStateKeyValueStoreId;
@@ -117,39 +118,39 @@ export class SessionPool {
117
118
  */
118
119
  async usableSessionsCount() {
119
120
  await this.ensureInitialized();
120
- return this.sessions.filter((session) => session.isUsable()).length;
121
+ return this.#sessions.filter((session) => session.isUsable()).length;
121
122
  }
122
123
  /**
123
124
  * Gets count of retired sessions in the pool.
124
125
  */
125
126
  async retiredSessionsCount() {
126
127
  await this.ensureInitialized();
127
- return this.sessions.filter((session) => !session.isUsable()).length;
128
+ return this.#sessions.filter((session) => !session.isUsable()).length;
128
129
  }
129
130
  /**
130
131
  * Starts periodic state persistence and potentially loads SessionPool state from {@link KeyValueStore}.
131
132
  * Called automatically on first use of any public method.
132
133
  */
133
134
  async ensureInitialized() {
134
- if (!this.initPromise) {
135
- this.initPromise = this.setupPool();
135
+ if (!this.#initPromise) {
136
+ this.#initPromise = this.setupPool();
136
137
  }
137
- return this.initPromise;
138
+ return this.#initPromise;
138
139
  }
139
140
  async setupPool() {
140
- if (!this.persistenceOptions.enable) {
141
+ if (!this.#persistenceOptions.enable) {
141
142
  return;
142
143
  }
143
144
  this.keyValueStore = await KeyValueStore.open(this.persistStateKeyValueStoreId ? { id: this.persistStateKeyValueStoreId } : null, {
144
145
  configuration: serviceLocator.getConfiguration(),
145
146
  });
146
147
  if (!this.persistStateKeyValueStoreId) {
147
- this.log.debug(`No 'persistStateKeyValueStoreId' options specified, this session pool's data has been saved in the KeyValueStore with the id: ${this.keyValueStore.id}`);
148
+ this.#log.debug(`No 'persistStateKeyValueStoreId' options specified, this session pool's data has been saved in the KeyValueStore with the id: ${this.keyValueStore.id}`);
148
149
  }
149
150
  // in case of migration happened and SessionPool state should be restored from the keyValueStore.
150
151
  await this.maybeLoadSessionPool();
151
- this.listener = this.persistState.bind(this);
152
- this.events.on("persistState" /* EventType.PERSIST_STATE */, this.listener);
152
+ this.#listener = this.persistState.bind(this);
153
+ this.#events.on("persistState" /* EventType.PERSIST_STATE */, this.#listener);
153
154
  }
154
155
  /**
155
156
  * Adds a new session to the session pool. The pool automatically creates sessions up to the maximum size of the pool,
@@ -169,8 +170,8 @@ export class SessionPool {
169
170
  if (!this.hasSpaceForSession()) {
170
171
  this.removeRetiredSessions();
171
172
  }
172
- const newSession = options instanceof Session ? options : await this._invokeCreateSessionFunction(options);
173
- this.log.debug(`Adding new Session - ${newSession.id}`);
173
+ const newSession = options instanceof Session ? options : await this.invokeCreateSessionFunction(options);
174
+ this.#log.debug(`Adding new Session - ${newSession.id}`);
174
175
  this.registerSession(newSession);
175
176
  }
176
177
  /**
@@ -181,7 +182,7 @@ export class SessionPool {
181
182
  */
182
183
  async newSession(sessionOptions) {
183
184
  await this.ensureInitialized();
184
- const newSession = await this._invokeCreateSessionFunction(sessionOptions);
185
+ const newSession = await this.invokeCreateSessionFunction(sessionOptions);
185
186
  this.registerSession(newSession);
186
187
  return newSession;
187
188
  }
@@ -194,7 +195,7 @@ export class SessionPool {
194
195
  */
195
196
  async getSession(sessionId) {
196
197
  await this.ensureInitialized();
197
- await this.queue.wait();
198
+ await this.#queue.wait();
198
199
  try {
199
200
  if (sessionId) {
200
201
  const session = this.sessionMap.get(sessionId);
@@ -212,14 +213,14 @@ export class SessionPool {
212
213
  return await this.createSession();
213
214
  }
214
215
  finally {
215
- this.queue.shift();
216
+ this.#queue.shift();
216
217
  }
217
218
  }
218
219
  /**
219
220
  * @param options - Override the persistence options provided in the constructor
220
221
  */
221
222
  async resetStore(options) {
222
- if (!this.persistenceOptions.enable && !options?.enable) {
223
+ if (!this.#persistenceOptions.enable && !options?.enable) {
223
224
  return;
224
225
  }
225
226
  await this.ensureInitialized();
@@ -234,7 +235,7 @@ export class SessionPool {
234
235
  return {
235
236
  usableSessionsCount: await this.usableSessionsCount(),
236
237
  retiredSessionsCount: await this.retiredSessionsCount(),
237
- sessions: this.sessions.map((session) => session.getState()),
238
+ sessions: this.#sessions.map((session) => session.getState()),
238
239
  };
239
240
  }
240
241
  /**
@@ -243,28 +244,28 @@ export class SessionPool {
243
244
  * @param options - Override the persistence options provided in the constructor
244
245
  */
245
246
  async persistState(options) {
246
- if (!this.persistenceOptions.enable && !options?.enable) {
247
+ if (!this.#persistenceOptions.enable && !options?.enable) {
247
248
  return;
248
249
  }
249
250
  await this.ensureInitialized();
250
- this.log.debug('Persisting state', {
251
+ this.#log.debug('Persisting state', {
251
252
  persistStateKeyValueStoreId: this.persistStateKeyValueStoreId,
252
253
  persistStateKey: this.persistStateKey,
253
254
  });
254
255
  await this.keyValueStore
255
256
  ?.setValue(this.persistStateKey, await this.getState())
256
- .catch((error) => this.log.warning(`Failed to persist the session pool stats to ${this.persistStateKey}`, { error }));
257
+ .catch((error) => this.#log.warning(`Failed to persist the session pool stats to ${this.persistStateKey}`, { error }));
257
258
  }
258
259
  /**
259
260
  * Removes listener from `persistState` event.
260
261
  * This function should be called after you are done with using the `SessionPool` instance.
261
262
  */
262
263
  async teardown() {
263
- if (!this.initPromise)
264
+ if (!this.#initPromise)
264
265
  return;
265
266
  await this.ensureInitialized();
266
- if (this.listener) {
267
- this.events.off("persistState" /* EventType.PERSIST_STATE */, this.listener);
267
+ if (this.#listener) {
268
+ this.#events.off("persistState" /* EventType.PERSIST_STATE */, this.#listener);
268
269
  }
269
270
  await this.persistState();
270
271
  }
@@ -272,11 +273,11 @@ export class SessionPool {
272
273
  * Removes retired `Session` instances from `SessionPool`.
273
274
  */
274
275
  removeRetiredSessions() {
275
- this.sessions = this.sessions.filter((storedSession) => {
276
+ this.#sessions = this.#sessions.filter((storedSession) => {
276
277
  if (storedSession.isUsable())
277
278
  return true;
278
279
  this.sessionMap.delete(storedSession.id);
279
- this.log.debug(`Removed Session - ${storedSession.id}`);
280
+ this.#log.debug(`Removed Session - ${storedSession.id}`);
280
281
  return false;
281
282
  });
282
283
  }
@@ -285,14 +286,14 @@ export class SessionPool {
285
286
  * @param newSession `Session` instance to be added.
286
287
  */
287
288
  registerSession(newSession) {
288
- this.sessions.push(newSession);
289
+ this.#sessions.push(newSession);
289
290
  this.sessionMap.set(newSession.id, newSession);
290
291
  }
291
292
  /**
292
293
  * Gets random index.
293
294
  */
294
295
  getRandomIndex() {
295
- return Math.floor(Math.random() * this.sessions.length);
296
+ return Math.floor(Math.random() * this.#sessions.length);
296
297
  }
297
298
  /**
298
299
  * Creates new session without any extra behavior.
@@ -315,7 +316,7 @@ export class SessionPool {
315
316
  * through `maybeLoadSessionPool` naturally wins because it arrives in
316
317
  * `perCallOptions`.
317
318
  */
318
- async _invokeCreateSessionFunction(perCallOptions) {
319
+ async invokeCreateSessionFunction(perCallOptions) {
319
320
  const sessionOptions = {
320
321
  fingerprint: createDefaultSessionFingerprint(),
321
322
  ...this.sessionOptions,
@@ -328,35 +329,35 @@ export class SessionPool {
328
329
  * @returns Newly created `Session` instance.
329
330
  */
330
331
  async createSession() {
331
- const newSession = await this._invokeCreateSessionFunction();
332
+ const newSession = await this.invokeCreateSessionFunction();
332
333
  this.registerSession(newSession);
333
- this.log.debug(`Created new Session - ${newSession.id}`);
334
+ this.#log.debug(`Created new Session - ${newSession.id}`);
334
335
  return newSession;
335
336
  }
336
337
  /**
337
338
  * Decides whether there is enough space for creating new session.
338
339
  */
339
340
  hasSpaceForSession() {
340
- return this.sessions.length < this.maxPoolSize;
341
+ return this.#sessions.length < this.maxPoolSize;
341
342
  }
342
343
  /**
343
344
  * Picks a session from the `SessionPool` according to the configured `sessionReuseStrategy`.
344
345
  * Returns `undefined` when no session should be reused and a new one should be created instead.
345
346
  */
346
347
  pickSession() {
347
- if (this.sessionReuseStrategy !== 'use-until-failure' && this.hasSpaceForSession())
348
+ if (this.#sessionReuseStrategy !== 'use-until-failure' && this.hasSpaceForSession())
348
349
  return undefined;
349
- if (this.sessionReuseStrategy === 'use-until-failure') {
350
- return this.sessions.find((session) => session.isUsable());
350
+ if (this.#sessionReuseStrategy === 'use-until-failure') {
351
+ return this.#sessions.find((session) => session.isUsable());
351
352
  }
352
353
  let picked;
353
- if (this.sessionReuseStrategy === 'round-robin') {
354
- const index = this.roundRobinIndex % this.sessions.length;
355
- this.roundRobinIndex = index + 1;
356
- picked = this.sessions[index];
354
+ if (this.#sessionReuseStrategy === 'round-robin') {
355
+ const index = this.#roundRobinIndex % this.#sessions.length;
356
+ this.#roundRobinIndex = index + 1;
357
+ picked = this.#sessions[index];
357
358
  }
358
359
  else {
359
- picked = this.sessions[this.getRandomIndex()];
360
+ picked = this.#sessions[this.getRandomIndex()];
360
361
  }
361
362
  return picked.isUsable() ? picked : undefined;
362
363
  }
@@ -369,18 +370,18 @@ export class SessionPool {
369
370
  if (!loadedSessionPool)
370
371
  return;
371
372
  // Invalidate old sessions and load active sessions only
372
- this.log.debug('Recreating state from KeyValueStore', {
373
+ this.#log.debug('Recreating state from KeyValueStore', {
373
374
  persistStateKeyValueStoreId: this.persistStateKeyValueStoreId,
374
375
  persistStateKey: this.persistStateKey,
375
376
  });
376
377
  for (const sessionObject of loadedSessionPool.sessions) {
377
378
  sessionObject.createdAt = new Date(sessionObject.createdAt);
378
379
  sessionObject.expiresAt = new Date(sessionObject.expiresAt);
379
- const recreatedSession = await this._invokeCreateSessionFunction(sessionObject);
380
+ const recreatedSession = await this.invokeCreateSessionFunction(sessionObject);
380
381
  if (recreatedSession.isUsable()) {
381
382
  this.registerSession(recreatedSession);
382
383
  }
383
384
  }
384
- this.log.debug(`${this.sessions.length} active sessions loaded from KeyValueStore`);
385
+ this.#log.debug(`${this.#sessions.length} active sessions loaded from KeyValueStore`);
385
386
  }
386
387
  }
@@ -140,12 +140,12 @@ export interface DatasetExportToOptions extends DatasetExportOptions {
140
140
  * @category Result Stores
141
141
  */
142
142
  export declare class Dataset<Data extends Dictionary = Dictionary> {
143
+ #private;
143
144
  readonly configuration: Configuration;
144
145
  id: string;
145
146
  name?: string;
146
147
  backend: DatasetBackend<Data>;
147
148
  log: CrawleeLogger;
148
- private readonly statsTracker;
149
149
  /**
150
150
  * @internal
151
151
  */
@@ -89,7 +89,7 @@ export class Dataset {
89
89
  name;
90
90
  backend;
91
91
  log;
92
- statsTracker = new StorageStatsTracker({
92
+ #statsTracker = new StorageStatsTracker({
93
93
  readCount: 0,
94
94
  writeCount: 0,
95
95
  });
@@ -108,7 +108,7 @@ export class Dataset {
108
108
  * the underlying storage backend). Counted per backend call.
109
109
  */
110
110
  get stats() {
111
- return this.statsTracker.current;
111
+ return this.#statsTracker.current;
112
112
  }
113
113
  /**
114
114
  * Stores an object or an array of objects to the dataset.
@@ -140,7 +140,7 @@ export class Dataset {
140
140
  });
141
141
  return;
142
142
  }
143
- this.statsTracker.add('writeCount');
143
+ this.#statsTracker.add('writeCount');
144
144
  await this.backend.pushData(items);
145
145
  }
146
146
  /**
@@ -166,7 +166,7 @@ export class Dataset {
166
166
  async readPage(options) {
167
167
  const buffered = this.bufferedJournalEntries()?.flatMap((entry) => entry.items);
168
168
  // Every branch below hits the backend exactly once.
169
- this.statsTracker.add('readCount');
169
+ this.#statsTracker.add('readCount');
170
170
  if (!buffered?.length) {
171
171
  return this.backend.getData(options);
172
172
  }
@@ -235,7 +235,7 @@ export class Dataset {
235
235
  // One backend call with all journaled items, in order - as close to atomic as the backend allows.
236
236
  // Straight to the backend: the items were validated and snapshotted at write time.
237
237
  if (items.length > 0) {
238
- this.statsTracker.add('writeCount');
238
+ this.#statsTracker.add('writeCount');
239
239
  await this.backend.pushData(items);
240
240
  }
241
241
  }
@@ -61,14 +61,11 @@ import type { StorageIdentifier } from './storage_instance_manager.js';
61
61
  * @category Result Stores
62
62
  */
63
63
  export declare class KeyValueStore {
64
+ #private;
64
65
  readonly configuration: Configuration;
65
66
  readonly id: string;
66
67
  readonly name?: string;
67
68
  private readonly backend;
68
- private persistStateEventStarted;
69
- /** Cache for persistent (auto-saved) values. When we try to set such value, the cache will be updated automatically. */
70
- private readonly cache;
71
- private readonly statsTracker;
72
69
  /**
73
70
  * @internal
74
71
  */
@@ -71,11 +71,12 @@ export class KeyValueStore {
71
71
  configuration;
72
72
  id;
73
73
  name;
74
+ // kept as TS-private: key_value_store tests spy on the backend directly
74
75
  backend;
75
- persistStateEventStarted = false;
76
+ #persistStateEventStarted = false;
76
77
  /** Cache for persistent (auto-saved) values. When we try to set such value, the cache will be updated automatically. */
77
- cache = new Map();
78
- statsTracker = new StorageStatsTracker({
78
+ #cache = new Map();
79
+ #statsTracker = new StorageStatsTracker({
79
80
  readCount: 0,
80
81
  writeCount: 0,
81
82
  deleteCount: 0,
@@ -95,7 +96,7 @@ export class KeyValueStore {
95
96
  * list operations issued to the underlying storage backend). Counted per backend call.
96
97
  */
97
98
  get stats() {
98
- return this.statsTracker.current;
99
+ return this.#statsTracker.current;
99
100
  }
100
101
  /**
101
102
  * Gets a value from the key-value store.
@@ -178,7 +179,7 @@ export class KeyValueStore {
178
179
  contentType: serialized.contentType ?? null,
179
180
  };
180
181
  }
181
- this.statsTracker.add('readCount');
182
+ this.#statsTracker.add('readCount');
182
183
  const record = await this.backend.getValue(key);
183
184
  if (!record)
184
185
  return null;
@@ -235,8 +236,8 @@ export class KeyValueStore {
235
236
  }
236
237
  async getAutoSavedValue(key, defaultValue = {}) {
237
238
  tryCancel();
238
- if (this.cache.has(key)) {
239
- return this.cache.get(key);
239
+ if (this.#cache.has(key)) {
240
+ return this.#cache.get(key);
240
241
  }
241
242
  // Auto-saved state is deliberately *not* transactional. The direct read bypasses any active
242
243
  // transaction - a buffered value seeded into this shared cache would survive a rollback forever.
@@ -245,25 +246,25 @@ export class KeyValueStore {
245
246
  // the value will in cache at this point, and returning the new fetched value would introduce two different instances of
246
247
  // the auto-saved object, and only the latter one would be persisted.
247
248
  // Therefore we re-check the cache here, and if such race condition happened, we drop the fetched value and return the cached one.
248
- if (this.cache.has(key)) {
249
- return this.cache.get(key);
249
+ if (this.#cache.has(key)) {
250
+ return this.#cache.get(key);
250
251
  }
251
- this.cache.set(key, value);
252
+ this.#cache.set(key, value);
252
253
  this.ensurePersistStateEvent();
253
254
  return value;
254
255
  }
255
256
  ensurePersistStateEvent() {
256
- if (this.persistStateEventStarted) {
257
+ if (this.#persistStateEventStarted) {
257
258
  return;
258
259
  }
259
260
  serviceLocator.getEventManager().on('persistState', async () => {
260
261
  const promises = [];
261
- for (const [key, value] of this.cache) {
262
+ for (const [key, value] of this.#cache) {
262
263
  promises.push(this.setValue(key, value).catch((error) => serviceLocator.getLogger().warning(`Failed to persist the state value to ${key}`, { error })));
263
264
  }
264
265
  await Promise.all(promises);
265
266
  });
266
- this.persistStateEventStarted = true;
267
+ this.#persistStateEventStarted = true;
267
268
  }
268
269
  async *fetchKeyValuePages(options, mapRecord) {
269
270
  // Reduce the journal once for the whole iteration, not once per key inside `readRecord`.
@@ -303,7 +304,7 @@ export class KeyValueStore {
303
304
  }
304
305
  let exclusiveStartKey;
305
306
  while (true) {
306
- this.statsTracker.add('listCount');
307
+ this.#statsTracker.add('listCount');
307
308
  const { items, isTruncated, nextExclusiveStartKey } = await this.backend.listKeys({
308
309
  ...options,
309
310
  exclusiveStartKey,
@@ -401,28 +402,28 @@ export class KeyValueStore {
401
402
  return;
402
403
  }
403
404
  // If we try to set the value of a cached state to a different reference, we need to update the cache accordingly.
404
- const cachedValue = this.cache.get(key);
405
+ const cachedValue = this.#cache.get(key);
405
406
  if (cachedValue && cachedValue !== value) {
406
407
  if (value === null) {
407
408
  // Cached state can be only object, so a propagation of `null` means removing all its properties.
408
- Object.keys(cachedValue).forEach((k) => this.cache.delete(k));
409
+ Object.keys(cachedValue).forEach((k) => this.#cache.delete(k));
409
410
  }
410
411
  else if (typeof value === 'object') {
411
412
  // We need to remove the keys that are no longer present in the new value.
412
413
  Object.keys(cachedValue)
413
414
  .filter((k) => !(k in value))
414
- .forEach((k) => this.cache.delete(k));
415
+ .forEach((k) => this.#cache.delete(k));
415
416
  // And update the existing ones + add new ones.
416
417
  Object.assign(cachedValue, value);
417
418
  }
418
419
  }
419
420
  // In this case delete the record.
420
421
  if (value === null) {
421
- this.statsTracker.add('deleteCount');
422
+ this.#statsTracker.add('deleteCount');
422
423
  return this.backend.deleteValue(key);
423
424
  }
424
425
  const serialized = serializeValue(value, optionsCopy.contentType);
425
- this.statsTracker.add('writeCount');
426
+ this.#statsTracker.add('writeCount');
426
427
  return this.backend.setValue({
427
428
  key,
428
429
  value: serialized.value,
@@ -454,7 +455,7 @@ export class KeyValueStore {
454
455
  /** @internal */
455
456
  clearCache() {
456
457
  rejectOperationInTransaction('KeyValueStore.clearCache()');
457
- this.cache.clear();
458
+ this.#cache.clear();
458
459
  }
459
460
  /**
460
461
  * Iterates over key-value store keys, yielding each in turn to an `iteratee` function.
@@ -12,9 +12,8 @@
12
12
  * @internal
13
13
  */
14
14
  export declare class RequestDeduplicationCache {
15
+ #private;
15
16
  private readonly size;
16
- private keys;
17
- private ids;
18
17
  constructor(size?: number);
19
18
  get(cacheKey: string): string | null;
20
19
  add(cacheKey: string, requestId: string): void;
@@ -13,26 +13,26 @@
13
13
  */
14
14
  export class RequestDeduplicationCache {
15
15
  size;
16
- keys;
17
- ids;
16
+ #keys;
17
+ #ids;
18
18
  // The slot count is the same for every queue, so it's a fixed default rather than a per-consumer option.
19
19
  constructor(size = 1_000_000) {
20
20
  this.size = size;
21
- this.keys = new Array(size);
22
- this.ids = new Array(size);
21
+ this.#keys = new Array(size);
22
+ this.#ids = new Array(size);
23
23
  }
24
24
  get(cacheKey) {
25
25
  const index = this.indexOf(cacheKey);
26
- return this.keys[index] === cacheKey ? this.ids[index] : null;
26
+ return this.#keys[index] === cacheKey ? this.#ids[index] : null;
27
27
  }
28
28
  add(cacheKey, requestId) {
29
29
  const index = this.indexOf(cacheKey);
30
- this.keys[index] = cacheKey;
31
- this.ids[index] = requestId;
30
+ this.#keys[index] = cacheKey;
31
+ this.#ids[index] = requestId;
32
32
  }
33
33
  clear() {
34
- this.keys = new Array(this.size);
35
- this.ids = new Array(this.size);
34
+ this.#keys = new Array(this.size);
35
+ this.#ids = new Array(this.size);
36
36
  }
37
37
  // A cheap FNV-1a hash of the cache key — avoids pulling in a dedicated hashing dependency.
38
38
  indexOf(cacheKey) {
@@ -216,28 +216,18 @@ export interface RequestListOptions {
216
216
  * @category Sources
217
217
  */
218
218
  export declare class RequestList implements IRequestLoader {
219
- private log;
219
+ #private;
220
220
  /**
221
221
  * Array of all requests from all sources, in the order as they appeared in sources.
222
222
  * All requests in the array have distinct uniqueKey!
223
223
  * @internal
224
224
  */
225
225
  readonly requests: (Request | RequestOptions)[];
226
- /** Index to the next item in requests array to fetch. All previous requests are either handled or in progress. */
227
- private nextIndex;
228
- /** Dictionary, key is Request.uniqueKey, value is corresponding index in the requests array. */
229
- private uniqueKeyToIndex;
230
226
  /**
231
227
  * Set of `uniqueKey`s of requests that were returned by fetchNextRequest().
232
228
  * @internal
233
229
  */
234
230
  inProgress: Set<string>;
235
- /**
236
- * `uniqueKey`s of requests that were in progress when the state was last persisted and thus need to be
237
- * re-crawled after a restart. They are served before advancing through the rest of the sources.
238
- * @internal
239
- */
240
- private requestsToRetry;
241
231
  /**
242
232
  * Starts as true because until we handle the first request, the list is effectively persisted by doing nothing.
243
233
  * @internal
@@ -248,17 +238,7 @@ export declare class RequestList implements IRequestLoader {
248
238
  * @internal
249
239
  */
250
240
  areRequestsPersisted: boolean;
251
- private isLoading;
252
- private isInitialized;
253
- private persistStateKey?;
254
- private persistRequestsKey?;
255
- private initialState?;
256
- private store?;
257
- private keepDuplicateUrls;
258
241
  private sources;
259
- private sourcesFunction?;
260
- private proxyConfiguration?;
261
- private httpClient?;
262
242
  /**
263
243
  * To create new instance of `RequestList` we need to use `RequestList.open()` factory method.
264
244
  * @param options All `RequestList` configuration options
@@ -437,7 +417,7 @@ export declare class RequestList implements IRequestLoader {
437
417
  /**
438
418
  * @internal wraps public utility for mocking purposes
439
419
  */
440
- private _downloadListOfUrls;
420
+ private downloadListOfUrls;
441
421
  }
442
422
  /**
443
423
  * Represents state of a {@link RequestList}. It can be used to resume a {@link RequestList} which has been previously processed.