@gpc-cli/api 1.0.18 → 1.0.20
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 +35 -29
- package/dist/index.d.ts +92 -2
- package/dist/index.js +158 -42
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
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
|
-
|
|
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.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -32,12 +32,12 @@ await client.edits.delete("com.example.app", edit.id);
|
|
|
32
32
|
|
|
33
33
|
## Client Factories
|
|
34
34
|
|
|
35
|
-
| Factory
|
|
36
|
-
|
|
|
37
|
-
| `createApiClient(options)`
|
|
38
|
-
| `createReportingClient(options)` | Vitals, crash rates, ANR, error reporting
|
|
39
|
-
| `createUsersClient(options)`
|
|
40
|
-
| `createHttpClient(options)`
|
|
35
|
+
| Factory | Purpose |
|
|
36
|
+
| -------------------------------- | ------------------------------------------------------------------ |
|
|
37
|
+
| `createApiClient(options)` | Core Play API -- apps, releases, listings, monetization, purchases |
|
|
38
|
+
| `createReportingClient(options)` | Vitals, crash rates, ANR, error reporting |
|
|
39
|
+
| `createUsersClient(options)` | Developer account users and permission grants |
|
|
40
|
+
| `createHttpClient(options)` | Low-level HTTP with auth, retry, and rate limiting |
|
|
41
41
|
|
|
42
42
|
All factories accept `ApiClientOptions`:
|
|
43
43
|
|
|
@@ -45,10 +45,10 @@ All factories accept `ApiClientOptions`:
|
|
|
45
45
|
import type { ApiClientOptions } from "@gpc-cli/api";
|
|
46
46
|
|
|
47
47
|
const options: ApiClientOptions = {
|
|
48
|
-
auth,
|
|
49
|
-
maxRetries: 3,
|
|
50
|
-
timeout: 30_000,
|
|
51
|
-
rateLimiter: undefined,
|
|
48
|
+
auth, // Required: { getAccessToken(): Promise<string> }
|
|
49
|
+
maxRetries: 3, // Default retry count
|
|
50
|
+
timeout: 30_000, // Request timeout in ms
|
|
51
|
+
rateLimiter: undefined, // Optional custom rate limiter
|
|
52
52
|
onRetry: (entry) => console.warn(`Retry #${entry.attempt}: ${entry.error}`),
|
|
53
53
|
};
|
|
54
54
|
```
|
|
@@ -118,12 +118,13 @@ await client.edits.commit("com.example.app", edit.id);
|
|
|
118
118
|
const edit = await client.edits.insert("com.example.app");
|
|
119
119
|
|
|
120
120
|
const screenshots = await client.images.list(
|
|
121
|
-
"com.example.app",
|
|
121
|
+
"com.example.app",
|
|
122
|
+
edit.id,
|
|
123
|
+
"en-US",
|
|
124
|
+
"phoneScreenshots",
|
|
122
125
|
);
|
|
123
126
|
|
|
124
|
-
await client.images.upload(
|
|
125
|
-
"com.example.app", edit.id, "en-US", "featureGraphic", "./feature.png",
|
|
126
|
-
);
|
|
127
|
+
await client.images.upload("com.example.app", edit.id, "en-US", "featureGraphic", "./feature.png");
|
|
127
128
|
|
|
128
129
|
await client.images.deleteAll("com.example.app", edit.id, "en-US", "phoneScreenshots");
|
|
129
130
|
await client.edits.commit("com.example.app", edit.id);
|
|
@@ -145,15 +146,23 @@ await client.subscriptions.deactivateBasePlan("com.example.app", "premium_monthl
|
|
|
145
146
|
|
|
146
147
|
```typescript
|
|
147
148
|
const { subscriptionOffers } = await client.subscriptions.listOffers(
|
|
148
|
-
"com.example.app",
|
|
149
|
+
"com.example.app",
|
|
150
|
+
"premium_monthly",
|
|
151
|
+
"p1m",
|
|
149
152
|
);
|
|
150
153
|
|
|
151
154
|
const offer = await client.subscriptions.getOffer(
|
|
152
|
-
"com.example.app",
|
|
155
|
+
"com.example.app",
|
|
156
|
+
"premium_monthly",
|
|
157
|
+
"p1m",
|
|
158
|
+
"intro_offer",
|
|
153
159
|
);
|
|
154
160
|
|
|
155
161
|
await client.subscriptions.activateOffer(
|
|
156
|
-
"com.example.app",
|
|
162
|
+
"com.example.app",
|
|
163
|
+
"premium_monthly",
|
|
164
|
+
"p1m",
|
|
165
|
+
"intro_offer",
|
|
157
166
|
);
|
|
158
167
|
```
|
|
159
168
|
|
|
@@ -175,9 +184,7 @@ await client.inappproducts.create("com.example.app", {
|
|
|
175
184
|
|
|
176
185
|
```typescript
|
|
177
186
|
// Verify a product purchase
|
|
178
|
-
const purchase = await client.purchases.getProduct(
|
|
179
|
-
"com.example.app", "coins_100", purchaseToken,
|
|
180
|
-
);
|
|
187
|
+
const purchase = await client.purchases.getProduct("com.example.app", "coins_100", purchaseToken);
|
|
181
188
|
|
|
182
189
|
// Acknowledge it
|
|
183
190
|
await client.purchases.acknowledgeProduct("com.example.app", "coins_100", purchaseToken);
|
|
@@ -270,10 +277,9 @@ await client.edits.commit("com.example.app", edit.id);
|
|
|
270
277
|
### Monetization
|
|
271
278
|
|
|
272
279
|
```typescript
|
|
273
|
-
const { convertedRegionPrices } = await client.monetization.convertRegionPrices(
|
|
274
|
-
"
|
|
275
|
-
|
|
276
|
-
);
|
|
280
|
+
const { convertedRegionPrices } = await client.monetization.convertRegionPrices("com.example.app", {
|
|
281
|
+
price: { currencyCode: "USD", units: "9", nanos: 990_000_000 },
|
|
282
|
+
});
|
|
277
283
|
```
|
|
278
284
|
|
|
279
285
|
### Deobfuscation
|
|
@@ -347,10 +353,10 @@ try {
|
|
|
347
353
|
await client.tracks.get("com.example.app", editId, "production");
|
|
348
354
|
} catch (error) {
|
|
349
355
|
if (error instanceof ApiError) {
|
|
350
|
-
console.error(error.code);
|
|
351
|
-
console.error(error.statusCode);
|
|
352
|
-
console.error(error.suggestion);
|
|
353
|
-
console.error(error.toJSON());
|
|
356
|
+
console.error(error.code); // e.g. "API_NOT_FOUND"
|
|
357
|
+
console.error(error.statusCode); // e.g. 404
|
|
358
|
+
console.error(error.suggestion); // actionable fix
|
|
359
|
+
console.error(error.toJSON()); // structured error object
|
|
354
360
|
}
|
|
355
361
|
}
|
|
356
362
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -854,6 +854,7 @@ interface PlayApiClient {
|
|
|
854
854
|
cancelSubscription(packageName: string, subscriptionId: string, token: string): Promise<void>;
|
|
855
855
|
deferSubscription(packageName: string, subscriptionId: string, token: string, body: SubscriptionDeferRequest): Promise<SubscriptionDeferResponse>;
|
|
856
856
|
revokeSubscriptionV2(packageName: string, token: string): Promise<void>;
|
|
857
|
+
refundSubscriptionV2(packageName: string, token: string): Promise<void>;
|
|
857
858
|
listVoided(packageName: string, options?: {
|
|
858
859
|
startTime?: string;
|
|
859
860
|
endTime?: string;
|
|
@@ -935,6 +936,10 @@ interface ReportingApiClient {
|
|
|
935
936
|
}
|
|
936
937
|
declare function createReportingClient(options: ApiClientOptions): ReportingApiClient;
|
|
937
938
|
|
|
939
|
+
interface GrantsListResponse {
|
|
940
|
+
grants: Grant[];
|
|
941
|
+
nextPageToken?: string;
|
|
942
|
+
}
|
|
938
943
|
interface UsersApiClient {
|
|
939
944
|
list(developerId: string, options?: {
|
|
940
945
|
pageToken?: string;
|
|
@@ -944,9 +949,94 @@ interface UsersApiClient {
|
|
|
944
949
|
create(developerId: string, user: Partial<User>): Promise<User>;
|
|
945
950
|
update(developerId: string, userId: string, user: Partial<User>, updateMask?: string): Promise<User>;
|
|
946
951
|
delete(developerId: string, userId: string): Promise<void>;
|
|
952
|
+
grants: {
|
|
953
|
+
list(developerId: string, email: string): Promise<GrantsListResponse>;
|
|
954
|
+
create(developerId: string, email: string, grant: Partial<Grant>): Promise<Grant>;
|
|
955
|
+
patch(developerId: string, email: string, packageName: string, grant: Partial<Grant>, updateMask?: string): Promise<Grant>;
|
|
956
|
+
delete(developerId: string, email: string, packageName: string): Promise<void>;
|
|
957
|
+
};
|
|
947
958
|
}
|
|
948
959
|
declare function createUsersClient(options: ApiClientOptions): UsersApiClient;
|
|
949
960
|
|
|
961
|
+
interface Leaderboard {
|
|
962
|
+
id: string;
|
|
963
|
+
name: string;
|
|
964
|
+
order: string;
|
|
965
|
+
iconUrl?: string;
|
|
966
|
+
}
|
|
967
|
+
interface LeaderboardScore {
|
|
968
|
+
leaderboardId: string;
|
|
969
|
+
scoreValue: string;
|
|
970
|
+
formattedScore: string;
|
|
971
|
+
writeTimestamp?: string;
|
|
972
|
+
tag?: string;
|
|
973
|
+
}
|
|
974
|
+
interface Achievement {
|
|
975
|
+
id: string;
|
|
976
|
+
name: string;
|
|
977
|
+
description: string;
|
|
978
|
+
state: "REVEALED" | "HIDDEN" | "UNLOCKED";
|
|
979
|
+
currentSteps?: number;
|
|
980
|
+
totalSteps?: number;
|
|
981
|
+
experiencePoints?: number;
|
|
982
|
+
formattedCurrentStepsString?: string;
|
|
983
|
+
}
|
|
984
|
+
interface GameEvent {
|
|
985
|
+
definitionId: string;
|
|
986
|
+
numEvents: string;
|
|
987
|
+
formattedNumEvents: string;
|
|
988
|
+
kind?: string;
|
|
989
|
+
}
|
|
990
|
+
interface GamesApiClient {
|
|
991
|
+
leaderboards: {
|
|
992
|
+
list(packageName: string): Promise<{
|
|
993
|
+
items?: Leaderboard[];
|
|
994
|
+
nextPageToken?: string;
|
|
995
|
+
}>;
|
|
996
|
+
get(packageName: string, leaderboardId: string): Promise<Leaderboard>;
|
|
997
|
+
getScores(packageName: string, leaderboardId: string, collection: string, timeSpan: string): Promise<{
|
|
998
|
+
items?: LeaderboardScore[];
|
|
999
|
+
}>;
|
|
1000
|
+
};
|
|
1001
|
+
achievements: {
|
|
1002
|
+
list(packageName: string): Promise<{
|
|
1003
|
+
items?: Achievement[];
|
|
1004
|
+
nextPageToken?: string;
|
|
1005
|
+
}>;
|
|
1006
|
+
reveal(packageName: string, achievementId: string): Promise<{
|
|
1007
|
+
currentState: string;
|
|
1008
|
+
}>;
|
|
1009
|
+
};
|
|
1010
|
+
events: {
|
|
1011
|
+
list(packageName: string): Promise<{
|
|
1012
|
+
items?: GameEvent[];
|
|
1013
|
+
nextPageToken?: string;
|
|
1014
|
+
}>;
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
declare function createGamesClient(options: ApiClientOptions): GamesApiClient;
|
|
1018
|
+
|
|
1019
|
+
interface CustomApp {
|
|
1020
|
+
packageName?: string;
|
|
1021
|
+
title: string;
|
|
1022
|
+
languageCode?: string;
|
|
1023
|
+
organizations?: Array<{
|
|
1024
|
+
organizationId: string;
|
|
1025
|
+
organizationName?: string;
|
|
1026
|
+
}>;
|
|
1027
|
+
}
|
|
1028
|
+
interface CustomAppsListResponse {
|
|
1029
|
+
customApps?: CustomApp[];
|
|
1030
|
+
nextPageToken?: string;
|
|
1031
|
+
}
|
|
1032
|
+
interface EnterpriseApiClient {
|
|
1033
|
+
apps: {
|
|
1034
|
+
create(organizationId: string, app: Partial<CustomApp>): Promise<CustomApp>;
|
|
1035
|
+
list(organizationId: string): Promise<CustomAppsListResponse>;
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
declare function createEnterpriseClient(options: ApiClientOptions): EnterpriseApiClient;
|
|
1039
|
+
|
|
950
1040
|
interface HttpClient {
|
|
951
1041
|
get<T>(path: string, params?: Record<string, string>): Promise<ApiResponse<T>>;
|
|
952
1042
|
post<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;
|
|
@@ -991,7 +1081,7 @@ declare function paginateParallel<TItem>(fetchPage: (pageToken?: string) => Prom
|
|
|
991
1081
|
nextPageToken?: string;
|
|
992
1082
|
}>;
|
|
993
1083
|
|
|
994
|
-
declare class
|
|
1084
|
+
declare class PlayApiError extends Error {
|
|
995
1085
|
readonly code: string;
|
|
996
1086
|
readonly statusCode?: number | undefined;
|
|
997
1087
|
readonly suggestion?: string | undefined;
|
|
@@ -1007,4 +1097,4 @@ declare class ApiError extends Error {
|
|
|
1007
1097
|
};
|
|
1008
1098
|
}
|
|
1009
1099
|
|
|
1010
|
-
export { type Anomaly, type AnomalyDetectionResponse, type ApiClientOptions,
|
|
1100
|
+
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 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 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 PagedResponse, type PaginateOptions, type PlayApiClient, PlayApiError, type ProductPurchase, type PurchaseOption, type PurchaseOptionsListResponse, RATE_LIMIT_BUCKETS, type RateLimitBucket, type RateLimiter, type RegionalBasePlanConfig, type Release, type ReleaseNote, type ReleaseStatus, type ReportBucket, type ReportType, type ReportingAggregation, type ReportingApiClient, type ReportingDimension, type ReportsListResponse, 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 SubscriptionsListResponse, type TaxAndComplianceSettings, type Testers, type TokenPagination, type Track, type TrackListResponse, 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 };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// src/errors.ts
|
|
2
|
-
var
|
|
2
|
+
var PlayApiError = class extends Error {
|
|
3
3
|
constructor(message, code, statusCode, suggestion) {
|
|
4
4
|
super(message);
|
|
5
5
|
this.code = code;
|
|
6
6
|
this.statusCode = statusCode;
|
|
7
7
|
this.suggestion = suggestion;
|
|
8
|
-
this.name = "
|
|
8
|
+
this.name = "PlayApiError";
|
|
9
9
|
}
|
|
10
10
|
exitCode = 4;
|
|
11
11
|
toJSON() {
|
|
@@ -40,7 +40,7 @@ function sanitizeErrorBody(body) {
|
|
|
40
40
|
function validateFilePath(filePath) {
|
|
41
41
|
const resolved = resolve(filePath);
|
|
42
42
|
if (!isAbsolute(resolved)) {
|
|
43
|
-
throw new
|
|
43
|
+
throw new PlayApiError(
|
|
44
44
|
"Invalid file path",
|
|
45
45
|
"API_INVALID_PATH",
|
|
46
46
|
void 0,
|
|
@@ -48,7 +48,12 @@ function validateFilePath(filePath) {
|
|
|
48
48
|
);
|
|
49
49
|
}
|
|
50
50
|
if (filePath.includes("\0")) {
|
|
51
|
-
throw new
|
|
51
|
+
throw new PlayApiError(
|
|
52
|
+
"Invalid file path: null bytes not allowed",
|
|
53
|
+
"API_INVALID_PATH",
|
|
54
|
+
void 0,
|
|
55
|
+
"Provide a valid file path without null bytes."
|
|
56
|
+
);
|
|
52
57
|
}
|
|
53
58
|
return resolved;
|
|
54
59
|
}
|
|
@@ -64,8 +69,21 @@ function envInt(name) {
|
|
|
64
69
|
function resolveOption(explicit, envName, fallback) {
|
|
65
70
|
return explicit ?? envInt(envName) ?? fallback;
|
|
66
71
|
}
|
|
67
|
-
function mapStatusToError(status,
|
|
72
|
+
function mapStatusToError(status, body) {
|
|
68
73
|
switch (status) {
|
|
74
|
+
case 400: {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(body);
|
|
77
|
+
if (parsed?.error?.status === "FAILED_PRECONDITION" && parsed.error.message?.toLowerCase().includes("edit")) {
|
|
78
|
+
return {
|
|
79
|
+
code: "API_EDIT_EXPIRED",
|
|
80
|
+
suggestion: "The edit session has expired. Retry the operation to open a fresh edit."
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
return { code: "API_HTTP_400", suggestion: "Check request parameters and try again." };
|
|
86
|
+
}
|
|
69
87
|
case 401:
|
|
70
88
|
return {
|
|
71
89
|
code: "API_UNAUTHORIZED",
|
|
@@ -155,7 +173,7 @@ function createHttpClient(options) {
|
|
|
155
173
|
}
|
|
156
174
|
const errorBody = await response.text();
|
|
157
175
|
const { code, suggestion } = mapStatusToError(response.status, errorBody);
|
|
158
|
-
const err = new
|
|
176
|
+
const err = new PlayApiError(
|
|
159
177
|
`${method} ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,
|
|
160
178
|
code,
|
|
161
179
|
response.status,
|
|
@@ -182,11 +200,11 @@ function createHttpClient(options) {
|
|
|
182
200
|
}
|
|
183
201
|
throw err;
|
|
184
202
|
} catch (error) {
|
|
185
|
-
if (error instanceof
|
|
203
|
+
if (error instanceof PlayApiError) {
|
|
186
204
|
throw error;
|
|
187
205
|
}
|
|
188
206
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
189
|
-
const timeoutErr = new
|
|
207
|
+
const timeoutErr = new PlayApiError(
|
|
190
208
|
`${method} ${path} timed out after ${timeout}ms`,
|
|
191
209
|
"API_TIMEOUT",
|
|
192
210
|
void 0,
|
|
@@ -206,7 +224,7 @@ function createHttpClient(options) {
|
|
|
206
224
|
}
|
|
207
225
|
throw timeoutErr;
|
|
208
226
|
}
|
|
209
|
-
const networkErr = new
|
|
227
|
+
const networkErr = new PlayApiError(
|
|
210
228
|
`${method} ${path} failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
211
229
|
"API_NETWORK_ERROR",
|
|
212
230
|
void 0,
|
|
@@ -229,7 +247,12 @@ function createHttpClient(options) {
|
|
|
229
247
|
clearTimeout(timer);
|
|
230
248
|
}
|
|
231
249
|
}
|
|
232
|
-
throw lastError ?? new
|
|
250
|
+
throw lastError ?? new PlayApiError(
|
|
251
|
+
"Request failed",
|
|
252
|
+
"API_NETWORK_ERROR",
|
|
253
|
+
void 0,
|
|
254
|
+
"Check your network connection and try again. Use --verbose for details."
|
|
255
|
+
);
|
|
233
256
|
}
|
|
234
257
|
function computeUploadTimeout(fileSizeBytes) {
|
|
235
258
|
if (uploadTimeoutExplicit !== void 0) return uploadTimeoutExplicit;
|
|
@@ -271,7 +294,7 @@ function createHttpClient(options) {
|
|
|
271
294
|
}
|
|
272
295
|
const errorBody = await response.text();
|
|
273
296
|
const { code, suggestion } = mapStatusToError(response.status, errorBody);
|
|
274
|
-
const err = new
|
|
297
|
+
const err = new PlayApiError(
|
|
275
298
|
`POST upload ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,
|
|
276
299
|
code,
|
|
277
300
|
response.status,
|
|
@@ -298,12 +321,12 @@ function createHttpClient(options) {
|
|
|
298
321
|
}
|
|
299
322
|
throw err;
|
|
300
323
|
} catch (error) {
|
|
301
|
-
if (error instanceof
|
|
324
|
+
if (error instanceof PlayApiError) {
|
|
302
325
|
throw error;
|
|
303
326
|
}
|
|
304
327
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
305
328
|
const sizeMb = Math.round(fileBuffer.byteLength / (1024 * 1024));
|
|
306
|
-
const timeoutErr = new
|
|
329
|
+
const timeoutErr = new PlayApiError(
|
|
307
330
|
`POST upload ${path} timed out after ${effectiveTimeout}ms (file: ${sizeMb} MB)`,
|
|
308
331
|
"API_TIMEOUT",
|
|
309
332
|
void 0,
|
|
@@ -323,7 +346,7 @@ function createHttpClient(options) {
|
|
|
323
346
|
}
|
|
324
347
|
throw timeoutErr;
|
|
325
348
|
}
|
|
326
|
-
const networkErr = new
|
|
349
|
+
const networkErr = new PlayApiError(
|
|
327
350
|
`POST upload ${path} failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
328
351
|
"API_NETWORK_ERROR",
|
|
329
352
|
void 0,
|
|
@@ -346,7 +369,12 @@ function createHttpClient(options) {
|
|
|
346
369
|
clearTimeout(timer);
|
|
347
370
|
}
|
|
348
371
|
}
|
|
349
|
-
throw lastError ?? new
|
|
372
|
+
throw lastError ?? new PlayApiError(
|
|
373
|
+
"Upload request failed",
|
|
374
|
+
"API_NETWORK_ERROR",
|
|
375
|
+
void 0,
|
|
376
|
+
"Check your network connection and try again. Use --verbose for details."
|
|
377
|
+
);
|
|
350
378
|
}
|
|
351
379
|
return {
|
|
352
380
|
get(path, params) {
|
|
@@ -389,7 +417,7 @@ function createHttpClient(options) {
|
|
|
389
417
|
if (!response.ok) {
|
|
390
418
|
const errorBody = await response.text();
|
|
391
419
|
const { code, suggestion } = mapStatusToError(response.status, errorBody);
|
|
392
|
-
throw new
|
|
420
|
+
throw new PlayApiError(
|
|
393
421
|
`GET ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,
|
|
394
422
|
code,
|
|
395
423
|
response.status,
|
|
@@ -467,7 +495,7 @@ function createApiClient(options) {
|
|
|
467
495
|
"application/octet-stream"
|
|
468
496
|
);
|
|
469
497
|
if (!data || !data.versionCode) {
|
|
470
|
-
throw new
|
|
498
|
+
throw new PlayApiError(
|
|
471
499
|
"Upload succeeded but no bundle data returned",
|
|
472
500
|
"API_EMPTY_RESPONSE",
|
|
473
501
|
200,
|
|
@@ -559,7 +587,7 @@ function createApiClient(options) {
|
|
|
559
587
|
filePath.endsWith(".png") ? "image/png" : "image/jpeg"
|
|
560
588
|
);
|
|
561
589
|
if (!data.image) {
|
|
562
|
-
throw new
|
|
590
|
+
throw new PlayApiError(
|
|
563
591
|
"Upload succeeded but no image data returned",
|
|
564
592
|
"API_EMPTY_RESPONSE",
|
|
565
593
|
200,
|
|
@@ -590,16 +618,11 @@ function createApiClient(options) {
|
|
|
590
618
|
},
|
|
591
619
|
dataSafety: {
|
|
592
620
|
async get(packageName) {
|
|
593
|
-
const { data } = await http.get(
|
|
594
|
-
`/${packageName}/dataSafety`
|
|
595
|
-
);
|
|
621
|
+
const { data } = await http.get(`/${packageName}/dataSafety`);
|
|
596
622
|
return data;
|
|
597
623
|
},
|
|
598
624
|
async update(packageName, body) {
|
|
599
|
-
const { data } = await http.put(
|
|
600
|
-
`/${packageName}/dataSafety`,
|
|
601
|
-
body
|
|
602
|
-
);
|
|
625
|
+
const { data } = await http.put(`/${packageName}/dataSafety`, body);
|
|
603
626
|
return data;
|
|
604
627
|
}
|
|
605
628
|
},
|
|
@@ -652,9 +675,7 @@ function createApiClient(options) {
|
|
|
652
675
|
return data;
|
|
653
676
|
},
|
|
654
677
|
async get(packageName, productId) {
|
|
655
|
-
const { data } = await http.get(
|
|
656
|
-
`/${packageName}/subscriptions/${productId}`
|
|
657
|
-
);
|
|
678
|
+
const { data } = await http.get(`/${packageName}/subscriptions/${productId}`);
|
|
658
679
|
return data;
|
|
659
680
|
},
|
|
660
681
|
async create(packageName, body, productId) {
|
|
@@ -669,7 +690,7 @@ function createApiClient(options) {
|
|
|
669
690
|
const params = {};
|
|
670
691
|
if (updateMask) params["updateMask"] = updateMask;
|
|
671
692
|
params["regionsVersion.version"] = regionsVersion || "2022/02";
|
|
672
|
-
|
|
693
|
+
const path = `/${packageName}/subscriptions/${productId}?${new URLSearchParams(params).toString()}`;
|
|
673
694
|
const { data } = await http.patch(path, body);
|
|
674
695
|
return data;
|
|
675
696
|
},
|
|
@@ -689,9 +710,7 @@ function createApiClient(options) {
|
|
|
689
710
|
return data;
|
|
690
711
|
},
|
|
691
712
|
async deleteBasePlan(packageName, productId, basePlanId) {
|
|
692
|
-
await http.delete(
|
|
693
|
-
`/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}`
|
|
694
|
-
);
|
|
713
|
+
await http.delete(`/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}`);
|
|
695
714
|
},
|
|
696
715
|
async migratePrices(packageName, productId, basePlanId, body) {
|
|
697
716
|
const { data } = await http.post(
|
|
@@ -724,7 +743,7 @@ function createApiClient(options) {
|
|
|
724
743
|
const params = {};
|
|
725
744
|
if (updateMask) params["updateMask"] = updateMask;
|
|
726
745
|
params["regionsVersion.version"] = regionsVersion || "2022/02";
|
|
727
|
-
|
|
746
|
+
const path = `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}?${new URLSearchParams(params).toString()}`;
|
|
728
747
|
const { data } = await http.patch(path, body);
|
|
729
748
|
return data;
|
|
730
749
|
},
|
|
@@ -844,6 +863,9 @@ function createApiClient(options) {
|
|
|
844
863
|
async revokeSubscriptionV2(packageName, token) {
|
|
845
864
|
await http.post(`/${packageName}/purchases/subscriptionsv2/tokens/${token}:revoke`);
|
|
846
865
|
},
|
|
866
|
+
async refundSubscriptionV2(packageName, token) {
|
|
867
|
+
await http.post(`/${packageName}/purchases/subscriptionsv2/tokens/${token}:refund`);
|
|
868
|
+
},
|
|
847
869
|
async listVoided(packageName, options2) {
|
|
848
870
|
await rateLimit(limiter, "voidedBurst");
|
|
849
871
|
await rateLimit(limiter, "voidedDaily");
|
|
@@ -906,7 +928,7 @@ function createApiClient(options) {
|
|
|
906
928
|
"application/octet-stream"
|
|
907
929
|
);
|
|
908
930
|
if (!data.deobfuscationFile) {
|
|
909
|
-
throw new
|
|
931
|
+
throw new PlayApiError(
|
|
910
932
|
"Upload succeeded but no deobfuscation file data returned",
|
|
911
933
|
"API_EMPTY_RESPONSE",
|
|
912
934
|
200,
|
|
@@ -1068,10 +1090,7 @@ function createApiClient(options) {
|
|
|
1068
1090
|
return data;
|
|
1069
1091
|
},
|
|
1070
1092
|
async create(packageName, body) {
|
|
1071
|
-
const { data } = await http.post(
|
|
1072
|
-
`/${packageName}/purchaseOptions`,
|
|
1073
|
-
body
|
|
1074
|
-
);
|
|
1093
|
+
const { data } = await http.post(`/${packageName}/purchaseOptions`, body);
|
|
1075
1094
|
return data;
|
|
1076
1095
|
},
|
|
1077
1096
|
async activate(packageName, purchaseOptionId) {
|
|
@@ -1113,9 +1132,7 @@ function createApiClient(options) {
|
|
|
1113
1132
|
return data.generatedApks || [];
|
|
1114
1133
|
},
|
|
1115
1134
|
async download(packageName, versionCode, id) {
|
|
1116
|
-
return http.download(
|
|
1117
|
-
`/${packageName}/generatedApks/${versionCode}/download/${id}`
|
|
1118
|
-
);
|
|
1135
|
+
return http.download(`/${packageName}/generatedApks/${versionCode}/download/${id}`);
|
|
1119
1136
|
}
|
|
1120
1137
|
}
|
|
1121
1138
|
};
|
|
@@ -1195,6 +1212,103 @@ function createUsersClient(options) {
|
|
|
1195
1212
|
},
|
|
1196
1213
|
async delete(developerId, userId) {
|
|
1197
1214
|
await http.delete(`/${developerId}/users/${userId}`);
|
|
1215
|
+
},
|
|
1216
|
+
grants: {
|
|
1217
|
+
async list(developerId, email) {
|
|
1218
|
+
const { data } = await http.get(
|
|
1219
|
+
`/${developerId}/users/${encodeURIComponent(email)}/grants`
|
|
1220
|
+
);
|
|
1221
|
+
return data;
|
|
1222
|
+
},
|
|
1223
|
+
async create(developerId, email, grant) {
|
|
1224
|
+
const { data } = await http.post(
|
|
1225
|
+
`/${developerId}/users/${encodeURIComponent(email)}/grants`,
|
|
1226
|
+
grant
|
|
1227
|
+
);
|
|
1228
|
+
return data;
|
|
1229
|
+
},
|
|
1230
|
+
async patch(developerId, email, packageName, grant, updateMask) {
|
|
1231
|
+
let path = `/${developerId}/users/${encodeURIComponent(email)}/grants/${encodeURIComponent(packageName)}`;
|
|
1232
|
+
if (updateMask) {
|
|
1233
|
+
path += `?updateMask=${encodeURIComponent(updateMask)}`;
|
|
1234
|
+
}
|
|
1235
|
+
const { data } = await http.patch(path, grant);
|
|
1236
|
+
return data;
|
|
1237
|
+
},
|
|
1238
|
+
async delete(developerId, email, packageName) {
|
|
1239
|
+
await http.delete(
|
|
1240
|
+
`/${developerId}/users/${encodeURIComponent(email)}/grants/${encodeURIComponent(packageName)}`
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// src/games-client.ts
|
|
1248
|
+
var GAMES_BASE_URL = "https://games.googleapis.com/games/v1";
|
|
1249
|
+
function createGamesClient(options) {
|
|
1250
|
+
const http = createHttpClient({ ...options, baseUrl: GAMES_BASE_URL });
|
|
1251
|
+
return {
|
|
1252
|
+
leaderboards: {
|
|
1253
|
+
async list(packageName) {
|
|
1254
|
+
const { data } = await http.get(
|
|
1255
|
+
`/leaderboards?applicationId=${packageName}`
|
|
1256
|
+
);
|
|
1257
|
+
return data;
|
|
1258
|
+
},
|
|
1259
|
+
async get(packageName, leaderboardId) {
|
|
1260
|
+
const { data } = await http.get(
|
|
1261
|
+
`/leaderboards/${leaderboardId}?applicationId=${packageName}`
|
|
1262
|
+
);
|
|
1263
|
+
return data;
|
|
1264
|
+
},
|
|
1265
|
+
async getScores(packageName, leaderboardId, collection, timeSpan) {
|
|
1266
|
+
const { data } = await http.get(
|
|
1267
|
+
`/leaderboards/${leaderboardId}/scores/${collection}?timeSpan=${timeSpan}&applicationId=${packageName}`
|
|
1268
|
+
);
|
|
1269
|
+
return data;
|
|
1270
|
+
}
|
|
1271
|
+
},
|
|
1272
|
+
achievements: {
|
|
1273
|
+
async list(packageName) {
|
|
1274
|
+
const { data } = await http.get(
|
|
1275
|
+
`/achievements?applicationId=${packageName}`
|
|
1276
|
+
);
|
|
1277
|
+
return data;
|
|
1278
|
+
},
|
|
1279
|
+
async reveal(packageName, achievementId) {
|
|
1280
|
+
const { data } = await http.post(
|
|
1281
|
+
`/achievements/${achievementId}/reveal?applicationId=${packageName}`,
|
|
1282
|
+
{}
|
|
1283
|
+
);
|
|
1284
|
+
return data;
|
|
1285
|
+
}
|
|
1286
|
+
},
|
|
1287
|
+
events: {
|
|
1288
|
+
async list(packageName) {
|
|
1289
|
+
const { data } = await http.get(
|
|
1290
|
+
`/events?applicationId=${packageName}`
|
|
1291
|
+
);
|
|
1292
|
+
return data;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// src/enterprise-client.ts
|
|
1299
|
+
var ENTERPRISE_BASE_URL = "https://playcustomapp.googleapis.com/playcustomapp/v1/organizations";
|
|
1300
|
+
function createEnterpriseClient(options) {
|
|
1301
|
+
const http = createHttpClient({ ...options, baseUrl: ENTERPRISE_BASE_URL });
|
|
1302
|
+
return {
|
|
1303
|
+
apps: {
|
|
1304
|
+
async create(organizationId, app) {
|
|
1305
|
+
const { data } = await http.post(`/${organizationId}/apps`, app);
|
|
1306
|
+
return data;
|
|
1307
|
+
},
|
|
1308
|
+
async list(organizationId) {
|
|
1309
|
+
const { data } = await http.get(`/${organizationId}/apps`);
|
|
1310
|
+
return data;
|
|
1311
|
+
}
|
|
1198
1312
|
}
|
|
1199
1313
|
};
|
|
1200
1314
|
}
|
|
@@ -1313,9 +1427,11 @@ async function paginateParallel(fetchPage, pageTokens, concurrency = 4) {
|
|
|
1313
1427
|
return { items: allItems, nextPageToken: lastNextPageToken };
|
|
1314
1428
|
}
|
|
1315
1429
|
export {
|
|
1316
|
-
|
|
1430
|
+
PlayApiError,
|
|
1317
1431
|
RATE_LIMIT_BUCKETS,
|
|
1318
1432
|
createApiClient,
|
|
1433
|
+
createEnterpriseClient,
|
|
1434
|
+
createGamesClient,
|
|
1319
1435
|
createHttpClient,
|
|
1320
1436
|
createRateLimiter,
|
|
1321
1437
|
createReportingClient,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/client.ts","../src/reporting-client.ts","../src/users-client.ts","../src/rate-limiter.ts","../src/paginate.ts"],"sourcesContent":["export class ApiError extends Error {\n public readonly exitCode = 4;\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode?: number,\n public readonly suggestion?: string,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n toJSON() {\n return {\n success: false,\n error: {\n code: this.code,\n message: this.message,\n suggestion: this.suggestion,\n },\n };\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { ApiError } from \"./errors.js\";\nimport type { ApiClientOptions, ApiResponse } from \"./types.js\";\n\n/** Strip HTML tags and collapse whitespace from a string. */\nfunction stripHtml(text: string): string {\n return text\n .replace(/<[^>]*>/g, \" \")\n .replace(/&[a-z]+;/gi, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** Extract a short, safe error summary from API response body (no tokens/secrets). */\nfunction sanitizeErrorBody(body: string): string {\n try {\n const parsed = JSON.parse(body) as {\n error?: { message?: string; status?: string; code?: number };\n };\n if (parsed?.error?.message) {\n return `${parsed.error.code ?? \"?\"} ${parsed.error.status ?? \"\"}: ${parsed.error.message}`.trim();\n }\n } catch {\n // not JSON — may be HTML error page\n }\n // Strip HTML tags before truncating\n const cleaned = body.startsWith(\"<\") ? stripHtml(body) : body;\n return cleaned.length > 200 ? cleaned.slice(0, 200) + \"...\" : cleaned;\n}\n\n/** Validate upload file path to prevent path traversal. */\nfunction validateFilePath(filePath: string): string {\n const resolved = resolve(filePath);\n if (!isAbsolute(resolved)) {\n throw new ApiError(\n \"Invalid file path\",\n \"API_INVALID_PATH\",\n undefined,\n \"File path must resolve to an absolute path.\",\n );\n }\n // Block obvious traversal patterns in the original input\n if (filePath.includes(\"\\0\")) {\n throw new ApiError(\"Invalid file path: null bytes not allowed\", \"API_INVALID_PATH\", undefined, \"Provide a valid file path without null bytes.\");\n }\n return resolved;\n}\n\nconst BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/applications\";\n\nconst UPLOAD_BASE_URL =\n \"https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications\";\n\nconst INTERNAL_SHARING_UPLOAD_BASE_URL =\n \"https://androidpublisher.googleapis.com/upload/internalappsharing/v3/applications\";\n\nexport interface HttpClient {\n get<T>(path: string, params?: Record<string, string>): Promise<ApiResponse<T>>;\n post<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n put<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n patch<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n delete<T>(path: string): Promise<ApiResponse<T>>;\n upload<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;\n uploadInternal<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;\n download(path: string): Promise<ArrayBuffer>;\n}\n\nfunction envInt(name: string): number | undefined {\n const val = process.env[name];\n if (val === undefined) return undefined;\n const n = Number(val);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction resolveOption(explicit: number | undefined, envName: string, fallback: number): number {\n return explicit ?? envInt(envName) ?? fallback;\n}\n\nfunction mapStatusToError(status: number, _body: string): { code: string; suggestion?: string } {\n switch (status) {\n case 401:\n return {\n code: \"API_UNAUTHORIZED\",\n suggestion: \"Check that your access token is valid and not expired.\",\n };\n case 403:\n return {\n code: \"API_FORBIDDEN\",\n suggestion: \"Ensure the service account has the required permissions for this operation.\",\n };\n case 404:\n return {\n code: \"API_NOT_FOUND\",\n suggestion: \"Verify the package name and resource IDs are correct.\",\n };\n case 409:\n return {\n code: \"API_EDIT_CONFLICT\",\n suggestion: \"Another edit may be in progress. Delete the existing edit and retry.\",\n };\n case 429:\n return {\n code: \"API_RATE_LIMITED\",\n suggestion: \"Too many requests. The client will retry automatically.\",\n };\n default:\n if (status >= 500) {\n return {\n code: \"API_SERVER_ERROR\",\n suggestion: \"Google Play API server error. The client will retry automatically.\",\n };\n }\n return { code: `API_HTTP_${status}` };\n }\n}\n\nfunction isRetryable(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction jitteredDelay(base: number, attempt: number, max: number): number {\n const exponential = base * 2 ** attempt;\n const capped = Math.min(exponential, max);\n return capped * (0.5 + Math.random() * 0.5);\n}\n\nexport function createHttpClient(options: ApiClientOptions): HttpClient {\n const maxRetries = resolveOption(options.maxRetries, \"GPC_MAX_RETRIES\", 3);\n const timeout = resolveOption(options.timeout, \"GPC_TIMEOUT\", 30_000);\n const uploadTimeoutExplicit = options.uploadTimeout ?? envInt(\"GPC_UPLOAD_TIMEOUT\");\n const baseDelay = resolveOption(options.baseDelay, \"GPC_BASE_DELAY\", 1_000);\n const maxDelay = resolveOption(options.maxDelay, \"GPC_MAX_DELAY\", 60_000);\n const onRetry = options.onRetry;\n\n async function request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<ApiResponse<T>> {\n let url = `${options.baseUrl ?? BASE_URL}${path}`;\n if (params) {\n const search = new URLSearchParams(params);\n url += `?${search.toString()}`;\n }\n\n // Fetch token once before retries — the auth layer handles its own caching and mutex\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const init: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n keepalive: true,\n };\n\n if (body !== undefined) {\n init.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, init);\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new ApiError(\n `${method} ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const timeoutErr = new ApiError(\n `${method} ${path} timed out after ${timeout}ms`,\n \"API_TIMEOUT\",\n undefined,\n \"The request exceeded the configured timeout. Consider increasing the timeout value.\",\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new ApiError(\n `${method} ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n // Should not reach here, but just in case\n throw lastError ?? new ApiError(\"Request failed\", \"API_NETWORK_ERROR\", undefined, \"Check your network connection and try again. Use --verbose for details.\");\n }\n\n /** Calculate upload timeout: explicit value, or auto-scale from file size (1 MB/s minimum throughput + 30s overhead). */\n function computeUploadTimeout(fileSizeBytes: number): number {\n if (uploadTimeoutExplicit !== undefined) return uploadTimeoutExplicit;\n // Base: 30s overhead + 1s per MB (assumes ~1 MB/s minimum upload speed)\n const sizeMb = fileSizeBytes / (1024 * 1024);\n return Math.max(timeout, 30_000 + Math.ceil(sizeMb) * 1_000);\n }\n\n async function uploadRequest<T>(\n path: string,\n filePath: string,\n contentType: string,\n baseUrl: string = UPLOAD_BASE_URL,\n ): Promise<ApiResponse<T>> {\n const url = `${baseUrl}${path}`;\n const safeFilePath = validateFilePath(filePath);\n const fileBuffer = await readFile(safeFilePath);\n const effectiveTimeout = computeUploadTimeout(fileBuffer.byteLength);\n\n // Fetch token once before retries\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), effectiveTimeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": contentType,\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: fileBuffer,\n signal: controller.signal,\n keepalive: true,\n });\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new ApiError(\n `POST upload ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const sizeMb = Math.round(fileBuffer.byteLength / (1024 * 1024));\n const timeoutErr = new ApiError(\n `POST upload ${path} timed out after ${effectiveTimeout}ms (file: ${sizeMb} MB)`,\n \"API_TIMEOUT\",\n undefined,\n `Upload timed out. Set GPC_UPLOAD_TIMEOUT=${effectiveTimeout * 2} (ms) or use --timeout to increase.`,\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new ApiError(\n `POST upload ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n throw lastError ?? new ApiError(\"Upload request failed\", \"API_NETWORK_ERROR\", undefined, \"Check your network connection and try again. Use --verbose for details.\");\n }\n\n return {\n get<T>(path: string, params?: Record<string, string>) {\n return request<T>(\"GET\", path, undefined, params);\n },\n post<T>(path: string, body?: unknown) {\n return request<T>(\"POST\", path, body);\n },\n put<T>(path: string, body?: unknown) {\n return request<T>(\"PUT\", path, body);\n },\n patch<T>(path: string, body?: unknown) {\n return request<T>(\"PATCH\", path, body);\n },\n delete<T>(path: string) {\n return request<T>(\"DELETE\", path);\n },\n upload<T>(path: string, filePath: string, contentType: string) {\n return uploadRequest<T>(path, filePath, contentType);\n },\n uploadInternal<T>(path: string, filePath: string, contentType: string) {\n return uploadRequest<T>(path, filePath, contentType, INTERNAL_SHARING_UPLOAD_BASE_URL);\n },\n async download(path: string): Promise<ArrayBuffer> {\n const url = `${options.baseUrl ?? BASE_URL}${path}`;\n const token = await options.auth.getAccessToken();\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n },\n signal: controller.signal,\n keepalive: true,\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n throw new ApiError(\n `GET ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n }\n\n return await response.arrayBuffer();\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n","import { ApiError } from \"./errors.js\";\nimport { createHttpClient } from \"./http.js\";\nimport type { RateLimiter } from \"./rate-limiter.js\";\nimport type {\n ApiClientOptions,\n AppDetails,\n AppEdit,\n AppRecoveriesListResponse,\n AppRecoveryAction,\n AppRecoveryTargeting,\n CreateAppRecoveryActionRequest,\n BasePlanMigratePricesRequest,\n Bundle,\n BundleListResponse,\n ConvertRegionPricesRequest,\n ConvertRegionPricesResponse,\n CountryAvailability,\n DataSafety,\n DeobfuscationFile,\n DeobfuscationUploadResponse,\n DeviceTierConfig,\n DeviceTierConfigsListResponse,\n ExternalTransaction,\n ExternalTransactionRefund,\n ExternallyHostedApk,\n ExternallyHostedApkResponse,\n Image,\n ImageType,\n ImageUploadResponse,\n ImagesDeleteAllResponse,\n ImagesListResponse,\n InAppProduct,\n InAppProductsListResponse,\n Listing,\n ListingsListResponse,\n OffersListResponse,\n ProductPurchase,\n Release,\n ReportsListResponse,\n ReportType,\n Review,\n ReviewReplyRequest,\n ReviewReplyResponse,\n ReviewsListOptions,\n ReviewsListResponse,\n Subscription,\n SubscriptionDeferRequest,\n SubscriptionDeferResponse,\n SubscriptionOffer,\n SubscriptionPurchase,\n SubscriptionPurchaseV2,\n SubscriptionsListResponse,\n Testers,\n Track,\n TrackListResponse,\n VoidedPurchasesListResponse,\n OneTimeProduct,\n OneTimeProductsListResponse,\n OneTimeOffer,\n OneTimeOffersListResponse,\n InternalAppSharingArtifact,\n GeneratedApk,\n GeneratedApksPerVersion,\n PurchaseOption,\n PurchaseOptionsListResponse,\n InAppProductsBatchUpdateRequest,\n InAppProductsBatchUpdateResponse,\n} from \"./types.js\";\n\nexport interface PlayApiClient {\n edits: {\n insert(packageName: string): Promise<AppEdit>;\n get(packageName: string, editId: string): Promise<AppEdit>;\n validate(packageName: string, editId: string): Promise<AppEdit>;\n commit(packageName: string, editId: string): Promise<AppEdit>;\n delete(packageName: string, editId: string): Promise<void>;\n };\n\n details: {\n get(packageName: string, editId: string): Promise<AppDetails>;\n update(packageName: string, editId: string, details: Partial<AppDetails>): Promise<AppDetails>;\n patch(packageName: string, editId: string, partial: Partial<AppDetails>): Promise<AppDetails>;\n };\n\n bundles: {\n list(packageName: string, editId: string): Promise<Bundle[]>;\n upload(packageName: string, editId: string, filePath: string): Promise<Bundle>;\n };\n\n tracks: {\n list(packageName: string, editId: string): Promise<Track[]>;\n get(packageName: string, editId: string, track: string): Promise<Track>;\n create(packageName: string, editId: string, trackName: string): Promise<Track>;\n update(packageName: string, editId: string, track: string, release: Release): Promise<Track>;\n };\n\n apks: {\n addExternallyHosted(\n packageName: string,\n editId: string,\n data: ExternallyHostedApk,\n ): Promise<ExternallyHostedApkResponse>;\n };\n\n listings: {\n list(packageName: string, editId: string): Promise<Listing[]>;\n get(packageName: string, editId: string, language: string): Promise<Listing>;\n update(\n packageName: string,\n editId: string,\n language: string,\n listing: Omit<Listing, \"language\">,\n ): Promise<Listing>;\n patch(\n packageName: string,\n editId: string,\n language: string,\n partial: Partial<Omit<Listing, \"language\">>,\n ): Promise<Listing>;\n delete(packageName: string, editId: string, language: string): Promise<void>;\n deleteAll(packageName: string, editId: string): Promise<void>;\n };\n\n images: {\n list(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n upload(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n filePath: string,\n ): Promise<Image>;\n delete(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n imageId: string,\n ): Promise<void>;\n deleteAll(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n };\n\n countryAvailability: {\n get(packageName: string, editId: string, track: string): Promise<CountryAvailability>;\n };\n\n dataSafety: {\n get(packageName: string): Promise<DataSafety>;\n update(packageName: string, data: DataSafety): Promise<DataSafety>;\n };\n\n reviews: {\n list(packageName: string, options?: ReviewsListOptions): Promise<ReviewsListResponse>;\n get(packageName: string, reviewId: string, translationLanguage?: string): Promise<Review>;\n reply(packageName: string, reviewId: string, replyText: string): Promise<ReviewReplyResponse>;\n };\n\n subscriptions: {\n list(\n packageName: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<SubscriptionsListResponse>;\n get(packageName: string, productId: string): Promise<Subscription>;\n create(packageName: string, data: Subscription, productId?: string): Promise<Subscription>;\n update(\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<Subscription>;\n delete(packageName: string, productId: string): Promise<void>;\n activateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deactivateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deleteBasePlan(packageName: string, productId: string, basePlanId: string): Promise<void>;\n migratePrices(\n packageName: string,\n productId: string,\n basePlanId: string,\n body: BasePlanMigratePricesRequest,\n ): Promise<Subscription>;\n listOffers(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<OffersListResponse>;\n getOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n createOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n data: SubscriptionOffer,\n offerId?: string,\n ): Promise<SubscriptionOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<SubscriptionOffer>;\n deleteOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<void>;\n activateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n deactivateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n };\n\n inappproducts: {\n list(\n packageName: string,\n options?: { token?: string; maxResults?: number },\n ): Promise<InAppProductsListResponse>;\n get(packageName: string, sku: string): Promise<InAppProduct>;\n create(packageName: string, data: InAppProduct, options?: { autoConvertMissingPrices?: boolean }): Promise<InAppProduct>;\n update(packageName: string, sku: string, data: InAppProduct, options?: { autoConvertMissingPrices?: boolean; allowMissing?: boolean }): Promise<InAppProduct>;\n delete(packageName: string, sku: string): Promise<void>;\n batchUpdate(\n packageName: string,\n requests: InAppProductsBatchUpdateRequest,\n ): Promise<InAppProductsBatchUpdateResponse>;\n batchGet(packageName: string, skus: string[]): Promise<InAppProduct[]>;\n };\n\n purchases: {\n getProduct(packageName: string, productId: string, token: string): Promise<ProductPurchase>;\n acknowledgeProduct(\n packageName: string,\n productId: string,\n token: string,\n body?: { developerPayload?: string },\n ): Promise<void>;\n consumeProduct(packageName: string, productId: string, token: string): Promise<void>;\n getSubscriptionV2(packageName: string, token: string): Promise<SubscriptionPurchaseV2>;\n getSubscriptionV1(\n packageName: string,\n subscriptionId: string,\n token: string,\n ): Promise<SubscriptionPurchase>;\n cancelSubscription(packageName: string, subscriptionId: string, token: string): Promise<void>;\n deferSubscription(\n packageName: string,\n subscriptionId: string,\n token: string,\n body: SubscriptionDeferRequest,\n ): Promise<SubscriptionDeferResponse>;\n revokeSubscriptionV2(packageName: string, token: string): Promise<void>;\n listVoided(\n packageName: string,\n options?: { startTime?: string; endTime?: string; maxResults?: number; token?: string },\n ): Promise<VoidedPurchasesListResponse>;\n };\n\n orders: {\n refund(\n packageName: string,\n orderId: string,\n body?: { fullRefund?: boolean; proratedRefund?: boolean },\n ): Promise<void>;\n };\n\n monetization: {\n convertRegionPrices(\n packageName: string,\n price: ConvertRegionPricesRequest,\n ): Promise<ConvertRegionPricesResponse>;\n };\n\n reports: {\n list(\n packageName: string,\n reportType: ReportType,\n year: number,\n month: number,\n ): Promise<ReportsListResponse>;\n };\n\n testers: {\n get(packageName: string, editId: string, track: string): Promise<Testers>;\n update(packageName: string, editId: string, track: string, testers: Testers): Promise<Testers>;\n };\n\n deobfuscation: {\n upload(\n packageName: string,\n editId: string,\n versionCode: number,\n filePath: string,\n ): Promise<DeobfuscationFile>;\n };\n\n appRecovery: {\n list(packageName: string, versionCode?: number): Promise<AppRecoveryAction[]>;\n cancel(packageName: string, appRecoveryId: string): Promise<void>;\n deploy(packageName: string, appRecoveryId: string): Promise<void>;\n create(packageName: string, request: CreateAppRecoveryActionRequest): Promise<AppRecoveryAction>;\n addTargeting(packageName: string, appRecoveryId: string, targeting: AppRecoveryTargeting): Promise<AppRecoveryAction>;\n };\n\n externalTransactions: {\n create(packageName: string, data: ExternalTransaction): Promise<ExternalTransaction>;\n get(packageName: string, transactionId: string): Promise<ExternalTransaction>;\n refund(\n packageName: string,\n transactionId: string,\n refundData: ExternalTransactionRefund,\n ): Promise<ExternalTransaction>;\n };\n\n deviceTiers: {\n list(packageName: string): Promise<DeviceTierConfig[]>;\n get(packageName: string, configId: string): Promise<DeviceTierConfig>;\n create(packageName: string, config: DeviceTierConfig): Promise<DeviceTierConfig>;\n };\n\n oneTimeProducts: {\n list(packageName: string): Promise<OneTimeProductsListResponse>;\n get(packageName: string, productId: string): Promise<OneTimeProduct>;\n create(packageName: string, product: OneTimeProduct): Promise<OneTimeProduct>;\n update(\n packageName: string,\n productId: string,\n product: Partial<OneTimeProduct>,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<OneTimeProduct>;\n delete(packageName: string, productId: string): Promise<void>;\n listOffers(packageName: string, productId: string): Promise<OneTimeOffersListResponse>;\n getOffer(\n packageName: string,\n productId: string,\n offerId: string,\n ): Promise<OneTimeOffer>;\n createOffer(\n packageName: string,\n productId: string,\n offer: OneTimeOffer,\n ): Promise<OneTimeOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n offerId: string,\n offer: Partial<OneTimeOffer>,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<OneTimeOffer>;\n deleteOffer(\n packageName: string,\n productId: string,\n offerId: string,\n ): Promise<void>;\n };\n\n purchaseOptions: {\n list(packageName: string): Promise<PurchaseOptionsListResponse>;\n get(packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;\n create(packageName: string, data: PurchaseOption): Promise<PurchaseOption>;\n activate(packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;\n deactivate(packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;\n };\n\n internalAppSharing: {\n uploadBundle(packageName: string, bundlePath: string): Promise<InternalAppSharingArtifact>;\n uploadApk(packageName: string, apkPath: string): Promise<InternalAppSharingArtifact>;\n };\n\n generatedApks: {\n list(packageName: string, versionCode: number): Promise<GeneratedApk[]>;\n download(packageName: string, versionCode: number, id: string): Promise<ArrayBuffer>;\n };\n}\n\nasync function rateLimit(limiter: RateLimiter | undefined, bucket: string): Promise<void> {\n if (limiter) await limiter.acquire(bucket);\n}\n\nexport function createApiClient(options: ApiClientOptions): PlayApiClient {\n const http = createHttpClient(options);\n const limiter = options.rateLimiter || undefined;\n\n return {\n edits: {\n async insert(packageName) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits`);\n return data;\n },\n\n async get(packageName, editId) {\n const { data } = await http.get<AppEdit>(`/${packageName}/edits/${editId}`);\n return data;\n },\n\n async validate(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:validate`);\n return data;\n },\n\n async commit(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:commit`);\n return data;\n },\n\n async delete(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}`);\n },\n },\n\n details: {\n async get(packageName, editId) {\n const { data } = await http.get<AppDetails>(`/${packageName}/edits/${editId}/details`);\n return data;\n },\n\n async update(packageName, editId, details) {\n const { data } = await http.put<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n details,\n );\n return data;\n },\n\n async patch(packageName, editId, partial) {\n const { data } = await http.patch<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n partial,\n );\n return data;\n },\n },\n\n bundles: {\n async list(packageName, editId) {\n const { data } = await http.get<BundleListResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n );\n return data.bundles;\n },\n\n async upload(packageName, editId, filePath) {\n const { data } = await http.upload<Bundle>(\n `/${packageName}/edits/${editId}/bundles`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data || !data.versionCode) {\n throw new ApiError(\n \"Upload succeeded but no bundle data returned\",\n \"API_EMPTY_RESPONSE\",\n 200,\n \"This is unexpected. Retry the upload or contact Google Play support if the issue persists.\",\n );\n }\n return data;\n },\n },\n\n tracks: {\n async list(packageName, editId) {\n const { data } = await http.get<TrackListResponse>(\n `/${packageName}/edits/${editId}/tracks`,\n );\n return data.tracks;\n },\n\n async get(packageName, editId, track) {\n const { data } = await http.get<Track>(`/${packageName}/edits/${editId}/tracks/${track}`);\n return data;\n },\n\n async create(packageName, editId, trackName) {\n const { data } = await http.post<Track>(`/${packageName}/edits/${editId}/tracks`, {\n track: trackName,\n });\n return data;\n },\n\n async update(packageName, editId, track, release) {\n const { data } = await http.put<Track>(`/${packageName}/edits/${editId}/tracks/${track}`, {\n track,\n releases: [release],\n });\n return data;\n },\n },\n\n apks: {\n async addExternallyHosted(packageName, editId, apkData) {\n const { data } = await http.post<ExternallyHostedApkResponse>(\n `/${packageName}/edits/${editId}/apks/externallyHosted`,\n { externallyHostedApk: apkData },\n );\n return data;\n },\n },\n\n listings: {\n async list(packageName, editId) {\n const { data } = await http.get<ListingsListResponse>(\n `/${packageName}/edits/${editId}/listings`,\n );\n return data.listings || [];\n },\n\n async get(packageName, editId, language) {\n const { data } = await http.get<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n );\n return data;\n },\n\n async update(packageName, editId, language, listing) {\n const { data } = await http.put<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n listing,\n );\n return data;\n },\n\n async patch(packageName, editId, language, partial) {\n const { data } = await http.patch<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n partial,\n );\n return data;\n },\n\n async delete(packageName, editId, language) {\n await http.delete(`/${packageName}/edits/${editId}/listings/${language}`);\n },\n\n async deleteAll(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}/listings`);\n },\n },\n\n images: {\n async list(packageName, editId, language, imageType) {\n const { data } = await http.get<ImagesListResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.images || [];\n },\n\n async upload(packageName, editId, language, imageType, filePath) {\n const { data } = await http.upload<ImageUploadResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n filePath,\n filePath.endsWith(\".png\") ? \"image/png\" : \"image/jpeg\",\n );\n if (!data.image) {\n throw new ApiError(\n \"Upload succeeded but no image data returned\",\n \"API_EMPTY_RESPONSE\",\n 200,\n \"This is unexpected. Retry the upload or contact Google Play support if the issue persists.\",\n );\n }\n return data.image;\n },\n\n async delete(packageName, editId, language, imageType, imageId) {\n await http.delete(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}/${imageId}`,\n );\n },\n\n async deleteAll(packageName, editId, language, imageType) {\n const { data } = await http.delete<ImagesDeleteAllResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.deleted || [];\n },\n },\n\n countryAvailability: {\n async get(packageName, editId, track) {\n const { data } = await http.get<CountryAvailability>(\n `/${packageName}/edits/${editId}/countryAvailability/${track}`,\n );\n return data;\n },\n },\n\n dataSafety: {\n async get(packageName) {\n const { data } = await http.get<DataSafety>(\n `/${packageName}/dataSafety`,\n );\n return data;\n },\n\n async update(packageName, body) {\n const { data } = await http.put<DataSafety>(\n `/${packageName}/dataSafety`,\n body,\n );\n return data;\n },\n },\n\n reviews: {\n async list(packageName, options?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.translationLanguage)\n params[\"translationLanguage\"] = options.translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<ReviewsListResponse>(\n `/${packageName}/reviews`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, reviewId, translationLanguage?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (translationLanguage) params[\"translationLanguage\"] = translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<Review>(\n `/${packageName}/reviews/${reviewId}`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async reply(packageName, reviewId, replyText) {\n await rateLimit(limiter, \"reviewsPost\");\n const body: ReviewReplyRequest = { replyText };\n const { data } = await http.post<ReviewReplyResponse>(\n `/${packageName}/reviews/${reviewId}:reply`,\n body,\n );\n return data;\n },\n },\n\n subscriptions: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.pageToken) params[\"pageToken\"] = options.pageToken;\n if (options?.pageSize) params[\"pageSize\"] = String(options.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<SubscriptionsListResponse>(\n `/${packageName}/subscriptions`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, productId) {\n const { data } = await http.get<Subscription>(\n `/${packageName}/subscriptions/${productId}`,\n );\n return data;\n },\n\n async create(packageName, body, productId?) {\n const params: Record<string, string> = {};\n if (productId) params[\"productId\"] = productId;\n params[\"regionsVersion.version\"] = \"2022/02\";\n const path = `/${packageName}/subscriptions?${new URLSearchParams(params).toString()}`;\n const { data } = await http.post<Subscription>(path, body);\n return data;\n },\n\n async update(packageName, productId, body, updateMask?, regionsVersion?) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n let path = `/${packageName}/subscriptions/${productId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<Subscription>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/subscriptions/${productId}`);\n },\n\n async activateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}:activate`,\n );\n return data;\n },\n\n async deactivateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}:deactivate`,\n );\n return data;\n },\n\n async deleteBasePlan(packageName, productId, basePlanId) {\n await http.delete(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}`,\n );\n },\n\n async migratePrices(packageName, productId, basePlanId, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}:migratePrices`,\n body,\n );\n return data;\n },\n\n async listOffers(packageName, productId, basePlanId) {\n const { data } = await http.get<OffersListResponse>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n );\n return data;\n },\n\n async getOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.get<SubscriptionOffer>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, basePlanId, body, offerId?) {\n const params: Record<string, string> = {};\n if (offerId) params[\"offerId\"] = offerId;\n params[\"regionsVersion.version\"] = \"2022/02\";\n const path = `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers?${new URLSearchParams(params).toString()}`;\n const { data } = await http.post<SubscriptionOffer>(path, body);\n return data;\n },\n\n async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask?, regionsVersion?) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n let path = `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<SubscriptionOffer>(path, body);\n return data;\n },\n\n async deleteOffer(packageName, productId, basePlanId, offerId) {\n await http.delete(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n },\n\n async activateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:activate`,\n );\n return data;\n },\n\n async deactivateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:deactivate`,\n );\n return data;\n },\n },\n\n inappproducts: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<InAppProductsListResponse>(\n `/${packageName}/inappproducts`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, sku) {\n const { data } = await http.get<InAppProduct>(`/${packageName}/inappproducts/${sku}`);\n return data;\n },\n\n async create(packageName, body, options?) {\n const params: Record<string, string> = {};\n if (options?.autoConvertMissingPrices) params[\"autoConvertMissingPrices\"] = \"true\";\n const hasParams = Object.keys(params).length > 0;\n const path = hasParams\n ? `/${packageName}/inappproducts?${new URLSearchParams(params).toString()}`\n : `/${packageName}/inappproducts`;\n const { data } = await http.post<InAppProduct>(path, body);\n return data;\n },\n\n async update(packageName, sku, body, options?) {\n const params: Record<string, string> = {};\n if (options?.autoConvertMissingPrices) params[\"autoConvertMissingPrices\"] = \"true\";\n if (options?.allowMissing) params[\"allowMissing\"] = \"true\";\n const hasParams = Object.keys(params).length > 0;\n const path = hasParams\n ? `/${packageName}/inappproducts/${sku}?${new URLSearchParams(params).toString()}`\n : `/${packageName}/inappproducts/${sku}`;\n const { data } = await http.put<InAppProduct>(path, body);\n return data;\n },\n\n async delete(packageName, sku) {\n await http.delete(`/${packageName}/inappproducts/${sku}`);\n },\n\n async batchUpdate(packageName, requests) {\n const { data } = await http.post<InAppProductsBatchUpdateResponse>(\n `/${packageName}/inappproducts:batchUpdate`,\n requests,\n );\n return data;\n },\n\n async batchGet(packageName, skus) {\n const params: Record<string, string> = {};\n if (skus.length > 0) {\n params[\"sku\"] = skus.join(\",\");\n }\n const { data } = await http.get<{ inappproduct: InAppProduct[] }>(\n `/${packageName}/inappproducts:batchGet`,\n Object.keys(params).length > 0 ? params : undefined,\n );\n return data.inappproduct || [];\n },\n },\n\n purchases: {\n async getProduct(packageName, productId, token) {\n const { data } = await http.get<ProductPurchase>(\n `/${packageName}/purchases/products/${productId}/tokens/${token}`,\n );\n return data;\n },\n\n async acknowledgeProduct(packageName, productId, token, body?) {\n await http.post(\n `/${packageName}/purchases/products/${productId}/tokens/${token}:acknowledge`,\n body,\n );\n },\n\n async consumeProduct(packageName, productId, token) {\n await http.post(`/${packageName}/purchases/products/${productId}/tokens/${token}:consume`);\n },\n\n async getSubscriptionV2(packageName, token) {\n const { data } = await http.get<SubscriptionPurchaseV2>(\n `/${packageName}/purchases/subscriptionsv2/tokens/${token}`,\n );\n return data;\n },\n\n async getSubscriptionV1(packageName, subscriptionId, token) {\n const { data } = await http.get<SubscriptionPurchase>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}`,\n );\n return data;\n },\n\n async cancelSubscription(packageName, subscriptionId, token) {\n await http.post(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:cancel`,\n );\n },\n\n async deferSubscription(packageName, subscriptionId, token, body) {\n const { data } = await http.post<SubscriptionDeferResponse>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:defer`,\n body,\n );\n return data;\n },\n\n async revokeSubscriptionV2(packageName, token) {\n await http.post(`/${packageName}/purchases/subscriptionsv2/tokens/${token}:revoke`);\n },\n\n async listVoided(packageName, options?) {\n await rateLimit(limiter, \"voidedBurst\");\n await rateLimit(limiter, \"voidedDaily\");\n const params: Record<string, string> = {};\n if (options?.startTime) params[\"startTime\"] = options.startTime;\n if (options?.endTime) params[\"endTime\"] = options.endTime;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.token) params[\"token\"] = options.token;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<VoidedPurchasesListResponse>(\n `/${packageName}/purchases/voidedpurchases`,\n hasParams ? params : undefined,\n );\n return data;\n },\n },\n\n orders: {\n async refund(packageName, orderId, body?) {\n await http.post(`/${packageName}/orders/${orderId}:refund`, body);\n },\n },\n\n monetization: {\n async convertRegionPrices(packageName, price) {\n const { data } = await http.post<ConvertRegionPricesResponse>(\n `/${packageName}/pricing:convertRegionPrices`,\n price,\n );\n return data;\n },\n },\n\n reports: {\n async list(packageName, reportType, year, month) {\n const monthStr = String(month).padStart(2, \"0\");\n const { data } = await http.get<ReportsListResponse>(\n `/${packageName}/reports/${reportType}/${year}/${monthStr}`,\n );\n return data;\n },\n },\n\n testers: {\n async get(packageName, editId, track) {\n const { data } = await http.get<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n );\n return data;\n },\n\n async update(packageName, editId, track, testersData) {\n const { data } = await http.put<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n testersData,\n );\n return data;\n },\n },\n\n deobfuscation: {\n async upload(packageName, editId, versionCode, filePath) {\n const { data } = await http.upload<DeobfuscationUploadResponse>(\n `/${packageName}/edits/${editId}/apks/${versionCode}/deobfuscationFiles/proguard`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data.deobfuscationFile) {\n throw new ApiError(\n \"Upload succeeded but no deobfuscation file data returned\",\n \"API_EMPTY_RESPONSE\",\n 200,\n \"This is unexpected. Retry the upload or contact Google Play support if the issue persists.\",\n );\n }\n return data.deobfuscationFile;\n },\n },\n\n appRecovery: {\n async list(packageName, versionCode?) {\n const params: Record<string, string> = {};\n if (versionCode !== undefined) params[\"versionCode\"] = String(versionCode);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<AppRecoveriesListResponse>(\n `/${packageName}/appRecoveries`,\n hasParams ? params : undefined,\n );\n return data.recoveryActions || [];\n },\n\n async cancel(packageName, appRecoveryId) {\n await http.post(`/${packageName}/appRecovery/${appRecoveryId}:cancel`);\n },\n\n async deploy(packageName, appRecoveryId) {\n await http.post(`/${packageName}/appRecovery/${appRecoveryId}:deploy`);\n },\n\n async create(packageName, request) {\n const { data } = await http.post<AppRecoveryAction>(\n `/${packageName}/appRecoveries`,\n request,\n );\n return data;\n },\n\n async addTargeting(packageName, appRecoveryId, targeting) {\n const { data } = await http.post<AppRecoveryAction>(\n `/${packageName}/appRecoveries/${appRecoveryId}:addTargeting`,\n targeting,\n );\n return data;\n },\n },\n\n externalTransactions: {\n async create(packageName, body) {\n const { data } = await http.post<ExternalTransaction>(\n `/${packageName}/externalTransactions`,\n body,\n );\n return data;\n },\n\n async get(packageName, transactionId) {\n const { data } = await http.get<ExternalTransaction>(\n `/${packageName}/externalTransactions/${transactionId}`,\n );\n return data;\n },\n\n async refund(packageName, transactionId, refundData) {\n const { data } = await http.post<ExternalTransaction>(\n `/${packageName}/externalTransactions/${transactionId}:refund`,\n refundData,\n );\n return data;\n },\n },\n\n deviceTiers: {\n async list(packageName) {\n const { data } = await http.get<DeviceTierConfigsListResponse>(\n `/${packageName}/deviceTierConfigs`,\n );\n return data.deviceTierConfigs || [];\n },\n\n async get(packageName, configId) {\n const { data } = await http.get<DeviceTierConfig>(\n `/${packageName}/deviceTierConfigs/${configId}`,\n );\n return data;\n },\n\n async create(packageName, config) {\n const { data } = await http.post<DeviceTierConfig>(\n `/${packageName}/deviceTierConfigs`,\n config,\n );\n return data;\n },\n },\n\n oneTimeProducts: {\n async list(packageName) {\n const { data } = await http.get<OneTimeProductsListResponse>(\n `/${packageName}/oneTimeProducts`,\n );\n return data;\n },\n\n async get(packageName, productId) {\n const { data } = await http.get<OneTimeProduct>(\n `/${packageName}/oneTimeProducts/${productId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const params = new URLSearchParams({ \"regionsVersion.version\": \"2022/02\" });\n const { data } = await http.post<OneTimeProduct>(\n `/${packageName}/oneTimeProducts?${params.toString()}`,\n body,\n );\n return data;\n },\n\n async update(packageName, productId, body, updateMask?, regionsVersion?) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n const path = `/${packageName}/oneTimeProducts/${productId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<OneTimeProduct>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/oneTimeProducts/${productId}`);\n },\n\n async listOffers(packageName, productId) {\n const { data } = await http.get<OneTimeOffersListResponse>(\n `/${packageName}/oneTimeProducts/${productId}/offers`,\n );\n return data;\n },\n\n async getOffer(packageName, productId, offerId) {\n const { data } = await http.get<OneTimeOffer>(\n `/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, body) {\n const { data } = await http.post<OneTimeOffer>(\n `/${packageName}/oneTimeProducts/${productId}/offers`,\n body,\n );\n return data;\n },\n\n async updateOffer(packageName, productId, offerId, body, updateMask?, regionsVersion?) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n const path = `/${packageName}/oneTimeProducts/${productId}/offers/${offerId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<OneTimeOffer>(path, body);\n return data;\n },\n\n async deleteOffer(packageName, productId, offerId) {\n await http.delete(`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`);\n },\n },\n\n purchaseOptions: {\n async list(packageName) {\n const { data } = await http.get<PurchaseOptionsListResponse>(\n `/${packageName}/purchaseOptions`,\n );\n return data;\n },\n\n async get(packageName, purchaseOptionId) {\n const { data } = await http.get<PurchaseOption>(\n `/${packageName}/purchaseOptions/${purchaseOptionId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<PurchaseOption>(\n `/${packageName}/purchaseOptions`,\n body,\n );\n return data;\n },\n\n async activate(packageName, purchaseOptionId) {\n const { data } = await http.post<PurchaseOption>(\n `/${packageName}/purchaseOptions/${purchaseOptionId}:activate`,\n );\n return data;\n },\n\n async deactivate(packageName, purchaseOptionId) {\n const { data } = await http.post<PurchaseOption>(\n `/${packageName}/purchaseOptions/${purchaseOptionId}:deactivate`,\n );\n return data;\n },\n },\n\n internalAppSharing: {\n async uploadBundle(packageName, bundlePath) {\n const { data } = await http.uploadInternal<InternalAppSharingArtifact>(\n `/${packageName}/artifacts/bundle`,\n bundlePath,\n \"application/octet-stream\",\n );\n return data;\n },\n\n async uploadApk(packageName, apkPath) {\n const { data } = await http.uploadInternal<InternalAppSharingArtifact>(\n `/${packageName}/artifacts/apk`,\n apkPath,\n \"application/vnd.android.package-archive\",\n );\n return data;\n },\n },\n\n generatedApks: {\n async list(packageName, versionCode) {\n const { data } = await http.get<GeneratedApksPerVersion>(\n `/${packageName}/generatedApks/${versionCode}`,\n );\n return data.generatedApks || [];\n },\n\n async download(packageName, versionCode, id) {\n return http.download(\n `/${packageName}/generatedApks/${versionCode}/download/${id}`,\n );\n },\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type {\n AnomalyDetectionResponse,\n ApiClientOptions,\n ErrorIssuesResponse,\n ErrorReportsResponse,\n MetricSetQuery,\n MetricSetResponse,\n VitalsMetricSet,\n} from \"./types.js\";\n\nconst REPORTING_BASE_URL = \"https://playdeveloperreporting.googleapis.com/v1beta1\";\n\nexport interface ReportingApiClient {\n queryMetricSet(\n packageName: string,\n metricSet: VitalsMetricSet,\n query: MetricSetQuery,\n ): Promise<MetricSetResponse>;\n\n getAnomalies(packageName: string): Promise<AnomalyDetectionResponse>;\n\n searchErrorIssues(\n packageName: string,\n filter?: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorIssuesResponse>;\n\n searchErrorReports(\n packageName: string,\n issueName: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorReportsResponse>;\n}\n\nexport function createReportingClient(options: ApiClientOptions): ReportingApiClient {\n const http = createHttpClient({ ...options, baseUrl: REPORTING_BASE_URL });\n\n return {\n async queryMetricSet(packageName, metricSet, query) {\n const { data } = await http.post<MetricSetResponse>(\n `/apps/${packageName}/${metricSet}:query`,\n query,\n );\n return data;\n },\n\n async getAnomalies(packageName) {\n const { data } = await http.get<AnomalyDetectionResponse>(`/apps/${packageName}/anomalies`);\n return data;\n },\n\n async searchErrorIssues(packageName, filter?, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (filter) params[\"filter\"] = filter;\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorIssuesResponse>(\n `/apps/${packageName}/errorIssues:search`,\n params,\n );\n return data;\n },\n\n async searchErrorReports(packageName, issueName, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorReportsResponse>(\n `/apps/${packageName}/errorIssues/${issueName}/reports`,\n params,\n );\n return data;\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { ApiClientOptions, User, UsersListResponse } from \"./types.js\";\n\nconst USERS_BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/developers\";\n\nexport interface UsersApiClient {\n list(\n developerId: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<UsersListResponse>;\n\n get(developerId: string, userId: string): Promise<User>;\n\n create(developerId: string, user: Partial<User>): Promise<User>;\n\n update(\n developerId: string,\n userId: string,\n user: Partial<User>,\n updateMask?: string,\n ): Promise<User>;\n\n delete(developerId: string, userId: string): Promise<void>;\n}\n\nexport function createUsersClient(options: ApiClientOptions): UsersApiClient {\n const http = createHttpClient({ ...options, baseUrl: USERS_BASE_URL });\n\n return {\n async list(developerId, listOptions?) {\n const params: Record<string, string> = {};\n if (listOptions?.pageToken) params[\"pageToken\"] = listOptions.pageToken;\n if (listOptions?.pageSize) params[\"pageSize\"] = String(listOptions.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<UsersListResponse>(\n `/${developerId}/users`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(developerId, userId) {\n const { data } = await http.get<User>(`/${developerId}/users/${userId}`);\n return data;\n },\n\n async create(developerId, user) {\n const { data } = await http.post<User>(`/${developerId}/users`, user);\n return data;\n },\n\n async update(developerId, userId, user, updateMask?) {\n let path = `/${developerId}/users/${userId}`;\n if (updateMask) {\n path += `?updateMask=${encodeURIComponent(updateMask).replace(/%2C/gi, \",\")}`;\n }\n const { data } = await http.patch<User>(path, user);\n return data;\n },\n\n async delete(developerId, userId) {\n await http.delete(`/${developerId}/users/${userId}`);\n },\n };\n}\n","export interface RateLimitBucket {\n name: string;\n maxTokens: number;\n refillRate: number;\n refillIntervalMs: number;\n}\n\nexport interface RateLimiter {\n acquire(bucket: string): Promise<void>;\n}\n\ninterface BucketState {\n tokens: number;\n lastRefillTime: number;\n config: RateLimitBucket;\n}\n\nexport const RATE_LIMIT_BUCKETS: Record<string, RateLimitBucket> = {\n default: { name: \"default\", maxTokens: 200, refillRate: 200, refillIntervalMs: 1_000 },\n reviewsGet: { name: \"reviewsGet\", maxTokens: 200, refillRate: 200, refillIntervalMs: 3_600_000 },\n reviewsPost: {\n name: \"reviewsPost\",\n maxTokens: 2_000,\n refillRate: 2_000,\n refillIntervalMs: 86_400_000,\n },\n voidedBurst: { name: \"voidedBurst\", maxTokens: 30, refillRate: 30, refillIntervalMs: 30_000 },\n voidedDaily: {\n name: \"voidedDaily\",\n maxTokens: 6_000,\n refillRate: 6_000,\n refillIntervalMs: 86_400_000,\n },\n};\n\nexport function createRateLimiter(buckets?: RateLimitBucket[]): RateLimiter {\n const states = new Map<string, BucketState>();\n\n if (buckets) {\n for (const bucket of buckets) {\n states.set(bucket.name, {\n tokens: bucket.maxTokens,\n lastRefillTime: Date.now(),\n config: bucket,\n });\n }\n }\n\n return {\n async acquire(bucket: string): Promise<void> {\n const state = states.get(bucket);\n if (!state) return;\n\n const now = Date.now();\n const elapsed = now - state.lastRefillTime;\n const refill = Math.floor(\n (elapsed / state.config.refillIntervalMs) * state.config.refillRate,\n );\n\n if (refill > 0) {\n state.tokens = Math.min(state.config.maxTokens, state.tokens + refill);\n state.lastRefillTime = now;\n }\n\n if (state.tokens > 0) {\n state.tokens--;\n return;\n }\n\n const tokensNeeded = 1;\n const waitMs = Math.ceil(\n (tokensNeeded / state.config.refillRate) * state.config.refillIntervalMs,\n );\n await new Promise((r) => setTimeout(r, waitMs));\n\n // Recalculate refill based on actual elapsed time since last refill\n const afterWait = Date.now();\n const totalElapsed = afterWait - state.lastRefillTime;\n const newTokens = Math.floor(\n (totalElapsed / state.config.refillIntervalMs) * state.config.refillRate,\n );\n state.tokens = Math.min(state.config.maxTokens, newTokens) - 1;\n state.lastRefillTime = afterWait;\n },\n };\n}\n","export interface PaginateOptions {\n limit?: number;\n startPageToken?: string;\n}\n\nexport async function* paginate<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): AsyncGenerator<TItem[], void, unknown> {\n let pageToken = options?.startPageToken;\n let collected = 0;\n const limit = options?.limit;\n\n for (;;) {\n if (limit !== undefined && collected >= limit) break;\n\n const page = await fetchPage(pageToken);\n const items = page.items;\n\n if (items.length === 0) break;\n\n if (limit !== undefined) {\n const remaining = limit - collected;\n if (items.length > remaining) {\n yield items.slice(0, remaining);\n return;\n }\n }\n\n yield items;\n collected += items.length;\n pageToken = page.nextPageToken;\n\n if (!pageToken) break;\n }\n}\n\nexport async function paginateAll<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastPageToken: string | undefined;\n const limit = options?.limit;\n\n for await (const items of paginate(fetchPage, options)) {\n allItems.push(...items);\n if (limit !== undefined && allItems.length >= limit) break;\n }\n\n // If we stopped due to limit, try to get the next page token for resumption\n if (limit !== undefined && allItems.length >= limit) {\n lastPageToken = undefined; // Already truncated by paginate\n }\n\n return { items: allItems, nextPageToken: lastPageToken };\n}\n\n/**\n * Fetch multiple known pages in parallel.\n * Useful when page tokens are predictable or when pre-fetching subsequent pages\n * after an initial sequential fetch reveals the token pattern.\n *\n * @param fetchPage - Function that fetches a page given a token\n * @param pageTokens - Array of page tokens to fetch concurrently\n * @param concurrency - Max concurrent requests (default: 4)\n */\nexport async function paginateParallel<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n pageTokens: string[],\n concurrency = 4,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastNextPageToken: string | undefined;\n\n // Process in batches of `concurrency`\n for (let i = 0; i < pageTokens.length; i += concurrency) {\n const batch = pageTokens.slice(i, i + concurrency);\n const results = await Promise.all(batch.map((token) => fetchPage(token)));\n\n for (const result of results) {\n allItems.push(...result.items);\n if (result.nextPageToken) {\n lastNextPageToken = result.nextPageToken;\n }\n }\n }\n\n return { items: allItems, nextPageToken: lastNextPageToken };\n}\n"],"mappings":"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","names":["options"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/client.ts","../src/reporting-client.ts","../src/users-client.ts","../src/games-client.ts","../src/enterprise-client.ts","../src/rate-limiter.ts","../src/paginate.ts"],"sourcesContent":["export class PlayApiError extends Error {\n public readonly exitCode = 4;\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode?: number,\n public readonly suggestion?: string,\n ) {\n super(message);\n this.name = \"PlayApiError\";\n }\n toJSON() {\n return {\n success: false,\n error: {\n code: this.code,\n message: this.message,\n suggestion: this.suggestion,\n },\n };\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { PlayApiError } from \"./errors.js\";\nimport type { ApiClientOptions, ApiResponse } from \"./types.js\";\n\n/** Strip HTML tags and collapse whitespace from a string. */\nfunction stripHtml(text: string): string {\n return text\n .replace(/<[^>]*>/g, \" \")\n .replace(/&[a-z]+;/gi, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** Extract a short, safe error summary from API response body (no tokens/secrets). */\nfunction sanitizeErrorBody(body: string): string {\n try {\n const parsed = JSON.parse(body) as {\n error?: { message?: string; status?: string; code?: number };\n };\n if (parsed?.error?.message) {\n return `${parsed.error.code ?? \"?\"} ${parsed.error.status ?? \"\"}: ${parsed.error.message}`.trim();\n }\n } catch {\n // not JSON — may be HTML error page\n }\n // Strip HTML tags before truncating\n const cleaned = body.startsWith(\"<\") ? stripHtml(body) : body;\n return cleaned.length > 200 ? cleaned.slice(0, 200) + \"...\" : cleaned;\n}\n\n/** Validate upload file path to prevent path traversal. */\nfunction validateFilePath(filePath: string): string {\n const resolved = resolve(filePath);\n if (!isAbsolute(resolved)) {\n throw new PlayApiError(\n \"Invalid file path\",\n \"API_INVALID_PATH\",\n undefined,\n \"File path must resolve to an absolute path.\",\n );\n }\n // Block obvious traversal patterns in the original input\n if (filePath.includes(\"\\0\")) {\n throw new PlayApiError(\n \"Invalid file path: null bytes not allowed\",\n \"API_INVALID_PATH\",\n undefined,\n \"Provide a valid file path without null bytes.\",\n );\n }\n return resolved;\n}\n\nconst BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/applications\";\n\nconst UPLOAD_BASE_URL =\n \"https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications\";\n\nconst INTERNAL_SHARING_UPLOAD_BASE_URL =\n \"https://androidpublisher.googleapis.com/upload/internalappsharing/v3/applications\";\n\nexport interface HttpClient {\n get<T>(path: string, params?: Record<string, string>): Promise<ApiResponse<T>>;\n post<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n put<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n patch<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;\n delete<T>(path: string): Promise<ApiResponse<T>>;\n upload<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;\n uploadInternal<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;\n download(path: string): Promise<ArrayBuffer>;\n}\n\nfunction envInt(name: string): number | undefined {\n const val = process.env[name];\n if (val === undefined) return undefined;\n const n = Number(val);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction resolveOption(explicit: number | undefined, envName: string, fallback: number): number {\n return explicit ?? envInt(envName) ?? fallback;\n}\n\nfunction mapStatusToError(status: number, body: string): { code: string; suggestion?: string } {\n switch (status) {\n case 400: {\n // Detect FAILED_PRECONDITION: edit has expired\n try {\n const parsed = JSON.parse(body) as { error?: { status?: string; message?: string } };\n if (\n parsed?.error?.status === \"FAILED_PRECONDITION\" &&\n parsed.error.message?.toLowerCase().includes(\"edit\")\n ) {\n return {\n code: \"API_EDIT_EXPIRED\",\n suggestion: \"The edit session has expired. Retry the operation to open a fresh edit.\",\n };\n }\n } catch {\n /* not JSON */\n }\n return { code: \"API_HTTP_400\", suggestion: \"Check request parameters and try again.\" };\n }\n case 401:\n return {\n code: \"API_UNAUTHORIZED\",\n suggestion: \"Check that your access token is valid and not expired.\",\n };\n case 403:\n return {\n code: \"API_FORBIDDEN\",\n suggestion: \"Ensure the service account has the required permissions for this operation.\",\n };\n case 404:\n return {\n code: \"API_NOT_FOUND\",\n suggestion: \"Verify the package name and resource IDs are correct.\",\n };\n case 409:\n return {\n code: \"API_EDIT_CONFLICT\",\n suggestion: \"Another edit may be in progress. Delete the existing edit and retry.\",\n };\n case 429:\n return {\n code: \"API_RATE_LIMITED\",\n suggestion: \"Too many requests. The client will retry automatically.\",\n };\n default:\n if (status >= 500) {\n return {\n code: \"API_SERVER_ERROR\",\n suggestion: \"Google Play API server error. The client will retry automatically.\",\n };\n }\n return { code: `API_HTTP_${status}` };\n }\n}\n\nfunction isRetryable(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction jitteredDelay(base: number, attempt: number, max: number): number {\n const exponential = base * 2 ** attempt;\n const capped = Math.min(exponential, max);\n return capped * (0.5 + Math.random() * 0.5);\n}\n\nexport function createHttpClient(options: ApiClientOptions): HttpClient {\n const maxRetries = resolveOption(options.maxRetries, \"GPC_MAX_RETRIES\", 3);\n const timeout = resolveOption(options.timeout, \"GPC_TIMEOUT\", 30_000);\n const uploadTimeoutExplicit = options.uploadTimeout ?? envInt(\"GPC_UPLOAD_TIMEOUT\");\n const baseDelay = resolveOption(options.baseDelay, \"GPC_BASE_DELAY\", 1_000);\n const maxDelay = resolveOption(options.maxDelay, \"GPC_MAX_DELAY\", 60_000);\n const onRetry = options.onRetry;\n\n async function request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<ApiResponse<T>> {\n let url = `${options.baseUrl ?? BASE_URL}${path}`;\n if (params) {\n const search = new URLSearchParams(params);\n url += `?${search.toString()}`;\n }\n\n // Fetch token once before retries — the auth layer handles its own caching and mutex\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const init: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n keepalive: true,\n };\n\n if (body !== undefined) {\n init.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, init);\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new PlayApiError(\n `${method} ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof PlayApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const timeoutErr = new PlayApiError(\n `${method} ${path} timed out after ${timeout}ms`,\n \"API_TIMEOUT\",\n undefined,\n \"The request exceeded the configured timeout. Consider increasing the timeout value.\",\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new PlayApiError(\n `${method} ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method,\n path,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n // Should not reach here, but just in case\n throw (\n lastError ??\n new PlayApiError(\n \"Request failed\",\n \"API_NETWORK_ERROR\",\n undefined,\n \"Check your network connection and try again. Use --verbose for details.\",\n )\n );\n }\n\n /** Calculate upload timeout: explicit value, or auto-scale from file size (1 MB/s minimum throughput + 30s overhead). */\n function computeUploadTimeout(fileSizeBytes: number): number {\n if (uploadTimeoutExplicit !== undefined) return uploadTimeoutExplicit;\n // Base: 30s overhead + 1s per MB (assumes ~1 MB/s minimum upload speed)\n const sizeMb = fileSizeBytes / (1024 * 1024);\n return Math.max(timeout, 30_000 + Math.ceil(sizeMb) * 1_000);\n }\n\n async function uploadRequest<T>(\n path: string,\n filePath: string,\n contentType: string,\n baseUrl: string = UPLOAD_BASE_URL,\n ): Promise<ApiResponse<T>> {\n const url = `${baseUrl}${path}`;\n const safeFilePath = validateFilePath(filePath);\n const fileBuffer = await readFile(safeFilePath);\n const effectiveTimeout = computeUploadTimeout(fileBuffer.byteLength);\n\n // Fetch token once before retries\n let token = await options.auth.getAccessToken();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n const delay = jitteredDelay(baseDelay, attempt - 1, maxDelay);\n await new Promise((r) => setTimeout(r, delay));\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), effectiveTimeout);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": contentType,\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: fileBuffer,\n signal: controller.signal,\n keepalive: true,\n });\n\n if (response.ok) {\n const text = await response.text();\n const data = text ? (JSON.parse(text) as T) : ({} as T);\n return { data, status: response.status };\n }\n\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n\n const err = new PlayApiError(\n `POST upload ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n\n if (isRetryable(response.status) && attempt < maxRetries) {\n lastError = err;\n const delay = jitteredDelay(baseDelay, attempt, maxDelay);\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n status: response.status,\n error: err.message,\n delayMs: Math.round(delay),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n\n // On 401, refresh token once before giving up\n if (response.status === 401 && attempt < maxRetries) {\n token = await options.auth.getAccessToken();\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (error) {\n if (error instanceof PlayApiError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const sizeMb = Math.round(fileBuffer.byteLength / (1024 * 1024));\n const timeoutErr = new PlayApiError(\n `POST upload ${path} timed out after ${effectiveTimeout}ms (file: ${sizeMb} MB)`,\n \"API_TIMEOUT\",\n undefined,\n `Upload timed out. Set GPC_UPLOAD_TIMEOUT=${effectiveTimeout * 2} (ms) or use --timeout to increase.`,\n );\n if (attempt < maxRetries) {\n lastError = timeoutErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: timeoutErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw timeoutErr;\n }\n\n const networkErr = new PlayApiError(\n `POST upload ${path} failed: ${error instanceof Error ? error.message : String(error)}`,\n \"API_NETWORK_ERROR\",\n undefined,\n \"A network error occurred. Check your internet connection.\",\n );\n if (attempt < maxRetries) {\n lastError = networkErr;\n onRetry?.({\n attempt: attempt + 1,\n method: \"POST\",\n path: `upload ${path}`,\n error: networkErr.message,\n delayMs: Math.round(jitteredDelay(baseDelay, attempt, maxDelay)),\n timestamp: new Date().toISOString(),\n });\n continue;\n }\n throw networkErr;\n } finally {\n clearTimeout(timer);\n }\n }\n\n throw (\n lastError ??\n new PlayApiError(\n \"Upload request failed\",\n \"API_NETWORK_ERROR\",\n undefined,\n \"Check your network connection and try again. Use --verbose for details.\",\n )\n );\n }\n\n return {\n get<T>(path: string, params?: Record<string, string>) {\n return request<T>(\"GET\", path, undefined, params);\n },\n post<T>(path: string, body?: unknown) {\n return request<T>(\"POST\", path, body);\n },\n put<T>(path: string, body?: unknown) {\n return request<T>(\"PUT\", path, body);\n },\n patch<T>(path: string, body?: unknown) {\n return request<T>(\"PATCH\", path, body);\n },\n delete<T>(path: string) {\n return request<T>(\"DELETE\", path);\n },\n upload<T>(path: string, filePath: string, contentType: string) {\n return uploadRequest<T>(path, filePath, contentType);\n },\n uploadInternal<T>(path: string, filePath: string, contentType: string) {\n return uploadRequest<T>(path, filePath, contentType, INTERNAL_SHARING_UPLOAD_BASE_URL);\n },\n async download(path: string): Promise<ArrayBuffer> {\n const url = `${options.baseUrl ?? BASE_URL}${path}`;\n const token = await options.auth.getAccessToken();\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Accept-Encoding\": \"gzip, deflate\",\n Connection: \"keep-alive\",\n },\n signal: controller.signal,\n keepalive: true,\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n const { code, suggestion } = mapStatusToError(response.status, errorBody);\n throw new PlayApiError(\n `GET ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,\n code,\n response.status,\n suggestion,\n );\n }\n\n return await response.arrayBuffer();\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n","import { PlayApiError } from \"./errors.js\";\nimport { createHttpClient } from \"./http.js\";\nimport type { RateLimiter } from \"./rate-limiter.js\";\nimport type {\n ApiClientOptions,\n AppDetails,\n AppEdit,\n AppRecoveriesListResponse,\n AppRecoveryAction,\n AppRecoveryTargeting,\n CreateAppRecoveryActionRequest,\n BasePlanMigratePricesRequest,\n Bundle,\n BundleListResponse,\n ConvertRegionPricesRequest,\n ConvertRegionPricesResponse,\n CountryAvailability,\n DataSafety,\n DeobfuscationFile,\n DeobfuscationUploadResponse,\n DeviceTierConfig,\n DeviceTierConfigsListResponse,\n ExternalTransaction,\n ExternalTransactionRefund,\n ExternallyHostedApk,\n ExternallyHostedApkResponse,\n Image,\n ImageType,\n ImageUploadResponse,\n ImagesDeleteAllResponse,\n ImagesListResponse,\n InAppProduct,\n InAppProductsListResponse,\n Listing,\n ListingsListResponse,\n OffersListResponse,\n ProductPurchase,\n Release,\n ReportsListResponse,\n ReportType,\n Review,\n ReviewReplyRequest,\n ReviewReplyResponse,\n ReviewsListOptions,\n ReviewsListResponse,\n Subscription,\n SubscriptionDeferRequest,\n SubscriptionDeferResponse,\n SubscriptionOffer,\n SubscriptionPurchase,\n SubscriptionPurchaseV2,\n SubscriptionsListResponse,\n Testers,\n Track,\n TrackListResponse,\n VoidedPurchasesListResponse,\n OneTimeProduct,\n OneTimeProductsListResponse,\n OneTimeOffer,\n OneTimeOffersListResponse,\n InternalAppSharingArtifact,\n GeneratedApk,\n GeneratedApksPerVersion,\n PurchaseOption,\n PurchaseOptionsListResponse,\n InAppProductsBatchUpdateRequest,\n InAppProductsBatchUpdateResponse,\n} from \"./types.js\";\n\nexport interface PlayApiClient {\n edits: {\n insert(packageName: string): Promise<AppEdit>;\n get(packageName: string, editId: string): Promise<AppEdit>;\n validate(packageName: string, editId: string): Promise<AppEdit>;\n commit(packageName: string, editId: string): Promise<AppEdit>;\n delete(packageName: string, editId: string): Promise<void>;\n };\n\n details: {\n get(packageName: string, editId: string): Promise<AppDetails>;\n update(packageName: string, editId: string, details: Partial<AppDetails>): Promise<AppDetails>;\n patch(packageName: string, editId: string, partial: Partial<AppDetails>): Promise<AppDetails>;\n };\n\n bundles: {\n list(packageName: string, editId: string): Promise<Bundle[]>;\n upload(packageName: string, editId: string, filePath: string): Promise<Bundle>;\n };\n\n tracks: {\n list(packageName: string, editId: string): Promise<Track[]>;\n get(packageName: string, editId: string, track: string): Promise<Track>;\n create(packageName: string, editId: string, trackName: string): Promise<Track>;\n update(packageName: string, editId: string, track: string, release: Release): Promise<Track>;\n };\n\n apks: {\n addExternallyHosted(\n packageName: string,\n editId: string,\n data: ExternallyHostedApk,\n ): Promise<ExternallyHostedApkResponse>;\n };\n\n listings: {\n list(packageName: string, editId: string): Promise<Listing[]>;\n get(packageName: string, editId: string, language: string): Promise<Listing>;\n update(\n packageName: string,\n editId: string,\n language: string,\n listing: Omit<Listing, \"language\">,\n ): Promise<Listing>;\n patch(\n packageName: string,\n editId: string,\n language: string,\n partial: Partial<Omit<Listing, \"language\">>,\n ): Promise<Listing>;\n delete(packageName: string, editId: string, language: string): Promise<void>;\n deleteAll(packageName: string, editId: string): Promise<void>;\n };\n\n images: {\n list(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n upload(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n filePath: string,\n ): Promise<Image>;\n delete(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n imageId: string,\n ): Promise<void>;\n deleteAll(\n packageName: string,\n editId: string,\n language: string,\n imageType: ImageType,\n ): Promise<Image[]>;\n };\n\n countryAvailability: {\n get(packageName: string, editId: string, track: string): Promise<CountryAvailability>;\n };\n\n dataSafety: {\n get(packageName: string): Promise<DataSafety>;\n update(packageName: string, data: DataSafety): Promise<DataSafety>;\n };\n\n reviews: {\n list(packageName: string, options?: ReviewsListOptions): Promise<ReviewsListResponse>;\n get(packageName: string, reviewId: string, translationLanguage?: string): Promise<Review>;\n reply(packageName: string, reviewId: string, replyText: string): Promise<ReviewReplyResponse>;\n };\n\n subscriptions: {\n list(\n packageName: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<SubscriptionsListResponse>;\n get(packageName: string, productId: string): Promise<Subscription>;\n create(packageName: string, data: Subscription, productId?: string): Promise<Subscription>;\n update(\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<Subscription>;\n delete(packageName: string, productId: string): Promise<void>;\n activateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deactivateBasePlan(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<Subscription>;\n deleteBasePlan(packageName: string, productId: string, basePlanId: string): Promise<void>;\n migratePrices(\n packageName: string,\n productId: string,\n basePlanId: string,\n body: BasePlanMigratePricesRequest,\n ): Promise<Subscription>;\n listOffers(\n packageName: string,\n productId: string,\n basePlanId: string,\n ): Promise<OffersListResponse>;\n getOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n createOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n data: SubscriptionOffer,\n offerId?: string,\n ): Promise<SubscriptionOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<SubscriptionOffer>;\n deleteOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<void>;\n activateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n deactivateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n ): Promise<SubscriptionOffer>;\n };\n\n inappproducts: {\n list(\n packageName: string,\n options?: { token?: string; maxResults?: number },\n ): Promise<InAppProductsListResponse>;\n get(packageName: string, sku: string): Promise<InAppProduct>;\n create(\n packageName: string,\n data: InAppProduct,\n options?: { autoConvertMissingPrices?: boolean },\n ): Promise<InAppProduct>;\n update(\n packageName: string,\n sku: string,\n data: InAppProduct,\n options?: { autoConvertMissingPrices?: boolean; allowMissing?: boolean },\n ): Promise<InAppProduct>;\n delete(packageName: string, sku: string): Promise<void>;\n batchUpdate(\n packageName: string,\n requests: InAppProductsBatchUpdateRequest,\n ): Promise<InAppProductsBatchUpdateResponse>;\n batchGet(packageName: string, skus: string[]): Promise<InAppProduct[]>;\n };\n\n purchases: {\n getProduct(packageName: string, productId: string, token: string): Promise<ProductPurchase>;\n acknowledgeProduct(\n packageName: string,\n productId: string,\n token: string,\n body?: { developerPayload?: string },\n ): Promise<void>;\n consumeProduct(packageName: string, productId: string, token: string): Promise<void>;\n getSubscriptionV2(packageName: string, token: string): Promise<SubscriptionPurchaseV2>;\n getSubscriptionV1(\n packageName: string,\n subscriptionId: string,\n token: string,\n ): Promise<SubscriptionPurchase>;\n cancelSubscription(packageName: string, subscriptionId: string, token: string): Promise<void>;\n deferSubscription(\n packageName: string,\n subscriptionId: string,\n token: string,\n body: SubscriptionDeferRequest,\n ): Promise<SubscriptionDeferResponse>;\n revokeSubscriptionV2(packageName: string, token: string): Promise<void>;\n refundSubscriptionV2(packageName: string, token: string): Promise<void>;\n listVoided(\n packageName: string,\n options?: { startTime?: string; endTime?: string; maxResults?: number; token?: string },\n ): Promise<VoidedPurchasesListResponse>;\n };\n\n orders: {\n refund(\n packageName: string,\n orderId: string,\n body?: { fullRefund?: boolean; proratedRefund?: boolean },\n ): Promise<void>;\n };\n\n monetization: {\n convertRegionPrices(\n packageName: string,\n price: ConvertRegionPricesRequest,\n ): Promise<ConvertRegionPricesResponse>;\n };\n\n reports: {\n list(\n packageName: string,\n reportType: ReportType,\n year: number,\n month: number,\n ): Promise<ReportsListResponse>;\n };\n\n testers: {\n get(packageName: string, editId: string, track: string): Promise<Testers>;\n update(packageName: string, editId: string, track: string, testers: Testers): Promise<Testers>;\n };\n\n deobfuscation: {\n upload(\n packageName: string,\n editId: string,\n versionCode: number,\n filePath: string,\n ): Promise<DeobfuscationFile>;\n };\n\n appRecovery: {\n list(packageName: string, versionCode?: number): Promise<AppRecoveryAction[]>;\n cancel(packageName: string, appRecoveryId: string): Promise<void>;\n deploy(packageName: string, appRecoveryId: string): Promise<void>;\n create(\n packageName: string,\n request: CreateAppRecoveryActionRequest,\n ): Promise<AppRecoveryAction>;\n addTargeting(\n packageName: string,\n appRecoveryId: string,\n targeting: AppRecoveryTargeting,\n ): Promise<AppRecoveryAction>;\n };\n\n externalTransactions: {\n create(packageName: string, data: ExternalTransaction): Promise<ExternalTransaction>;\n get(packageName: string, transactionId: string): Promise<ExternalTransaction>;\n refund(\n packageName: string,\n transactionId: string,\n refundData: ExternalTransactionRefund,\n ): Promise<ExternalTransaction>;\n };\n\n deviceTiers: {\n list(packageName: string): Promise<DeviceTierConfig[]>;\n get(packageName: string, configId: string): Promise<DeviceTierConfig>;\n create(packageName: string, config: DeviceTierConfig): Promise<DeviceTierConfig>;\n };\n\n oneTimeProducts: {\n list(packageName: string): Promise<OneTimeProductsListResponse>;\n get(packageName: string, productId: string): Promise<OneTimeProduct>;\n create(packageName: string, product: OneTimeProduct): Promise<OneTimeProduct>;\n update(\n packageName: string,\n productId: string,\n product: Partial<OneTimeProduct>,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<OneTimeProduct>;\n delete(packageName: string, productId: string): Promise<void>;\n listOffers(packageName: string, productId: string): Promise<OneTimeOffersListResponse>;\n getOffer(packageName: string, productId: string, offerId: string): Promise<OneTimeOffer>;\n createOffer(packageName: string, productId: string, offer: OneTimeOffer): Promise<OneTimeOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n offerId: string,\n offer: Partial<OneTimeOffer>,\n updateMask?: string,\n regionsVersion?: string,\n ): Promise<OneTimeOffer>;\n deleteOffer(packageName: string, productId: string, offerId: string): Promise<void>;\n };\n\n purchaseOptions: {\n list(packageName: string): Promise<PurchaseOptionsListResponse>;\n get(packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;\n create(packageName: string, data: PurchaseOption): Promise<PurchaseOption>;\n activate(packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;\n deactivate(packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;\n };\n\n internalAppSharing: {\n uploadBundle(packageName: string, bundlePath: string): Promise<InternalAppSharingArtifact>;\n uploadApk(packageName: string, apkPath: string): Promise<InternalAppSharingArtifact>;\n };\n\n generatedApks: {\n list(packageName: string, versionCode: number): Promise<GeneratedApk[]>;\n download(packageName: string, versionCode: number, id: string): Promise<ArrayBuffer>;\n };\n}\n\nasync function rateLimit(limiter: RateLimiter | undefined, bucket: string): Promise<void> {\n if (limiter) await limiter.acquire(bucket);\n}\n\nexport function createApiClient(options: ApiClientOptions): PlayApiClient {\n const http = createHttpClient(options);\n const limiter = options.rateLimiter || undefined;\n\n return {\n edits: {\n async insert(packageName) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits`);\n return data;\n },\n\n async get(packageName, editId) {\n const { data } = await http.get<AppEdit>(`/${packageName}/edits/${editId}`);\n return data;\n },\n\n async validate(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:validate`);\n return data;\n },\n\n async commit(packageName, editId) {\n const { data } = await http.post<AppEdit>(`/${packageName}/edits/${editId}:commit`);\n return data;\n },\n\n async delete(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}`);\n },\n },\n\n details: {\n async get(packageName, editId) {\n const { data } = await http.get<AppDetails>(`/${packageName}/edits/${editId}/details`);\n return data;\n },\n\n async update(packageName, editId, details) {\n const { data } = await http.put<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n details,\n );\n return data;\n },\n\n async patch(packageName, editId, partial) {\n const { data } = await http.patch<AppDetails>(\n `/${packageName}/edits/${editId}/details`,\n partial,\n );\n return data;\n },\n },\n\n bundles: {\n async list(packageName, editId) {\n const { data } = await http.get<BundleListResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n );\n return data.bundles;\n },\n\n async upload(packageName, editId, filePath) {\n const { data } = await http.upload<Bundle>(\n `/${packageName}/edits/${editId}/bundles`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data || !data.versionCode) {\n throw new PlayApiError(\n \"Upload succeeded but no bundle data returned\",\n \"API_EMPTY_RESPONSE\",\n 200,\n \"This is unexpected. Retry the upload or contact Google Play support if the issue persists.\",\n );\n }\n return data;\n },\n },\n\n tracks: {\n async list(packageName, editId) {\n const { data } = await http.get<TrackListResponse>(\n `/${packageName}/edits/${editId}/tracks`,\n );\n return data.tracks;\n },\n\n async get(packageName, editId, track) {\n const { data } = await http.get<Track>(`/${packageName}/edits/${editId}/tracks/${track}`);\n return data;\n },\n\n async create(packageName, editId, trackName) {\n const { data } = await http.post<Track>(`/${packageName}/edits/${editId}/tracks`, {\n track: trackName,\n });\n return data;\n },\n\n async update(packageName, editId, track, release) {\n const { data } = await http.put<Track>(`/${packageName}/edits/${editId}/tracks/${track}`, {\n track,\n releases: [release],\n });\n return data;\n },\n },\n\n apks: {\n async addExternallyHosted(packageName, editId, apkData) {\n const { data } = await http.post<ExternallyHostedApkResponse>(\n `/${packageName}/edits/${editId}/apks/externallyHosted`,\n { externallyHostedApk: apkData },\n );\n return data;\n },\n },\n\n listings: {\n async list(packageName, editId) {\n const { data } = await http.get<ListingsListResponse>(\n `/${packageName}/edits/${editId}/listings`,\n );\n return data.listings || [];\n },\n\n async get(packageName, editId, language) {\n const { data } = await http.get<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n );\n return data;\n },\n\n async update(packageName, editId, language, listing) {\n const { data } = await http.put<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n listing,\n );\n return data;\n },\n\n async patch(packageName, editId, language, partial) {\n const { data } = await http.patch<Listing>(\n `/${packageName}/edits/${editId}/listings/${language}`,\n partial,\n );\n return data;\n },\n\n async delete(packageName, editId, language) {\n await http.delete(`/${packageName}/edits/${editId}/listings/${language}`);\n },\n\n async deleteAll(packageName, editId) {\n await http.delete(`/${packageName}/edits/${editId}/listings`);\n },\n },\n\n images: {\n async list(packageName, editId, language, imageType) {\n const { data } = await http.get<ImagesListResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.images || [];\n },\n\n async upload(packageName, editId, language, imageType, filePath) {\n const { data } = await http.upload<ImageUploadResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n filePath,\n filePath.endsWith(\".png\") ? \"image/png\" : \"image/jpeg\",\n );\n if (!data.image) {\n throw new PlayApiError(\n \"Upload succeeded but no image data returned\",\n \"API_EMPTY_RESPONSE\",\n 200,\n \"This is unexpected. Retry the upload or contact Google Play support if the issue persists.\",\n );\n }\n return data.image;\n },\n\n async delete(packageName, editId, language, imageType, imageId) {\n await http.delete(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}/${imageId}`,\n );\n },\n\n async deleteAll(packageName, editId, language, imageType) {\n const { data } = await http.delete<ImagesDeleteAllResponse>(\n `/${packageName}/edits/${editId}/listings/${language}/${imageType}`,\n );\n return data.deleted || [];\n },\n },\n\n countryAvailability: {\n async get(packageName, editId, track) {\n const { data } = await http.get<CountryAvailability>(\n `/${packageName}/edits/${editId}/countryAvailability/${track}`,\n );\n return data;\n },\n },\n\n dataSafety: {\n async get(packageName) {\n const { data } = await http.get<DataSafety>(`/${packageName}/dataSafety`);\n return data;\n },\n\n async update(packageName, body) {\n const { data } = await http.put<DataSafety>(`/${packageName}/dataSafety`, body);\n return data;\n },\n },\n\n reviews: {\n async list(packageName, options?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.translationLanguage)\n params[\"translationLanguage\"] = options.translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<ReviewsListResponse>(\n `/${packageName}/reviews`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, reviewId, translationLanguage?) {\n await rateLimit(limiter, \"reviewsGet\");\n const params: Record<string, string> = {};\n if (translationLanguage) params[\"translationLanguage\"] = translationLanguage;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<Review>(\n `/${packageName}/reviews/${reviewId}`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async reply(packageName, reviewId, replyText) {\n await rateLimit(limiter, \"reviewsPost\");\n const body: ReviewReplyRequest = { replyText };\n const { data } = await http.post<ReviewReplyResponse>(\n `/${packageName}/reviews/${reviewId}:reply`,\n body,\n );\n return data;\n },\n },\n\n subscriptions: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.pageToken) params[\"pageToken\"] = options.pageToken;\n if (options?.pageSize) params[\"pageSize\"] = String(options.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<SubscriptionsListResponse>(\n `/${packageName}/subscriptions`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, productId) {\n const { data } = await http.get<Subscription>(`/${packageName}/subscriptions/${productId}`);\n return data;\n },\n\n async create(packageName, body, productId?) {\n const params: Record<string, string> = {};\n if (productId) params[\"productId\"] = productId;\n params[\"regionsVersion.version\"] = \"2022/02\";\n const path = `/${packageName}/subscriptions?${new URLSearchParams(params).toString()}`;\n const { data } = await http.post<Subscription>(path, body);\n return data;\n },\n\n async update(packageName, productId, body, updateMask?, regionsVersion?) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n const path = `/${packageName}/subscriptions/${productId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<Subscription>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/subscriptions/${productId}`);\n },\n\n async activateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}:activate`,\n );\n return data;\n },\n\n async deactivateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}:deactivate`,\n );\n return data;\n },\n\n async deleteBasePlan(packageName, productId, basePlanId) {\n await http.delete(`/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}`);\n },\n\n async migratePrices(packageName, productId, basePlanId, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}:migratePrices`,\n body,\n );\n return data;\n },\n\n async listOffers(packageName, productId, basePlanId) {\n const { data } = await http.get<OffersListResponse>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n );\n return data;\n },\n\n async getOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.get<SubscriptionOffer>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, basePlanId, body, offerId?) {\n const params: Record<string, string> = {};\n if (offerId) params[\"offerId\"] = offerId;\n params[\"regionsVersion.version\"] = \"2022/02\";\n const path = `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers?${new URLSearchParams(params).toString()}`;\n const { data } = await http.post<SubscriptionOffer>(path, body);\n return data;\n },\n\n async updateOffer(\n packageName,\n productId,\n basePlanId,\n offerId,\n body,\n updateMask?,\n regionsVersion?,\n ) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n const path = `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<SubscriptionOffer>(path, body);\n return data;\n },\n\n async deleteOffer(packageName, productId, basePlanId, offerId) {\n await http.delete(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n },\n\n async activateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:activate`,\n );\n return data;\n },\n\n async deactivateOffer(packageName, productId, basePlanId, offerId) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}:deactivate`,\n );\n return data;\n },\n },\n\n inappproducts: {\n async list(packageName, options?) {\n const params: Record<string, string> = {};\n if (options?.token) params[\"token\"] = options.token;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<InAppProductsListResponse>(\n `/${packageName}/inappproducts`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(packageName, sku) {\n const { data } = await http.get<InAppProduct>(`/${packageName}/inappproducts/${sku}`);\n return data;\n },\n\n async create(packageName, body, options?) {\n const params: Record<string, string> = {};\n if (options?.autoConvertMissingPrices) params[\"autoConvertMissingPrices\"] = \"true\";\n const hasParams = Object.keys(params).length > 0;\n const path = hasParams\n ? `/${packageName}/inappproducts?${new URLSearchParams(params).toString()}`\n : `/${packageName}/inappproducts`;\n const { data } = await http.post<InAppProduct>(path, body);\n return data;\n },\n\n async update(packageName, sku, body, options?) {\n const params: Record<string, string> = {};\n if (options?.autoConvertMissingPrices) params[\"autoConvertMissingPrices\"] = \"true\";\n if (options?.allowMissing) params[\"allowMissing\"] = \"true\";\n const hasParams = Object.keys(params).length > 0;\n const path = hasParams\n ? `/${packageName}/inappproducts/${sku}?${new URLSearchParams(params).toString()}`\n : `/${packageName}/inappproducts/${sku}`;\n const { data } = await http.put<InAppProduct>(path, body);\n return data;\n },\n\n async delete(packageName, sku) {\n await http.delete(`/${packageName}/inappproducts/${sku}`);\n },\n\n async batchUpdate(packageName, requests) {\n const { data } = await http.post<InAppProductsBatchUpdateResponse>(\n `/${packageName}/inappproducts:batchUpdate`,\n requests,\n );\n return data;\n },\n\n async batchGet(packageName, skus) {\n const params: Record<string, string> = {};\n if (skus.length > 0) {\n params[\"sku\"] = skus.join(\",\");\n }\n const { data } = await http.get<{ inappproduct: InAppProduct[] }>(\n `/${packageName}/inappproducts:batchGet`,\n Object.keys(params).length > 0 ? params : undefined,\n );\n return data.inappproduct || [];\n },\n },\n\n purchases: {\n async getProduct(packageName, productId, token) {\n const { data } = await http.get<ProductPurchase>(\n `/${packageName}/purchases/products/${productId}/tokens/${token}`,\n );\n return data;\n },\n\n async acknowledgeProduct(packageName, productId, token, body?) {\n await http.post(\n `/${packageName}/purchases/products/${productId}/tokens/${token}:acknowledge`,\n body,\n );\n },\n\n async consumeProduct(packageName, productId, token) {\n await http.post(`/${packageName}/purchases/products/${productId}/tokens/${token}:consume`);\n },\n\n async getSubscriptionV2(packageName, token) {\n const { data } = await http.get<SubscriptionPurchaseV2>(\n `/${packageName}/purchases/subscriptionsv2/tokens/${token}`,\n );\n return data;\n },\n\n async getSubscriptionV1(packageName, subscriptionId, token) {\n const { data } = await http.get<SubscriptionPurchase>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}`,\n );\n return data;\n },\n\n async cancelSubscription(packageName, subscriptionId, token) {\n await http.post(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:cancel`,\n );\n },\n\n async deferSubscription(packageName, subscriptionId, token, body) {\n const { data } = await http.post<SubscriptionDeferResponse>(\n `/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}:defer`,\n body,\n );\n return data;\n },\n\n async revokeSubscriptionV2(packageName, token) {\n await http.post(`/${packageName}/purchases/subscriptionsv2/tokens/${token}:revoke`);\n },\n\n async refundSubscriptionV2(packageName, token) {\n await http.post(`/${packageName}/purchases/subscriptionsv2/tokens/${token}:refund`);\n },\n\n async listVoided(packageName, options?) {\n await rateLimit(limiter, \"voidedBurst\");\n await rateLimit(limiter, \"voidedDaily\");\n const params: Record<string, string> = {};\n if (options?.startTime) params[\"startTime\"] = options.startTime;\n if (options?.endTime) params[\"endTime\"] = options.endTime;\n if (options?.maxResults) params[\"maxResults\"] = String(options.maxResults);\n if (options?.token) params[\"token\"] = options.token;\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<VoidedPurchasesListResponse>(\n `/${packageName}/purchases/voidedpurchases`,\n hasParams ? params : undefined,\n );\n return data;\n },\n },\n\n orders: {\n async refund(packageName, orderId, body?) {\n await http.post(`/${packageName}/orders/${orderId}:refund`, body);\n },\n },\n\n monetization: {\n async convertRegionPrices(packageName, price) {\n const { data } = await http.post<ConvertRegionPricesResponse>(\n `/${packageName}/pricing:convertRegionPrices`,\n price,\n );\n return data;\n },\n },\n\n reports: {\n async list(packageName, reportType, year, month) {\n const monthStr = String(month).padStart(2, \"0\");\n const { data } = await http.get<ReportsListResponse>(\n `/${packageName}/reports/${reportType}/${year}/${monthStr}`,\n );\n return data;\n },\n },\n\n testers: {\n async get(packageName, editId, track) {\n const { data } = await http.get<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n );\n return data;\n },\n\n async update(packageName, editId, track, testersData) {\n const { data } = await http.put<Testers>(\n `/${packageName}/edits/${editId}/testers/${track}`,\n testersData,\n );\n return data;\n },\n },\n\n deobfuscation: {\n async upload(packageName, editId, versionCode, filePath) {\n const { data } = await http.upload<DeobfuscationUploadResponse>(\n `/${packageName}/edits/${editId}/apks/${versionCode}/deobfuscationFiles/proguard`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data.deobfuscationFile) {\n throw new PlayApiError(\n \"Upload succeeded but no deobfuscation file data returned\",\n \"API_EMPTY_RESPONSE\",\n 200,\n \"This is unexpected. Retry the upload or contact Google Play support if the issue persists.\",\n );\n }\n return data.deobfuscationFile;\n },\n },\n\n appRecovery: {\n async list(packageName, versionCode?) {\n const params: Record<string, string> = {};\n if (versionCode !== undefined) params[\"versionCode\"] = String(versionCode);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<AppRecoveriesListResponse>(\n `/${packageName}/appRecoveries`,\n hasParams ? params : undefined,\n );\n return data.recoveryActions || [];\n },\n\n async cancel(packageName, appRecoveryId) {\n await http.post(`/${packageName}/appRecovery/${appRecoveryId}:cancel`);\n },\n\n async deploy(packageName, appRecoveryId) {\n await http.post(`/${packageName}/appRecovery/${appRecoveryId}:deploy`);\n },\n\n async create(packageName, request) {\n const { data } = await http.post<AppRecoveryAction>(\n `/${packageName}/appRecoveries`,\n request,\n );\n return data;\n },\n\n async addTargeting(packageName, appRecoveryId, targeting) {\n const { data } = await http.post<AppRecoveryAction>(\n `/${packageName}/appRecoveries/${appRecoveryId}:addTargeting`,\n targeting,\n );\n return data;\n },\n },\n\n externalTransactions: {\n async create(packageName, body) {\n const { data } = await http.post<ExternalTransaction>(\n `/${packageName}/externalTransactions`,\n body,\n );\n return data;\n },\n\n async get(packageName, transactionId) {\n const { data } = await http.get<ExternalTransaction>(\n `/${packageName}/externalTransactions/${transactionId}`,\n );\n return data;\n },\n\n async refund(packageName, transactionId, refundData) {\n const { data } = await http.post<ExternalTransaction>(\n `/${packageName}/externalTransactions/${transactionId}:refund`,\n refundData,\n );\n return data;\n },\n },\n\n deviceTiers: {\n async list(packageName) {\n const { data } = await http.get<DeviceTierConfigsListResponse>(\n `/${packageName}/deviceTierConfigs`,\n );\n return data.deviceTierConfigs || [];\n },\n\n async get(packageName, configId) {\n const { data } = await http.get<DeviceTierConfig>(\n `/${packageName}/deviceTierConfigs/${configId}`,\n );\n return data;\n },\n\n async create(packageName, config) {\n const { data } = await http.post<DeviceTierConfig>(\n `/${packageName}/deviceTierConfigs`,\n config,\n );\n return data;\n },\n },\n\n oneTimeProducts: {\n async list(packageName) {\n const { data } = await http.get<OneTimeProductsListResponse>(\n `/${packageName}/oneTimeProducts`,\n );\n return data;\n },\n\n async get(packageName, productId) {\n const { data } = await http.get<OneTimeProduct>(\n `/${packageName}/oneTimeProducts/${productId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const params = new URLSearchParams({ \"regionsVersion.version\": \"2022/02\" });\n const { data } = await http.post<OneTimeProduct>(\n `/${packageName}/oneTimeProducts?${params.toString()}`,\n body,\n );\n return data;\n },\n\n async update(packageName, productId, body, updateMask?, regionsVersion?) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n const path = `/${packageName}/oneTimeProducts/${productId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<OneTimeProduct>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/oneTimeProducts/${productId}`);\n },\n\n async listOffers(packageName, productId) {\n const { data } = await http.get<OneTimeOffersListResponse>(\n `/${packageName}/oneTimeProducts/${productId}/offers`,\n );\n return data;\n },\n\n async getOffer(packageName, productId, offerId) {\n const { data } = await http.get<OneTimeOffer>(\n `/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, body) {\n const { data } = await http.post<OneTimeOffer>(\n `/${packageName}/oneTimeProducts/${productId}/offers`,\n body,\n );\n return data;\n },\n\n async updateOffer(packageName, productId, offerId, body, updateMask?, regionsVersion?) {\n const params: Record<string, string> = {};\n if (updateMask) params[\"updateMask\"] = updateMask;\n params[\"regionsVersion.version\"] = regionsVersion || \"2022/02\";\n const path = `/${packageName}/oneTimeProducts/${productId}/offers/${offerId}?${new URLSearchParams(params).toString()}`;\n const { data } = await http.patch<OneTimeOffer>(path, body);\n return data;\n },\n\n async deleteOffer(packageName, productId, offerId) {\n await http.delete(`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`);\n },\n },\n\n purchaseOptions: {\n async list(packageName) {\n const { data } = await http.get<PurchaseOptionsListResponse>(\n `/${packageName}/purchaseOptions`,\n );\n return data;\n },\n\n async get(packageName, purchaseOptionId) {\n const { data } = await http.get<PurchaseOption>(\n `/${packageName}/purchaseOptions/${purchaseOptionId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<PurchaseOption>(`/${packageName}/purchaseOptions`, body);\n return data;\n },\n\n async activate(packageName, purchaseOptionId) {\n const { data } = await http.post<PurchaseOption>(\n `/${packageName}/purchaseOptions/${purchaseOptionId}:activate`,\n );\n return data;\n },\n\n async deactivate(packageName, purchaseOptionId) {\n const { data } = await http.post<PurchaseOption>(\n `/${packageName}/purchaseOptions/${purchaseOptionId}:deactivate`,\n );\n return data;\n },\n },\n\n internalAppSharing: {\n async uploadBundle(packageName, bundlePath) {\n const { data } = await http.uploadInternal<InternalAppSharingArtifact>(\n `/${packageName}/artifacts/bundle`,\n bundlePath,\n \"application/octet-stream\",\n );\n return data;\n },\n\n async uploadApk(packageName, apkPath) {\n const { data } = await http.uploadInternal<InternalAppSharingArtifact>(\n `/${packageName}/artifacts/apk`,\n apkPath,\n \"application/vnd.android.package-archive\",\n );\n return data;\n },\n },\n\n generatedApks: {\n async list(packageName, versionCode) {\n const { data } = await http.get<GeneratedApksPerVersion>(\n `/${packageName}/generatedApks/${versionCode}`,\n );\n return data.generatedApks || [];\n },\n\n async download(packageName, versionCode, id) {\n return http.download(`/${packageName}/generatedApks/${versionCode}/download/${id}`);\n },\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type {\n AnomalyDetectionResponse,\n ApiClientOptions,\n ErrorIssuesResponse,\n ErrorReportsResponse,\n MetricSetQuery,\n MetricSetResponse,\n VitalsMetricSet,\n} from \"./types.js\";\n\nconst REPORTING_BASE_URL = \"https://playdeveloperreporting.googleapis.com/v1beta1\";\n\nexport interface ReportingApiClient {\n queryMetricSet(\n packageName: string,\n metricSet: VitalsMetricSet,\n query: MetricSetQuery,\n ): Promise<MetricSetResponse>;\n\n getAnomalies(packageName: string): Promise<AnomalyDetectionResponse>;\n\n searchErrorIssues(\n packageName: string,\n filter?: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorIssuesResponse>;\n\n searchErrorReports(\n packageName: string,\n issueName: string,\n pageSize?: number,\n pageToken?: string,\n ): Promise<ErrorReportsResponse>;\n}\n\nexport function createReportingClient(options: ApiClientOptions): ReportingApiClient {\n const http = createHttpClient({ ...options, baseUrl: REPORTING_BASE_URL });\n\n return {\n async queryMetricSet(packageName, metricSet, query) {\n const { data } = await http.post<MetricSetResponse>(\n `/apps/${packageName}/${metricSet}:query`,\n query,\n );\n return data;\n },\n\n async getAnomalies(packageName) {\n const { data } = await http.get<AnomalyDetectionResponse>(`/apps/${packageName}/anomalies`);\n return data;\n },\n\n async searchErrorIssues(packageName, filter?, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (filter) params[\"filter\"] = filter;\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorIssuesResponse>(\n `/apps/${packageName}/errorIssues:search`,\n params,\n );\n return data;\n },\n\n async searchErrorReports(packageName, issueName, pageSize?, pageToken?) {\n const params: Record<string, string> = {};\n if (pageSize) params[\"pageSize\"] = String(pageSize);\n if (pageToken) params[\"pageToken\"] = pageToken;\n const { data } = await http.get<ErrorReportsResponse>(\n `/apps/${packageName}/errorIssues/${issueName}/reports`,\n params,\n );\n return data;\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { ApiClientOptions, User, UsersListResponse, Grant } from \"./types.js\";\n\nconst USERS_BASE_URL = \"https://androidpublisher.googleapis.com/androidpublisher/v3/developers\";\n\nexport interface GrantsListResponse {\n grants: Grant[];\n nextPageToken?: string;\n}\n\nexport interface UsersApiClient {\n list(\n developerId: string,\n options?: { pageToken?: string; pageSize?: number },\n ): Promise<UsersListResponse>;\n\n get(developerId: string, userId: string): Promise<User>;\n\n create(developerId: string, user: Partial<User>): Promise<User>;\n\n update(\n developerId: string,\n userId: string,\n user: Partial<User>,\n updateMask?: string,\n ): Promise<User>;\n\n delete(developerId: string, userId: string): Promise<void>;\n\n grants: {\n list(developerId: string, email: string): Promise<GrantsListResponse>;\n create(developerId: string, email: string, grant: Partial<Grant>): Promise<Grant>;\n patch(\n developerId: string,\n email: string,\n packageName: string,\n grant: Partial<Grant>,\n updateMask?: string,\n ): Promise<Grant>;\n delete(developerId: string, email: string, packageName: string): Promise<void>;\n };\n}\n\nexport function createUsersClient(options: ApiClientOptions): UsersApiClient {\n const http = createHttpClient({ ...options, baseUrl: USERS_BASE_URL });\n\n return {\n async list(developerId, listOptions?) {\n const params: Record<string, string> = {};\n if (listOptions?.pageToken) params[\"pageToken\"] = listOptions.pageToken;\n if (listOptions?.pageSize) params[\"pageSize\"] = String(listOptions.pageSize);\n const hasParams = Object.keys(params).length > 0;\n const { data } = await http.get<UsersListResponse>(\n `/${developerId}/users`,\n hasParams ? params : undefined,\n );\n return data;\n },\n\n async get(developerId, userId) {\n const { data } = await http.get<User>(`/${developerId}/users/${userId}`);\n return data;\n },\n\n async create(developerId, user) {\n const { data } = await http.post<User>(`/${developerId}/users`, user);\n return data;\n },\n\n async update(developerId, userId, user, updateMask?) {\n let path = `/${developerId}/users/${userId}`;\n if (updateMask) {\n path += `?updateMask=${encodeURIComponent(updateMask).replace(/%2C/gi, \",\")}`;\n }\n const { data } = await http.patch<User>(path, user);\n return data;\n },\n\n async delete(developerId, userId) {\n await http.delete(`/${developerId}/users/${userId}`);\n },\n\n grants: {\n async list(developerId, email) {\n const { data } = await http.get<GrantsListResponse>(\n `/${developerId}/users/${encodeURIComponent(email)}/grants`,\n );\n return data;\n },\n\n async create(developerId, email, grant) {\n const { data } = await http.post<Grant>(\n `/${developerId}/users/${encodeURIComponent(email)}/grants`,\n grant,\n );\n return data;\n },\n\n async patch(developerId, email, packageName, grant, updateMask?) {\n let path = `/${developerId}/users/${encodeURIComponent(email)}/grants/${encodeURIComponent(packageName)}`;\n if (updateMask) {\n path += `?updateMask=${encodeURIComponent(updateMask)}`;\n }\n const { data } = await http.patch<Grant>(path, grant);\n return data;\n },\n\n async delete(developerId, email, packageName) {\n await http.delete(\n `/${developerId}/users/${encodeURIComponent(email)}/grants/${encodeURIComponent(packageName)}`,\n );\n },\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { ApiClientOptions } from \"./types.js\";\n\nconst GAMES_BASE_URL = \"https://games.googleapis.com/games/v1\";\n\nexport interface Leaderboard {\n id: string;\n name: string;\n order: string;\n iconUrl?: string;\n}\n\nexport interface LeaderboardScore {\n leaderboardId: string;\n scoreValue: string;\n formattedScore: string;\n writeTimestamp?: string;\n tag?: string;\n}\n\nexport interface Achievement {\n id: string;\n name: string;\n description: string;\n state: \"REVEALED\" | \"HIDDEN\" | \"UNLOCKED\";\n currentSteps?: number;\n totalSteps?: number;\n experiencePoints?: number;\n formattedCurrentStepsString?: string;\n}\n\nexport interface GameEvent {\n definitionId: string;\n numEvents: string;\n formattedNumEvents: string;\n kind?: string;\n}\n\nexport interface GamesApiClient {\n leaderboards: {\n list(packageName: string): Promise<{ items?: Leaderboard[]; nextPageToken?: string }>;\n get(packageName: string, leaderboardId: string): Promise<Leaderboard>;\n getScores(\n packageName: string,\n leaderboardId: string,\n collection: string,\n timeSpan: string,\n ): Promise<{ items?: LeaderboardScore[] }>;\n };\n achievements: {\n list(packageName: string): Promise<{ items?: Achievement[]; nextPageToken?: string }>;\n reveal(packageName: string, achievementId: string): Promise<{ currentState: string }>;\n };\n events: {\n list(packageName: string): Promise<{ items?: GameEvent[]; nextPageToken?: string }>;\n };\n}\n\nexport function createGamesClient(options: ApiClientOptions): GamesApiClient {\n const http = createHttpClient({ ...options, baseUrl: GAMES_BASE_URL });\n\n return {\n leaderboards: {\n async list(packageName) {\n const { data } = await http.get<{ items?: Leaderboard[]; nextPageToken?: string }>(\n `/leaderboards?applicationId=${packageName}`,\n );\n return data;\n },\n async get(packageName, leaderboardId) {\n const { data } = await http.get<Leaderboard>(\n `/leaderboards/${leaderboardId}?applicationId=${packageName}`,\n );\n return data;\n },\n async getScores(packageName, leaderboardId, collection, timeSpan) {\n const { data } = await http.get<{ items?: LeaderboardScore[] }>(\n `/leaderboards/${leaderboardId}/scores/${collection}?timeSpan=${timeSpan}&applicationId=${packageName}`,\n );\n return data;\n },\n },\n achievements: {\n async list(packageName) {\n const { data } = await http.get<{ items?: Achievement[]; nextPageToken?: string }>(\n `/achievements?applicationId=${packageName}`,\n );\n return data;\n },\n async reveal(packageName, achievementId) {\n const { data } = await http.post<{ currentState: string }>(\n `/achievements/${achievementId}/reveal?applicationId=${packageName}`,\n {},\n );\n return data;\n },\n },\n events: {\n async list(packageName) {\n const { data } = await http.get<{ items?: GameEvent[]; nextPageToken?: string }>(\n `/events?applicationId=${packageName}`,\n );\n return data;\n },\n },\n };\n}\n","import { createHttpClient } from \"./http.js\";\nimport type { ApiClientOptions } from \"./types.js\";\n\nconst ENTERPRISE_BASE_URL = \"https://playcustomapp.googleapis.com/playcustomapp/v1/organizations\";\n\nexport interface CustomApp {\n packageName?: string;\n title: string;\n languageCode?: string;\n organizations?: Array<{ organizationId: string; organizationName?: string }>;\n}\n\nexport interface CustomAppsListResponse {\n customApps?: CustomApp[];\n nextPageToken?: string;\n}\n\nexport interface EnterpriseApiClient {\n apps: {\n create(organizationId: string, app: Partial<CustomApp>): Promise<CustomApp>;\n list(organizationId: string): Promise<CustomAppsListResponse>;\n };\n}\n\nexport function createEnterpriseClient(options: ApiClientOptions): EnterpriseApiClient {\n const http = createHttpClient({ ...options, baseUrl: ENTERPRISE_BASE_URL });\n\n return {\n apps: {\n async create(organizationId, app) {\n const { data } = await http.post<CustomApp>(`/${organizationId}/apps`, app);\n return data;\n },\n async list(organizationId) {\n const { data } = await http.get<CustomAppsListResponse>(`/${organizationId}/apps`);\n return data;\n },\n },\n };\n}\n","export interface RateLimitBucket {\n name: string;\n maxTokens: number;\n refillRate: number;\n refillIntervalMs: number;\n}\n\nexport interface RateLimiter {\n acquire(bucket: string): Promise<void>;\n}\n\ninterface BucketState {\n tokens: number;\n lastRefillTime: number;\n config: RateLimitBucket;\n}\n\nexport const RATE_LIMIT_BUCKETS: Record<string, RateLimitBucket> = {\n default: { name: \"default\", maxTokens: 200, refillRate: 200, refillIntervalMs: 1_000 },\n reviewsGet: { name: \"reviewsGet\", maxTokens: 200, refillRate: 200, refillIntervalMs: 3_600_000 },\n reviewsPost: {\n name: \"reviewsPost\",\n maxTokens: 2_000,\n refillRate: 2_000,\n refillIntervalMs: 86_400_000,\n },\n voidedBurst: { name: \"voidedBurst\", maxTokens: 30, refillRate: 30, refillIntervalMs: 30_000 },\n voidedDaily: {\n name: \"voidedDaily\",\n maxTokens: 6_000,\n refillRate: 6_000,\n refillIntervalMs: 86_400_000,\n },\n};\n\nexport function createRateLimiter(buckets?: RateLimitBucket[]): RateLimiter {\n const states = new Map<string, BucketState>();\n\n if (buckets) {\n for (const bucket of buckets) {\n states.set(bucket.name, {\n tokens: bucket.maxTokens,\n lastRefillTime: Date.now(),\n config: bucket,\n });\n }\n }\n\n return {\n async acquire(bucket: string): Promise<void> {\n const state = states.get(bucket);\n if (!state) return;\n\n const now = Date.now();\n const elapsed = now - state.lastRefillTime;\n const refill = Math.floor(\n (elapsed / state.config.refillIntervalMs) * state.config.refillRate,\n );\n\n if (refill > 0) {\n state.tokens = Math.min(state.config.maxTokens, state.tokens + refill);\n state.lastRefillTime = now;\n }\n\n if (state.tokens > 0) {\n state.tokens--;\n return;\n }\n\n const tokensNeeded = 1;\n const waitMs = Math.ceil(\n (tokensNeeded / state.config.refillRate) * state.config.refillIntervalMs,\n );\n await new Promise((r) => setTimeout(r, waitMs));\n\n // Recalculate refill based on actual elapsed time since last refill\n const afterWait = Date.now();\n const totalElapsed = afterWait - state.lastRefillTime;\n const newTokens = Math.floor(\n (totalElapsed / state.config.refillIntervalMs) * state.config.refillRate,\n );\n state.tokens = Math.min(state.config.maxTokens, newTokens) - 1;\n state.lastRefillTime = afterWait;\n },\n };\n}\n","export interface PaginateOptions {\n limit?: number;\n startPageToken?: string;\n}\n\nexport async function* paginate<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): AsyncGenerator<TItem[], void, unknown> {\n let pageToken = options?.startPageToken;\n let collected = 0;\n const limit = options?.limit;\n\n for (;;) {\n if (limit !== undefined && collected >= limit) break;\n\n const page = await fetchPage(pageToken);\n const items = page.items;\n\n if (items.length === 0) break;\n\n if (limit !== undefined) {\n const remaining = limit - collected;\n if (items.length > remaining) {\n yield items.slice(0, remaining);\n return;\n }\n }\n\n yield items;\n collected += items.length;\n pageToken = page.nextPageToken;\n\n if (!pageToken) break;\n }\n}\n\nexport async function paginateAll<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n options?: PaginateOptions,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastPageToken: string | undefined;\n const limit = options?.limit;\n\n for await (const items of paginate(fetchPage, options)) {\n allItems.push(...items);\n if (limit !== undefined && allItems.length >= limit) break;\n }\n\n // If we stopped due to limit, try to get the next page token for resumption\n if (limit !== undefined && allItems.length >= limit) {\n lastPageToken = undefined; // Already truncated by paginate\n }\n\n return { items: allItems, nextPageToken: lastPageToken };\n}\n\n/**\n * Fetch multiple known pages in parallel.\n * Useful when page tokens are predictable or when pre-fetching subsequent pages\n * after an initial sequential fetch reveals the token pattern.\n *\n * @param fetchPage - Function that fetches a page given a token\n * @param pageTokens - Array of page tokens to fetch concurrently\n * @param concurrency - Max concurrent requests (default: 4)\n */\nexport async function paginateParallel<TItem>(\n fetchPage: (pageToken?: string) => Promise<{ items: TItem[]; nextPageToken?: string }>,\n pageTokens: string[],\n concurrency = 4,\n): Promise<{ items: TItem[]; nextPageToken?: string }> {\n const allItems: TItem[] = [];\n let lastNextPageToken: string | undefined;\n\n // Process in batches of `concurrency`\n for (let i = 0; i < pageTokens.length; i += concurrency) {\n const batch = pageTokens.slice(i, i + concurrency);\n const results = await Promise.all(batch.map((token) => fetchPage(token)));\n\n for (const result of results) {\n allItems.push(...result.items);\n if (result.nextPageToken) {\n lastNextPageToken = result.nextPageToken;\n }\n }\n }\n\n return { items: allItems, nextPageToken: lastNextPageToken };\n}\n"],"mappings":"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","names":["options"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gpc-cli/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "Typed client for Google Play Developer API v3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^25.3.5"
|
|
35
35
|
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/yasserstudio/gpc"
|
|
39
|
+
},
|
|
36
40
|
"scripts": {
|
|
37
41
|
"build": "tsup",
|
|
38
42
|
"dev": "tsup --watch",
|