scrapely 1.2.24 → 1.2.26
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 +18 -2
- package/dist/actor.js +32 -4
- package/dist/charging.d.ts +4 -2
- package/dist/charging.js +17 -11
- package/package.json +1 -1
package/dist/actor.d.ts
CHANGED
|
@@ -21,8 +21,24 @@ import { type ApiStorageConfig } from './storage/api-storage-client.js';
|
|
|
21
21
|
import { ChargingManager, type ChargeOptions as ChargingChargeOptions, type ChargeResult as ChargingChargeResult } from './charging.js';
|
|
22
22
|
/** Options for a multi-event charged push (`Actor.pushData(row, { charges })`). */
|
|
23
23
|
export interface PushDataChargeOptions {
|
|
24
|
-
/** Events per row, e.g. `{ result: 1, page: 3 }
|
|
25
|
-
charges
|
|
24
|
+
/** Events per row, e.g. `{ result: 1, page: 3 }` (per batch with `chargePer: 'batch'`). */
|
|
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;
|
|
36
|
+
/**
|
|
37
|
+
* 'row' (default): `charges` for every row. 'batch': once for the whole push, e.g.
|
|
38
|
+
* `pushData(pageRows, { charges: { document: 1 }, chargePer: 'batch' })`: all rows are
|
|
39
|
+
* stored if the charge is accepted, none if it is refused.
|
|
40
|
+
*/
|
|
41
|
+
chargePer?: 'row' | 'batch';
|
|
26
42
|
}
|
|
27
43
|
import { createProxyConfiguration, type CreateProxyConfigurationOptions } from './proxy-configuration.js';
|
|
28
44
|
import { type BrowserConfiguration, type BrowserConfigurationOptions } from './browser-configuration.js';
|
package/dist/actor.js
CHANGED
|
@@ -520,13 +520,41 @@ class Actor {
|
|
|
520
520
|
async pushData(item, eventNameOrOptions) {
|
|
521
521
|
Actor._ensureActorInit('pushData');
|
|
522
522
|
if (eventNameOrOptions !== undefined && typeof eventNameOrOptions === 'object') {
|
|
523
|
+
const opts = eventNameOrOptions;
|
|
523
524
|
const { Dataset } = await import('crawlee');
|
|
524
|
-
const dataset =
|
|
525
|
-
|
|
525
|
+
const dataset = opts.dataset === undefined
|
|
526
|
+
? await Dataset.open()
|
|
527
|
+
: typeof opts.dataset === 'string' ? await Dataset.open(opts.dataset) : opts.dataset;
|
|
528
|
+
const isDefaultDataset = dataset.id === this.config.get('defaultDatasetId');
|
|
529
|
+
if (opts.charges !== undefined) {
|
|
530
|
+
if (opts.eventName !== undefined)
|
|
531
|
+
throw new Error('Pass either eventName or charges, not both');
|
|
532
|
+
return (0, charging_js_2.pushDataWithCharges)({
|
|
533
|
+
chargingManager: this.chargingManager,
|
|
534
|
+
items: item,
|
|
535
|
+
charges: opts.charges,
|
|
536
|
+
chargePer: opts.chargePer ?? 'row',
|
|
537
|
+
isDefaultDataset,
|
|
538
|
+
pushFn: async (rows) => { await dataset.pushData(rows); },
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
if (opts.chargePer !== undefined && opts.chargePer !== 'row')
|
|
542
|
+
throw new Error("chargePer needs charges: {...}");
|
|
543
|
+
if (isDefaultDataset)
|
|
544
|
+
return this.pushData(item, opts.eventName);
|
|
545
|
+
if (opts.eventName === 'apify-default-dataset-item' || opts.eventName === 'scrapely-default-dataset-item') {
|
|
546
|
+
throw new Error(`Cannot charge for synthetic event '${opts.eventName}' manually`);
|
|
547
|
+
}
|
|
548
|
+
if (opts.eventName === undefined) {
|
|
549
|
+
// A plain push to a named dataset: not gated by the default dataset's safety net.
|
|
550
|
+
await dataset.pushData(item);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
return (0, charging_js_1.pushDataAndCharge)({
|
|
526
554
|
chargingManager: this.chargingManager,
|
|
527
555
|
items: item,
|
|
528
|
-
|
|
529
|
-
isDefaultDataset:
|
|
556
|
+
eventName: opts.eventName,
|
|
557
|
+
isDefaultDataset: false,
|
|
530
558
|
pushFn: async (rows) => { await dataset.pushData(rows); },
|
|
531
559
|
});
|
|
532
560
|
}
|
package/dist/charging.d.ts
CHANGED
|
@@ -140,7 +140,7 @@ export declare class ChargingManager {
|
|
|
140
140
|
* default-dataset-item event on the default dataset when it is priced, and
|
|
141
141
|
* how many rows the remaining budget pays for in full.
|
|
142
142
|
*/
|
|
143
|
-
_rowCharges(charges: Record<string, number>, isDefaultDataset: boolean, rowCount: number): {
|
|
143
|
+
_rowCharges(charges: Record<string, number>, isDefaultDataset: boolean, rowCount: number, batch?: boolean): {
|
|
144
144
|
perRow: Record<string, number>;
|
|
145
145
|
rows: number;
|
|
146
146
|
};
|
|
@@ -296,12 +296,14 @@ export declare function validateRowCharges(charges: unknown): Record<string, num
|
|
|
296
296
|
* the rows that are kept, so no row is stored part-paid and no event is billed
|
|
297
297
|
* for a row that was not stored. Unpriced events are ignored.
|
|
298
298
|
*/
|
|
299
|
-
export declare function pushDataWithCharges<T>({ chargingManager, items, charges, isDefaultDataset, pushFn, }: {
|
|
299
|
+
export declare function pushDataWithCharges<T>({ chargingManager, items, charges, isDefaultDataset, pushFn, chargePer, }: {
|
|
300
300
|
chargingManager: ChargingManager;
|
|
301
301
|
items: T | T[];
|
|
302
302
|
charges: Record<string, number>;
|
|
303
303
|
isDefaultDataset: boolean;
|
|
304
304
|
pushFn: (rows: T | T[]) => Promise<void>;
|
|
305
|
+
/** 'batch': charge `charges` once for the whole push; all rows stored if accepted, none if refused. */
|
|
306
|
+
chargePer?: 'row' | 'batch';
|
|
305
307
|
}): Promise<ChargeResult>;
|
|
306
308
|
/**
|
|
307
309
|
* @internal True when a dataset push certainly stored nothing: the storage API
|
package/dist/charging.js
CHANGED
|
@@ -286,7 +286,7 @@ class ChargingManager {
|
|
|
286
286
|
* default-dataset-item event on the default dataset when it is priced, and
|
|
287
287
|
* how many rows the remaining budget pays for in full.
|
|
288
288
|
*/
|
|
289
|
-
_rowCharges(charges, isDefaultDataset, rowCount) {
|
|
289
|
+
_rowCharges(charges, isDefaultDataset, rowCount, batch = false) {
|
|
290
290
|
const perRow = {};
|
|
291
291
|
for (const [name, n] of Object.entries(charges)) {
|
|
292
292
|
if ((this.calculateEventPrice(name) ?? 0) > 0)
|
|
@@ -294,11 +294,13 @@ class ChargingManager {
|
|
|
294
294
|
}
|
|
295
295
|
if (isDefaultDataset) {
|
|
296
296
|
const def = resolveDefaultDatasetItemEventName(this.pricingInfo);
|
|
297
|
+
// Per stored row, also for a batch.
|
|
297
298
|
if (!(def in perRow) && (this.calculateEventPrice(def) ?? 0) > 0)
|
|
298
|
-
perRow[def] = 1;
|
|
299
|
+
perRow[def] = batch ? rowCount : 1;
|
|
299
300
|
}
|
|
300
301
|
const rowCost = Object.entries(perRow).reduce((a, [name, n]) => a + (this.calculateEventPrice(name) ?? 0) * n, 0);
|
|
301
|
-
|
|
302
|
+
// Units charged for: rows, or the one batch (rowCost is then the batch's cost).
|
|
303
|
+
let rows = batch ? 1 : rowCount;
|
|
302
304
|
if (rowCost > 0 && Number.isFinite(this.maxTotalChargeUsd)) {
|
|
303
305
|
const fit = Math.floor(Number((this.remainingBudgetUsd() / rowCost).toFixed(4)));
|
|
304
306
|
rows = Math.min(rows, Math.max(0, fit));
|
|
@@ -1337,8 +1339,11 @@ function validateRowCharges(charges) {
|
|
|
1337
1339
|
* the rows that are kept, so no row is stored part-paid and no event is billed
|
|
1338
1340
|
* for a row that was not stored. Unpriced events are ignored.
|
|
1339
1341
|
*/
|
|
1340
|
-
async function pushDataWithCharges({ chargingManager, items, charges, isDefaultDataset, pushFn, }) {
|
|
1342
|
+
async function pushDataWithCharges({ chargingManager, items, charges, isDefaultDataset, pushFn, chargePer = 'row', }) {
|
|
1341
1343
|
const perRowIn = validateRowCharges(charges);
|
|
1344
|
+
if (chargePer !== 'row' && chargePer !== 'batch')
|
|
1345
|
+
throw new Error("chargePer must be 'row' or 'batch'");
|
|
1346
|
+
const batch = chargePer === 'batch';
|
|
1342
1347
|
const rowsIn = Array.isArray(items) ? items : [items];
|
|
1343
1348
|
const single = !Array.isArray(items);
|
|
1344
1349
|
const store = (rows) => chargeGatedPush.run(true, () => pushFn(single ? rows[0] : rows));
|
|
@@ -1353,7 +1358,7 @@ async function pushDataWithCharges({ chargingManager, items, charges, isDefaultD
|
|
|
1353
1358
|
await store(rowsIn);
|
|
1354
1359
|
return { eventChargeLimitReached: false, chargedCount: 0, chargeableWithinLimit: {} };
|
|
1355
1360
|
}
|
|
1356
|
-
let { perRow, rows } = chargingManager._rowCharges(perRowIn, isDefaultDataset, rowsIn.length);
|
|
1361
|
+
let { perRow, rows } = chargingManager._rowCharges(perRowIn, isDefaultDataset, rowsIn.length, batch);
|
|
1357
1362
|
if (Object.keys(perRow).length === 0) {
|
|
1358
1363
|
// Only free events: an unpaid push (prepaid-row rules apply).
|
|
1359
1364
|
const pastLimit = chargingManager.isChargeLimitReached();
|
|
@@ -1425,23 +1430,24 @@ async function pushDataWithCharges({ chargingManager, items, charges, isDefaultD
|
|
|
1425
1430
|
chargingManager._noteRefusedDefaultDatasetItems(rowsIn.length);
|
|
1426
1431
|
return { eventChargeLimitReached: true, chargedCount: 0, chargeableWithinLimit: chargingManager._chargeableWithinLimit() };
|
|
1427
1432
|
}
|
|
1428
|
-
|
|
1433
|
+
const kept = batch ? rowsIn : rowsIn.slice(0, rows);
|
|
1434
|
+
if (kept.length < rowsIn.length) {
|
|
1429
1435
|
chargingManager._markChargeLimitHit();
|
|
1430
1436
|
if (isDefaultDataset)
|
|
1431
|
-
chargingManager._noteRefusedDefaultDatasetItems(rowsIn.length -
|
|
1437
|
+
chargingManager._noteRefusedDefaultDatasetItems(rowsIn.length - kept.length);
|
|
1432
1438
|
}
|
|
1433
1439
|
try {
|
|
1434
|
-
await store(
|
|
1440
|
+
await store(kept);
|
|
1435
1441
|
}
|
|
1436
1442
|
catch (pushErr) {
|
|
1437
|
-
console.error(`[Scrapely] Dataset push failed after charges accepted (rows=${
|
|
1443
|
+
console.error(`[Scrapely] Dataset push failed after charges accepted (rows=${kept.length}): ${pushErr.message}; voiding the charges`);
|
|
1438
1444
|
if (pushCertainlyFailed(pushErr))
|
|
1439
1445
|
await undo(ops);
|
|
1440
1446
|
throw pushErr;
|
|
1441
1447
|
}
|
|
1442
1448
|
return {
|
|
1443
|
-
eventChargeLimitReached:
|
|
1444
|
-
chargedCount:
|
|
1449
|
+
eventChargeLimitReached: kept.length < rowsIn.length || chargingManager.isChargeLimitReached(),
|
|
1450
|
+
chargedCount: kept.length,
|
|
1445
1451
|
chargeableWithinLimit: chargingManager._chargeableWithinLimit(),
|
|
1446
1452
|
};
|
|
1447
1453
|
});
|