@crawlee/core 4.0.0-beta.13 → 4.0.0-beta.130

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 (280) hide show
  1. package/README.md +17 -13
  2. package/autoscaling/autoscaled_pool.d.ts +67 -172
  3. package/autoscaling/autoscaled_pool.js +182 -329
  4. package/autoscaling/concurrency_system.d.ts +268 -0
  5. package/autoscaling/concurrency_system.js +362 -0
  6. package/autoscaling/cpu_load_signal.d.ts +43 -0
  7. package/autoscaling/cpu_load_signal.js +47 -0
  8. package/autoscaling/event_loop_load_signal.d.ts +51 -0
  9. package/autoscaling/event_loop_load_signal.js +60 -0
  10. package/autoscaling/index.d.ts +6 -1
  11. package/autoscaling/index.js +6 -1
  12. package/autoscaling/load_signal.d.ts +100 -0
  13. package/autoscaling/load_signal.js +105 -0
  14. package/autoscaling/memory_load_signal.d.ts +47 -0
  15. package/autoscaling/memory_load_signal.js +106 -0
  16. package/autoscaling/snapshotter.d.ts +58 -163
  17. package/autoscaling/snapshotter.js +45 -263
  18. package/autoscaling/storage_backend_load_signal.d.ts +56 -0
  19. package/autoscaling/storage_backend_load_signal.js +73 -0
  20. package/autoscaling/system_status.d.ts +67 -89
  21. package/autoscaling/system_status.js +92 -122
  22. package/autoscaling/weighted_avg.d.ts +5 -0
  23. package/autoscaling/weighted_avg.js +14 -0
  24. package/byte_utils.d.ts +17 -0
  25. package/byte_utils.js +42 -0
  26. package/configuration.d.ts +96 -223
  27. package/configuration.js +170 -222
  28. package/cookie_utils.d.ts +3 -2
  29. package/cookie_utils.js +18 -7
  30. package/crawlers/context_pipeline.d.ts +10 -1
  31. package/crawlers/context_pipeline.js +31 -8
  32. package/crawlers/crawler_commons.d.ts +90 -129
  33. package/crawlers/crawler_commons.js +1 -116
  34. package/crawlers/error_snapshotter.d.ts +2 -5
  35. package/crawlers/error_snapshotter.js +7 -8
  36. package/crawlers/error_tracker.d.ts +0 -1
  37. package/crawlers/error_tracker.js +0 -1
  38. package/crawlers/index.d.ts +1 -3
  39. package/crawlers/index.js +0 -3
  40. package/crawlers/internals/types.d.ts +0 -1
  41. package/crawlers/internals/types.js +0 -1
  42. package/crawlers/statistics.d.ts +187 -63
  43. package/crawlers/statistics.js +354 -164
  44. package/debug.d.ts +36 -0
  45. package/debug.js +70 -0
  46. package/enqueue_links/enqueue_links.d.ts +68 -154
  47. package/enqueue_links/enqueue_links.js +38 -210
  48. package/enqueue_links/index.d.ts +0 -1
  49. package/enqueue_links/index.js +0 -1
  50. package/enqueue_links/shared.d.ts +52 -26
  51. package/enqueue_links/shared.js +115 -66
  52. package/errors.d.ts +72 -4
  53. package/errors.js +89 -5
  54. package/events/event_manager.d.ts +35 -9
  55. package/events/event_manager.js +12 -13
  56. package/events/index.d.ts +0 -1
  57. package/events/index.js +0 -1
  58. package/events/local_event_manager.d.ts +15 -3
  59. package/events/local_event_manager.js +39 -13
  60. package/http.d.ts +9 -0
  61. package/http.js +28 -0
  62. package/index.d.ts +7 -4
  63. package/index.js +6 -3
  64. package/iterables.d.ts +79 -0
  65. package/iterables.js +134 -0
  66. package/log.d.ts +82 -3
  67. package/log.js +106 -1
  68. package/memory-storage/consts.d.ts +4 -0
  69. package/memory-storage/consts.js +4 -0
  70. package/memory-storage/index.d.ts +1 -0
  71. package/memory-storage/index.js +1 -0
  72. package/memory-storage/memory-storage.d.ts +38 -0
  73. package/memory-storage/memory-storage.js +130 -0
  74. package/memory-storage/resource-clients/common/base-client.d.ts +4 -0
  75. package/memory-storage/resource-clients/common/base-client.js +6 -0
  76. package/memory-storage/resource-clients/dataset.d.ts +40 -0
  77. package/memory-storage/resource-clients/dataset.js +108 -0
  78. package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
  79. package/memory-storage/resource-clients/key-value-store.js +201 -0
  80. package/memory-storage/resource-clients/request-queue.d.ts +77 -0
  81. package/memory-storage/resource-clients/request-queue.js +409 -0
  82. package/memory-storage/utils.d.ts +16 -0
  83. package/memory-storage/utils.js +41 -0
  84. package/owned_or_injected.d.ts +58 -0
  85. package/owned_or_injected.js +98 -0
  86. package/package.json +14 -13
  87. package/proxy_configuration.d.ts +24 -132
  88. package/proxy_configuration.js +32 -147
  89. package/recoverable_state.d.ts +155 -0
  90. package/recoverable_state.js +231 -0
  91. package/request.d.ts +80 -16
  92. package/request.js +147 -68
  93. package/router.d.ts +193 -21
  94. package/router.js +188 -43
  95. package/serialization.d.ts +0 -1
  96. package/serialization.js +15 -15
  97. package/service_locator.d.ts +165 -0
  98. package/service_locator.js +253 -0
  99. package/session_pool/consts.d.ts +1 -2
  100. package/session_pool/consts.js +1 -2
  101. package/session_pool/errors.d.ts +0 -1
  102. package/session_pool/errors.js +0 -1
  103. package/session_pool/fingerprint.d.ts +9 -0
  104. package/session_pool/fingerprint.js +30 -0
  105. package/session_pool/index.d.ts +0 -2
  106. package/session_pool/index.js +0 -2
  107. package/session_pool/session.d.ts +35 -88
  108. package/session_pool/session.js +101 -159
  109. package/session_pool/session_pool.d.ts +73 -91
  110. package/session_pool/session_pool.js +172 -165
  111. package/storages/batched_adds.d.ts +37 -0
  112. package/storages/batched_adds.js +73 -0
  113. package/storages/dataset.d.ts +114 -54
  114. package/storages/dataset.js +291 -148
  115. package/storages/index.d.ts +10 -8
  116. package/storages/index.js +8 -8
  117. package/storages/key_value_store.d.ts +185 -42
  118. package/storages/key_value_store.js +445 -169
  119. package/storages/key_value_store_codec.d.ts +32 -0
  120. package/storages/key_value_store_codec.js +113 -0
  121. package/storages/request_dedup_cache.d.ts +22 -0
  122. package/storages/request_dedup_cache.js +48 -0
  123. package/storages/request_list.d.ts +52 -115
  124. package/storages/request_list.js +183 -152
  125. package/storages/request_loader.d.ts +101 -0
  126. package/storages/request_loader.js +1 -0
  127. package/storages/request_manager.d.ts +33 -0
  128. package/storages/request_manager.js +1 -0
  129. package/storages/request_manager_tandem.d.ts +97 -0
  130. package/storages/request_manager_tandem.js +197 -0
  131. package/storages/request_queue.d.ts +290 -47
  132. package/storages/request_queue.js +762 -216
  133. package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +45 -89
  134. package/storages/sitemap_request_loader.js +438 -0
  135. package/storages/storage_instance_manager.d.ts +87 -0
  136. package/storages/storage_instance_manager.js +256 -0
  137. package/storages/storage_stats.d.ts +48 -0
  138. package/storages/storage_stats.js +29 -0
  139. package/storages/throttling_request_manager.d.ts +239 -0
  140. package/storages/throttling_request_manager.js +646 -0
  141. package/storages/transaction.d.ts +252 -0
  142. package/storages/transaction.js +251 -0
  143. package/storages/utils.d.ts +59 -11
  144. package/storages/utils.js +75 -15
  145. package/system-info/cpu-info.d.ts +67 -0
  146. package/system-info/cpu-info.js +216 -0
  147. package/system-info/memory-info.d.ts +31 -0
  148. package/system-info/memory-info.js +115 -0
  149. package/system-info/ps-tree.d.ts +17 -0
  150. package/system-info/ps-tree.js +144 -0
  151. package/system-info/runtime.d.ts +14 -0
  152. package/system-info/runtime.js +80 -0
  153. package/typedefs.d.ts +0 -6
  154. package/typedefs.js +0 -1
  155. package/url.d.ts +9 -0
  156. package/url.js +11 -0
  157. package/validators.d.ts +22 -18
  158. package/validators.js +13 -18
  159. package/autoscaling/autoscaled_pool.d.ts.map +0 -1
  160. package/autoscaling/autoscaled_pool.js.map +0 -1
  161. package/autoscaling/index.d.ts.map +0 -1
  162. package/autoscaling/index.js.map +0 -1
  163. package/autoscaling/snapshotter.d.ts.map +0 -1
  164. package/autoscaling/snapshotter.js.map +0 -1
  165. package/autoscaling/system_status.d.ts.map +0 -1
  166. package/autoscaling/system_status.js.map +0 -1
  167. package/configuration.d.ts.map +0 -1
  168. package/configuration.js.map +0 -1
  169. package/cookie_utils.d.ts.map +0 -1
  170. package/cookie_utils.js.map +0 -1
  171. package/crawlers/context_pipeline.d.ts.map +0 -1
  172. package/crawlers/context_pipeline.js.map +0 -1
  173. package/crawlers/crawler_commons.d.ts.map +0 -1
  174. package/crawlers/crawler_commons.js.map +0 -1
  175. package/crawlers/crawler_utils.d.ts +0 -10
  176. package/crawlers/crawler_utils.d.ts.map +0 -1
  177. package/crawlers/crawler_utils.js +0 -12
  178. package/crawlers/crawler_utils.js.map +0 -1
  179. package/crawlers/error_snapshotter.d.ts.map +0 -1
  180. package/crawlers/error_snapshotter.js.map +0 -1
  181. package/crawlers/error_tracker.d.ts.map +0 -1
  182. package/crawlers/error_tracker.js.map +0 -1
  183. package/crawlers/index.d.ts.map +0 -1
  184. package/crawlers/index.js.map +0 -1
  185. package/crawlers/internals/types.d.ts.map +0 -1
  186. package/crawlers/internals/types.js.map +0 -1
  187. package/crawlers/statistics.d.ts.map +0 -1
  188. package/crawlers/statistics.js.map +0 -1
  189. package/enqueue_links/enqueue_links.d.ts.map +0 -1
  190. package/enqueue_links/enqueue_links.js.map +0 -1
  191. package/enqueue_links/index.d.ts.map +0 -1
  192. package/enqueue_links/index.js.map +0 -1
  193. package/enqueue_links/shared.d.ts.map +0 -1
  194. package/enqueue_links/shared.js.map +0 -1
  195. package/errors.d.ts.map +0 -1
  196. package/errors.js.map +0 -1
  197. package/events/event_manager.d.ts.map +0 -1
  198. package/events/event_manager.js.map +0 -1
  199. package/events/index.d.ts.map +0 -1
  200. package/events/index.js.map +0 -1
  201. package/events/local_event_manager.d.ts.map +0 -1
  202. package/events/local_event_manager.js.map +0 -1
  203. package/http_clients/base-http-client.d.ts +0 -140
  204. package/http_clients/base-http-client.d.ts.map +0 -1
  205. package/http_clients/base-http-client.js +0 -40
  206. package/http_clients/base-http-client.js.map +0 -1
  207. package/http_clients/form-data-like.d.ts +0 -67
  208. package/http_clients/form-data-like.d.ts.map +0 -1
  209. package/http_clients/form-data-like.js +0 -5
  210. package/http_clients/form-data-like.js.map +0 -1
  211. package/http_clients/got-scraping-http-client.d.ts +0 -20
  212. package/http_clients/got-scraping-http-client.d.ts.map +0 -1
  213. package/http_clients/got-scraping-http-client.js +0 -82
  214. package/http_clients/got-scraping-http-client.js.map +0 -1
  215. package/http_clients/index.d.ts +0 -3
  216. package/http_clients/index.d.ts.map +0 -1
  217. package/http_clients/index.js +0 -3
  218. package/http_clients/index.js.map +0 -1
  219. package/index.d.ts.map +0 -1
  220. package/index.js.map +0 -1
  221. package/log.d.ts.map +0 -1
  222. package/log.js.map +0 -1
  223. package/proxy_configuration.d.ts.map +0 -1
  224. package/proxy_configuration.js.map +0 -1
  225. package/request.d.ts.map +0 -1
  226. package/request.js.map +0 -1
  227. package/router.d.ts.map +0 -1
  228. package/router.js.map +0 -1
  229. package/serialization.d.ts.map +0 -1
  230. package/serialization.js.map +0 -1
  231. package/session_pool/consts.d.ts.map +0 -1
  232. package/session_pool/consts.js.map +0 -1
  233. package/session_pool/errors.d.ts.map +0 -1
  234. package/session_pool/errors.js.map +0 -1
  235. package/session_pool/events.d.ts +0 -3
  236. package/session_pool/events.d.ts.map +0 -1
  237. package/session_pool/events.js +0 -3
  238. package/session_pool/events.js.map +0 -1
  239. package/session_pool/index.d.ts.map +0 -1
  240. package/session_pool/index.js.map +0 -1
  241. package/session_pool/session.d.ts.map +0 -1
  242. package/session_pool/session.js.map +0 -1
  243. package/session_pool/session_pool.d.ts.map +0 -1
  244. package/session_pool/session_pool.js.map +0 -1
  245. package/storages/access_checking.d.ts +0 -13
  246. package/storages/access_checking.d.ts.map +0 -1
  247. package/storages/access_checking.js +0 -14
  248. package/storages/access_checking.js.map +0 -1
  249. package/storages/dataset.d.ts.map +0 -1
  250. package/storages/dataset.js.map +0 -1
  251. package/storages/index.d.ts.map +0 -1
  252. package/storages/index.js.map +0 -1
  253. package/storages/key_value_store.d.ts.map +0 -1
  254. package/storages/key_value_store.js.map +0 -1
  255. package/storages/request_list.d.ts.map +0 -1
  256. package/storages/request_list.js.map +0 -1
  257. package/storages/request_provider.d.ts +0 -308
  258. package/storages/request_provider.d.ts.map +0 -1
  259. package/storages/request_provider.js +0 -555
  260. package/storages/request_provider.js.map +0 -1
  261. package/storages/request_queue.d.ts.map +0 -1
  262. package/storages/request_queue.js.map +0 -1
  263. package/storages/request_queue_v2.d.ts +0 -87
  264. package/storages/request_queue_v2.d.ts.map +0 -1
  265. package/storages/request_queue_v2.js +0 -438
  266. package/storages/request_queue_v2.js.map +0 -1
  267. package/storages/sitemap_request_list.d.ts.map +0 -1
  268. package/storages/sitemap_request_list.js +0 -430
  269. package/storages/sitemap_request_list.js.map +0 -1
  270. package/storages/storage_manager.d.ts +0 -58
  271. package/storages/storage_manager.d.ts.map +0 -1
  272. package/storages/storage_manager.js +0 -105
  273. package/storages/storage_manager.js.map +0 -1
  274. package/storages/utils.d.ts.map +0 -1
  275. package/storages/utils.js.map +0 -1
  276. package/tsconfig.build.tsbuildinfo +0 -1
  277. package/typedefs.d.ts.map +0 -1
  278. package/typedefs.js.map +0 -1
  279. package/validators.d.ts.map +0 -1
  280. package/validators.js.map +0 -1
@@ -1,24 +1,6 @@
1
- import type { Cookie as CookieObject, Dictionary } from '@crawlee/types';
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 { Log } from '@apify/log';
5
- import type { ProxyInfo } from '../proxy_configuration.js';
6
- /**
7
- * Persistable {@link Session} state.
8
- */
9
- export interface SessionState {
10
- id: string;
11
- cookieJar: SerializedCookieJar;
12
- proxyInfo?: ProxyInfo;
13
- userData: object;
14
- errorScore: number;
15
- maxErrorScore: number;
16
- errorScoreDecrement: number;
17
- usageCount: number;
18
- maxUsageCount: number;
19
- expiresAt: string;
20
- createdAt: string;
21
- }
3
+ import type { CrawleeLogger } from '../log.js';
22
4
  export interface SessionOptions {
23
5
  /** Id of session used for generating fingerprints. It is used as proxy session name. */
24
6
  id?: string;
@@ -59,12 +41,22 @@ export interface SessionOptions {
59
41
  * @default 50
60
42
  */
61
43
  maxUsageCount?: number;
62
- /** SessionPool instance. Session will emit the `sessionRetired` event on this instance. */
63
- sessionPool?: import('./session_pool.js').SessionPool;
64
- log?: Log;
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;
65
51
  errorScore?: number;
66
52
  cookieJar?: CookieJar;
67
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;
68
60
  }
69
61
  /**
70
62
  * Sessions are used to store information such as cookies and can be used for generating fingerprints and proxy sessions.
@@ -72,21 +64,10 @@ export interface SessionOptions {
72
64
  * Session internal state can be enriched with custom user data for example some authorization tokens and specific headers in general.
73
65
  * @category Scaling
74
66
  */
75
- export declare class Session {
67
+ export declare class Session implements ISession {
68
+ #private;
76
69
  readonly id: string;
77
- private maxAgeSecs;
78
- userData: Dictionary;
79
- private _maxErrorScore;
80
- private _errorScoreDecrement;
81
- private _createdAt;
82
- private _expiresAt;
83
- private _usageCount;
84
- private _maxUsageCount;
85
- private sessionPool;
86
- private _errorScore;
87
- private _proxyInfo?;
88
- private _cookieJar;
89
- private log;
70
+ readonly userData: Dictionary;
90
71
  get errorScore(): number;
91
72
  get usageCount(): number;
92
73
  get maxErrorScore(): number;
@@ -96,10 +77,17 @@ export declare class Session {
96
77
  get maxUsageCount(): number;
97
78
  get cookieJar(): CookieJar;
98
79
  get proxyInfo(): ProxyInfo | undefined;
80
+ get fingerprint(): SessionFingerprint | undefined;
81
+ set fingerprint(fingerprint: SessionFingerprint | undefined);
82
+ /**
83
+ * `true` once {@link Session.retire|`retire()`} has been called. Retirement is terminal:
84
+ * a retired session is never picked by the pool and cannot be revived via `markGood()`.
85
+ */
86
+ get retired(): boolean;
99
87
  /**
100
88
  * Session configuration.
101
89
  */
102
- constructor(options: SessionOptions);
90
+ constructor(options?: SessionOptions);
103
91
  /**
104
92
  * Indicates whether the session is blocked.
105
93
  * Session is blocked once it reaches the `maxErrorScore`.
@@ -118,7 +106,7 @@ export declare class Session {
118
106
  isMaxUsageCountReached(): boolean;
119
107
  /**
120
108
  * Indicates whether the session can be used for next requests.
121
- * Session is usable when it is not expired, not blocked and the maximum usage count has not be reached.
109
+ * Session is usable when it is not retired, not expired, not blocked and the maximum usage count has not be reached.
122
110
  */
123
111
  isUsable(): boolean;
124
112
  /**
@@ -132,11 +120,11 @@ export declare class Session {
132
120
  */
133
121
  getState(): SessionState;
134
122
  /**
135
- * Marks session as blocked and emits event on the `SessionPool`
136
- * This method should be used if the session usage was unsuccessful
137
- * and you are sure that it is because of the session configuration and not any external matters.
138
- * For example when server returns 403 status code.
139
- * If the session does not work due to some external factors as server error such as 5XX you probably want to use `markBad` method.
123
+ * Permanently retires the session `isUsable()` will return `false` from here on,
124
+ * and no `markGood()` / `markBad()` can revive it. Calling `retire()` again is a no-op.
125
+ *
126
+ * Use this when you're confident the session itself is the problem (e.g. a `403` response).
127
+ * For transient external failures (such as `5XX` responses), use `markBad()` instead.
140
128
  */
141
129
  retire(): void;
142
130
  /**
@@ -144,60 +132,19 @@ export declare class Session {
144
132
  * Should be used when the session has been used unsuccessfully. For example because of timeouts.
145
133
  */
146
134
  markBad(): void;
147
- /**
148
- * With certain status codes: `401`, `403` or `429` we can be certain
149
- * that the target website is blocking us. This function helps to do this conveniently
150
- * by retiring the session when such code is received. Optionally, the default status
151
- * codes can be extended in the second parameter.
152
- * @param statusCode HTTP status code.
153
- * @returns Whether the session was retired.
154
- */
155
- retireOnBlockedStatusCodes(statusCode: number): boolean;
156
- /**
157
- * Saves cookies from an HTTP response to be used with the session.
158
- * It expects an object with a `headers` property that's either an `Object`
159
- * (typical Node.js responses) or a `Function` (Puppeteer Response).
160
- *
161
- * It then parses and saves the cookies from the `set-cookie` header, if available.
162
- */
163
- setCookiesFromResponse(response: Response): void;
164
- /**
165
- * Saves an array with cookie objects to be used with the session.
166
- * The objects should be in the format that
167
- * [Puppeteer uses](https://pptr.dev/#?product=Puppeteer&version=v2.0.0&show=api-pagecookiesurls),
168
- * but you can also use this function to set cookies manually:
169
- *
170
- * ```
171
- * [
172
- * { name: 'cookie1', value: 'my-cookie' },
173
- * { name: 'cookie2', value: 'your-cookie' }
174
- * ]
175
- * ```
176
- */
177
- setCookies(cookies: CookieObject[], url: string): void;
178
- /**
179
- * Returns cookies in a format compatible with puppeteer/playwright and ready to be used with `page.setCookie`.
180
- * @param url website url. Only cookies stored for this url will be returned
181
- */
182
- getCookies(url: string): CookieObject[];
183
135
  /**
184
136
  * Returns cookies saved with the session in the typical
185
137
  * key1=value1; key2=value2 format, ready to be used in
186
138
  * a cookie header or elsewhere.
187
139
  * @returns Represents `Cookie` header.
188
140
  */
189
- getCookieString(url: string): string;
141
+ getCookieString(url: string): Promise<string>;
190
142
  /**
191
143
  * Sets a cookie within this session for the specific URL.
192
144
  */
193
- setCookie(rawCookie: string, url: string): void;
194
- /**
195
- * Sets cookies.
196
- */
197
- protected _setCookies(cookies: Cookie[], url: string): void;
145
+ setCookie(rawCookie: string, url: string): Promise<void>;
198
146
  /**
199
147
  * Checks if session is not usable. if it is not retires the session.
200
148
  */
201
- protected _maybeSelfRetire(): void;
149
+ private maybeSelfRetire;
202
150
  }
203
- //# sourceMappingURL=session.d.ts.map
@@ -1,10 +1,28 @@
1
- import { EventEmitter } from 'node:events';
2
- import ow from 'ow';
3
1
  import { CookieJar } from 'tough-cookie';
2
+ import { z } from 'zod';
4
3
  import { cryptoRandomObjectId } from '@apify/utilities';
5
- import { browserPoolCookieToToughCookie, getCookiesFromResponse, getDefaultCookieExpirationDate, toughCookieToBrowserPoolCookie, } from '../cookie_utils.js';
6
- import { log as defaultLog } from '../log.js';
7
- import { EVENT_SESSION_RETIRED } from './events.js';
4
+ import { getDefaultCookieExpirationDate } from '../cookie_utils.js';
5
+ import { serviceLocator } from '../service_locator.js';
6
+ import { parseArgument, schemas, validators } from '../validators.js';
7
+ // `schemas.anyObject` passes values through by reference (object schemas return a pruned plain
8
+ // copy), so class instances like cookie jars and loggers keep their prototype.
9
+ const sessionOptionsSchema = z.strictObject({
10
+ id: z.string().default(() => `session_${cryptoRandomObjectId(10)}`),
11
+ cookieJar: schemas.anyObject.default(() => new CookieJar()),
12
+ proxyInfo: schemas.anyObject.optional(),
13
+ maxAgeSecs: schemas.anyNumber.default(3000),
14
+ userData: schemas.anyObject.default(() => ({})),
15
+ maxErrorScore: schemas.anyNumber.default(3),
16
+ errorScoreDecrement: schemas.anyNumber.default(0.5),
17
+ createdAt: z.date().default(() => new Date()),
18
+ expiresAt: z.date().optional(),
19
+ usageCount: schemas.anyNumber.default(0),
20
+ errorScore: schemas.anyNumber.default(0),
21
+ maxUsageCount: schemas.anyNumber.default(50),
22
+ retired: z.boolean().default(false),
23
+ log: validators.logger.default(() => serviceLocator.getLogger()),
24
+ fingerprint: schemas.anyObject.optional(),
25
+ });
8
26
  /**
9
27
  * Sessions are used to store information such as cookies and can be used for generating fingerprints and proxy sessions.
10
28
  * You can imagine each session as a specific user, with its own cookies, IP (via proxy) and potentially a unique browser fingerprint.
@@ -13,83 +31,79 @@ import { EVENT_SESSION_RETIRED } from './events.js';
13
31
  */
14
32
  export class Session {
15
33
  id;
16
- maxAgeSecs;
17
34
  userData;
18
- _maxErrorScore;
19
- _errorScoreDecrement;
20
- _createdAt;
21
- _expiresAt;
22
- _usageCount;
23
- _maxUsageCount;
24
- sessionPool;
25
- _errorScore;
26
- _proxyInfo;
27
- _cookieJar;
28
- log;
35
+ #maxErrorScore;
36
+ #errorScoreDecrement;
37
+ #createdAt;
38
+ #expiresAt;
39
+ #usageCount;
40
+ #maxUsageCount;
41
+ #errorScore;
42
+ #retired = false;
43
+ #proxyInfo;
44
+ #cookieJar;
45
+ #fingerprint;
46
+ #log;
29
47
  get errorScore() {
30
- return this._errorScore;
48
+ return this.#errorScore;
31
49
  }
32
50
  get usageCount() {
33
- return this._usageCount;
51
+ return this.#usageCount;
34
52
  }
35
53
  get maxErrorScore() {
36
- return this._maxErrorScore;
54
+ return this.#maxErrorScore;
37
55
  }
38
56
  get errorScoreDecrement() {
39
- return this._errorScoreDecrement;
57
+ return this.#errorScoreDecrement;
40
58
  }
41
59
  get expiresAt() {
42
- return this._expiresAt;
60
+ return this.#expiresAt;
43
61
  }
44
62
  get createdAt() {
45
- return this._createdAt;
63
+ return this.#createdAt;
46
64
  }
47
65
  get maxUsageCount() {
48
- return this._maxUsageCount;
66
+ return this.#maxUsageCount;
49
67
  }
50
68
  get cookieJar() {
51
- return this._cookieJar;
69
+ return this.#cookieJar;
52
70
  }
53
71
  get proxyInfo() {
54
- return this._proxyInfo;
72
+ return this.#proxyInfo;
73
+ }
74
+ get fingerprint() {
75
+ return this.#fingerprint;
76
+ }
77
+ set fingerprint(fingerprint) {
78
+ this.#fingerprint = fingerprint;
79
+ }
80
+ /**
81
+ * `true` once {@link Session.retire|`retire()`} has been called. Retirement is terminal:
82
+ * a retired session is never picked by the pool and cannot be revived via `markGood()`.
83
+ */
84
+ get retired() {
85
+ return this.#retired;
55
86
  }
56
87
  /**
57
88
  * Session configuration.
58
89
  */
59
- constructor(options) {
60
- ow(options, ow.object.exactShape({
61
- sessionPool: ow.object.instanceOf(EventEmitter),
62
- id: ow.optional.string,
63
- cookieJar: ow.optional.object,
64
- proxyInfo: ow.optional.object,
65
- maxAgeSecs: ow.optional.number,
66
- userData: ow.optional.object,
67
- maxErrorScore: ow.optional.number,
68
- errorScoreDecrement: ow.optional.number,
69
- createdAt: ow.optional.date,
70
- expiresAt: ow.optional.date,
71
- usageCount: ow.optional.number,
72
- errorScore: ow.optional.number,
73
- maxUsageCount: ow.optional.number,
74
- log: ow.optional.object,
75
- }));
76
- const { sessionPool, id = `session_${cryptoRandomObjectId(10)}`, cookieJar = new CookieJar(), proxyInfo = undefined, maxAgeSecs = 3000, userData = {}, maxErrorScore = 3, errorScoreDecrement = 0.5, createdAt = new Date(), usageCount = 0, errorScore = 0, maxUsageCount = 50, log = defaultLog, } = options;
77
- const { expiresAt = getDefaultCookieExpirationDate(maxAgeSecs) } = options;
78
- this.log = log.child({ prefix: 'Session' });
79
- this._cookieJar = cookieJar.setCookie ? cookieJar : CookieJar.fromJSON(JSON.stringify(cookieJar));
80
- this._proxyInfo = proxyInfo;
90
+ constructor(options = {}) {
91
+ const { id, cookieJar, proxyInfo, maxAgeSecs, userData, maxErrorScore, errorScoreDecrement, createdAt, usageCount, errorScore, maxUsageCount, retired, log, fingerprint, expiresAt = getDefaultCookieExpirationDate(maxAgeSecs), } = parseArgument(options, sessionOptionsSchema);
92
+ this.#log = log.child({ prefix: 'Session' });
93
+ this.#cookieJar = cookieJar.setCookie ? cookieJar : CookieJar.fromJSON(JSON.stringify(cookieJar));
94
+ this.#proxyInfo = proxyInfo;
95
+ this.#fingerprint = fingerprint;
81
96
  this.id = id;
82
- this.maxAgeSecs = maxAgeSecs;
83
97
  this.userData = userData;
84
- this._maxErrorScore = maxErrorScore;
85
- this._errorScoreDecrement = errorScoreDecrement;
98
+ this.#maxErrorScore = maxErrorScore;
99
+ this.#errorScoreDecrement = errorScoreDecrement;
86
100
  // Internal
87
- this._expiresAt = expiresAt;
88
- this._createdAt = createdAt;
89
- this._usageCount = usageCount; // indicates how many times the session has been used
90
- this._errorScore = errorScore; // indicates number of markBaded request with the session
91
- this._maxUsageCount = maxUsageCount;
92
- this.sessionPool = sessionPool;
101
+ this.#expiresAt = expiresAt;
102
+ this.#createdAt = createdAt;
103
+ this.#usageCount = usageCount; // indicates how many times the session has been used
104
+ this.#errorScore = errorScore; // indicates number of markBaded request with the session
105
+ this.#maxUsageCount = maxUsageCount;
106
+ this.#retired = retired;
93
107
  }
94
108
  /**
95
109
  * Indicates whether the session is blocked.
@@ -115,21 +129,21 @@ export class Session {
115
129
  }
116
130
  /**
117
131
  * Indicates whether the session can be used for next requests.
118
- * Session is usable when it is not expired, not blocked and the maximum usage count has not be reached.
132
+ * Session is usable when it is not retired, not expired, not blocked and the maximum usage count has not be reached.
119
133
  */
120
134
  isUsable() {
121
- return !this.isBlocked() && !this.isExpired() && !this.isMaxUsageCountReached();
135
+ return !this.#retired && !this.isBlocked() && !this.isExpired() && !this.isMaxUsageCountReached();
122
136
  }
123
137
  /**
124
138
  * This method should be called after a successful session usage.
125
139
  * It increases `usageCount` and potentially lowers the `errorScore` by the `errorScoreDecrement`.
126
140
  */
127
141
  markGood() {
128
- this._usageCount += 1;
129
- if (this._errorScore > 0) {
130
- this._errorScore -= this._errorScoreDecrement;
142
+ this.#usageCount += 1;
143
+ if (this.#errorScore > 0) {
144
+ this.#errorScore -= this.#errorScoreDecrement;
131
145
  }
132
- this._maybeSelfRetire();
146
+ this.maybeSelfRetire();
133
147
  }
134
148
  /**
135
149
  * Gets session state for persistence in KeyValueStore.
@@ -139,8 +153,9 @@ export class Session {
139
153
  return {
140
154
  id: this.id,
141
155
  cookieJar: this.cookieJar.toJSON(),
142
- proxyInfo: this._proxyInfo,
156
+ proxyInfo: this.#proxyInfo,
143
157
  userData: this.userData,
158
+ fingerprint: this.#fingerprint,
144
159
  maxErrorScore: this.maxErrorScore,
145
160
  errorScoreDecrement: this.errorScoreDecrement,
146
161
  expiresAt: this.expiresAt.toISOString(),
@@ -148,89 +163,31 @@ export class Session {
148
163
  usageCount: this.usageCount,
149
164
  maxUsageCount: this.maxUsageCount,
150
165
  errorScore: this.errorScore,
166
+ retired: this.#retired,
151
167
  };
152
168
  }
153
169
  /**
154
- * Marks session as blocked and emits event on the `SessionPool`
155
- * This method should be used if the session usage was unsuccessful
156
- * and you are sure that it is because of the session configuration and not any external matters.
157
- * For example when server returns 403 status code.
158
- * If the session does not work due to some external factors as server error such as 5XX you probably want to use `markBad` method.
170
+ * Permanently retires the session `isUsable()` will return `false` from here on,
171
+ * and no `markGood()` / `markBad()` can revive it. Calling `retire()` again is a no-op.
172
+ *
173
+ * Use this when you're confident the session itself is the problem (e.g. a `403` response).
174
+ * For transient external failures (such as `5XX` responses), use `markBad()` instead.
159
175
  */
160
176
  retire() {
161
- // mark it as an invalid by increasing the error score count.
162
- this._errorScore += this._maxErrorScore;
163
- this._usageCount += 1;
164
- // emit event so we can retire browser in puppeteer pool
165
- this.sessionPool.emit(EVENT_SESSION_RETIRED, this);
177
+ if (this.#retired)
178
+ return;
179
+ this.#errorScore += this.#maxErrorScore;
180
+ this.#usageCount += 1;
181
+ this.#retired = true;
166
182
  }
167
183
  /**
168
184
  * Increases usage and error count.
169
185
  * Should be used when the session has been used unsuccessfully. For example because of timeouts.
170
186
  */
171
187
  markBad() {
172
- this._errorScore += 1;
173
- this._usageCount += 1;
174
- this._maybeSelfRetire();
175
- }
176
- /**
177
- * With certain status codes: `401`, `403` or `429` we can be certain
178
- * that the target website is blocking us. This function helps to do this conveniently
179
- * by retiring the session when such code is received. Optionally, the default status
180
- * codes can be extended in the second parameter.
181
- * @param statusCode HTTP status code.
182
- * @returns Whether the session was retired.
183
- */
184
- retireOnBlockedStatusCodes(statusCode) {
185
- // eslint-disable-next-line dot-notation -- accessing private property
186
- const isBlocked = this.sessionPool['blockedStatusCodes'].includes(statusCode);
187
- if (isBlocked) {
188
- this.retire();
189
- }
190
- return isBlocked;
191
- }
192
- /**
193
- * Saves cookies from an HTTP response to be used with the session.
194
- * It expects an object with a `headers` property that's either an `Object`
195
- * (typical Node.js responses) or a `Function` (Puppeteer Response).
196
- *
197
- * It then parses and saves the cookies from the `set-cookie` header, if available.
198
- */
199
- setCookiesFromResponse(response) {
200
- try {
201
- const cookies = getCookiesFromResponse(response).filter((c) => c);
202
- this._setCookies(cookies, response.url);
203
- }
204
- catch (e) {
205
- const err = e;
206
- // if invalid Cookie header is provided just log the exception.
207
- this.log.exception(err, 'Could not get cookies from response');
208
- }
209
- }
210
- /**
211
- * Saves an array with cookie objects to be used with the session.
212
- * The objects should be in the format that
213
- * [Puppeteer uses](https://pptr.dev/#?product=Puppeteer&version=v2.0.0&show=api-pagecookiesurls),
214
- * but you can also use this function to set cookies manually:
215
- *
216
- * ```
217
- * [
218
- * { name: 'cookie1', value: 'my-cookie' },
219
- * { name: 'cookie2', value: 'your-cookie' }
220
- * ]
221
- * ```
222
- */
223
- setCookies(cookies, url) {
224
- const normalizedCookies = cookies.map((c) => browserPoolCookieToToughCookie(c, this.maxAgeSecs));
225
- this._setCookies(normalizedCookies, url);
226
- }
227
- /**
228
- * Returns cookies in a format compatible with puppeteer/playwright and ready to be used with `page.setCookie`.
229
- * @param url website url. Only cookies stored for this url will be returned
230
- */
231
- getCookies(url) {
232
- const cookies = this.cookieJar.getCookiesSync(url);
233
- return cookies.map((c) => toughCookieToBrowserPoolCookie(c));
188
+ this.#errorScore += 1;
189
+ this.#usageCount += 1;
190
+ this.maybeSelfRetire();
234
191
  }
235
192
  /**
236
193
  * Returns cookies saved with the session in the typical
@@ -238,41 +195,26 @@ export class Session {
238
195
  * a cookie header or elsewhere.
239
196
  * @returns Represents `Cookie` header.
240
197
  */
241
- getCookieString(url) {
242
- return this.cookieJar.getCookieStringSync(url, {});
198
+ async getCookieString(url) {
199
+ return this.cookieJar.getCookieString(url, {});
243
200
  }
244
201
  /**
245
202
  * Sets a cookie within this session for the specific URL.
246
203
  */
247
- setCookie(rawCookie, url) {
248
- this.cookieJar.setCookieSync(rawCookie, url);
249
- }
250
- /**
251
- * Sets cookies.
252
- */
253
- _setCookies(cookies, url) {
254
- const errorMessages = [];
255
- for (const cookie of cookies) {
256
- try {
257
- this.cookieJar.setCookieSync(cookie, url, { ignoreError: false });
258
- }
259
- catch (e) {
260
- const err = e;
261
- errorMessages.push(err.message);
262
- }
204
+ async setCookie(rawCookie, url) {
205
+ try {
206
+ await this.cookieJar.setCookie(rawCookie, url);
263
207
  }
264
- // if invalid cookies are provided just log the exception. No need to retry the request automatically.
265
- if (errorMessages.length) {
266
- this.log.debug('Could not set cookies.', { errorMessages });
208
+ catch (e) {
209
+ this.#log.warning('Could not set cookie.', { url, error: e.message });
267
210
  }
268
211
  }
269
212
  /**
270
213
  * Checks if session is not usable. if it is not retires the session.
271
214
  */
272
- _maybeSelfRetire() {
215
+ maybeSelfRetire() {
273
216
  if (!this.isUsable()) {
274
217
  this.retire();
275
218
  }
276
219
  }
277
220
  }
278
- //# sourceMappingURL=session.js.map