@gpc-cli/api 1.0.25 → 1.0.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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Typed Google Play Developer API v3 client for TypeScript. Part of [GPC](https://github.com/yasserstudio/gpc).
4
4
 
5
- The entire Google Play Developer API in one typed client — 187 endpoints covering edits, releases, tracks, listings, images, subscriptions, in-app products, purchases, reviews, vitals, reports, users, and testers. Built-in rate limiting, retry logic, and pagination. Works with your existing service account — no new credentials required.
5
+ The entire Google Play Developer API in one typed client — 204 endpoints covering edits, releases, tracks, listings, images, subscriptions, in-app products, purchases, reviews, vitals, reports, users, and testers. Built-in rate limiting, retry logic, and pagination. Works with your existing service account — no new credentials required.
6
6
 
7
7
  ## Install
8
8
 
package/dist/index.d.ts CHANGED
@@ -7,7 +7,20 @@ interface RateLimitBucket {
7
7
  interface RateLimiter {
8
8
  acquire(bucket: string): Promise<void>;
9
9
  }
10
+ /**
11
+ * Google Play Developer API quota model (as of 2025):
12
+ * - 200,000 queries per day total
13
+ * - 6 independent per-minute buckets at 3,000 queries/min each
14
+ *
15
+ * The per-minute buckets are the practical constraint for CLI usage.
16
+ * Daily limits are tracked locally via gpc quota.
17
+ */
10
18
  declare const RATE_LIMIT_BUCKETS: Record<string, RateLimitBucket>;
19
+ /**
20
+ * Map an API path to the appropriate rate-limit bucket.
21
+ * Google's quota is structured by resource type.
22
+ */
23
+ declare function resolveBucket(path: string): string;
11
24
  declare function createRateLimiter(buckets?: RateLimitBucket[]): RateLimiter;
12
25
 
13
26
  interface RetryLogEntry {
@@ -127,6 +140,10 @@ interface ApkInfo {
127
140
  sha256: string;
128
141
  };
129
142
  }
143
+ interface ApksListResponse {
144
+ apks: ApkInfo[];
145
+ kind?: string;
146
+ }
130
147
  interface DeobfuscationFile {
131
148
  symbolType: string;
132
149
  }
@@ -508,12 +525,14 @@ interface SubscriptionDeferResponse {
508
525
  newExpiryTimeMillis: string;
509
526
  }
510
527
  interface VoidedPurchase {
528
+ kind?: string;
511
529
  purchaseToken: string;
512
530
  purchaseTimeMillis: string;
513
531
  voidedTimeMillis: string;
514
532
  orderId: string;
515
533
  voidedSource: number;
516
534
  voidedReason: number;
535
+ voidedQuantity?: number;
517
536
  }
518
537
  interface VoidedPurchasesListResponse {
519
538
  voidedPurchases: VoidedPurchase[];
@@ -990,6 +1009,8 @@ interface PlayApiClient {
990
1009
  list(packageName: string, track: string): Promise<ReleaseSummary[]>;
991
1010
  };
992
1011
  apks: {
1012
+ list(packageName: string, editId: string): Promise<ApkInfo[]>;
1013
+ upload(packageName: string, editId: string, filePath: string, uploadOptions?: ResumableUploadOptions): Promise<ApkInfo>;
993
1014
  addExternallyHosted(packageName: string, editId: string, data: ExternallyHostedApk): Promise<ExternallyHostedApkResponse>;
994
1015
  };
995
1016
  listings: {
@@ -1040,6 +1061,38 @@ interface PlayApiClient {
1040
1061
  deleteOffer(packageName: string, productId: string, basePlanId: string, offerId: string): Promise<void>;
1041
1062
  activateOffer(packageName: string, productId: string, basePlanId: string, offerId: string): Promise<SubscriptionOffer>;
1042
1063
  deactivateOffer(packageName: string, productId: string, basePlanId: string, offerId: string): Promise<SubscriptionOffer>;
1064
+ batchUpdateBasePlanStates(packageName: string, productId: string, requests: {
1065
+ requests: Array<{
1066
+ activateBasePlanRequest?: {
1067
+ basePlanId: string;
1068
+ };
1069
+ deactivateBasePlanRequest?: {
1070
+ basePlanId: string;
1071
+ };
1072
+ }>;
1073
+ }): Promise<Subscription>;
1074
+ batchGetOffers(packageName: string, productId: string, basePlanId: string, offerIds: string[]): Promise<{
1075
+ subscriptionOffers: SubscriptionOffer[];
1076
+ }>;
1077
+ batchUpdateOffers(packageName: string, productId: string, basePlanId: string, requests: {
1078
+ requests: Array<{
1079
+ subscriptionOffer: Partial<SubscriptionOffer>;
1080
+ updateMask?: string;
1081
+ regionsVersion?: string;
1082
+ }>;
1083
+ }): Promise<{
1084
+ subscriptionOffers: SubscriptionOffer[];
1085
+ }>;
1086
+ batchUpdateOfferStates(packageName: string, productId: string, basePlanId: string, requests: {
1087
+ requests: Array<{
1088
+ activateSubscriptionOfferRequest?: {
1089
+ offerId: string;
1090
+ };
1091
+ deactivateSubscriptionOfferRequest?: {
1092
+ offerId: string;
1093
+ };
1094
+ }>;
1095
+ }): Promise<Subscription>;
1043
1096
  };
1044
1097
  inappproducts: {
1045
1098
  list(packageName: string, options?: {
@@ -1083,6 +1136,8 @@ interface PlayApiClient {
1083
1136
  listVoided(packageName: string, options?: {
1084
1137
  startTime?: string;
1085
1138
  endTime?: string;
1139
+ type?: number;
1140
+ includeQuantityBasedPartialRefund?: boolean;
1086
1141
  maxResults?: number;
1087
1142
  token?: string;
1088
1143
  }): Promise<VoidedPurchasesListResponse>;
@@ -1137,6 +1192,17 @@ interface PlayApiClient {
1137
1192
  createOffer(packageName: string, productId: string, offer: OneTimeOffer): Promise<OneTimeOffer>;
1138
1193
  updateOffer(packageName: string, productId: string, offerId: string, offer: Partial<OneTimeOffer>, updateMask?: string, regionsVersion?: string): Promise<OneTimeOffer>;
1139
1194
  deleteOffer(packageName: string, productId: string, offerId: string): Promise<void>;
1195
+ batchGet(packageName: string, productIds: string[]): Promise<OneTimeProduct[]>;
1196
+ batchUpdate(packageName: string, requests: {
1197
+ requests: Array<{
1198
+ oneTimeProduct: Partial<OneTimeProduct>;
1199
+ updateMask?: string;
1200
+ regionsVersion?: string;
1201
+ }>;
1202
+ }): Promise<{
1203
+ oneTimeProducts: OneTimeProduct[];
1204
+ }>;
1205
+ batchDelete(packageName: string, productIds: string[]): Promise<void>;
1140
1206
  };
1141
1207
  purchaseOptions: {
1142
1208
  list(packageName: string): Promise<PurchaseOptionsListResponse>;
@@ -1329,4 +1395,4 @@ declare class PlayApiError extends Error {
1329
1395
  /** Files below this threshold use simple upload instead. */
1330
1396
  declare const RESUMABLE_THRESHOLD: number;
1331
1397
 
1332
- export { type Achievement, type Anomaly, type AnomalyDetectionResponse, type ApiClientOptions, type ApiResponse, type ApkInfo, type AppDetails, type AppEdit, type AppRecoveriesListResponse, type AppRecoveryAction, type AppRecoveryTargeting, type BasePlan, type BasePlanMigratePricesRequest, type BatchGetOrdersResponse, type Bundle, type BundleListResponse, type ConvertRegionPricesRequest, type ConvertRegionPricesResponse, type ConvertedRegionPrice, type CountryAvailability, type CreateAppRecoveryActionRequest, type CustomApp, type CustomAppsListResponse, type DataSafety, type DataSafetyDataType, type DataSafetyPurpose, type DeobfuscationFile, type DeobfuscationUploadResponse, type DeveloperComment, type DeveloperPermission, type DeviceGroup, type DeviceSelector, type DeviceTier, type DeviceTierConfig, type DeviceTierConfigsListResponse, type EnterpriseApiClient, type ErrorIssue, type ErrorIssuesResponse, type ErrorReport, type ErrorReportsResponse, type ExternalTransaction, type ExternalTransactionAmount, type ExternalTransactionRefund, type ExternallyHostedApk, type ExternallyHostedApkResponse, type GameEvent, type GamesApiClient, type GeneratedApk, type GeneratedApksPerVersion, type Grant, type GrantsListResponse, type HttpClient, type Image, type ImageType, type ImageUploadResponse, type ImagesDeleteAllResponse, type ImagesListResponse, type InAppProduct, type InAppProductListing, type InAppProductsBatchDeleteRequest, type InAppProductsBatchGetRequest, type InAppProductsBatchUpdateRequest, type InAppProductsBatchUpdateResponse, type InAppProductsListResponse, type InternalAppSharingArtifact, type Leaderboard, type LeaderboardScore, type Listing, type ListingsListResponse, type MetricRow, type MetricSetQuery, type MetricSetResponse, type Money, type OffersListResponse, type OneTimeOffer, type OneTimeOfferRegionalConfig, type OneTimeOffersListResponse, type OneTimeProduct, type OneTimeProductListing, type OneTimeProductsListResponse, type Order, type OrderLineItem, type PagedResponse, type PaginateOptions, type PlayApiClient, PlayApiError, type ProductPurchase, type ProductPurchaseLineItem, type ProductPurchaseV2, type PurchaseOption, type PurchaseOptionsListResponse, RATE_LIMIT_BUCKETS, RESUMABLE_THRESHOLD, type RateLimitBucket, type RateLimiter, type RegionalBasePlanConfig, type Release, type ReleaseNote, type ReleaseStatus, type ReleaseSummary, type ReleasesListResponse, type ReportBucket, type ReportType, type ReportingAggregation, type ReportingApiClient, type ReportingDimension, type ReportsListResponse, type ResumableUploadOptions, type RetryLogEntry, type Review, type ReviewComment, type ReviewReplyRequest, type ReviewReplyResponse, type ReviewsListOptions, type ReviewsListResponse, type StatsDimension, type Subscription, type SubscriptionDeferRequest, type SubscriptionDeferResponse, type SubscriptionListing, type SubscriptionOffer, type SubscriptionOfferPhase, type SubscriptionPurchase, type SubscriptionPurchaseLineItem, type SubscriptionPurchaseV2, type SubscriptionsBatchGetRequest, type SubscriptionsBatchGetResponse, type SubscriptionsBatchUpdateRequest, type SubscriptionsBatchUpdateResponse, type SubscriptionsListResponse, type SubscriptionsV2CancelRequest, type SubscriptionsV2DeferRequest, type SubscriptionsV2DeferResponse, type TaxAndComplianceSettings, type Testers, type TokenPagination, type Track, type TrackListResponse, type UploadProgressEvent, type UploadResponse, type User, type UserComment, type UsersApiClient, type UsersListResponse, type VitalsMetricSet, type VoidedPurchase, type VoidedPurchasesListResponse, createApiClient, createEnterpriseClient, createGamesClient, createHttpClient, createRateLimiter, createReportingClient, createUsersClient, paginate, paginateAll, paginateParallel };
1398
+ export { type Achievement, type Anomaly, type AnomalyDetectionResponse, type ApiClientOptions, type ApiResponse, type ApkInfo, type ApksListResponse, type AppDetails, type AppEdit, type AppRecoveriesListResponse, type AppRecoveryAction, type AppRecoveryTargeting, type BasePlan, type BasePlanMigratePricesRequest, type BatchGetOrdersResponse, type Bundle, type BundleListResponse, type ConvertRegionPricesRequest, type ConvertRegionPricesResponse, type ConvertedRegionPrice, type CountryAvailability, type CreateAppRecoveryActionRequest, type CustomApp, type CustomAppsListResponse, type DataSafety, type DataSafetyDataType, type DataSafetyPurpose, type DeobfuscationFile, type DeobfuscationUploadResponse, type DeveloperComment, type DeveloperPermission, type DeviceGroup, type DeviceSelector, type DeviceTier, type DeviceTierConfig, type DeviceTierConfigsListResponse, type EnterpriseApiClient, type ErrorIssue, type ErrorIssuesResponse, type ErrorReport, type ErrorReportsResponse, type ExternalTransaction, type ExternalTransactionAmount, type ExternalTransactionRefund, type ExternallyHostedApk, type ExternallyHostedApkResponse, type GameEvent, type GamesApiClient, type GeneratedApk, type GeneratedApksPerVersion, type Grant, type GrantsListResponse, type HttpClient, type Image, type ImageType, type ImageUploadResponse, type ImagesDeleteAllResponse, type ImagesListResponse, type InAppProduct, type InAppProductListing, type InAppProductsBatchDeleteRequest, type InAppProductsBatchGetRequest, type InAppProductsBatchUpdateRequest, type InAppProductsBatchUpdateResponse, type InAppProductsListResponse, type InternalAppSharingArtifact, type Leaderboard, type LeaderboardScore, type Listing, type ListingsListResponse, type MetricRow, type MetricSetQuery, type MetricSetResponse, type Money, type OffersListResponse, type OneTimeOffer, type OneTimeOfferRegionalConfig, type OneTimeOffersListResponse, type OneTimeProduct, type OneTimeProductListing, type OneTimeProductsListResponse, type Order, type OrderLineItem, type PagedResponse, type PaginateOptions, type PlayApiClient, PlayApiError, type ProductPurchase, type ProductPurchaseLineItem, type ProductPurchaseV2, type PurchaseOption, type PurchaseOptionsListResponse, RATE_LIMIT_BUCKETS, RESUMABLE_THRESHOLD, type RateLimitBucket, type RateLimiter, type RegionalBasePlanConfig, type Release, type ReleaseNote, type ReleaseStatus, type ReleaseSummary, type ReleasesListResponse, type ReportBucket, type ReportType, type ReportingAggregation, type ReportingApiClient, type ReportingDimension, type ReportsListResponse, type ResumableUploadOptions, type RetryLogEntry, type Review, type ReviewComment, type ReviewReplyRequest, type ReviewReplyResponse, type ReviewsListOptions, type ReviewsListResponse, type StatsDimension, type Subscription, type SubscriptionDeferRequest, type SubscriptionDeferResponse, type SubscriptionListing, type SubscriptionOffer, type SubscriptionOfferPhase, type SubscriptionPurchase, type SubscriptionPurchaseLineItem, type SubscriptionPurchaseV2, type SubscriptionsBatchGetRequest, type SubscriptionsBatchGetResponse, type SubscriptionsBatchUpdateRequest, type SubscriptionsBatchUpdateResponse, type SubscriptionsListResponse, type SubscriptionsV2CancelRequest, type SubscriptionsV2DeferRequest, type SubscriptionsV2DeferResponse, type TaxAndComplianceSettings, type Testers, type TokenPagination, type Track, type TrackListResponse, type UploadProgressEvent, type UploadResponse, type User, type UserComment, type UsersApiClient, type UsersListResponse, type VitalsMetricSet, type VoidedPurchase, type VoidedPurchasesListResponse, createApiClient, createEnterpriseClient, createGamesClient, createHttpClient, createRateLimiter, createReportingClient, createUsersClient, paginate, paginateAll, paginateParallel, resolveBucket };
package/dist/index.js CHANGED
@@ -733,7 +733,8 @@ function createHttpClient(options) {
733
733
  return Math.max(timeout, 3e4 + Math.ceil(sizeMb) * 1e3);
734
734
  }
735
735
  async function uploadRequest(path, filePath, contentType, baseUrl = UPLOAD_BASE_URL) {
736
- const url = `${baseUrl}${path}`;
736
+ const separator = path.includes("?") ? "&" : "?";
737
+ const url = `${baseUrl}${path}${separator}uploadType=media`;
737
738
  const safeFilePath = validateFilePath(filePath);
738
739
  const fileBuffer = await readFile(safeFilePath);
739
740
  const effectiveTimeout = computeUploadTimeout(fileBuffer.byteLength);
@@ -942,13 +943,99 @@ function createHttpClient(options) {
942
943
  };
943
944
  }
944
945
 
946
+ // src/rate-limiter.ts
947
+ var RATE_LIMIT_BUCKETS = {
948
+ edits: { name: "edits", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
949
+ purchases: { name: "purchases", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
950
+ reviews: { name: "reviews", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
951
+ reporting: { name: "reporting", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
952
+ monetization: { name: "monetization", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 },
953
+ default: { name: "default", maxTokens: 3e3, refillRate: 3e3, refillIntervalMs: 6e4 }
954
+ };
955
+ function resolveBucket(path) {
956
+ if (path.includes("/edits/") || path.includes("/edits:")) return "edits";
957
+ if (path.includes("/purchases/") || path.includes("/orders")) return "purchases";
958
+ if (path.includes("/reviews")) return "reviews";
959
+ if (path.includes("playdeveloperreporting") || path.includes("MetricSet") || path.includes("anomalies")) return "reporting";
960
+ if (path.includes("/inappproducts") || path.includes("/oneTimeProducts") || path.includes("/subscriptions") || path.includes("/monetization")) return "monetization";
961
+ return "default";
962
+ }
963
+ function createRateLimiter(buckets) {
964
+ const states = /* @__PURE__ */ new Map();
965
+ const effectiveBuckets = buckets ?? Object.values(RATE_LIMIT_BUCKETS);
966
+ for (const bucket of effectiveBuckets) {
967
+ states.set(bucket.name, {
968
+ tokens: bucket.maxTokens,
969
+ lastRefillTime: Date.now(),
970
+ config: bucket
971
+ });
972
+ }
973
+ return {
974
+ async acquire(bucket) {
975
+ const state = states.get(bucket);
976
+ if (!state) return;
977
+ const now = Date.now();
978
+ const elapsed = now - state.lastRefillTime;
979
+ const refill = Math.floor(
980
+ elapsed / state.config.refillIntervalMs * state.config.refillRate
981
+ );
982
+ if (refill > 0) {
983
+ state.tokens = Math.min(state.config.maxTokens, state.tokens + refill);
984
+ state.lastRefillTime = now;
985
+ }
986
+ if (state.tokens > 0) {
987
+ state.tokens--;
988
+ return;
989
+ }
990
+ const tokensNeeded = 1;
991
+ const waitMs = Math.ceil(
992
+ tokensNeeded / state.config.refillRate * state.config.refillIntervalMs
993
+ );
994
+ await new Promise((r) => setTimeout(r, waitMs));
995
+ const afterWait = Date.now();
996
+ const totalElapsed = afterWait - state.lastRefillTime;
997
+ const newTokens = Math.floor(
998
+ totalElapsed / state.config.refillIntervalMs * state.config.refillRate
999
+ );
1000
+ state.tokens = Math.max(0, Math.min(state.config.maxTokens, newTokens) - 1);
1001
+ state.lastRefillTime = afterWait;
1002
+ }
1003
+ };
1004
+ }
1005
+
945
1006
  // src/client.ts
946
- async function rateLimit(limiter, bucket) {
947
- if (limiter) await limiter.acquire(bucket);
1007
+ async function autoRateLimit(limiter, path) {
1008
+ if (!limiter) return;
1009
+ const bucket = resolveBucket(path);
1010
+ await limiter.acquire(bucket);
948
1011
  }
949
1012
  function createApiClient(options) {
950
- const http = createHttpClient(options);
951
- const limiter = options.rateLimiter || void 0;
1013
+ const rawHttp = createHttpClient(options);
1014
+ const defaultLimiter = createRateLimiter();
1015
+ const limiter = options.rateLimiter || defaultLimiter;
1016
+ const http = {
1017
+ ...rawHttp,
1018
+ async get(path, params) {
1019
+ await autoRateLimit(limiter, path);
1020
+ return rawHttp.get(path, params);
1021
+ },
1022
+ async post(path, body) {
1023
+ await autoRateLimit(limiter, path);
1024
+ return rawHttp.post(path, body);
1025
+ },
1026
+ async put(path, body) {
1027
+ await autoRateLimit(limiter, path);
1028
+ return rawHttp.put(path, body);
1029
+ },
1030
+ async patch(path, body) {
1031
+ await autoRateLimit(limiter, path);
1032
+ return rawHttp.patch(path, body);
1033
+ },
1034
+ async delete(path) {
1035
+ await autoRateLimit(limiter, path);
1036
+ return rawHttp.delete(path);
1037
+ }
1038
+ };
952
1039
  return {
953
1040
  edits: {
954
1041
  async insert(packageName) {
@@ -1057,6 +1144,29 @@ function createApiClient(options) {
1057
1144
  }
1058
1145
  },
1059
1146
  apks: {
1147
+ async list(packageName, editId) {
1148
+ const { data } = await http.get(
1149
+ `/${packageName}/edits/${editId}/apks`
1150
+ );
1151
+ return data.apks || [];
1152
+ },
1153
+ async upload(packageName, editId, filePath, uploadOptions) {
1154
+ const { data } = await http.uploadResumable(
1155
+ `/${packageName}/edits/${editId}/apks`,
1156
+ filePath,
1157
+ "application/vnd.android.package-archive",
1158
+ uploadOptions
1159
+ );
1160
+ if (!data || !data.versionCode) {
1161
+ throw new PlayApiError(
1162
+ "Upload succeeded but no APK data returned",
1163
+ "API_EMPTY_RESPONSE",
1164
+ 200,
1165
+ "This is unexpected. Retry the upload or contact Google Play support if the issue persists."
1166
+ );
1167
+ }
1168
+ return data;
1169
+ },
1060
1170
  async addExternallyHosted(packageName, editId, apkData) {
1061
1171
  const { data } = await http.post(
1062
1172
  `/${packageName}/edits/${editId}/apks/externallyHosted`,
@@ -1154,7 +1264,6 @@ function createApiClient(options) {
1154
1264
  },
1155
1265
  reviews: {
1156
1266
  async list(packageName, options2) {
1157
- await rateLimit(limiter, "reviewsGet");
1158
1267
  const params = {};
1159
1268
  if (options2?.token) params["token"] = options2.token;
1160
1269
  if (options2?.maxResults) params["maxResults"] = String(options2.maxResults);
@@ -1168,7 +1277,6 @@ function createApiClient(options) {
1168
1277
  return data;
1169
1278
  },
1170
1279
  async get(packageName, reviewId, translationLanguage) {
1171
- await rateLimit(limiter, "reviewsGet");
1172
1280
  const params = {};
1173
1281
  if (translationLanguage) params["translationLanguage"] = translationLanguage;
1174
1282
  const hasParams = Object.keys(params).length > 0;
@@ -1179,7 +1287,6 @@ function createApiClient(options) {
1179
1287
  return data;
1180
1288
  },
1181
1289
  async reply(packageName, reviewId, replyText) {
1182
- await rateLimit(limiter, "reviewsPost");
1183
1290
  const body = { replyText };
1184
1291
  const { data } = await http.post(
1185
1292
  `/${packageName}/reviews/${reviewId}:reply`,
@@ -1303,6 +1410,34 @@ function createApiClient(options) {
1303
1410
  `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:deactivate`
1304
1411
  );
1305
1412
  return data;
1413
+ },
1414
+ async batchUpdateBasePlanStates(packageName, productId, requests) {
1415
+ const { data } = await http.post(
1416
+ `/${packageName}/subscriptions/${productId}/basePlans:batchUpdateStates`,
1417
+ requests
1418
+ );
1419
+ return data;
1420
+ },
1421
+ async batchGetOffers(packageName, productId, basePlanId, offerIds) {
1422
+ const { data } = await http.post(
1423
+ `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers:batchGet`,
1424
+ { requests: offerIds.map((id) => ({ offerId: id })) }
1425
+ );
1426
+ return data;
1427
+ },
1428
+ async batchUpdateOffers(packageName, productId, basePlanId, requests) {
1429
+ const { data } = await http.post(
1430
+ `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers:batchUpdate`,
1431
+ requests
1432
+ );
1433
+ return data;
1434
+ },
1435
+ async batchUpdateOfferStates(packageName, productId, basePlanId, requests) {
1436
+ const { data } = await http.post(
1437
+ `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers:batchUpdateStates`,
1438
+ requests
1439
+ );
1440
+ return data;
1306
1441
  }
1307
1442
  },
1308
1443
  inappproducts: {
@@ -1443,11 +1578,11 @@ function createApiClient(options) {
1443
1578
  return data;
1444
1579
  },
1445
1580
  async listVoided(packageName, options2) {
1446
- await rateLimit(limiter, "voidedBurst");
1447
- await rateLimit(limiter, "voidedDaily");
1448
1581
  const params = {};
1449
1582
  if (options2?.startTime) params["startTime"] = options2.startTime;
1450
1583
  if (options2?.endTime) params["endTime"] = options2.endTime;
1584
+ if (options2?.type !== void 0) params["type"] = String(options2.type);
1585
+ if (options2?.includeQuantityBasedPartialRefund) params["includeQuantityBasedPartialRefund"] = "true";
1451
1586
  if (options2?.maxResults) params["maxResults"] = String(options2.maxResults);
1452
1587
  if (options2?.token) params["token"] = options2.token;
1453
1588
  const hasParams = Object.keys(params).length > 0;
@@ -1663,6 +1798,26 @@ function createApiClient(options) {
1663
1798
  },
1664
1799
  async deleteOffer(packageName, productId, offerId) {
1665
1800
  await http.delete(`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`);
1801
+ },
1802
+ async batchGet(packageName, productIds) {
1803
+ const params = productIds.map((id) => `productIds=${encodeURIComponent(id)}`).join("&");
1804
+ const { data } = await http.get(
1805
+ `/${packageName}/oneTimeProducts:batchGet?${params}`
1806
+ );
1807
+ return data.oneTimeProducts || [];
1808
+ },
1809
+ async batchUpdate(packageName, requests) {
1810
+ const { data } = await http.post(
1811
+ `/${packageName}/oneTimeProducts:batchUpdate`,
1812
+ requests
1813
+ );
1814
+ return data;
1815
+ },
1816
+ async batchDelete(packageName, productIds) {
1817
+ await http.post(
1818
+ `/${packageName}/oneTimeProducts:batchDelete`,
1819
+ { requests: productIds.map((id) => ({ productId: id })) }
1820
+ );
1666
1821
  }
1667
1822
  },
1668
1823
  purchaseOptions: {
@@ -1727,69 +1882,6 @@ function createApiClient(options) {
1727
1882
  };
1728
1883
  }
1729
1884
 
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
1885
  // src/reporting-client.ts
1794
1886
  var REPORTING_BASE_URL = "https://playdeveloperreporting.googleapis.com/v1beta1";
1795
1887
  function createReportingClient(options) {
@@ -2038,6 +2130,7 @@ export {
2038
2130
  createUsersClient,
2039
2131
  paginate,
2040
2132
  paginateAll,
2041
- paginateParallel
2133
+ paginateParallel,
2134
+ resolveBucket
2042
2135
  };
2043
2136
  //# sourceMappingURL=index.js.map