scrapely 1.2.21 → 1.2.23

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
@@ -19,6 +19,11 @@ import { Configuration, type ConfigurationOptions } from './configuration.js';
19
19
  import type { StorageClient } from '@crawlee/types';
20
20
  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
+ /** Options for a multi-event charged push (`Actor.pushData(row, { charges })`). */
23
+ export interface PushDataChargeOptions {
24
+ /** Events per row, e.g. `{ result: 1, page: 3 }`. */
25
+ charges: Record<string, number>;
26
+ }
22
27
  import { createProxyConfiguration, type CreateProxyConfigurationOptions } from './proxy-configuration.js';
23
28
  import { type BrowserConfiguration, type BrowserConfigurationOptions } from './browser-configuration.js';
24
29
  import { type Clearance, type SolveOptions, type SolverVendorStatus } from './solver.js';
@@ -405,7 +410,14 @@ export declare class Actor {
405
410
  * @returns ChargeResult indicating if the user's spending limit was reached
406
411
  */
407
412
  static pushData<Data extends Record<string, any>>(item: Data | Data[], eventName: string): Promise<ChargeResult>;
408
- pushData<Data extends Record<string, any>>(item: Data | Data[], eventName?: string): Promise<void | ChargeResult>;
413
+ /**
414
+ * Stores rows that each cost several pay-per-event events, charged atomically:
415
+ * `pushData(row, { charges: { result: 1, page: 3 } })` charges 1 `result` and 3 `page`
416
+ * events per row. A row is stored only when all of its events were charged; rows the
417
+ * spending limit cannot pay for in full are not stored.
418
+ */
419
+ static pushData<Data extends Record<string, any>>(item: Data | Data[], options: PushDataChargeOptions): Promise<ChargeResult>;
420
+ pushData<Data extends Record<string, any>>(item: Data | Data[], eventNameOrOptions?: string | PushDataChargeOptions): Promise<void | ChargeResult>;
409
421
  private usesPushDataInterception;
410
422
  private pushDataViaInterceptedClient;
411
423
  private pushDataWithExplicitCharging;
package/dist/actor.js CHANGED
@@ -29,6 +29,7 @@ const events_client_js_1 = require("./events/events-client.js");
29
29
  const scrapely_event_manager_js_1 = require("./events/scrapely-event-manager.js");
30
30
  const secrets_js_1 = require("./crypto/secrets.js");
31
31
  const charging_js_1 = require("./charging.js");
32
+ const charging_js_2 = require("./charging.js");
32
33
  const charging_client_js_1 = require("./charging_client.js");
33
34
  const proxy_configuration_js_1 = require("./proxy-configuration.js");
34
35
  const browser_configuration_js_1 = require("./browser-configuration.js");
@@ -513,11 +514,23 @@ class Actor {
513
514
  }
514
515
  return cachedInput ?? undefined;
515
516
  }
516
- static async pushData(item, eventName) {
517
- return Actor.getDefaultInstance().pushData(item, eventName);
517
+ static async pushData(item, eventNameOrOptions) {
518
+ return Actor.getDefaultInstance().pushData(item, eventNameOrOptions);
518
519
  }
519
- async pushData(item, eventName) {
520
+ async pushData(item, eventNameOrOptions) {
520
521
  Actor._ensureActorInit('pushData');
522
+ 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)({
526
+ chargingManager: this.chargingManager,
527
+ items: item,
528
+ charges: eventNameOrOptions.charges,
529
+ isDefaultDataset: dataset.id === this.config.get('defaultDatasetId'),
530
+ pushFn: async (rows) => { await dataset.pushData(rows); },
531
+ });
532
+ }
533
+ const eventName = eventNameOrOptions;
521
534
  // Exact synthetic names only — prefix would block real priced events like apify-foo.
522
535
  if (eventName === 'apify-default-dataset-item' ||
523
536
  eventName === 'scrapely-default-dataset-item') {
@@ -86,6 +86,19 @@ export declare class ChargingManager {
86
86
  * Actors never go positive, so they get nothing extra for free.
87
87
  */
88
88
  private prepaidRowBalance;
89
+ /**
90
+ * Run spend the platform counts against maxTotalChargeUsd that this SDK does
91
+ * not charge itself (compute/proxy/browser usage, server-billed events).
92
+ * Learnt from the charge endpoint's remainingBudgetNd; only ever grows.
93
+ */
94
+ private platformOtherUsd;
95
+ private lastRemainingBudgetNd;
96
+ /** maxTotalChargeUsd minus this SDK's charges and the platform's other run spend. */
97
+ private remainingBudgetUsd;
98
+ /** Fold the last charge response's remainingBudgetNd into the local budget (monotonic). */
99
+ private syncPlatformBudget;
100
+ /** @internal Platform spend outside this SDK's charges (tests). */
101
+ _platformOtherUsd(): number;
89
102
  /** @internal Called by Actor shutdown before the final flush. */
90
103
  close(): void;
91
104
  /**
@@ -110,6 +123,15 @@ export declare class ChargingManager {
110
123
  _notePrepaidCharge(eventName: string, chargedCount: number): void;
111
124
  /** @internal */
112
125
  _isPayPerEvent(): boolean;
126
+ /**
127
+ * @internal The priced part of a multi-event row (`charges`), plus the
128
+ * default-dataset-item event on the default dataset when it is priced, and
129
+ * how many rows the remaining budget pays for in full.
130
+ */
131
+ _rowCharges(charges: Record<string, number>, isDefaultDataset: boolean, rowCount: number): {
132
+ perRow: Record<string, number>;
133
+ rows: number;
134
+ };
113
135
  /** @internal Current prepaid-row balance (tests). */
114
136
  _prepaidRowBalance(): number;
115
137
  /**
@@ -252,6 +274,23 @@ export declare function pushDataAndCharge<T>({ chargingManager, items, eventName
252
274
  isDefaultDataset: boolean;
253
275
  pushFn: (limitedItems: T | T[]) => Promise<void>;
254
276
  }): Promise<ChargeResult>;
277
+ /** Validate `{ eventName: eventsPerRow }` for a multi-event push. */
278
+ export declare function validateRowCharges(charges: unknown): Record<string, number>;
279
+ /**
280
+ * Push rows that each cost several events, atomically per row
281
+ * (`charges = { result: 1, page: 3 }`). A row is stored only when every one of
282
+ * its events was charged: rows the budget cannot pay for in full are not
283
+ * stored, and an operation that came back short is voided and re-charged for
284
+ * the rows that are kept, so no row is stored part-paid and no event is billed
285
+ * for a row that was not stored. Unpriced events are ignored.
286
+ */
287
+ export declare function pushDataWithCharges<T>({ chargingManager, items, charges, isDefaultDataset, pushFn, }: {
288
+ chargingManager: ChargingManager;
289
+ items: T | T[];
290
+ charges: Record<string, number>;
291
+ isDefaultDataset: boolean;
292
+ pushFn: (rows: T | T[]) => Promise<void>;
293
+ }): Promise<ChargeResult>;
255
294
  /**
256
295
  * @internal True when a dataset push certainly stored nothing: the storage API
257
296
  * answered with an error status, or the request never reached it. Timeouts and
package/dist/charging.js CHANGED
@@ -9,6 +9,8 @@ exports.resolveDefaultDatasetItemEventName = resolveDefaultDatasetItemEventName;
9
9
  exports.hasDefaultDatasetItemEventInPricing = hasDefaultDatasetItemEventInPricing;
10
10
  exports.mergeChargeResults = mergeChargeResults;
11
11
  exports.pushDataAndCharge = pushDataAndCharge;
12
+ exports.validateRowCharges = validateRowCharges;
13
+ exports.pushDataWithCharges = pushDataWithCharges;
12
14
  exports.pushCertainlyFailed = pushCertainlyFailed;
13
15
  // SPDX-License-Identifier: Apache-2.0
14
16
  // Derived from apify-sdk-js (src/charging.ts),
@@ -163,6 +165,31 @@ class ChargingManager {
163
165
  * Actors never go positive, so they get nothing extra for free.
164
166
  */
165
167
  prepaidRowBalance = 0;
168
+ /**
169
+ * Run spend the platform counts against maxTotalChargeUsd that this SDK does
170
+ * not charge itself (compute/proxy/browser usage, server-billed events).
171
+ * Learnt from the charge endpoint's remainingBudgetNd; only ever grows.
172
+ */
173
+ platformOtherUsd = 0;
174
+ lastRemainingBudgetNd = null;
175
+ /** maxTotalChargeUsd minus this SDK's charges and the platform's other run spend. */
176
+ remainingBudgetUsd() {
177
+ return this.maxTotalChargeUsd - this.calculateTotalChargedAmount() - this.platformOtherUsd;
178
+ }
179
+ /** Fold the last charge response's remainingBudgetNd into the local budget (monotonic). */
180
+ syncPlatformBudget() {
181
+ const nd = this.lastRemainingBudgetNd;
182
+ this.lastRemainingBudgetNd = null;
183
+ if (nd === null || nd < 0 || !Number.isFinite(this.maxTotalChargeUsd))
184
+ return;
185
+ const other = Number((this.maxTotalChargeUsd - nd / 1e9 - this.calculateTotalChargedAmount()).toFixed(9));
186
+ if (other > this.platformOtherUsd)
187
+ this.platformOtherUsd = other;
188
+ }
189
+ /** @internal Platform spend outside this SDK's charges (tests). */
190
+ _platformOtherUsd() {
191
+ return this.platformOtherUsd;
192
+ }
166
193
  /** @internal Called by Actor shutdown before the final flush. */
167
194
  close() {
168
195
  this._closed = true;
@@ -234,6 +261,30 @@ class ChargingManager {
234
261
  _isPayPerEvent() {
235
262
  return this.chargingState !== undefined && this.isPayPerEvent;
236
263
  }
264
+ /**
265
+ * @internal The priced part of a multi-event row (`charges`), plus the
266
+ * default-dataset-item event on the default dataset when it is priced, and
267
+ * how many rows the remaining budget pays for in full.
268
+ */
269
+ _rowCharges(charges, isDefaultDataset, rowCount) {
270
+ const perRow = {};
271
+ for (const [name, n] of Object.entries(charges)) {
272
+ if ((this.calculateEventPrice(name) ?? 0) > 0)
273
+ perRow[name] = n;
274
+ }
275
+ if (isDefaultDataset) {
276
+ const def = resolveDefaultDatasetItemEventName(this.pricingInfo);
277
+ if (!(def in perRow) && (this.calculateEventPrice(def) ?? 0) > 0)
278
+ perRow[def] = 1;
279
+ }
280
+ const rowCost = Object.entries(perRow).reduce((a, [name, n]) => a + (this.calculateEventPrice(name) ?? 0) * n, 0);
281
+ let rows = rowCount;
282
+ if (rowCost > 0 && Number.isFinite(this.maxTotalChargeUsd)) {
283
+ const fit = Math.floor(Number((this.remainingBudgetUsd() / rowCost).toFixed(4)));
284
+ rows = Math.min(rows, Math.max(0, fit));
285
+ }
286
+ return { perRow, rows };
287
+ }
237
288
  /** @internal Current prepaid-row balance (tests). */
238
289
  _prepaidRowBalance() {
239
290
  return this.prepaidRowBalance;
@@ -517,7 +568,7 @@ class ChargingManager {
517
568
  return eventName;
518
569
  }
519
570
  calculateMaxChargesByPrice(price) {
520
- const unroundedResult = (this.maxTotalChargeUsd - this.calculateTotalChargedAmount()) / price;
571
+ const unroundedResult = this.remainingBudgetUsd() / price;
521
572
  const roundedResult = Math.floor(Number(unroundedResult.toFixed(4)));
522
573
  return Math.max(0, roundedResult);
523
574
  }
@@ -625,6 +676,8 @@ class ChargingManager {
625
676
  });
626
677
  const body = extractChargeResponseBody(response);
627
678
  const accepted = readAcceptedCount(body, intent.count);
679
+ const remaining = body.remainingBudgetNd;
680
+ this.lastRemainingBudgetNd = typeof remaining === 'number' && Number.isFinite(remaining) && remaining >= 0 ? remaining : null;
628
681
  return accepted;
629
682
  }
630
683
  catch (err) {
@@ -930,6 +983,7 @@ class ChargingManager {
930
983
  if (accepted < chargedCount)
931
984
  this.markChargeLimitHit();
932
985
  chargedCount = this.applyAcceptedCount(normalizedEventName, chargedCount, accepted, eventPricing.price);
986
+ this.syncPlatformBudget();
933
987
  }
934
988
  else {
935
989
  throw new ChargeUncertainError(`Charge for event '${normalizedEventName}' (count=${chargedCount}) was not confirmed by the platform; operationId=${intent.idempotencyKey}`, {
@@ -1042,8 +1096,9 @@ async function pushDataAndCharge({ chargingManager, items, eventName, isDefaultD
1042
1096
  let unpaidPastLimit = false;
1043
1097
  if (isDefaultDataset &&
1044
1098
  requested > 0 &&
1045
- chargingManager._isPayPerEvent() &&
1046
- !chargingManager._isPaidPerItem(eventName, isDefaultDataset)) {
1099
+ // Optional calls: partial managers (tests, older shims) skip the net, as before.
1100
+ chargingManager._isPayPerEvent?.() === true &&
1101
+ !chargingManager._isPaidPerItem?.(eventName, isDefaultDataset)) {
1047
1102
  unpaidPastLimit = chargingManager.isChargeLimitReached?.() ?? false;
1048
1103
  const allowed = chargingManager._takeUnpaidRows(requested);
1049
1104
  if (allowed < requested) {
@@ -1236,6 +1291,137 @@ async function pushDataAndCharge({ chargingManager, items, eventName, isDefaultD
1236
1291
  };
1237
1292
  });
1238
1293
  }
1294
+ /** Validate `{ eventName: eventsPerRow }` for a multi-event push. */
1295
+ function validateRowCharges(charges) {
1296
+ if (!charges || typeof charges !== 'object' || Array.isArray(charges) || Object.keys(charges).length === 0) {
1297
+ throw new Error('charges must be a non-empty object of { eventName: countPerRow }');
1298
+ }
1299
+ const out = {};
1300
+ for (const [name, count] of Object.entries(charges)) {
1301
+ if (!name)
1302
+ throw new Error('charges keys must be event names');
1303
+ if (isSyntheticEvent(name))
1304
+ throw new Error(`Cannot charge for synthetic event '${name}' manually`);
1305
+ if (typeof count !== 'number' || !Number.isInteger(count) || count < 1) {
1306
+ throw new Error(`charges['${name}'] must be a positive integer (events per row)`);
1307
+ }
1308
+ out[name] = count;
1309
+ }
1310
+ return out;
1311
+ }
1312
+ /**
1313
+ * Push rows that each cost several events, atomically per row
1314
+ * (`charges = { result: 1, page: 3 }`). A row is stored only when every one of
1315
+ * its events was charged: rows the budget cannot pay for in full are not
1316
+ * stored, and an operation that came back short is voided and re-charged for
1317
+ * the rows that are kept, so no row is stored part-paid and no event is billed
1318
+ * for a row that was not stored. Unpriced events are ignored.
1319
+ */
1320
+ async function pushDataWithCharges({ chargingManager, items, charges, isDefaultDataset, pushFn, }) {
1321
+ const perRowIn = validateRowCharges(charges);
1322
+ const rowsIn = Array.isArray(items) ? items : [items];
1323
+ const single = !Array.isArray(items);
1324
+ const store = (rows) => chargeGatedPush.run(true, () => pushFn(single ? rows[0] : rows));
1325
+ if (rowsIn.length === 0)
1326
+ return { eventChargeLimitReached: false, chargedCount: 0, chargeableWithinLimit: {} };
1327
+ return chargingManager._withOperationLock(async () => {
1328
+ if (chargingManager.isClosed()) {
1329
+ throw new Error('ChargingManager is closed (actor is shutting down); charge rejected');
1330
+ }
1331
+ const voidsConfirmed = (await chargingManager._retryPendingVoids?.()) !== false;
1332
+ if (!chargingManager._isPayPerEvent()) {
1333
+ await store(rowsIn);
1334
+ return { eventChargeLimitReached: false, chargedCount: 0, chargeableWithinLimit: {} };
1335
+ }
1336
+ let { perRow, rows } = chargingManager._rowCharges(perRowIn, isDefaultDataset, rowsIn.length);
1337
+ if (Object.keys(perRow).length === 0) {
1338
+ // Only free events: an unpaid push (prepaid-row rules apply).
1339
+ const pastLimit = chargingManager.isChargeLimitReached();
1340
+ const allowed = isDefaultDataset ? chargingManager._takeUnpaidRows(rowsIn.length) : rowsIn.length;
1341
+ if (allowed < rowsIn.length)
1342
+ chargingManager._noteRefusedDefaultDatasetItems(rowsIn.length - allowed);
1343
+ if (allowed > 0)
1344
+ await store(rowsIn.slice(0, allowed));
1345
+ return { eventChargeLimitReached: pastLimit, chargedCount: 0, chargeableWithinLimit: chargingManager._chargeableWithinLimit() };
1346
+ }
1347
+ if (!voidsConfirmed && Object.keys(perRow).some((n) => !isSyntheticEvent(n))) {
1348
+ throw new Error('[Scrapely] An earlier charge for a failed dataset push could not be voided yet; retry the push');
1349
+ }
1350
+ const undo = async (ops) => {
1351
+ for (const op of ops) {
1352
+ if (op.charged <= 0)
1353
+ continue;
1354
+ if (!op.operationId)
1355
+ chargingManager.applyAcceptedCount(op.name, op.charged, 0);
1356
+ else if (op.uncertain)
1357
+ await chargingManager._cancelUncertainCharge(op.name, op.operationId, op.charged);
1358
+ else
1359
+ await chargingManager._voidCharge(op.name, op.operationId, op.charged);
1360
+ }
1361
+ };
1362
+ const order = Object.entries(perRow).sort(([a], [b]) => Number(isSyntheticEvent(a)) - Number(isSyntheticEvent(b)) || a.localeCompare(b));
1363
+ let ops = [];
1364
+ for (let attempt = 0; attempt < 4 && rows > 0; attempt++) {
1365
+ ops = [];
1366
+ let shortTo = null;
1367
+ for (const [name, n] of order) {
1368
+ const want = n * rows;
1369
+ chargingManager._takeLastAcceptedOperationId?.();
1370
+ let got;
1371
+ try {
1372
+ const r = await chargingManager._chargeExclusive({ eventName: name, count: want });
1373
+ got = r.chargedCount;
1374
+ ops.push({ name, charged: got, operationId: chargingManager._takeLastAcceptedOperationId?.(), uncertain: false });
1375
+ }
1376
+ catch (err) {
1377
+ if (!(err instanceof ChargeUncertainError)) {
1378
+ await undo(ops);
1379
+ throw err;
1380
+ }
1381
+ // Not confirmed: stays pending and is re-posted at exit, so it counts as accepted.
1382
+ got = err.count;
1383
+ ops.push({ name, charged: got, operationId: err.operationId, uncertain: true });
1384
+ }
1385
+ if (got < want) {
1386
+ shortTo = Math.floor(got / n);
1387
+ break;
1388
+ }
1389
+ }
1390
+ if (shortTo === null)
1391
+ break;
1392
+ // An event came back short: void this attempt and retry with the rows it pays for.
1393
+ await undo(ops);
1394
+ ops = [];
1395
+ rows = shortTo;
1396
+ }
1397
+ if (rows <= 0 || ops.length === 0) {
1398
+ await undo(ops);
1399
+ chargingManager._markChargeLimitHit();
1400
+ if (isDefaultDataset)
1401
+ chargingManager._noteRefusedDefaultDatasetItems(rowsIn.length);
1402
+ return { eventChargeLimitReached: true, chargedCount: 0, chargeableWithinLimit: chargingManager._chargeableWithinLimit() };
1403
+ }
1404
+ if (rows < rowsIn.length) {
1405
+ chargingManager._markChargeLimitHit();
1406
+ if (isDefaultDataset)
1407
+ chargingManager._noteRefusedDefaultDatasetItems(rowsIn.length - rows);
1408
+ }
1409
+ try {
1410
+ await store(rowsIn.slice(0, rows));
1411
+ }
1412
+ catch (pushErr) {
1413
+ console.error(`[Scrapely] Dataset push failed after charges accepted (rows=${rows}): ${pushErr.message}; voiding the charges`);
1414
+ if (pushCertainlyFailed(pushErr))
1415
+ await undo(ops);
1416
+ throw pushErr;
1417
+ }
1418
+ return {
1419
+ eventChargeLimitReached: rows < rowsIn.length || chargingManager.isChargeLimitReached(),
1420
+ chargedCount: rows,
1421
+ chargeableWithinLimit: chargingManager._chargeableWithinLimit(),
1422
+ };
1423
+ });
1424
+ }
1239
1425
  /** HTTP status of an API/client error, if the server answered. */
1240
1426
  function httpStatusOf(err) {
1241
1427
  const e = err;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import './log-env.js';
2
2
  export { setCdpUrl } from './patch-browser-pool.js';
3
- export { Actor, ACTOR_PERMISSION_LEVEL, type ActorInput, type InitOptions, type MainOptions, type ExitOptions, type RebootOptions, type AbortOptions, 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';
3
+ 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
4
  export type { StorageAlias, StorageId, StorageName, StorageIdentifier, StorageIdentifierWithoutAlias, } from './storage-identifiers.js';
5
5
  export { ApifyClient, type ApifyClientOptions, type ActorRun } from 'scrapely-client';
6
6
  export { Configuration, type ConfigurationOptions } from './configuration.js';
7
7
  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
8
  export { ScrapelyEventManager as PlatformEventManager } from './events/scrapely-event-manager.js';
9
- export { ChargingManager, ChargeUncertainError, ChargeRejectedError, DEFAULT_DATASET_ITEM_EVENT, APIFY_DEFAULT_DATASET_ITEM_EVENT, SCRAPELY_DEFAULT_DATASET_ITEM_EVENT, hasDefaultDatasetItemEventInPricing, isDefaultDatasetItemEvent, resolveDefaultDatasetItemEventName, mergeChargeResults, pushDataAndCharge, type ChargeOptions, type ChargeResult, type ActorPricingInfo, } from './charging.js';
9
+ 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
10
  export { createChargingClient, pushDataChargingContext, USES_PUSH_DATA_INTERCEPTION, type PpeAwarePushDataContext, } from './charging_client.js';
11
11
  export { BillingTracker, type BillingClient } from './storage/billing-tracker.js';
12
12
  export { ApiStorageClientFactory, type ApiStorageConfig } from './storage/api-storage-client.js';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- 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.USES_PUSH_DATA_INTERCEPTION = exports.pushDataChargingContext = exports.createChargingClient = 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 = void 0;
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;
5
5
  require("./log-env.js");
6
6
  var patch_browser_pool_js_1 = require("./patch-browser-pool.js");
7
7
  Object.defineProperty(exports, "setCdpUrl", { enumerable: true, get: function () { return patch_browser_pool_js_1.setCdpUrl; } });
@@ -43,6 +43,8 @@ Object.defineProperty(exports, "isDefaultDatasetItemEvent", { enumerable: true,
43
43
  Object.defineProperty(exports, "resolveDefaultDatasetItemEventName", { enumerable: true, get: function () { return charging_js_1.resolveDefaultDatasetItemEventName; } });
44
44
  Object.defineProperty(exports, "mergeChargeResults", { enumerable: true, get: function () { return charging_js_1.mergeChargeResults; } });
45
45
  Object.defineProperty(exports, "pushDataAndCharge", { enumerable: true, get: function () { return charging_js_1.pushDataAndCharge; } });
46
+ Object.defineProperty(exports, "pushDataWithCharges", { enumerable: true, get: function () { return charging_js_1.pushDataWithCharges; } });
47
+ Object.defineProperty(exports, "validateRowCharges", { enumerable: true, get: function () { return charging_js_1.validateRowCharges; } });
46
48
  var charging_client_js_1 = require("./charging_client.js");
47
49
  Object.defineProperty(exports, "createChargingClient", { enumerable: true, get: function () { return charging_client_js_1.createChargingClient; } });
48
50
  Object.defineProperty(exports, "pushDataChargingContext", { enumerable: true, get: function () { return charging_client_js_1.pushDataChargingContext; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scrapely",
3
- "version": "1.2.21",
3
+ "version": "1.2.23",
4
4
  "description": "Scrapely SDK for building JavaScript and TypeScript Actors",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,6 +23,8 @@
23
23
  "test": "npx tsx tests/test-mvp.ts",
24
24
  "test:charging": "npx tsx --test tests/charging-pending.test.ts",
25
25
  "test:charge-limit-guard": "npx tsx --test tests/charge-limit-guard.test.ts",
26
+ "test:charge-multi-event": "npx tsx --test tests/charge-multi-event.test.ts",
27
+ "test:charge-platform-budget": "npx tsx --test tests/charge-platform-budget.test.ts",
26
28
  "test:storage-retries": "npx tsx --test tests/storage-retries.test.ts",
27
29
  "test:push-idempotency": "npx tsx --test tests/push-idempotency.test.ts",
28
30
  "test:stdio-drain": "npx tsx --test tests/stdio-drain.test.ts",