@gpc-cli/api 1.0.25 → 1.0.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/index.js CHANGED
@@ -549,6 +549,31 @@ function enhanceApiError(status, body) {
549
549
  ].join("\n")
550
550
  };
551
551
  }
552
+ if ((status === 403 || status === 400) && (errorMsg.includes("changes not sent for review") || errorMsg.includes("changesnotsentforreview") || errorMsg.includes("review") && errorMsg.includes("rejected"))) {
553
+ return {
554
+ code: "API_CHANGES_NOT_SENT_FOR_REVIEW",
555
+ message: "This app has a rejected update. The API requires explicit acknowledgement before committing changes.",
556
+ suggestion: [
557
+ "Add --changes-not-sent-for-review to your command:",
558
+ " gpc releases upload app.aab --track internal --changes-not-sent-for-review",
559
+ "",
560
+ "This applies your changes without sending them for review.",
561
+ "You must manually send for review from the Google Play Console when ready."
562
+ ].join("\n")
563
+ };
564
+ }
565
+ if (status === 400 && (errorMsg.includes("changes_already_in_review") || errorMsg.includes("already in review"))) {
566
+ return {
567
+ code: "API_CHANGES_ALREADY_IN_REVIEW",
568
+ message: "Changes are already in review. Committing this edit would cancel the existing review.",
569
+ suggestion: [
570
+ "Wait for the current review to complete, or re-run without --error-if-in-review",
571
+ "to cancel the existing review and submit new changes.",
572
+ "",
573
+ "To prevent accidental review cancellation in CI, keep --error-if-in-review."
574
+ ].join("\n")
575
+ };
576
+ }
552
577
  return void 0;
553
578
  }
554
579
  function mapStatusToError(status, body) {
@@ -733,7 +758,8 @@ function createHttpClient(options) {
733
758
  return Math.max(timeout, 3e4 + Math.ceil(sizeMb) * 1e3);
734
759
  }
735
760
  async function uploadRequest(path, filePath, contentType, baseUrl = UPLOAD_BASE_URL) {
736
- const url = `${baseUrl}${path}`;
761
+ const separator = path.includes("?") ? "&" : "?";
762
+ const url = `${baseUrl}${path}${separator}uploadType=media`;
737
763
  const safeFilePath = validateFilePath(filePath);
738
764
  const fileBuffer = await readFile(safeFilePath);
739
765
  const effectiveTimeout = computeUploadTimeout(fileBuffer.byteLength);
@@ -942,13 +968,104 @@ function createHttpClient(options) {
942
968
  };
943
969
  }
944
970
 
971
+ // src/rate-limiter.ts
972
+ var RATE_LIMIT_BUCKETS = {
973
+ edits: { name: "edits", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
974
+ purchases: { name: "purchases", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
975
+ reviews: { name: "reviews", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
976
+ reporting: { name: "reporting", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
977
+ monetization: { name: "monetization", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
978
+ default: { name: "default", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 }
979
+ };
980
+ function resolveBucket(path) {
981
+ if (path.includes("/edits/") || path.includes("/edits:")) return "edits";
982
+ if (path.includes("/purchases/") || path.includes("/orders")) return "purchases";
983
+ if (path.includes("/reviews")) return "reviews";
984
+ if (path.includes("playdeveloperreporting") || path.includes("MetricSet") || path.includes("anomalies")) return "reporting";
985
+ if (path.includes("/inappproducts") || path.includes("/oneTimeProducts") || path.includes("/subscriptions") || path.includes("/monetization")) return "monetization";
986
+ return "default";
987
+ }
988
+ function createRateLimiter(buckets) {
989
+ const states = /* @__PURE__ */ new Map();
990
+ const effectiveBuckets = buckets ?? Object.values(RATE_LIMIT_BUCKETS);
991
+ for (const bucket of effectiveBuckets) {
992
+ states.set(bucket.name, {
993
+ tokens: bucket.maxTokens,
994
+ lastRefillTime: Date.now(),
995
+ config: bucket
996
+ });
997
+ }
998
+ return {
999
+ async acquire(bucket) {
1000
+ const state = states.get(bucket);
1001
+ if (!state) return;
1002
+ const now = Date.now();
1003
+ const elapsed = now - state.lastRefillTime;
1004
+ const refill = Math.floor(
1005
+ elapsed / state.config.refillIntervalMs * state.config.refillRate
1006
+ );
1007
+ if (refill > 0) {
1008
+ state.tokens = Math.min(state.config.maxTokens, state.tokens + refill);
1009
+ state.lastRefillTime = now;
1010
+ }
1011
+ if (state.tokens > 0) {
1012
+ state.tokens--;
1013
+ return;
1014
+ }
1015
+ const tokensNeeded = 1;
1016
+ const waitMs = Math.ceil(
1017
+ tokensNeeded / state.config.refillRate * state.config.refillIntervalMs
1018
+ );
1019
+ await new Promise((r) => setTimeout(r, waitMs));
1020
+ const afterWait = Date.now();
1021
+ const totalElapsed = afterWait - state.lastRefillTime;
1022
+ const newTokens = Math.floor(
1023
+ totalElapsed / state.config.refillIntervalMs * state.config.refillRate
1024
+ );
1025
+ state.tokens = Math.max(0, Math.min(state.config.maxTokens, newTokens) - 1);
1026
+ state.lastRefillTime = afterWait;
1027
+ }
1028
+ };
1029
+ }
1030
+
945
1031
  // src/client.ts
946
- async function rateLimit(limiter, bucket) {
947
- if (limiter) await limiter.acquire(bucket);
1032
+ var DEFAULT_REGIONS_VERSION = "2022/02";
1033
+ function applyMutationOptions(params, options) {
1034
+ if (options?.allowMissing) params["allowMissing"] = "true";
1035
+ if (options?.latencyTolerance) params["latencyTolerance"] = options.latencyTolerance;
1036
+ }
1037
+ async function autoRateLimit(limiter, path) {
1038
+ if (!limiter) return;
1039
+ const bucket = resolveBucket(path);
1040
+ await limiter.acquire(bucket);
948
1041
  }
949
1042
  function createApiClient(options) {
950
- const http = createHttpClient(options);
951
- const limiter = options.rateLimiter || void 0;
1043
+ const rawHttp = createHttpClient(options);
1044
+ const defaultLimiter = createRateLimiter();
1045
+ const limiter = options.rateLimiter || defaultLimiter;
1046
+ const http = {
1047
+ ...rawHttp,
1048
+ async get(path, params) {
1049
+ await autoRateLimit(limiter, path);
1050
+ return rawHttp.get(path, params);
1051
+ },
1052
+ async post(path, body) {
1053
+ await autoRateLimit(limiter, path);
1054
+ return rawHttp.post(path, body);
1055
+ },
1056
+ async put(path, body) {
1057
+ await autoRateLimit(limiter, path);
1058
+ return rawHttp.put(path, body);
1059
+ },
1060
+ async patch(path, body) {
1061
+ await autoRateLimit(limiter, path);
1062
+ return rawHttp.patch(path, body);
1063
+ },
1064
+ async delete(path) {
1065
+ await autoRateLimit(limiter, path);
1066
+ return rawHttp.delete(path);
1067
+ }
1068
+ };
952
1069
  return {
953
1070
  edits: {
954
1071
  async insert(packageName) {
@@ -963,8 +1080,15 @@ function createApiClient(options) {
963
1080
  const { data } = await http.post(`/${packageName}/edits/${editId}:validate`);
964
1081
  return data;
965
1082
  },
966
- async commit(packageName, editId) {
967
- const { data } = await http.post(`/${packageName}/edits/${editId}:commit`);
1083
+ async commit(packageName, editId, options2) {
1084
+ let path = `/${packageName}/edits/${editId}:commit`;
1085
+ if (options2?.changesNotSentForReview || options2?.changesInReviewBehavior) {
1086
+ const params = new URLSearchParams();
1087
+ if (options2.changesNotSentForReview) params.set("changesNotSentForReview", "true");
1088
+ if (options2.changesInReviewBehavior) params.set("changesInReviewBehavior", options2.changesInReviewBehavior);
1089
+ path += `?${params.toString()}`;
1090
+ }
1091
+ const { data } = await http.post(path);
968
1092
  return data;
969
1093
  },
970
1094
  async delete(packageName, editId) {
@@ -998,9 +1122,13 @@ function createApiClient(options) {
998
1122
  );
999
1123
  return data.bundles;
1000
1124
  },
1001
- async upload(packageName, editId, filePath, uploadOptions) {
1125
+ async upload(packageName, editId, filePath, uploadOptions, deviceTierConfigId) {
1126
+ let bundlePath = `/${packageName}/edits/${editId}/bundles`;
1127
+ if (deviceTierConfigId) {
1128
+ bundlePath += `?${new URLSearchParams({ deviceTierConfigId }).toString()}`;
1129
+ }
1002
1130
  const { data } = await http.uploadResumable(
1003
- `/${packageName}/edits/${editId}/bundles`,
1131
+ bundlePath,
1004
1132
  filePath,
1005
1133
  "application/octet-stream",
1006
1134
  uploadOptions
@@ -1057,6 +1185,29 @@ function createApiClient(options) {
1057
1185
  }
1058
1186
  },
1059
1187
  apks: {
1188
+ async list(packageName, editId) {
1189
+ const { data } = await http.get(
1190
+ `/${packageName}/edits/${editId}/apks`
1191
+ );
1192
+ return data.apks || [];
1193
+ },
1194
+ async upload(packageName, editId, filePath, uploadOptions) {
1195
+ const { data } = await http.uploadResumable(
1196
+ `/${packageName}/edits/${editId}/apks`,
1197
+ filePath,
1198
+ "application/vnd.android.package-archive",
1199
+ uploadOptions
1200
+ );
1201
+ if (!data || !data.versionCode) {
1202
+ throw new PlayApiError(
1203
+ "Upload succeeded but no APK data returned",
1204
+ "API_EMPTY_RESPONSE",
1205
+ 200,
1206
+ "This is unexpected. Retry the upload or contact Google Play support if the issue persists."
1207
+ );
1208
+ }
1209
+ return data;
1210
+ },
1060
1211
  async addExternallyHosted(packageName, editId, apkData) {
1061
1212
  const { data } = await http.post(
1062
1213
  `/${packageName}/edits/${editId}/apks/externallyHosted`,
@@ -1134,6 +1285,36 @@ function createApiClient(options) {
1134
1285
  return data.deleted || [];
1135
1286
  }
1136
1287
  },
1288
+ expansionFiles: {
1289
+ async get(packageName, editId, apkVersionCode, expansionFileType) {
1290
+ const { data } = await http.get(
1291
+ `/${packageName}/edits/${editId}/apks/${apkVersionCode}/expansionFiles/${expansionFileType}`
1292
+ );
1293
+ return data;
1294
+ },
1295
+ async update(packageName, editId, apkVersionCode, expansionFileType, body) {
1296
+ const { data } = await http.put(
1297
+ `/${packageName}/edits/${editId}/apks/${apkVersionCode}/expansionFiles/${expansionFileType}`,
1298
+ body
1299
+ );
1300
+ return data;
1301
+ },
1302
+ async patch(packageName, editId, apkVersionCode, expansionFileType, body) {
1303
+ const { data } = await http.patch(
1304
+ `/${packageName}/edits/${editId}/apks/${apkVersionCode}/expansionFiles/${expansionFileType}`,
1305
+ body
1306
+ );
1307
+ return data;
1308
+ },
1309
+ async upload(packageName, editId, apkVersionCode, expansionFileType, filePath) {
1310
+ const { data } = await http.upload(
1311
+ `/${packageName}/edits/${editId}/apks/${apkVersionCode}/expansionFiles/${expansionFileType}`,
1312
+ filePath,
1313
+ "application/octet-stream"
1314
+ );
1315
+ return data.expansionFile;
1316
+ }
1317
+ },
1137
1318
  countryAvailability: {
1138
1319
  async get(packageName, editId, track) {
1139
1320
  const { data } = await http.get(
@@ -1154,10 +1335,10 @@ function createApiClient(options) {
1154
1335
  },
1155
1336
  reviews: {
1156
1337
  async list(packageName, options2) {
1157
- await rateLimit(limiter, "reviewsGet");
1158
1338
  const params = {};
1159
1339
  if (options2?.token) params["token"] = options2.token;
1160
1340
  if (options2?.maxResults) params["maxResults"] = String(options2.maxResults);
1341
+ if (options2?.startIndex !== void 0) params["startIndex"] = String(options2.startIndex);
1161
1342
  if (options2?.translationLanguage)
1162
1343
  params["translationLanguage"] = options2.translationLanguage;
1163
1344
  const hasParams = Object.keys(params).length > 0;
@@ -1168,7 +1349,6 @@ function createApiClient(options) {
1168
1349
  return data;
1169
1350
  },
1170
1351
  async get(packageName, reviewId, translationLanguage) {
1171
- await rateLimit(limiter, "reviewsGet");
1172
1352
  const params = {};
1173
1353
  if (translationLanguage) params["translationLanguage"] = translationLanguage;
1174
1354
  const hasParams = Object.keys(params).length > 0;
@@ -1179,7 +1359,6 @@ function createApiClient(options) {
1179
1359
  return data;
1180
1360
  },
1181
1361
  async reply(packageName, reviewId, replyText) {
1182
- await rateLimit(limiter, "reviewsPost");
1183
1362
  const body = { replyText };
1184
1363
  const { data } = await http.post(
1185
1364
  `/${packageName}/reviews/${reviewId}:reply`,
@@ -1204,18 +1383,19 @@ function createApiClient(options) {
1204
1383
  const { data } = await http.get(`/${packageName}/subscriptions/${productId}`);
1205
1384
  return data;
1206
1385
  },
1207
- async create(packageName, body, productId) {
1386
+ async create(packageName, body, productId, regionsVersion) {
1208
1387
  const params = {};
1209
1388
  if (productId) params["productId"] = productId;
1210
- params["regionsVersion.version"] = "2022/02";
1389
+ params["regionsVersion.version"] = regionsVersion || DEFAULT_REGIONS_VERSION;
1211
1390
  const path = `/${packageName}/subscriptions?${new URLSearchParams(params).toString()}`;
1212
1391
  const { data } = await http.post(path, body);
1213
1392
  return data;
1214
1393
  },
1215
- async update(packageName, productId, body, updateMask, regionsVersion) {
1394
+ async update(packageName, productId, body, updateMask, regionsVersion, options2) {
1216
1395
  const params = {};
1217
1396
  if (updateMask) params["updateMask"] = updateMask;
1218
- params["regionsVersion.version"] = regionsVersion || "2022/02";
1397
+ params["regionsVersion.version"] = regionsVersion || DEFAULT_REGIONS_VERSION;
1398
+ applyMutationOptions(params, options2);
1219
1399
  const path = `/${packageName}/subscriptions/${productId}?${new URLSearchParams(params).toString()}`;
1220
1400
  const { data } = await http.patch(path, body);
1221
1401
  return data;
@@ -1271,18 +1451,19 @@ function createApiClient(options) {
1271
1451
  );
1272
1452
  return data;
1273
1453
  },
1274
- async createOffer(packageName, productId, basePlanId, body, offerId) {
1454
+ async createOffer(packageName, productId, basePlanId, body, offerId, regionsVersion) {
1275
1455
  const params = {};
1276
1456
  if (offerId) params["offerId"] = offerId;
1277
- params["regionsVersion.version"] = "2022/02";
1457
+ params["regionsVersion.version"] = regionsVersion || DEFAULT_REGIONS_VERSION;
1278
1458
  const path = `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers?${new URLSearchParams(params).toString()}`;
1279
1459
  const { data } = await http.post(path, body);
1280
1460
  return data;
1281
1461
  },
1282
- async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask, regionsVersion) {
1462
+ async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask, regionsVersion, options2) {
1283
1463
  const params = {};
1284
1464
  if (updateMask) params["updateMask"] = updateMask;
1285
- params["regionsVersion.version"] = regionsVersion || "2022/02";
1465
+ params["regionsVersion.version"] = regionsVersion || DEFAULT_REGIONS_VERSION;
1466
+ applyMutationOptions(params, options2);
1286
1467
  const path = `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}?${new URLSearchParams(params).toString()}`;
1287
1468
  const { data } = await http.patch(path, body);
1288
1469
  return data;
@@ -1303,6 +1484,34 @@ function createApiClient(options) {
1303
1484
  `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:deactivate`
1304
1485
  );
1305
1486
  return data;
1487
+ },
1488
+ async batchUpdateBasePlanStates(packageName, productId, requests) {
1489
+ const { data } = await http.post(
1490
+ `/${packageName}/subscriptions/${productId}/basePlans:batchUpdateStates`,
1491
+ requests
1492
+ );
1493
+ return data;
1494
+ },
1495
+ async batchGetOffers(packageName, productId, basePlanId, offerIds) {
1496
+ const { data } = await http.post(
1497
+ `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers:batchGet`,
1498
+ { requests: offerIds.map((id) => ({ offerId: id })) }
1499
+ );
1500
+ return data;
1501
+ },
1502
+ async batchUpdateOffers(packageName, productId, basePlanId, requests) {
1503
+ const { data } = await http.post(
1504
+ `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers:batchUpdate`,
1505
+ requests
1506
+ );
1507
+ return data;
1508
+ },
1509
+ async batchUpdateOfferStates(packageName, productId, basePlanId, requests) {
1510
+ const { data } = await http.post(
1511
+ `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers:batchUpdateStates`,
1512
+ requests
1513
+ );
1514
+ return data;
1306
1515
  }
1307
1516
  },
1308
1517
  inappproducts: {
@@ -1443,11 +1652,11 @@ function createApiClient(options) {
1443
1652
  return data;
1444
1653
  },
1445
1654
  async listVoided(packageName, options2) {
1446
- await rateLimit(limiter, "voidedBurst");
1447
- await rateLimit(limiter, "voidedDaily");
1448
1655
  const params = {};
1449
1656
  if (options2?.startTime) params["startTime"] = options2.startTime;
1450
1657
  if (options2?.endTime) params["endTime"] = options2.endTime;
1658
+ if (options2?.type !== void 0) params["type"] = String(options2.type);
1659
+ if (options2?.includeQuantityBasedPartialRefund) params["includeQuantityBasedPartialRefund"] = "true";
1451
1660
  if (options2?.maxResults) params["maxResults"] = String(options2.maxResults);
1452
1661
  if (options2?.token) params["token"] = options2.token;
1453
1662
  const hasParams = Object.keys(params).length > 0;
@@ -1510,9 +1719,10 @@ function createApiClient(options) {
1510
1719
  }
1511
1720
  },
1512
1721
  deobfuscation: {
1513
- async upload(packageName, editId, versionCode, filePath) {
1722
+ async upload(packageName, editId, versionCode, filePath, fileType) {
1723
+ const deobType = fileType || "proguard";
1514
1724
  const { data } = await http.upload(
1515
- `/${packageName}/edits/${editId}/apks/${versionCode}/deobfuscationFiles/proguard`,
1725
+ `/${packageName}/edits/${editId}/apks/${versionCode}/deobfuscationFiles/${deobType}`,
1516
1726
  filePath,
1517
1727
  "application/octet-stream"
1518
1728
  );
@@ -1603,9 +1813,14 @@ function createApiClient(options) {
1603
1813
  }
1604
1814
  },
1605
1815
  oneTimeProducts: {
1606
- async list(packageName) {
1816
+ async list(packageName, options2) {
1817
+ const params = {};
1818
+ if (options2?.pageToken) params["pageToken"] = options2.pageToken;
1819
+ if (options2?.pageSize) params["pageSize"] = String(options2.pageSize);
1820
+ const hasParams = Object.keys(params).length > 0;
1607
1821
  const { data } = await http.get(
1608
- `/${packageName}/oneTimeProducts`
1822
+ `/${packageName}/oneTimeProducts`,
1823
+ hasParams ? params : void 0
1609
1824
  );
1610
1825
  return data;
1611
1826
  },
@@ -1615,18 +1830,19 @@ function createApiClient(options) {
1615
1830
  );
1616
1831
  return data;
1617
1832
  },
1618
- async create(packageName, body) {
1619
- const params = new URLSearchParams({ "regionsVersion.version": "2022/02" });
1833
+ async create(packageName, body, regionsVersion) {
1834
+ const params = new URLSearchParams({ "regionsVersion.version": regionsVersion || DEFAULT_REGIONS_VERSION });
1620
1835
  const { data } = await http.post(
1621
1836
  `/${packageName}/oneTimeProducts?${params.toString()}`,
1622
1837
  body
1623
1838
  );
1624
1839
  return data;
1625
1840
  },
1626
- async update(packageName, productId, body, updateMask, regionsVersion) {
1841
+ async update(packageName, productId, body, updateMask, regionsVersion, options2) {
1627
1842
  const params = {};
1628
1843
  if (updateMask) params["updateMask"] = updateMask;
1629
- params["regionsVersion.version"] = regionsVersion || "2022/02";
1844
+ params["regionsVersion.version"] = regionsVersion || DEFAULT_REGIONS_VERSION;
1845
+ applyMutationOptions(params, options2);
1630
1846
  const path = `/${packageName}/oneTimeProducts/${productId}?${new URLSearchParams(params).toString()}`;
1631
1847
  const { data } = await http.patch(path, body);
1632
1848
  return data;
@@ -1646,23 +1862,45 @@ function createApiClient(options) {
1646
1862
  );
1647
1863
  return data;
1648
1864
  },
1649
- async createOffer(packageName, productId, body) {
1865
+ async createOffer(packageName, productId, body, regionsVersion) {
1866
+ const params = new URLSearchParams({ "regionsVersion.version": regionsVersion || DEFAULT_REGIONS_VERSION });
1650
1867
  const { data } = await http.post(
1651
- `/${packageName}/oneTimeProducts/${productId}/offers`,
1868
+ `/${packageName}/oneTimeProducts/${productId}/offers?${params.toString()}`,
1652
1869
  body
1653
1870
  );
1654
1871
  return data;
1655
1872
  },
1656
- async updateOffer(packageName, productId, offerId, body, updateMask, regionsVersion) {
1873
+ async updateOffer(packageName, productId, offerId, body, updateMask, regionsVersion, options2) {
1657
1874
  const params = {};
1658
1875
  if (updateMask) params["updateMask"] = updateMask;
1659
- params["regionsVersion.version"] = regionsVersion || "2022/02";
1876
+ params["regionsVersion.version"] = regionsVersion || DEFAULT_REGIONS_VERSION;
1877
+ applyMutationOptions(params, options2);
1660
1878
  const path = `/${packageName}/oneTimeProducts/${productId}/offers/${offerId}?${new URLSearchParams(params).toString()}`;
1661
1879
  const { data } = await http.patch(path, body);
1662
1880
  return data;
1663
1881
  },
1664
1882
  async deleteOffer(packageName, productId, offerId) {
1665
1883
  await http.delete(`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`);
1884
+ },
1885
+ async batchGet(packageName, productIds) {
1886
+ const params = productIds.map((id) => `productIds=${encodeURIComponent(id)}`).join("&");
1887
+ const { data } = await http.get(
1888
+ `/${packageName}/oneTimeProducts:batchGet?${params}`
1889
+ );
1890
+ return data.oneTimeProducts || [];
1891
+ },
1892
+ async batchUpdate(packageName, requests) {
1893
+ const { data } = await http.post(
1894
+ `/${packageName}/oneTimeProducts:batchUpdate`,
1895
+ requests
1896
+ );
1897
+ return data;
1898
+ },
1899
+ async batchDelete(packageName, productIds) {
1900
+ await http.post(
1901
+ `/${packageName}/oneTimeProducts:batchDelete`,
1902
+ { requests: productIds.map((id) => ({ productId: id })) }
1903
+ );
1666
1904
  }
1667
1905
  },
1668
1906
  purchaseOptions: {
@@ -1727,69 +1965,6 @@ function createApiClient(options) {
1727
1965
  };
1728
1966
  }
1729
1967
 
1730
- // src/rate-limiter.ts
1731
- var RATE_LIMIT_BUCKETS = {
1732
- default: { name: "default", maxTokens: 200, refillRate: 200, refillIntervalMs: 1e3 },
1733
- reviewsGet: { name: "reviewsGet", maxTokens: 200, refillRate: 200, refillIntervalMs: 36e5 },
1734
- reviewsPost: {
1735
- name: "reviewsPost",
1736
- maxTokens: 2e3,
1737
- refillRate: 2e3,
1738
- refillIntervalMs: 864e5
1739
- },
1740
- voidedBurst: { name: "voidedBurst", maxTokens: 30, refillRate: 30, refillIntervalMs: 3e4 },
1741
- voidedDaily: {
1742
- name: "voidedDaily",
1743
- maxTokens: 6e3,
1744
- refillRate: 6e3,
1745
- refillIntervalMs: 864e5
1746
- },
1747
- reporting: { name: "reporting", maxTokens: 10, refillRate: 10, refillIntervalMs: 1e3 }
1748
- };
1749
- function createRateLimiter(buckets) {
1750
- const states = /* @__PURE__ */ new Map();
1751
- if (buckets) {
1752
- for (const bucket of buckets) {
1753
- states.set(bucket.name, {
1754
- tokens: bucket.maxTokens,
1755
- lastRefillTime: Date.now(),
1756
- config: bucket
1757
- });
1758
- }
1759
- }
1760
- return {
1761
- async acquire(bucket) {
1762
- const state = states.get(bucket);
1763
- if (!state) return;
1764
- const now = Date.now();
1765
- const elapsed = now - state.lastRefillTime;
1766
- const refill = Math.floor(
1767
- elapsed / state.config.refillIntervalMs * state.config.refillRate
1768
- );
1769
- if (refill > 0) {
1770
- state.tokens = Math.min(state.config.maxTokens, state.tokens + refill);
1771
- state.lastRefillTime = now;
1772
- }
1773
- if (state.tokens > 0) {
1774
- state.tokens--;
1775
- return;
1776
- }
1777
- const tokensNeeded = 1;
1778
- const waitMs = Math.ceil(
1779
- tokensNeeded / state.config.refillRate * state.config.refillIntervalMs
1780
- );
1781
- await new Promise((r) => setTimeout(r, waitMs));
1782
- const afterWait = Date.now();
1783
- const totalElapsed = afterWait - state.lastRefillTime;
1784
- const newTokens = Math.floor(
1785
- totalElapsed / state.config.refillIntervalMs * state.config.refillRate
1786
- );
1787
- state.tokens = Math.min(state.config.maxTokens, newTokens) - 1;
1788
- state.lastRefillTime = afterWait;
1789
- }
1790
- };
1791
- }
1792
-
1793
1968
  // src/reporting-client.ts
1794
1969
  var REPORTING_BASE_URL = "https://playdeveloperreporting.googleapis.com/v1beta1";
1795
1970
  function createReportingClient(options) {
@@ -2038,6 +2213,7 @@ export {
2038
2213
  createUsersClient,
2039
2214
  paginate,
2040
2215
  paginateAll,
2041
- paginateParallel
2216
+ paginateParallel,
2217
+ resolveBucket
2042
2218
  };
2043
2219
  //# sourceMappingURL=index.js.map