scrapely 1.2.25 → 1.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/actor.d.ts CHANGED
@@ -11,7 +11,7 @@ export declare enum ACTOR_PERMISSION_LEVEL {
11
11
  /** User has full administrative access */
12
12
  ADMIN = "ADMIN"
13
13
  }
14
- import { ApifyClient } from 'scrapely-client';
14
+ import type { ApifyClient } from 'scrapely-client';
15
15
  import type { ActorRun, Webhook } from 'scrapely-client';
16
16
  import type { ActorCallOptions, ActorStartOptions, RunAbortOptions, TaskCallOptions } from 'scrapely-client';
17
17
  import { type EventTypeName } from '@crawlee/core';
@@ -22,7 +22,17 @@ import { ChargingManager, type ChargeOptions as ChargingChargeOptions, type Char
22
22
  /** Options for a multi-event charged push (`Actor.pushData(row, { charges })`). */
23
23
  export interface PushDataChargeOptions {
24
24
  /** Events per row, e.g. `{ result: 1, page: 3 }` (per batch with `chargePer: 'batch'`). */
25
- charges: Record<string, number>;
25
+ charges?: Record<string, number>;
26
+ /** One event per row (same as `pushData(item, eventName)`); not together with `charges`. */
27
+ eventName?: string;
28
+ /**
29
+ * Push to this named dataset (name, or a Dataset from `Actor.openDataset`) instead of the
30
+ * default one, with the same charge-first semantics, e.g.
31
+ * `pushData(rows, { eventName: 'comment', dataset: \`comments-${runId}\` })`. Rows of a named
32
+ * dataset carry no implicit default-dataset-item event and are not gated by the default
33
+ * dataset's spending-limit safety net; charged pushes store only the rows that were charged.
34
+ */
35
+ dataset?: string | Dataset;
26
36
  /**
27
37
  * 'row' (default): `charges` for every row. 'batch': once for the whole push, e.g.
28
38
  * `pushData(pageRows, { charges: { document: 1 }, chargePer: 'batch' })`: all rows are
@@ -323,7 +333,8 @@ export declare class Actor {
323
333
  * succeeds.
324
334
  */
325
335
  private _lifecycleStarted;
326
- private readonly _apifyClient;
336
+ /** Created on first use: scrapely-client is only loaded when something needs the API client. */
337
+ private _apifyClient;
327
338
  private readonly chargingManager;
328
339
  /**
329
340
  * Creates an Actor instance (Apify SDK-compatible alternative to static helpers).
package/dist/actor.js CHANGED
@@ -31,6 +31,7 @@ const secrets_js_1 = require("./crypto/secrets.js");
31
31
  const charging_js_1 = require("./charging.js");
32
32
  const charging_js_2 = require("./charging.js");
33
33
  const charging_client_js_1 = require("./charging_client.js");
34
+ const client_loader_js_1 = require("./client-loader.js");
34
35
  const proxy_configuration_js_1 = require("./proxy-configuration.js");
35
36
  const browser_configuration_js_1 = require("./browser-configuration.js");
36
37
  const utils_js_1 = require("./utils.js");
@@ -111,6 +112,7 @@ class Actor {
111
112
  * succeeds.
112
113
  */
113
114
  _lifecycleStarted = false;
115
+ /** Created on first use: scrapely-client is only loaded when something needs the API client. */
114
116
  _apifyClient;
115
117
  chargingManager;
116
118
  /**
@@ -119,12 +121,12 @@ class Actor {
119
121
  constructor(options = {}) {
120
122
  this.config =
121
123
  Object.keys(options).length === 0 ? configuration_js_1.Configuration.getGlobalConfig() : new configuration_js_1.Configuration(options);
122
- this._apifyClient = this.newClient();
123
- this.chargingManager = new charging_js_1.ChargingManager(this.config, this._apifyClient);
124
+ this.chargingManager = new charging_js_1.ChargingManager(this.config, () => this.apifyClient);
124
125
  Actor._instance ??= this;
125
126
  }
126
127
  /** Default ApifyClient instance for this Actor (Apify-compatible instance accessor). */
127
128
  get apifyClient() {
129
+ this._apifyClient ??= this.newClient();
128
130
  return this._apifyClient;
129
131
  }
130
132
  _ensureInit(methodName) {
@@ -278,8 +280,12 @@ class Actor {
278
280
  };
279
281
  this.on('migrating', gracefulShutdownHandlers.migrating);
280
282
  }
281
- apifyClientInstance = this._apifyClient;
282
- apifyClientAssigned = true;
283
+ // Same as before the client became lazy: this Actor's client (once
284
+ // created) is the process default returned by newClient().
285
+ if (this._apifyClient) {
286
+ apifyClientInstance = this._apifyClient;
287
+ apifyClientAssigned = true;
288
+ }
283
289
  await this.chargingManager.init();
284
290
  // Storage clients refuse default-dataset writes past this run's limit.
285
291
  (0, charging_js_1.setActiveChargingManager)(this.chargingManager);
@@ -337,7 +343,10 @@ class Actor {
337
343
  }
338
344
  (0, events_client_js_1.disconnectEvents)();
339
345
  (0, patch_storage_js_1.disconnectStorage)();
340
- if (apifyClientAssigned) {
346
+ // Also when the client was only created during this init (lazily,
347
+ // e.g. by the pricing lookup): never leave a failed init's client
348
+ // as the process default.
349
+ if (apifyClientAssigned || apifyClientInstance !== prevApifyClientInstance) {
341
350
  apifyClientInstance = prevApifyClientInstance;
342
351
  }
343
352
  }
@@ -424,7 +433,7 @@ class Actor {
424
433
  if (metamorphCount) {
425
434
  const count = parseInt(metamorphCount, 10);
426
435
  if (count > 0) {
427
- const { KeyValueStore } = await import('crawlee');
436
+ const { KeyValueStore } = await import('@crawlee/core');
428
437
  const store = await KeyValueStore.open();
429
438
  const metamorphKey = `INPUT-METAMORPH-${count}`;
430
439
  const metamorphInput = await store.getValue(metamorphKey);
@@ -455,7 +464,7 @@ class Actor {
455
464
  }
456
465
  }
457
466
  else {
458
- const { KeyValueStore } = await import('crawlee');
467
+ const { KeyValueStore } = await import('@crawlee/core');
459
468
  const store = await KeyValueStore.open();
460
469
  const inputKey = Actor._actorConfig().get('inputKey', 'INPUT');
461
470
  input = await store.getValue(inputKey);
@@ -520,14 +529,41 @@ class Actor {
520
529
  async pushData(item, eventNameOrOptions) {
521
530
  Actor._ensureActorInit('pushData');
522
531
  if (eventNameOrOptions !== undefined && typeof eventNameOrOptions === 'object') {
523
- const { Dataset } = await import('crawlee');
524
- const dataset = await Dataset.open();
525
- return (0, charging_js_2.pushDataWithCharges)({
532
+ const opts = eventNameOrOptions;
533
+ const { Dataset } = await import('@crawlee/core');
534
+ const dataset = opts.dataset === undefined
535
+ ? await Dataset.open()
536
+ : typeof opts.dataset === 'string' ? await Dataset.open(opts.dataset) : opts.dataset;
537
+ const isDefaultDataset = dataset.id === this.config.get('defaultDatasetId');
538
+ if (opts.charges !== undefined) {
539
+ if (opts.eventName !== undefined)
540
+ throw new Error('Pass either eventName or charges, not both');
541
+ return (0, charging_js_2.pushDataWithCharges)({
542
+ chargingManager: this.chargingManager,
543
+ items: item,
544
+ charges: opts.charges,
545
+ chargePer: opts.chargePer ?? 'row',
546
+ isDefaultDataset,
547
+ pushFn: async (rows) => { await dataset.pushData(rows); },
548
+ });
549
+ }
550
+ if (opts.chargePer !== undefined && opts.chargePer !== 'row')
551
+ throw new Error("chargePer needs charges: {...}");
552
+ if (isDefaultDataset)
553
+ return this.pushData(item, opts.eventName);
554
+ if (opts.eventName === 'apify-default-dataset-item' || opts.eventName === 'scrapely-default-dataset-item') {
555
+ throw new Error(`Cannot charge for synthetic event '${opts.eventName}' manually`);
556
+ }
557
+ if (opts.eventName === undefined) {
558
+ // A plain push to a named dataset: not gated by the default dataset's safety net.
559
+ await dataset.pushData(item);
560
+ return;
561
+ }
562
+ return (0, charging_js_1.pushDataAndCharge)({
526
563
  chargingManager: this.chargingManager,
527
564
  items: item,
528
- charges: eventNameOrOptions.charges,
529
- chargePer: eventNameOrOptions.chargePer ?? 'row',
530
- isDefaultDataset: dataset.id === this.config.get('defaultDatasetId'),
565
+ eventName: opts.eventName,
566
+ isDefaultDataset: false,
531
567
  pushFn: async (rows) => { await dataset.pushData(rows); },
532
568
  });
533
569
  }
@@ -537,7 +573,7 @@ class Actor {
537
573
  eventName === 'scrapely-default-dataset-item') {
538
574
  throw new Error(`Cannot charge for synthetic event '${eventName}' manually`);
539
575
  }
540
- const { Dataset } = await import('crawlee');
576
+ const { Dataset } = await import('@crawlee/core');
541
577
  const dataset = await Dataset.open();
542
578
  if (eventName === undefined && !this.usesPushDataInterception(dataset)) {
543
579
  // Charge-limit safety net (also for local storage): this push is not
@@ -557,11 +593,16 @@ class Actor {
557
593
  return this.pushDataWithExplicitCharging(dataset, item, eventName);
558
594
  }
559
595
  usesPushDataInterception(dataset) {
560
- return Boolean(dataset.client[charging_client_js_1.USES_PUSH_DATA_INTERCEPTION]);
596
+ // Only a scrapely-client dataset client carries the marker, so when the
597
+ // SDK's scrapely-client was never loaded no client can be intercepting.
598
+ const client = (0, client_loader_js_1.loadedScrapelyClient)();
599
+ if (!client)
600
+ return false;
601
+ return Boolean(dataset.client[client.USES_PUSH_DATA_INTERCEPTION]);
561
602
  }
562
603
  async pushDataViaInterceptedClient(dataset, item, eventName) {
563
604
  const context = { eventName };
564
- await charging_client_js_1.pushDataChargingContext.run(context, async () => {
605
+ await (0, client_loader_js_1.loadedScrapelyClient)().pushDataChargingContext.run(context, async () => {
565
606
  await dataset.pushData(item);
566
607
  });
567
608
  return (context.chargeResult ?? {
@@ -586,7 +627,7 @@ class Actor {
586
627
  }
587
628
  static async getValue(key) {
588
629
  Actor._ensureActorInit('getValue');
589
- const { KeyValueStore } = await import('crawlee');
630
+ const { KeyValueStore } = await import('@crawlee/core');
590
631
  const store = await KeyValueStore.open();
591
632
  return store.getValue(key);
592
633
  }
@@ -611,7 +652,7 @@ class Actor {
611
652
  */
612
653
  static async setValue(key, value, options) {
613
654
  Actor._ensureActorInit('setValue');
614
- const { KeyValueStore } = await import('crawlee');
655
+ const { KeyValueStore } = await import('@crawlee/core');
615
656
  const store = await KeyValueStore.open();
616
657
  await store.setValue(key, value, options);
617
658
  }
@@ -684,19 +725,19 @@ class Actor {
684
725
  return storageOptions;
685
726
  }
686
727
  static async _openDataset(actorConfig, nameOrIdOrOptions, openOptions) {
687
- const { Dataset } = await import('crawlee');
728
+ const { Dataset } = await import('@crawlee/core');
688
729
  const resolved = Actor._resolveStorageIdentifier(nameOrIdOrOptions, 'datasets', actorConfig);
689
730
  const storageOpts = Actor._buildStorageOpenOptions(actorConfig, openOptions);
690
731
  return Dataset.open(resolved, storageOpts);
691
732
  }
692
733
  static async _openKeyValueStore(actorConfig, nameOrIdOrOptions, openOptions) {
693
- const { KeyValueStore } = await import('crawlee');
734
+ const { KeyValueStore } = await import('@crawlee/core');
694
735
  const resolved = Actor._resolveStorageIdentifier(nameOrIdOrOptions, 'keyValueStores', actorConfig);
695
736
  const storageOpts = Actor._buildStorageOpenOptions(actorConfig, openOptions);
696
737
  return KeyValueStore.open(resolved, storageOpts);
697
738
  }
698
739
  static async _openRequestQueue(actorConfig, nameOrIdOrOptions, openOptions) {
699
- const { RequestQueue } = await import('crawlee');
740
+ const { RequestQueue } = await import('@crawlee/core');
700
741
  const resolved = Actor._resolveStorageIdentifier(nameOrIdOrOptions, 'requestQueues', actorConfig);
701
742
  const storageOpts = Actor._buildStorageOpenOptions(actorConfig, openOptions);
702
743
  return RequestQueue.open(resolved, storageOpts);
@@ -1334,7 +1375,7 @@ class Actor {
1334
1375
  stateKey = 'APIFY_GLOBAL_STATE';
1335
1376
  initialState = defaultValue;
1336
1377
  }
1337
- const { KeyValueStore } = await import('crawlee');
1378
+ const { KeyValueStore } = await import('@crawlee/core');
1338
1379
  const kvStore = await KeyValueStore.open(options?.keyValueStoreName, {
1339
1380
  config: options?.config ?? Actor._actorConfig(),
1340
1381
  });
@@ -70,7 +70,6 @@ export declare function mergeChargeResults(a: ChargeResult, b: ChargeResult): Ch
70
70
  */
71
71
  export declare class ChargingManager {
72
72
  private readonly configuration;
73
- private readonly apifyClient;
74
73
  /** Set during actor shutdown; rejects new charge operations after the final flush. */
75
74
  private _closed;
76
75
  /** Sticky: the platform refused or capped a charge (HTTP 402 / fewer accepted) or the local gate trimmed one. */
@@ -177,7 +176,13 @@ export declare class ChargingManager {
177
176
  private readonly postAttempts;
178
177
  private readonly pendingMaxEntries;
179
178
  private readonly idempotencySafeAgeMs;
180
- constructor(configuration: Configuration, apifyClient: ApifyClient);
179
+ private readonly apifyClientSource;
180
+ /**
181
+ * @param apifyClient - the API client, or a function returning it (called
182
+ * on first use, so runs that never need the API never load the client).
183
+ */
184
+ constructor(configuration: Configuration, apifyClient: ApifyClient | (() => ApifyClient));
185
+ private get apifyClient();
181
186
  /** @internal Serialize allowance calculation, side effects, and local reservation. */
182
187
  _withOperationLock<T>(operation: () => Promise<T>): Promise<T>;
183
188
  private get isPayPerEvent();
package/dist/charging.js CHANGED
@@ -149,7 +149,6 @@ function mergeChargeResults(a, b) {
149
149
  */
150
150
  class ChargingManager {
151
151
  configuration;
152
- apifyClient;
153
152
  /** Set during actor shutdown; rejects new charge operations after the final flush. */
154
153
  _closed = false;
155
154
  /** Sticky: the platform refused or capped a charge (HTTP 402 / fewer accepted) or the local gate trimmed one. */
@@ -369,13 +368,22 @@ class ChargingManager {
369
368
  postAttempts = POST_ATTEMPTS;
370
369
  pendingMaxEntries = PENDING_MAX_ENTRIES;
371
370
  idempotencySafeAgeMs = exports.CHARGE_IDEMPOTENCY_SAFE_AGE_MS;
371
+ apifyClientSource;
372
+ /**
373
+ * @param apifyClient - the API client, or a function returning it (called
374
+ * on first use, so runs that never need the API never load the client).
375
+ */
372
376
  constructor(configuration, apifyClient) {
373
377
  this.configuration = configuration;
374
- this.apifyClient = apifyClient;
378
+ this.apifyClientSource = apifyClient;
375
379
  this.maxTotalChargeUsd = configuration.get('maxTotalChargeUsd') || Infinity;
376
380
  this.isAtHome = !!configuration.get('isAtHome');
377
381
  this.actorRunId = configuration.get('actorRunId') || '';
378
382
  }
383
+ get apifyClient() {
384
+ const source = this.apifyClientSource;
385
+ return typeof source === 'function' ? source() : source;
386
+ }
379
387
  /** @internal Serialize allowance calculation, side effects, and local reservation. */
380
388
  async _withOperationLock(operation) {
381
389
  const previous = this.operationTail;
@@ -402,9 +410,13 @@ class ChargingManager {
402
410
  async fetchPricingInfo() {
403
411
  const actorPricingInfo = this.configuration.get('actorPricingInfo');
404
412
  const chargedEventCounts = this.configuration.get('chargedEventCounts');
405
- if (actorPricingInfo && chargedEventCounts) {
413
+ // The platform worker always injects the charged event counts, and the
414
+ // pricing info only when the actor has pricing (both from the same
415
+ // actor.pricingInfos[0] the run object reports). Counts without pricing
416
+ // therefore mean "no pricing": no API round trip at init.
417
+ if (chargedEventCounts) {
406
418
  return {
407
- pricingInfo: JSON.parse(actorPricingInfo),
419
+ pricingInfo: actorPricingInfo ? JSON.parse(actorPricingInfo) : undefined,
408
420
  chargedEventCounts: JSON.parse(chargedEventCounts),
409
421
  maxTotalChargeUsd: this.configuration.get('maxTotalChargeUsd') || Infinity,
410
422
  };
@@ -1,8 +1,6 @@
1
- import type { ApifyClientOptions, PpeAwarePushDataContext } from 'scrapely-client';
2
- import { ApifyClient, USES_PUSH_DATA_INTERCEPTION, pushDataChargingContext } from 'scrapely-client';
1
+ import type { ApifyClient, ApifyClientOptions, PpeAwarePushDataContext } from 'scrapely-client';
3
2
  import { type ChargingManager } from './charging.js';
4
3
  import type { Configuration } from './configuration.js';
5
- export { USES_PUSH_DATA_INTERCEPTION, pushDataChargingContext };
6
4
  export type { PpeAwarePushDataContext };
7
5
  /**
8
6
  * Returns a `scrapely-client` `ApifyClient` configured with the SDK's charging
@@ -1,11 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pushDataChargingContext = exports.USES_PUSH_DATA_INTERCEPTION = void 0;
4
3
  exports.createChargingClient = createChargingClient;
5
- const scrapely_client_1 = require("scrapely-client");
6
- Object.defineProperty(exports, "USES_PUSH_DATA_INTERCEPTION", { enumerable: true, get: function () { return scrapely_client_1.USES_PUSH_DATA_INTERCEPTION; } });
7
- Object.defineProperty(exports, "pushDataChargingContext", { enumerable: true, get: function () { return scrapely_client_1.pushDataChargingContext; } });
8
4
  const charging_js_1 = require("./charging.js");
5
+ const client_loader_js_1 = require("./client-loader.js");
9
6
  /**
10
7
  * Adapts the SDK's {@link ChargingManager} to `scrapely-client`'s
11
8
  * {@link ChargingHooks} protocol. The client only routes `pushItems()`
@@ -45,7 +42,8 @@ function createChargingHooks(actor) {
45
42
  * the pricing check happens lazily on every `dataset()` call.
46
43
  */
47
44
  function createChargingClient(options, actor) {
48
- return new scrapely_client_1.ApifyClient({
45
+ const { ApifyClient } = (0, client_loader_js_1.scrapelyClient)();
46
+ return new ApifyClient({
49
47
  ...options,
50
48
  defaultDatasetId: actor.config.get('defaultDatasetId'),
51
49
  charging: createChargingHooks(actor),
@@ -0,0 +1,20 @@
1
+ /**
2
+ * scrapely-client, loaded on first use (axios, proxy-agent and friends cost
3
+ * ~0.7 s under gVisor, and most runs never need the API client).
4
+ *
5
+ * `USES_PUSH_DATA_INTERCEPTION` and `pushDataChargingContext` come from this
6
+ * module (not declared in the SDK) so the SDK and the client share a single
7
+ * symbol and a single async-local storage instance. Identity matters:
8
+ * `Actor.pushData()` checks dataset clients for this symbol, and the ambient
9
+ * charging context read inside the client's intercepted `pushItems()` must be
10
+ * the one `Actor.pushData()` entered.
11
+ *
12
+ * Loaded by the SDK entry: keep this file free of heavy imports.
13
+ */
14
+ export type ScrapelyClientModule = typeof import('scrapely-client');
15
+ /** The SDK's scrapely-client (loads it on first call). */
16
+ export declare function scrapelyClient(): ScrapelyClientModule;
17
+ /** The SDK's scrapely-client if it is already loaded, without loading it. */
18
+ export declare function loadedScrapelyClient(): ScrapelyClientModule | undefined;
19
+ /** Run `listener` once the SDK's scrapely-client is loaded (now, if it already is). */
20
+ export declare function onScrapelyClientLoaded(listener: (mod: ScrapelyClientModule) => void): void;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scrapelyClient = scrapelyClient;
4
+ exports.loadedScrapelyClient = loadedScrapelyClient;
5
+ exports.onScrapelyClientLoaded = onScrapelyClientLoaded;
6
+ let scrapelyClientModule;
7
+ const loadListeners = [];
8
+ function loaded(mod) {
9
+ if (scrapelyClientModule)
10
+ return scrapelyClientModule;
11
+ scrapelyClientModule = mod;
12
+ for (const listener of loadListeners.splice(0))
13
+ listener(mod);
14
+ return mod;
15
+ }
16
+ /** The SDK's scrapely-client (loads it on first call). */
17
+ function scrapelyClient() {
18
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
19
+ return scrapelyClientModule ?? loaded(require('scrapely-client'));
20
+ }
21
+ /** The SDK's scrapely-client if it is already loaded, without loading it. */
22
+ function loadedScrapelyClient() {
23
+ if (scrapelyClientModule)
24
+ return scrapelyClientModule;
25
+ try {
26
+ const cached = require.cache[require.resolve('scrapely-client')];
27
+ if (cached?.loaded)
28
+ return loaded(cached.exports);
29
+ }
30
+ catch {
31
+ // not resolvable — then nothing can be using it
32
+ }
33
+ return undefined;
34
+ }
35
+ /** Run `listener` once the SDK's scrapely-client is loaded (now, if it already is). */
36
+ function onScrapelyClientLoaded(listener) {
37
+ const mod = loadedScrapelyClient();
38
+ if (mod)
39
+ listener(mod);
40
+ else
41
+ loadListeners.push(listener);
42
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Off-thread ESM load hook (module.register) for Node versions without
3
+ * module.registerHooks (Node 20, 22.0-22.14). Registered by
4
+ * patch-browser-pool.ts only when puppeteer is installed for ESM imports.
5
+ *
6
+ * Appends one call to puppeteer-core's ESM PuppeteerNode.js that hands the
7
+ * class to patchPuppeteerNodeClass (published on a global by the preload in
8
+ * the main thread), before the package entry creates its default instance.
9
+ * Keep the pattern and suffix in sync with PUPPETEER_NODE_ESM_URL_RE /
10
+ * PUPPETEER_NODE_ESM_SUFFIX in patch-browser-pool.ts (a test checks this).
11
+ */
12
+ export declare const PUPPETEER_NODE_ESM_URL_RE: RegExp;
13
+ export declare const PUPPETEER_NODE_ESM_SUFFIX = "\n;globalThis[Symbol.for(\"scrapely.patchPuppeteerNodeClass\")]?.(PuppeteerNode);\n";
14
+ interface LoadResult {
15
+ format?: string | null;
16
+ source?: string | ArrayBuffer | ArrayBufferView | null;
17
+ shortCircuit?: boolean;
18
+ }
19
+ export declare function load(url: string, context: unknown, nextLoad: (url: string, context: unknown) => Promise<LoadResult>): Promise<LoadResult>;
20
+ export {};
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Off-thread ESM load hook (module.register) for Node versions without
3
+ * module.registerHooks (Node 20, 22.0-22.14). Registered by
4
+ * patch-browser-pool.ts only when puppeteer is installed for ESM imports.
5
+ *
6
+ * Appends one call to puppeteer-core's ESM PuppeteerNode.js that hands the
7
+ * class to patchPuppeteerNodeClass (published on a global by the preload in
8
+ * the main thread), before the package entry creates its default instance.
9
+ * Keep the pattern and suffix in sync with PUPPETEER_NODE_ESM_URL_RE /
10
+ * PUPPETEER_NODE_ESM_SUFFIX in patch-browser-pool.ts (a test checks this).
11
+ */
12
+ export const PUPPETEER_NODE_ESM_URL_RE = /\/puppeteer-core\/lib\/(esm\/)?puppeteer\/node\/PuppeteerNode\.js$/;
13
+ export const PUPPETEER_NODE_ESM_SUFFIX = '\n;globalThis[Symbol.for("scrapely.patchPuppeteerNodeClass")]?.(PuppeteerNode);\n';
14
+ export async function load(url, context, nextLoad) {
15
+ const result = await nextLoad(url, context);
16
+ if (result?.format === 'module' && result.source != null && PUPPETEER_NODE_ESM_URL_RE.test(url)) {
17
+ const source = typeof result.source === 'string' ? result.source : new TextDecoder().decode(result.source);
18
+ return { ...result, source: source + PUPPETEER_NODE_ESM_SUFFIX };
19
+ }
20
+ return result;
21
+ }
@@ -0,0 +1,18 @@
1
+ import type * as Sdk from './index.js';
2
+ declare const sdk: typeof Sdk;
3
+ export * from './index.js';
4
+ /** `import scrapely from 'scrapely'`: the CommonJS exports object, as before this entry existed. */
5
+ export default sdk;
6
+ export declare const PlaywrightCrawler: typeof import("crawlee").PlaywrightCrawler;
7
+ export declare const PuppeteerCrawler: typeof import("crawlee").PuppeteerCrawler;
8
+ export declare const CheerioCrawler: typeof import("crawlee").CheerioCrawler;
9
+ export declare const HttpCrawler: typeof import("crawlee").HttpCrawler;
10
+ export declare const BasicCrawler: typeof import("crawlee").BasicCrawler;
11
+ export declare const BrowserCrawler: typeof import("crawlee").BrowserCrawler;
12
+ export declare const JSDOMCrawler: typeof import("crawlee").JSDOMCrawler;
13
+ export declare const LinkeDOMCrawler: typeof import("crawlee").LinkeDOMCrawler;
14
+ export declare const ApifyClient: typeof import("scrapely-client").ScrapelyClient;
15
+ export declare const playwrightUtils: typeof Sdk.playwrightUtils;
16
+ export declare const puppeteerUtils: typeof Sdk.puppeteerUtils;
17
+ export declare const pushDataChargingContext: typeof Sdk.pushDataChargingContext;
18
+ export declare let USES_PUSH_DATA_INTERCEPTION: typeof Sdk.USES_PUSH_DATA_INTERCEPTION | undefined;
package/dist/index.d.ts CHANGED
@@ -1,13 +1,26 @@
1
1
  import './log-env.js';
2
+ import type * as CrawleeBasic from '@crawlee/basic';
3
+ import type * as CrawleeBrowser from '@crawlee/browser';
4
+ import type * as CrawleeCheerio from '@crawlee/cheerio';
5
+ import type * as CrawleeHttp from '@crawlee/http';
6
+ import type * as CrawleeJsdom from '@crawlee/jsdom';
7
+ import type * as CrawleeLinkedom from '@crawlee/linkedom';
8
+ import type * as CrawleePlaywright from '@crawlee/playwright';
9
+ import type * as CrawleePuppeteer from '@crawlee/puppeteer';
10
+ import type * as ScrapelyClient from 'scrapely-client';
2
11
  export { setCdpUrl } from './patch-browser-pool.js';
3
12
  export { Actor, ACTOR_PERMISSION_LEVEL, type ActorInput, type InitOptions, type MainOptions, type ExitOptions, type RebootOptions, type AbortOptions, type PushDataChargeOptions, type MetamorphOptions, type RecordOptions, type OpenStorageOptions, type CallOptions, type CallTaskOptions, type StartOptions, type SetStatusMessageOptions, type WebhookOptions, type ApifyEnv, type UserFunc, type Token, type Timeout, EXIT_CODES, } from './actor';
4
13
  export type { StorageAlias, StorageId, StorageName, StorageIdentifier, StorageIdentifierWithoutAlias, } from './storage-identifiers.js';
5
- export { ApifyClient, type ApifyClientOptions, type ActorRun } from 'scrapely-client';
14
+ export type { ApifyClientOptions, ActorRun } from 'scrapely-client';
15
+ export declare const ApifyClient: typeof ScrapelyClient.ApifyClient;
16
+ export type ApifyClient = ScrapelyClient.ApifyClient;
6
17
  export { Configuration, type ConfigurationOptions } from './configuration.js';
7
18
  export { DEGRADED_STATUS_MESSAGE, IpBanned, SolveAttemptError, SolverAuthError, SolverRateLimited, VendorUnavailable, degradedStatusMessage, detectVendor, isBlocked, reportSolveOutcome, solve, solverConfigured, solverStatus, stepAllowed, type Clearance, type SolveCookie, type SolveOptions, type SolverStepRequest, type SolverVendorStatus, } from './solver.js';
8
19
  export { ScrapelyEventManager as PlatformEventManager } from './events/scrapely-event-manager.js';
9
20
  export { ChargingManager, ChargeUncertainError, ChargeRejectedError, DEFAULT_DATASET_ITEM_EVENT, APIFY_DEFAULT_DATASET_ITEM_EVENT, SCRAPELY_DEFAULT_DATASET_ITEM_EVENT, hasDefaultDatasetItemEventInPricing, isDefaultDatasetItemEvent, resolveDefaultDatasetItemEventName, mergeChargeResults, pushDataAndCharge, pushDataWithCharges, validateRowCharges, type ChargeOptions, type ChargeResult, type ActorPricingInfo, } from './charging.js';
10
- export { createChargingClient, pushDataChargingContext, USES_PUSH_DATA_INTERCEPTION, type PpeAwarePushDataContext, } from './charging_client.js';
21
+ export { createChargingClient, type PpeAwarePushDataContext, } from './charging_client.js';
22
+ export declare const pushDataChargingContext: typeof ScrapelyClient.pushDataChargingContext;
23
+ export declare const USES_PUSH_DATA_INTERCEPTION: typeof ScrapelyClient.USES_PUSH_DATA_INTERCEPTION;
11
24
  export { BillingTracker, type BillingClient } from './storage/billing-tracker.js';
12
25
  export { ApiStorageClientFactory, type ApiStorageConfig } from './storage/api-storage-client.js';
13
26
  export { ProxyConfiguration, isPlatformProxySentinel, validateProxySessionId } from './scrapely-proxy-configuration.js';
@@ -18,13 +31,21 @@ export type { LoggerOptions, KeyValueStoreIteratorOptions, KeyValueStoreOptions,
18
31
  export type { KeyConsumer } from './storage/key-value-store-client.js';
19
32
  export { utils, enqueueLinks, type EnqueueLinksOptions } from './utils.js';
20
33
  export { ScrapelyRequestList, type RequestListSource } from './request-list.js';
21
- export { PlaywrightCrawler } from '@crawlee/playwright';
22
- export { PuppeteerCrawler } from '@crawlee/puppeteer';
23
- export { CheerioCrawler } from '@crawlee/cheerio';
24
- export { HttpCrawler } from '@crawlee/http';
25
- export { BasicCrawler } from '@crawlee/basic';
26
- export { BrowserCrawler } from '@crawlee/browser';
27
- export { JSDOMCrawler } from '@crawlee/jsdom';
28
- export { LinkeDOMCrawler } from '@crawlee/linkedom';
29
- export { playwrightUtils } from '@crawlee/playwright';
30
- export { puppeteerUtils } from '@crawlee/puppeteer';
34
+ export declare const PlaywrightCrawler: typeof CrawleePlaywright.PlaywrightCrawler;
35
+ export type PlaywrightCrawler = CrawleePlaywright.PlaywrightCrawler;
36
+ export declare const PuppeteerCrawler: typeof CrawleePuppeteer.PuppeteerCrawler;
37
+ export type PuppeteerCrawler = CrawleePuppeteer.PuppeteerCrawler;
38
+ export declare const CheerioCrawler: typeof CrawleeCheerio.CheerioCrawler;
39
+ export type CheerioCrawler = CrawleeCheerio.CheerioCrawler;
40
+ export declare const HttpCrawler: typeof CrawleeHttp.HttpCrawler;
41
+ export type HttpCrawler<Context extends CrawleeHttp.InternalHttpCrawlingContext<any, any, CrawleeHttp.HttpCrawler<Context>>> = CrawleeHttp.HttpCrawler<Context>;
42
+ export declare const BasicCrawler: typeof CrawleeBasic.BasicCrawler;
43
+ export type BasicCrawler<Context extends CrawleeBasic.CrawlingContext = CrawleeBasic.BasicCrawlingContext> = CrawleeBasic.BasicCrawler<Context>;
44
+ export declare const BrowserCrawler: typeof CrawleeBrowser.BrowserCrawler;
45
+ export type BrowserCrawler<InternalBrowserPoolOptions extends import('@crawlee/browser-pool').BrowserPoolOptions = import('@crawlee/browser-pool').BrowserPoolOptions, LaunchOptions extends Record<string, any> | undefined = Record<string, any>, Context extends CrawleeBrowser.BrowserCrawlingContext = CrawleeBrowser.BrowserCrawlingContext, GoToOptions extends Record<string, any> = Record<string, any>> = CrawleeBrowser.BrowserCrawler<InternalBrowserPoolOptions, LaunchOptions, Context, GoToOptions>;
46
+ export declare const JSDOMCrawler: typeof CrawleeJsdom.JSDOMCrawler;
47
+ export type JSDOMCrawler = CrawleeJsdom.JSDOMCrawler;
48
+ export declare const LinkeDOMCrawler: typeof CrawleeLinkedom.LinkeDOMCrawler;
49
+ export type LinkeDOMCrawler = CrawleeLinkedom.LinkeDOMCrawler;
50
+ export declare const playwrightUtils: typeof CrawleePlaywright.playwrightUtils;
51
+ export declare const puppeteerUtils: typeof CrawleePuppeteer.puppeteerUtils;
package/dist/index.js CHANGED
@@ -1,17 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.log = exports.RequestQueue = exports.KeyValueStore = exports.Dataset = exports.createBrowserConfiguration = exports.BrowserConfiguration = exports.getPlatformProxyEnv = exports.createProxyConfiguration = exports.validateProxySessionId = exports.isPlatformProxySentinel = exports.ProxyConfiguration = exports.ApiStorageClientFactory = exports.BillingTracker = exports.USES_PUSH_DATA_INTERCEPTION = exports.pushDataChargingContext = exports.createChargingClient = exports.validateRowCharges = exports.pushDataWithCharges = exports.pushDataAndCharge = exports.mergeChargeResults = exports.resolveDefaultDatasetItemEventName = exports.isDefaultDatasetItemEvent = exports.hasDefaultDatasetItemEventInPricing = exports.SCRAPELY_DEFAULT_DATASET_ITEM_EVENT = exports.APIFY_DEFAULT_DATASET_ITEM_EVENT = exports.DEFAULT_DATASET_ITEM_EVENT = exports.ChargeRejectedError = exports.ChargeUncertainError = exports.ChargingManager = exports.PlatformEventManager = exports.stepAllowed = exports.solverStatus = exports.solverConfigured = exports.solve = exports.reportSolveOutcome = exports.isBlocked = exports.detectVendor = exports.degradedStatusMessage = exports.VendorUnavailable = exports.SolverRateLimited = exports.SolverAuthError = exports.SolveAttemptError = exports.IpBanned = exports.DEGRADED_STATUS_MESSAGE = exports.Configuration = exports.ApifyClient = exports.EXIT_CODES = exports.ACTOR_PERMISSION_LEVEL = exports.Actor = exports.setCdpUrl = void 0;
4
- exports.puppeteerUtils = exports.playwrightUtils = exports.LinkeDOMCrawler = exports.JSDOMCrawler = exports.BrowserCrawler = exports.BasicCrawler = exports.HttpCrawler = exports.CheerioCrawler = exports.PuppeteerCrawler = exports.PlaywrightCrawler = exports.ScrapelyRequestList = exports.enqueueLinks = exports.utils = exports.LoggerText = exports.LoggerJson = exports.Logger = exports.LogLevel = exports.Log = void 0;
3
+ exports.Logger = exports.LogLevel = exports.Log = exports.log = exports.RequestQueue = exports.KeyValueStore = exports.Dataset = exports.createBrowserConfiguration = exports.BrowserConfiguration = exports.getPlatformProxyEnv = exports.createProxyConfiguration = exports.validateProxySessionId = exports.isPlatformProxySentinel = exports.ProxyConfiguration = exports.ApiStorageClientFactory = exports.BillingTracker = exports.createChargingClient = exports.validateRowCharges = exports.pushDataWithCharges = exports.pushDataAndCharge = exports.mergeChargeResults = exports.resolveDefaultDatasetItemEventName = exports.isDefaultDatasetItemEvent = exports.hasDefaultDatasetItemEventInPricing = exports.SCRAPELY_DEFAULT_DATASET_ITEM_EVENT = exports.APIFY_DEFAULT_DATASET_ITEM_EVENT = exports.DEFAULT_DATASET_ITEM_EVENT = exports.ChargeRejectedError = exports.ChargeUncertainError = exports.ChargingManager = exports.PlatformEventManager = exports.stepAllowed = exports.solverStatus = exports.solverConfigured = exports.solve = exports.reportSolveOutcome = exports.isBlocked = exports.detectVendor = exports.degradedStatusMessage = exports.VendorUnavailable = exports.SolverRateLimited = exports.SolverAuthError = exports.SolveAttemptError = exports.IpBanned = exports.DEGRADED_STATUS_MESSAGE = exports.Configuration = exports.EXIT_CODES = exports.ACTOR_PERMISSION_LEVEL = exports.Actor = exports.setCdpUrl = void 0;
4
+ exports.ScrapelyRequestList = exports.enqueueLinks = exports.utils = exports.LoggerText = exports.LoggerJson = void 0;
5
5
  require("./log-env.js");
6
+ const lazy_exports_js_1 = require("./lazy-exports.js");
6
7
  var patch_browser_pool_js_1 = require("./patch-browser-pool.js");
7
8
  Object.defineProperty(exports, "setCdpUrl", { enumerable: true, get: function () { return patch_browser_pool_js_1.setCdpUrl; } });
8
9
  var actor_1 = require("./actor");
9
10
  Object.defineProperty(exports, "Actor", { enumerable: true, get: function () { return actor_1.Actor; } });
10
11
  Object.defineProperty(exports, "ACTOR_PERMISSION_LEVEL", { enumerable: true, get: function () { return actor_1.ACTOR_PERMISSION_LEVEL; } });
11
12
  Object.defineProperty(exports, "EXIT_CODES", { enumerable: true, get: function () { return actor_1.EXIT_CODES; } });
12
- // Apify-compatible client exports (scrapely-client provides ApifyClient as an alias of ScrapelyClient)
13
- var scrapely_client_1 = require("scrapely-client");
14
- Object.defineProperty(exports, "ApifyClient", { enumerable: true, get: function () { return scrapely_client_1.ApifyClient; } });
15
13
  var configuration_js_1 = require("./configuration.js");
16
14
  Object.defineProperty(exports, "Configuration", { enumerable: true, get: function () { return configuration_js_1.Configuration; } });
17
15
  var solver_js_1 = require("./solver.js");
@@ -47,8 +45,6 @@ Object.defineProperty(exports, "pushDataWithCharges", { enumerable: true, get: f
47
45
  Object.defineProperty(exports, "validateRowCharges", { enumerable: true, get: function () { return charging_js_1.validateRowCharges; } });
48
46
  var charging_client_js_1 = require("./charging_client.js");
49
47
  Object.defineProperty(exports, "createChargingClient", { enumerable: true, get: function () { return charging_client_js_1.createChargingClient; } });
50
- Object.defineProperty(exports, "pushDataChargingContext", { enumerable: true, get: function () { return charging_client_js_1.pushDataChargingContext; } });
51
- Object.defineProperty(exports, "USES_PUSH_DATA_INTERCEPTION", { enumerable: true, get: function () { return charging_client_js_1.USES_PUSH_DATA_INTERCEPTION; } });
52
48
  var billing_tracker_js_1 = require("./storage/billing-tracker.js");
53
49
  Object.defineProperty(exports, "BillingTracker", { enumerable: true, get: function () { return billing_tracker_js_1.BillingTracker; } });
54
50
  // Storage exports - API-based storage
@@ -85,28 +81,10 @@ Object.defineProperty(exports, "enqueueLinks", { enumerable: true, get: function
85
81
  // Request list (requestListSources input format; parity with the Python SDK's ScrapelyRequestList)
86
82
  var request_list_js_1 = require("./request-list.js");
87
83
  Object.defineProperty(exports, "ScrapelyRequestList", { enumerable: true, get: function () { return request_list_js_1.ScrapelyRequestList; } });
88
- // Crawler exports - re-export from crawlee packages for Apify SDK compatibility
89
- var playwright_1 = require("@crawlee/playwright");
90
- Object.defineProperty(exports, "PlaywrightCrawler", { enumerable: true, get: function () { return playwright_1.PlaywrightCrawler; } });
91
- var puppeteer_1 = require("@crawlee/puppeteer");
92
- Object.defineProperty(exports, "PuppeteerCrawler", { enumerable: true, get: function () { return puppeteer_1.PuppeteerCrawler; } });
93
- var cheerio_1 = require("@crawlee/cheerio");
94
- Object.defineProperty(exports, "CheerioCrawler", { enumerable: true, get: function () { return cheerio_1.CheerioCrawler; } });
95
- var http_1 = require("@crawlee/http");
96
- Object.defineProperty(exports, "HttpCrawler", { enumerable: true, get: function () { return http_1.HttpCrawler; } });
97
- var basic_1 = require("@crawlee/basic");
98
- Object.defineProperty(exports, "BasicCrawler", { enumerable: true, get: function () { return basic_1.BasicCrawler; } });
99
- var browser_1 = require("@crawlee/browser");
100
- Object.defineProperty(exports, "BrowserCrawler", { enumerable: true, get: function () { return browser_1.BrowserCrawler; } });
101
- var jsdom_1 = require("@crawlee/jsdom");
102
- Object.defineProperty(exports, "JSDOMCrawler", { enumerable: true, get: function () { return jsdom_1.JSDOMCrawler; } });
103
- var linkedom_1 = require("@crawlee/linkedom");
104
- Object.defineProperty(exports, "LinkeDOMCrawler", { enumerable: true, get: function () { return linkedom_1.LinkeDOMCrawler; } });
105
- // Utility exports for browser automation
106
- var playwright_2 = require("@crawlee/playwright");
107
- Object.defineProperty(exports, "playwrightUtils", { enumerable: true, get: function () { return playwright_2.playwrightUtils; } });
108
- var puppeteer_2 = require("@crawlee/puppeteer");
109
- Object.defineProperty(exports, "puppeteerUtils", { enumerable: true, get: function () { return puppeteer_2.puppeteerUtils; } });
110
84
  // Note: crawlee types are available through the real crawlee package which is installed
111
85
  // as a dependency. The build system creates a symlink from node_modules/crawlee to the
112
86
  // real crawlee package inside scrapely/node_modules/crawlee.
87
+ // Must stay a plain call (not `export ... from`): cjs-module-lexer must not see
88
+ // these names, or every ESM import of the SDK would load them (see lazy-exports.ts).
89
+ // module.exports, not `exports`: tsx/esbuild replace module.exports in dev and tests.
90
+ (0, lazy_exports_js_1.defineLazyExports)(module.exports);