@gpc-cli/api 1.0.27 → 1.0.28
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 +73 -267
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/LICENSE +0 -21
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
|
+
208 endpoints across edits, releases, tracks, listings, subscriptions, in-app products, purchases, reviews, vitals, reports, users, and testers. Built-in rate limiting, retry logic, and pagination.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -19,204 +19,53 @@ import { resolveAuth } from "@gpc-cli/auth";
|
|
|
19
19
|
const auth = await resolveAuth({
|
|
20
20
|
serviceAccountPath: "./service-account.json",
|
|
21
21
|
});
|
|
22
|
-
|
|
23
22
|
const client = createApiClient({ auth });
|
|
24
23
|
|
|
25
|
-
// List all tracks
|
|
26
24
|
const edit = await client.edits.insert("com.example.app");
|
|
27
25
|
const tracks = await client.tracks.list("com.example.app", edit.id);
|
|
28
26
|
console.log(tracks);
|
|
29
|
-
|
|
30
27
|
await client.edits.delete("com.example.app", edit.id);
|
|
31
28
|
```
|
|
32
29
|
|
|
33
30
|
## Client Factories
|
|
34
31
|
|
|
35
|
-
| Factory
|
|
36
|
-
|
|
|
37
|
-
| `createApiClient(options)`
|
|
38
|
-
| `createReportingClient(options)` | Vitals, crash rates, ANR, error reporting
|
|
39
|
-
| `createUsersClient(options)`
|
|
40
|
-
| `createHttpClient(options)`
|
|
41
|
-
|
|
42
|
-
All factories accept `ApiClientOptions`:
|
|
32
|
+
| Factory | Purpose |
|
|
33
|
+
| ------- | ------- |
|
|
34
|
+
| `createApiClient(options)` | Core Play API: apps, releases, listings, monetization, purchases |
|
|
35
|
+
| `createReportingClient(options)` | Vitals, crash rates, ANR, error reporting |
|
|
36
|
+
| `createUsersClient(options)` | Developer account users and permission grants |
|
|
37
|
+
| `createHttpClient(options)` | Low-level HTTP with auth, retry, and rate limiting |
|
|
43
38
|
|
|
44
39
|
```typescript
|
|
45
|
-
import type { ApiClientOptions } from "@gpc-cli/api";
|
|
46
|
-
|
|
47
40
|
const options: ApiClientOptions = {
|
|
48
|
-
auth,
|
|
49
|
-
maxRetries: 3,
|
|
50
|
-
timeout: 30_000,
|
|
51
|
-
|
|
52
|
-
onRetry: (entry) => console.warn(`Retry #${entry.attempt}: ${entry.error}`),
|
|
41
|
+
auth, // Required: { getAccessToken(): Promise<string> }
|
|
42
|
+
maxRetries: 3, // Default retry count
|
|
43
|
+
timeout: 30_000, // Request timeout in ms
|
|
44
|
+
onRetry: (entry) => console.warn(`Retry #${entry.attempt}`),
|
|
53
45
|
};
|
|
54
46
|
```
|
|
55
47
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
### Edits
|
|
59
|
-
|
|
60
|
-
Every modification to app metadata, tracks, or listings requires an edit session.
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
const edit = await client.edits.insert("com.example.app");
|
|
64
|
-
|
|
65
|
-
// ... make changes within the edit ...
|
|
66
|
-
|
|
67
|
-
await client.edits.validate("com.example.app", edit.id);
|
|
68
|
-
await client.edits.commit("com.example.app", edit.id);
|
|
69
|
-
```
|
|
48
|
+
## Common Workflows
|
|
70
49
|
|
|
71
|
-
###
|
|
50
|
+
### Upload and release
|
|
72
51
|
|
|
73
52
|
```typescript
|
|
74
53
|
const edit = await client.edits.insert("com.example.app");
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
await client.edits.commit("com.example.app", edit.id);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Tracks & Releases
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
const edit = await client.edits.insert("com.example.app");
|
|
84
|
-
|
|
85
|
-
const tracks = await client.tracks.list("com.example.app", edit.id);
|
|
86
|
-
const production = await client.tracks.get("com.example.app", edit.id, "production");
|
|
87
|
-
|
|
88
|
-
await client.tracks.update("com.example.app", edit.id, "production", {
|
|
54
|
+
await client.bundles.upload("com.example.app", edit.id, "./app.aab");
|
|
55
|
+
await client.tracks.update("com.example.app", edit.id, "beta", {
|
|
89
56
|
versionCodes: ["42"],
|
|
90
|
-
status: "
|
|
91
|
-
userFraction: 0.1,
|
|
57
|
+
status: "completed",
|
|
92
58
|
releaseNotes: [{ language: "en-US", text: "Bug fixes" }],
|
|
93
59
|
});
|
|
94
|
-
|
|
95
|
-
await client.edits.commit("com.example.app", edit.id);
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Listings
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
const edit = await client.edits.insert("com.example.app");
|
|
102
|
-
|
|
103
|
-
const listings = await client.listings.list("com.example.app", edit.id);
|
|
104
|
-
const en = await client.listings.get("com.example.app", edit.id, "en-US");
|
|
105
|
-
|
|
106
|
-
await client.listings.update("com.example.app", edit.id, "en-US", {
|
|
107
|
-
title: "My App",
|
|
108
|
-
shortDescription: "A great app",
|
|
109
|
-
fullDescription: "Full description here...",
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
await client.edits.commit("com.example.app", edit.id);
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Images
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
const edit = await client.edits.insert("com.example.app");
|
|
119
|
-
|
|
120
|
-
const screenshots = await client.images.list(
|
|
121
|
-
"com.example.app",
|
|
122
|
-
edit.id,
|
|
123
|
-
"en-US",
|
|
124
|
-
"phoneScreenshots",
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
await client.images.upload("com.example.app", edit.id, "en-US", "featureGraphic", "./feature.png");
|
|
128
|
-
|
|
129
|
-
await client.images.deleteAll("com.example.app", edit.id, "en-US", "phoneScreenshots");
|
|
130
60
|
await client.edits.commit("com.example.app", edit.id);
|
|
131
61
|
```
|
|
132
62
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
### Subscriptions
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
const { subscriptions } = await client.subscriptions.list("com.example.app");
|
|
139
|
-
const sub = await client.subscriptions.get("com.example.app", "premium_monthly");
|
|
140
|
-
|
|
141
|
-
await client.subscriptions.activateBasePlan("com.example.app", "premium_monthly", "p1m");
|
|
142
|
-
await client.subscriptions.deactivateBasePlan("com.example.app", "premium_monthly", "p1m");
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Subscription Offers
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
const { subscriptionOffers } = await client.subscriptions.listOffers(
|
|
149
|
-
"com.example.app",
|
|
150
|
-
"premium_monthly",
|
|
151
|
-
"p1m",
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
const offer = await client.subscriptions.getOffer(
|
|
155
|
-
"com.example.app",
|
|
156
|
-
"premium_monthly",
|
|
157
|
-
"p1m",
|
|
158
|
-
"intro_offer",
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
await client.subscriptions.activateOffer(
|
|
162
|
-
"com.example.app",
|
|
163
|
-
"premium_monthly",
|
|
164
|
-
"p1m",
|
|
165
|
-
"intro_offer",
|
|
166
|
-
);
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### In-App Products
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
const { inappproduct } = await client.inappproducts.list("com.example.app");
|
|
173
|
-
const product = await client.inappproducts.get("com.example.app", "coins_100");
|
|
174
|
-
|
|
175
|
-
await client.inappproducts.create("com.example.app", {
|
|
176
|
-
sku: "coins_500",
|
|
177
|
-
status: "active",
|
|
178
|
-
purchaseType: "managedUser",
|
|
179
|
-
defaultPrice: { currencyCode: "USD", units: "4", nanos: 990_000_000 },
|
|
180
|
-
});
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Purchases
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
// Verify a product purchase
|
|
187
|
-
const purchase = await client.purchases.getProduct("com.example.app", "coins_100", purchaseToken);
|
|
188
|
-
|
|
189
|
-
// Acknowledge it
|
|
190
|
-
await client.purchases.acknowledgeProduct("com.example.app", "coins_100", purchaseToken);
|
|
191
|
-
|
|
192
|
-
// Verify a subscription (v2)
|
|
193
|
-
const sub = await client.purchases.getSubscriptionV2("com.example.app", purchaseToken);
|
|
194
|
-
|
|
195
|
-
// List voided purchases
|
|
196
|
-
const { voidedPurchases } = await client.purchases.listVoided("com.example.app", {
|
|
197
|
-
startTime: "1700000000000",
|
|
198
|
-
maxResults: 100,
|
|
199
|
-
});
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Reviews
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
const { reviews } = await client.reviews.list("com.example.app", { maxResults: 50 });
|
|
206
|
-
const review = await client.reviews.get("com.example.app", reviewId);
|
|
207
|
-
await client.reviews.reply("com.example.app", reviewId, "Thanks for the feedback!");
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Vitals & Error Reporting
|
|
211
|
-
|
|
212
|
-
Uses a separate client that targets the Play Developer Reporting API.
|
|
63
|
+
### Query crash rates
|
|
213
64
|
|
|
214
65
|
```typescript
|
|
215
66
|
import { createReportingClient } from "@gpc-cli/api";
|
|
216
67
|
|
|
217
68
|
const reporting = createReportingClient({ auth });
|
|
218
|
-
|
|
219
|
-
// Query crash rate
|
|
220
69
|
const crashes = await reporting.queryMetricSet("com.example.app", "crashRateMetricSet", {
|
|
221
70
|
metrics: ["crashRate", "userPerceivedCrashRate"],
|
|
222
71
|
timelineSpec: {
|
|
@@ -225,75 +74,52 @@ const crashes = await reporting.queryMetricSet("com.example.app", "crashRateMetr
|
|
|
225
74
|
endTime: { year: 2026, month: 3, day: 1 },
|
|
226
75
|
},
|
|
227
76
|
});
|
|
228
|
-
|
|
229
|
-
// Detect anomalies
|
|
230
|
-
const { anomalies } = await reporting.getAnomalies("com.example.app");
|
|
231
|
-
|
|
232
|
-
// Search error issues
|
|
233
|
-
const { errorIssues } = await reporting.searchErrorIssues("com.example.app");
|
|
234
77
|
```
|
|
235
78
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
### Reports
|
|
79
|
+
### Manage subscriptions
|
|
239
80
|
|
|
240
81
|
```typescript
|
|
241
|
-
const {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
Report types: `earnings`, `sales`, `estimated_sales`, `installs`, `crashes`, `ratings`, `reviews`, `store_performance`, `subscriptions`, `play_balance`.
|
|
245
|
-
|
|
246
|
-
### Users & Grants
|
|
247
|
-
|
|
248
|
-
Uses a separate client for developer account management.
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
import { createUsersClient } from "@gpc-cli/api";
|
|
252
|
-
|
|
253
|
-
const users = createUsersClient({ auth });
|
|
254
|
-
|
|
255
|
-
const { users: devUsers } = await users.list(developerId);
|
|
256
|
-
const user = await users.get(developerId, userId);
|
|
257
|
-
|
|
258
|
-
await users.create(developerId, {
|
|
259
|
-
email: "dev@example.com",
|
|
260
|
-
developerAccountPermission: ["CAN_MANAGE_PUBLIC_APKS", "CAN_REPLY_TO_REVIEWS"],
|
|
261
|
-
});
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Testers
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
const edit = await client.edits.insert("com.example.app");
|
|
268
|
-
const testers = await client.testers.get("com.example.app", edit.id, "internal");
|
|
269
|
-
|
|
270
|
-
await client.testers.update("com.example.app", edit.id, "internal", {
|
|
271
|
-
googleGroups: ["testers@example.com"],
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
await client.edits.commit("com.example.app", edit.id);
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### Monetization
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
const { convertedRegionPrices } = await client.monetization.convertRegionPrices("com.example.app", {
|
|
281
|
-
price: { currencyCode: "USD", units: "9", nanos: 990_000_000 },
|
|
282
|
-
});
|
|
82
|
+
const { subscriptions } = await client.subscriptions.list("com.example.app");
|
|
83
|
+
await client.subscriptions.activateBasePlan("com.example.app", "premium_monthly", "p1m");
|
|
283
84
|
```
|
|
284
85
|
|
|
285
|
-
###
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
const
|
|
289
|
-
await client.
|
|
290
|
-
|
|
291
|
-
|
|
86
|
+
### Verify purchases
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const purchase = await client.purchases.getProduct("com.example.app", "coins_100", token);
|
|
90
|
+
await client.purchases.acknowledgeProduct("com.example.app", "coins_100", token);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## All API Modules
|
|
94
|
+
|
|
95
|
+
| Module | Methods |
|
|
96
|
+
| ------ | ------- |
|
|
97
|
+
| `client.edits` | insert, get, validate, commit, delete |
|
|
98
|
+
| `client.bundles` | upload, list |
|
|
99
|
+
| `client.tracks` | list, get, update |
|
|
100
|
+
| `client.listings` | list, get, update, delete, deleteAll |
|
|
101
|
+
| `client.images` | list, upload, delete, deleteAll |
|
|
102
|
+
| `client.subscriptions` | list, get, create, patch, archive, activate/deactivate base plans and offers |
|
|
103
|
+
| `client.inappproducts` | list, get, create, update, delete, batchGet, batchUpdate, batchDelete |
|
|
104
|
+
| `client.oneTimeProducts` | list, get, create, patch, delete, batchGet, batchUpdate, batchDelete |
|
|
105
|
+
| `client.purchases` | getProduct, acknowledgeProduct, getSubscriptionV2, revokeSubscription, refund, listVoided |
|
|
106
|
+
| `client.reviews` | list, get, reply |
|
|
107
|
+
| `client.testers` | get, update |
|
|
108
|
+
| `client.reports` | list |
|
|
109
|
+
| `client.monetization` | convertRegionPrices |
|
|
110
|
+
| `client.deobfuscation` | upload |
|
|
111
|
+
| `client.expansionFiles` | get, update, patch, upload |
|
|
112
|
+
| `client.dataSafety` | get, update |
|
|
113
|
+
| `client.deviceTiers` | list, get, create |
|
|
114
|
+
| `client.internalSharing` | uploadBundle, uploadApk |
|
|
115
|
+
| `client.generatedApks` | list, download |
|
|
116
|
+
| `client.externalTransactions` | create, get, refund |
|
|
117
|
+
| `client.appRecovery` | create, deploy, cancel, list |
|
|
118
|
+
| `reporting.*` | queryMetricSet, getAnomalies, searchErrorIssues, searchErrorReports |
|
|
119
|
+
| `users.*` | list, get, create, patch, delete, listGrants, createGrant, patchGrant, deleteGrant |
|
|
292
120
|
|
|
293
121
|
## Pagination
|
|
294
122
|
|
|
295
|
-
Built-in helpers for paginated endpoints:
|
|
296
|
-
|
|
297
123
|
```typescript
|
|
298
124
|
import { paginateAll } from "@gpc-cli/api";
|
|
299
125
|
|
|
@@ -309,42 +135,9 @@ const allReviews = await paginateAll(async (pageToken) => {
|
|
|
309
135
|
});
|
|
310
136
|
```
|
|
311
137
|
|
|
312
|
-
## Type Exports
|
|
313
|
-
|
|
314
|
-
All Google Play API types are exported for use in your own code:
|
|
315
|
-
|
|
316
|
-
```typescript
|
|
317
|
-
import type {
|
|
318
|
-
PlayApiClient,
|
|
319
|
-
ReportingApiClient,
|
|
320
|
-
UsersApiClient,
|
|
321
|
-
ApiClientOptions,
|
|
322
|
-
Track,
|
|
323
|
-
Release,
|
|
324
|
-
ReleaseStatus,
|
|
325
|
-
Bundle,
|
|
326
|
-
Listing,
|
|
327
|
-
Subscription,
|
|
328
|
-
BasePlan,
|
|
329
|
-
SubscriptionOffer,
|
|
330
|
-
InAppProduct,
|
|
331
|
-
Review,
|
|
332
|
-
ProductPurchase,
|
|
333
|
-
SubscriptionPurchaseV2,
|
|
334
|
-
VoidedPurchase,
|
|
335
|
-
MetricSetQuery,
|
|
336
|
-
MetricSetResponse,
|
|
337
|
-
ErrorIssue,
|
|
338
|
-
User,
|
|
339
|
-
Grant,
|
|
340
|
-
ImageType,
|
|
341
|
-
Money,
|
|
342
|
-
} from "@gpc-cli/api";
|
|
343
|
-
```
|
|
344
|
-
|
|
345
138
|
## Error Handling
|
|
346
139
|
|
|
347
|
-
API errors throw `ApiError` with a code, HTTP status, and actionable suggestion
|
|
140
|
+
API errors throw `ApiError` with a code, HTTP status, and actionable suggestion. Retries are automatic for 429 and 5xx with exponential backoff and jitter.
|
|
348
141
|
|
|
349
142
|
```typescript
|
|
350
143
|
import { ApiError } from "@gpc-cli/api";
|
|
@@ -353,20 +146,33 @@ try {
|
|
|
353
146
|
await client.tracks.get("com.example.app", editId, "production");
|
|
354
147
|
} catch (error) {
|
|
355
148
|
if (error instanceof ApiError) {
|
|
356
|
-
console.error(error.code);
|
|
357
|
-
console.error(error.statusCode); //
|
|
149
|
+
console.error(error.code); // "API_NOT_FOUND"
|
|
150
|
+
console.error(error.statusCode); // 404
|
|
358
151
|
console.error(error.suggestion); // actionable fix
|
|
359
|
-
console.error(error.toJSON()); // structured error object
|
|
360
152
|
}
|
|
361
153
|
}
|
|
362
154
|
```
|
|
363
155
|
|
|
364
|
-
|
|
156
|
+
## Type Exports
|
|
157
|
+
|
|
158
|
+
All Google Play API types are exported:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import type {
|
|
162
|
+
PlayApiClient, ReportingApiClient, UsersApiClient, ApiClientOptions,
|
|
163
|
+
Track, Release, ReleaseStatus, Bundle, Listing,
|
|
164
|
+
Subscription, BasePlan, SubscriptionOffer, InAppProduct,
|
|
165
|
+
Review, ProductPurchase, SubscriptionPurchaseV2, VoidedPurchase,
|
|
166
|
+
MetricSetQuery, MetricSetResponse, ErrorIssue,
|
|
167
|
+
User, Grant, ImageType, Money,
|
|
168
|
+
} from "@gpc-cli/api";
|
|
169
|
+
```
|
|
365
170
|
|
|
366
171
|
## Documentation
|
|
367
172
|
|
|
368
173
|
- [Full documentation](https://yasserstudio.github.io/gpc/)
|
|
369
|
-
- [SDK usage guide](https://yasserstudio.github.io/gpc/advanced/sdk-usage
|
|
174
|
+
- [SDK usage guide](https://yasserstudio.github.io/gpc/advanced/sdk-usage)
|
|
175
|
+
- [API coverage map](https://yasserstudio.github.io/gpc/reference/api-coverage)
|
|
370
176
|
|
|
371
177
|
## License
|
|
372
178
|
|
package/dist/index.js
CHANGED
|
@@ -1312,6 +1312,14 @@ function createApiClient(options) {
|
|
|
1312
1312
|
filePath,
|
|
1313
1313
|
"application/octet-stream"
|
|
1314
1314
|
);
|
|
1315
|
+
if (!data.expansionFile) {
|
|
1316
|
+
throw new PlayApiError(
|
|
1317
|
+
"Upload succeeded but no expansion file data returned",
|
|
1318
|
+
"API_EMPTY_RESPONSE",
|
|
1319
|
+
200,
|
|
1320
|
+
"This is unexpected. Retry the upload or contact Google Play support if the issue persists."
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1315
1323
|
return data.expansionFile;
|
|
1316
1324
|
}
|
|
1317
1325
|
},
|