@crawlee/basic 4.0.0-beta.81 → 4.0.0-beta.82

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.
@@ -46,7 +46,13 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
46
46
  */
47
47
  requestHandler?: RequestHandler<ExtendedContext>;
48
48
  /**
49
- * Allows the user to extend the crawling context passed to the request handler with custom functionality.
49
+ * Allows the user to extend the crawling context with custom functionality (helpers, references, etc.).
50
+ *
51
+ * `extendContext` runs *before* navigation, so the returned members are visible to the
52
+ * `preNavigationHooks`, `postNavigationHooks`, and the `requestHandler` alike. As a consequence,
53
+ * the `context` passed to `extendContext` is the pre-navigation {@link CrawlingContext} and does
54
+ * **not** include navigation-dependent members (e.g. `page`, `response`, `$`, `body`). If you need
55
+ * those, use a `postNavigationHook` or the `requestHandler` instead.
50
56
  *
51
57
  * **Example usage:**
52
58
  *
@@ -66,7 +72,7 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
66
72
  * });
67
73
  * ```
68
74
  */
69
- extendContext?: (context: Context) => Awaitable<ContextExtension>;
75
+ extendContext?: (context: CrawlingContext) => Awaitable<ContextExtension>;
70
76
  /**
71
77
  * *Intended for BasicCrawler subclasses*. Prepares a context pipeline that transforms the initial crawling context into the shape given by the `Context` type parameter.
72
78
  *
@@ -507,13 +507,27 @@ export class BasicCrawler {
507
507
  return { enqueueLinks: enqueueLinksWrapper, addRequests, sendRequest };
508
508
  }
509
509
  buildFinalContextPipeline() {
510
- let contextPipeline = (this.contextPipelineOptions.contextPipelineBuilder?.() ??
510
+ const subclassPipeline = (this.contextPipelineOptions.contextPipelineBuilder?.() ??
511
511
  this.buildContextPipeline());
512
+ // `extendContext` runs *before* the subclass navigation pipeline (which includes the
513
+ // pre/post-navigation hooks). This makes the extension visible to those hooks and to the
514
+ // request handler alike. The trade-off is that `extendContext` cannot access
515
+ // navigation-dependent context members (e.g. `page`, `response`, `$`, `body`), as those
516
+ // don't exist yet at this point in the pipeline.
517
+ // The `extendContext` output (`ContextExtension`) is carried through the subclass pipeline at
518
+ // runtime (the pipeline copies each middleware's returned members onto the shared context), but
519
+ // TypeScript cannot express that `Context` transitively includes `ContextExtension` here. The
520
+ // casts below are sound because `buildFinalContextPipeline` is declared to return the fully
521
+ // resolved `ExtendedContext` (= `Context & ContextExtension`).
512
522
  const { extendContext } = this.contextPipelineOptions;
523
+ let contextPipeline;
513
524
  if (extendContext !== undefined) {
514
- contextPipeline = contextPipeline.compose({
515
- action: async (context) => await extendContext(context),
516
- });
525
+ contextPipeline = ContextPipeline.create()
526
+ .compose({ action: async (context) => await extendContext(context) })
527
+ .chain(subclassPipeline);
528
+ }
529
+ else {
530
+ contextPipeline = subclassPipeline;
517
531
  }
518
532
  contextPipeline = contextPipeline.compose({
519
533
  action: async (context) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crawlee/basic",
3
- "version": "4.0.0-beta.81",
3
+ "version": "4.0.0-beta.82",
4
4
  "description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
5
5
  "engines": {
6
6
  "node": ">=22.0.0"
@@ -42,10 +42,10 @@
42
42
  "@apify/datastructures": "^2.0.0",
43
43
  "@apify/timeout": "^0.3.2",
44
44
  "@apify/utilities": "^2.15.5",
45
- "@crawlee/core": "4.0.0-beta.81",
46
- "@crawlee/http-client": "4.0.0-beta.81",
47
- "@crawlee/types": "4.0.0-beta.81",
48
- "@crawlee/utils": "4.0.0-beta.81",
45
+ "@crawlee/core": "4.0.0-beta.82",
46
+ "@crawlee/http-client": "4.0.0-beta.82",
47
+ "@crawlee/types": "4.0.0-beta.82",
48
+ "@crawlee/utils": "4.0.0-beta.82",
49
49
  "csv-stringify": "^6.5.2",
50
50
  "fs-extra": "^11.3.0",
51
51
  "ow": "^2.0.0",
@@ -54,7 +54,7 @@
54
54
  "type-fest": "^4.41.0"
55
55
  },
56
56
  "optionalDependencies": {
57
- "@crawlee/impit-client": "^4.0.0-beta.81"
57
+ "@crawlee/impit-client": "^4.0.0-beta.82"
58
58
  },
59
59
  "lerna": {
60
60
  "command": {
@@ -63,5 +63,5 @@
63
63
  }
64
64
  }
65
65
  },
66
- "gitHead": "80dc6b4fc82237e63a51a71153809ec8dfd0cc50"
66
+ "gitHead": "eb1096f7c7743d124375ef011fbbadb19476822e"
67
67
  }