@gpc-cli/api 1.0.5 → 1.0.7
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 +321 -28
- package/dist/index.d.ts +246 -1
- package/dist/index.js +234 -9
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
// src/http.ts
|
|
2
|
-
import { readFile } from "fs/promises";
|
|
3
|
-
import { resolve, isAbsolute } from "path";
|
|
4
|
-
|
|
5
1
|
// src/errors.ts
|
|
6
2
|
var ApiError = class extends Error {
|
|
7
3
|
constructor(message, code, statusCode, suggestion) {
|
|
@@ -25,6 +21,8 @@ var ApiError = class extends Error {
|
|
|
25
21
|
};
|
|
26
22
|
|
|
27
23
|
// src/http.ts
|
|
24
|
+
import { readFile } from "fs/promises";
|
|
25
|
+
import { resolve, isAbsolute } from "path";
|
|
28
26
|
function sanitizeErrorBody(body) {
|
|
29
27
|
try {
|
|
30
28
|
const parsed = JSON.parse(body);
|
|
@@ -52,6 +50,7 @@ function validateFilePath(filePath) {
|
|
|
52
50
|
}
|
|
53
51
|
var BASE_URL = "https://androidpublisher.googleapis.com/androidpublisher/v3/applications";
|
|
54
52
|
var UPLOAD_BASE_URL = "https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications";
|
|
53
|
+
var INTERNAL_SHARING_UPLOAD_BASE_URL = "https://androidpublisher.googleapis.com/upload/internalappsharing/v3/applications";
|
|
55
54
|
function envInt(name) {
|
|
56
55
|
const val = process.env[name];
|
|
57
56
|
if (val === void 0) return void 0;
|
|
@@ -227,8 +226,8 @@ function createHttpClient(options) {
|
|
|
227
226
|
}
|
|
228
227
|
throw lastError ?? new ApiError("Request failed", "API_NETWORK_ERROR");
|
|
229
228
|
}
|
|
230
|
-
async function uploadRequest(path, filePath, contentType) {
|
|
231
|
-
const url = `${
|
|
229
|
+
async function uploadRequest(path, filePath, contentType, baseUrl = UPLOAD_BASE_URL) {
|
|
230
|
+
const url = `${baseUrl}${path}`;
|
|
232
231
|
const safeFilePath = validateFilePath(filePath);
|
|
233
232
|
const fileBuffer = await readFile(safeFilePath);
|
|
234
233
|
let token = await options.auth.getAccessToken();
|
|
@@ -355,6 +354,40 @@ function createHttpClient(options) {
|
|
|
355
354
|
},
|
|
356
355
|
upload(path, filePath, contentType) {
|
|
357
356
|
return uploadRequest(path, filePath, contentType);
|
|
357
|
+
},
|
|
358
|
+
uploadInternal(path, filePath, contentType) {
|
|
359
|
+
return uploadRequest(path, filePath, contentType, INTERNAL_SHARING_UPLOAD_BASE_URL);
|
|
360
|
+
},
|
|
361
|
+
async download(path) {
|
|
362
|
+
const url = `${options.baseUrl ?? BASE_URL}${path}`;
|
|
363
|
+
const token = await options.auth.getAccessToken();
|
|
364
|
+
const controller = new AbortController();
|
|
365
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
366
|
+
try {
|
|
367
|
+
const response = await fetch(url, {
|
|
368
|
+
method: "GET",
|
|
369
|
+
headers: {
|
|
370
|
+
Authorization: `Bearer ${token}`,
|
|
371
|
+
"Accept-Encoding": "gzip, deflate",
|
|
372
|
+
Connection: "keep-alive"
|
|
373
|
+
},
|
|
374
|
+
signal: controller.signal,
|
|
375
|
+
keepalive: true
|
|
376
|
+
});
|
|
377
|
+
if (!response.ok) {
|
|
378
|
+
const errorBody = await response.text();
|
|
379
|
+
const { code, suggestion } = mapStatusToError(response.status, errorBody);
|
|
380
|
+
throw new ApiError(
|
|
381
|
+
`GET ${path} failed with status ${response.status}: ${sanitizeErrorBody(errorBody)}`,
|
|
382
|
+
code,
|
|
383
|
+
response.status,
|
|
384
|
+
suggestion
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
return await response.arrayBuffer();
|
|
388
|
+
} finally {
|
|
389
|
+
clearTimeout(timer);
|
|
390
|
+
}
|
|
358
391
|
}
|
|
359
392
|
};
|
|
360
393
|
}
|
|
@@ -422,7 +455,12 @@ function createApiClient(options) {
|
|
|
422
455
|
"application/octet-stream"
|
|
423
456
|
);
|
|
424
457
|
if (!data.bundle) {
|
|
425
|
-
throw new
|
|
458
|
+
throw new ApiError(
|
|
459
|
+
"Upload succeeded but no bundle data returned",
|
|
460
|
+
"API_EMPTY_RESPONSE",
|
|
461
|
+
200,
|
|
462
|
+
"This is unexpected. Retry the upload or contact Google Play support if the issue persists."
|
|
463
|
+
);
|
|
426
464
|
}
|
|
427
465
|
return data.bundle;
|
|
428
466
|
}
|
|
@@ -494,7 +532,12 @@ function createApiClient(options) {
|
|
|
494
532
|
filePath.endsWith(".png") ? "image/png" : "image/jpeg"
|
|
495
533
|
);
|
|
496
534
|
if (!data.image) {
|
|
497
|
-
throw new
|
|
535
|
+
throw new ApiError(
|
|
536
|
+
"Upload succeeded but no image data returned",
|
|
537
|
+
"API_EMPTY_RESPONSE",
|
|
538
|
+
200,
|
|
539
|
+
"This is unexpected. Retry the upload or contact Google Play support if the issue persists."
|
|
540
|
+
);
|
|
498
541
|
}
|
|
499
542
|
return data.image;
|
|
500
543
|
},
|
|
@@ -518,6 +561,21 @@ function createApiClient(options) {
|
|
|
518
561
|
return data;
|
|
519
562
|
}
|
|
520
563
|
},
|
|
564
|
+
dataSafety: {
|
|
565
|
+
async get(packageName, editId) {
|
|
566
|
+
const { data } = await http.get(
|
|
567
|
+
`/${packageName}/edits/${editId}/dataSafety`
|
|
568
|
+
);
|
|
569
|
+
return data;
|
|
570
|
+
},
|
|
571
|
+
async update(packageName, editId, body) {
|
|
572
|
+
const { data } = await http.put(
|
|
573
|
+
`/${packageName}/edits/${editId}/dataSafety`,
|
|
574
|
+
body
|
|
575
|
+
);
|
|
576
|
+
return data;
|
|
577
|
+
}
|
|
578
|
+
},
|
|
521
579
|
reviews: {
|
|
522
580
|
async list(packageName, options2) {
|
|
523
581
|
await rateLimit(limiter, "reviewsGet");
|
|
@@ -792,10 +850,177 @@ function createApiClient(options) {
|
|
|
792
850
|
"application/octet-stream"
|
|
793
851
|
);
|
|
794
852
|
if (!data.deobfuscationFile) {
|
|
795
|
-
throw new
|
|
853
|
+
throw new ApiError(
|
|
854
|
+
"Upload succeeded but no deobfuscation file data returned",
|
|
855
|
+
"API_EMPTY_RESPONSE",
|
|
856
|
+
200,
|
|
857
|
+
"This is unexpected. Retry the upload or contact Google Play support if the issue persists."
|
|
858
|
+
);
|
|
796
859
|
}
|
|
797
860
|
return data.deobfuscationFile;
|
|
798
861
|
}
|
|
862
|
+
},
|
|
863
|
+
appRecovery: {
|
|
864
|
+
async list(packageName) {
|
|
865
|
+
const { data } = await http.post(
|
|
866
|
+
`/${packageName}/appRecoveries`
|
|
867
|
+
);
|
|
868
|
+
return data.recoveryActions || [];
|
|
869
|
+
},
|
|
870
|
+
async cancel(packageName, appRecoveryId) {
|
|
871
|
+
await http.post(`/${packageName}/appRecovery/${appRecoveryId}:cancel`);
|
|
872
|
+
},
|
|
873
|
+
async deploy(packageName, appRecoveryId) {
|
|
874
|
+
await http.post(`/${packageName}/appRecovery/${appRecoveryId}:deploy`);
|
|
875
|
+
},
|
|
876
|
+
async create(packageName, request) {
|
|
877
|
+
const { data } = await http.post(
|
|
878
|
+
`/${packageName}/appRecoveries`,
|
|
879
|
+
request
|
|
880
|
+
);
|
|
881
|
+
return data;
|
|
882
|
+
},
|
|
883
|
+
async addTargeting(packageName, appRecoveryId, targeting) {
|
|
884
|
+
const { data } = await http.post(
|
|
885
|
+
`/${packageName}/appRecoveries/${appRecoveryId}:addTargeting`,
|
|
886
|
+
targeting
|
|
887
|
+
);
|
|
888
|
+
return data;
|
|
889
|
+
}
|
|
890
|
+
},
|
|
891
|
+
externalTransactions: {
|
|
892
|
+
async create(packageName, body) {
|
|
893
|
+
const { data } = await http.post(
|
|
894
|
+
`/${packageName}/externalTransactions`,
|
|
895
|
+
body
|
|
896
|
+
);
|
|
897
|
+
return data;
|
|
898
|
+
},
|
|
899
|
+
async get(packageName, transactionId) {
|
|
900
|
+
const { data } = await http.get(
|
|
901
|
+
`/${packageName}/externalTransactions/${transactionId}`
|
|
902
|
+
);
|
|
903
|
+
return data;
|
|
904
|
+
},
|
|
905
|
+
async refund(packageName, transactionId, refundData) {
|
|
906
|
+
const { data } = await http.post(
|
|
907
|
+
`/${packageName}/externalTransactions/${transactionId}:refund`,
|
|
908
|
+
refundData
|
|
909
|
+
);
|
|
910
|
+
return data;
|
|
911
|
+
}
|
|
912
|
+
},
|
|
913
|
+
deviceTiers: {
|
|
914
|
+
async list(packageName) {
|
|
915
|
+
const { data } = await http.get(
|
|
916
|
+
`/${packageName}/deviceTierConfigs`
|
|
917
|
+
);
|
|
918
|
+
return data.deviceTierConfigs || [];
|
|
919
|
+
},
|
|
920
|
+
async get(packageName, configId) {
|
|
921
|
+
const { data } = await http.get(
|
|
922
|
+
`/${packageName}/deviceTierConfigs/${configId}`
|
|
923
|
+
);
|
|
924
|
+
return data;
|
|
925
|
+
},
|
|
926
|
+
async create(packageName, config) {
|
|
927
|
+
const { data } = await http.post(
|
|
928
|
+
`/${packageName}/deviceTierConfigs`,
|
|
929
|
+
config
|
|
930
|
+
);
|
|
931
|
+
return data;
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
oneTimeProducts: {
|
|
935
|
+
async list(packageName) {
|
|
936
|
+
const { data } = await http.get(
|
|
937
|
+
`/${packageName}/oneTimeProducts`
|
|
938
|
+
);
|
|
939
|
+
return data;
|
|
940
|
+
},
|
|
941
|
+
async get(packageName, productId) {
|
|
942
|
+
const { data } = await http.get(
|
|
943
|
+
`/${packageName}/oneTimeProducts/${productId}`
|
|
944
|
+
);
|
|
945
|
+
return data;
|
|
946
|
+
},
|
|
947
|
+
async create(packageName, body) {
|
|
948
|
+
const { data } = await http.post(
|
|
949
|
+
`/${packageName}/oneTimeProducts`,
|
|
950
|
+
body
|
|
951
|
+
);
|
|
952
|
+
return data;
|
|
953
|
+
},
|
|
954
|
+
async update(packageName, productId, body) {
|
|
955
|
+
const { data } = await http.patch(
|
|
956
|
+
`/${packageName}/oneTimeProducts/${productId}`,
|
|
957
|
+
body
|
|
958
|
+
);
|
|
959
|
+
return data;
|
|
960
|
+
},
|
|
961
|
+
async delete(packageName, productId) {
|
|
962
|
+
await http.delete(`/${packageName}/oneTimeProducts/${productId}`);
|
|
963
|
+
},
|
|
964
|
+
async listOffers(packageName, productId) {
|
|
965
|
+
const { data } = await http.get(
|
|
966
|
+
`/${packageName}/oneTimeProducts/${productId}/offers`
|
|
967
|
+
);
|
|
968
|
+
return data;
|
|
969
|
+
},
|
|
970
|
+
async getOffer(packageName, productId, offerId) {
|
|
971
|
+
const { data } = await http.get(
|
|
972
|
+
`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`
|
|
973
|
+
);
|
|
974
|
+
return data;
|
|
975
|
+
},
|
|
976
|
+
async createOffer(packageName, productId, body) {
|
|
977
|
+
const { data } = await http.post(
|
|
978
|
+
`/${packageName}/oneTimeProducts/${productId}/offers`,
|
|
979
|
+
body
|
|
980
|
+
);
|
|
981
|
+
return data;
|
|
982
|
+
},
|
|
983
|
+
async updateOffer(packageName, productId, offerId, body) {
|
|
984
|
+
const { data } = await http.patch(
|
|
985
|
+
`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`,
|
|
986
|
+
body
|
|
987
|
+
);
|
|
988
|
+
return data;
|
|
989
|
+
},
|
|
990
|
+
async deleteOffer(packageName, productId, offerId) {
|
|
991
|
+
await http.delete(`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`);
|
|
992
|
+
}
|
|
993
|
+
},
|
|
994
|
+
internalAppSharing: {
|
|
995
|
+
async uploadBundle(packageName, bundlePath) {
|
|
996
|
+
const { data } = await http.uploadInternal(
|
|
997
|
+
`/${packageName}/artifacts/bundle`,
|
|
998
|
+
bundlePath,
|
|
999
|
+
"application/octet-stream"
|
|
1000
|
+
);
|
|
1001
|
+
return data;
|
|
1002
|
+
},
|
|
1003
|
+
async uploadApk(packageName, apkPath) {
|
|
1004
|
+
const { data } = await http.uploadInternal(
|
|
1005
|
+
`/${packageName}/artifacts/apk`,
|
|
1006
|
+
apkPath,
|
|
1007
|
+
"application/vnd.android.package-archive"
|
|
1008
|
+
);
|
|
1009
|
+
return data;
|
|
1010
|
+
}
|
|
1011
|
+
},
|
|
1012
|
+
generatedApks: {
|
|
1013
|
+
async list(packageName, versionCode) {
|
|
1014
|
+
const { data } = await http.get(
|
|
1015
|
+
`/${packageName}/generatedApks/${versionCode}`
|
|
1016
|
+
);
|
|
1017
|
+
return data.generatedApks || [];
|
|
1018
|
+
},
|
|
1019
|
+
async download(packageName, versionCode, id) {
|
|
1020
|
+
return http.download(
|
|
1021
|
+
`/${packageName}/generatedApks/${versionCode}/download/${id}`
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
799
1024
|
}
|
|
800
1025
|
};
|
|
801
1026
|
}
|