scrapely 1.2.22 → 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.
@@ -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
  /**
package/dist/charging.js CHANGED
@@ -165,6 +165,31 @@ class ChargingManager {
165
165
  * Actors never go positive, so they get nothing extra for free.
166
166
  */
167
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
+ }
168
193
  /** @internal Called by Actor shutdown before the final flush. */
169
194
  close() {
170
195
  this._closed = true;
@@ -255,7 +280,7 @@ class ChargingManager {
255
280
  const rowCost = Object.entries(perRow).reduce((a, [name, n]) => a + (this.calculateEventPrice(name) ?? 0) * n, 0);
256
281
  let rows = rowCount;
257
282
  if (rowCost > 0 && Number.isFinite(this.maxTotalChargeUsd)) {
258
- const fit = Math.floor(Number(((this.maxTotalChargeUsd - this.calculateTotalChargedAmount()) / rowCost).toFixed(4)));
283
+ const fit = Math.floor(Number((this.remainingBudgetUsd() / rowCost).toFixed(4)));
259
284
  rows = Math.min(rows, Math.max(0, fit));
260
285
  }
261
286
  return { perRow, rows };
@@ -543,7 +568,7 @@ class ChargingManager {
543
568
  return eventName;
544
569
  }
545
570
  calculateMaxChargesByPrice(price) {
546
- const unroundedResult = (this.maxTotalChargeUsd - this.calculateTotalChargedAmount()) / price;
571
+ const unroundedResult = this.remainingBudgetUsd() / price;
547
572
  const roundedResult = Math.floor(Number(unroundedResult.toFixed(4)));
548
573
  return Math.max(0, roundedResult);
549
574
  }
@@ -651,6 +676,8 @@ class ChargingManager {
651
676
  });
652
677
  const body = extractChargeResponseBody(response);
653
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;
654
681
  return accepted;
655
682
  }
656
683
  catch (err) {
@@ -956,6 +983,7 @@ class ChargingManager {
956
983
  if (accepted < chargedCount)
957
984
  this.markChargeLimitHit();
958
985
  chargedCount = this.applyAcceptedCount(normalizedEventName, chargedCount, accepted, eventPricing.price);
986
+ this.syncPlatformBudget();
959
987
  }
960
988
  else {
961
989
  throw new ChargeUncertainError(`Charge for event '${normalizedEventName}' (count=${chargedCount}) was not confirmed by the platform; operationId=${intent.idempotencyKey}`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scrapely",
3
- "version": "1.2.22",
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",
@@ -24,6 +24,7 @@
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
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",
27
28
  "test:storage-retries": "npx tsx --test tests/storage-retries.test.ts",
28
29
  "test:push-idempotency": "npx tsx --test tests/push-idempotency.test.ts",
29
30
  "test:stdio-drain": "npx tsx --test tests/stdio-drain.test.ts",