@gpc-cli/api 1.0.30 → 1.0.32
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 +3 -3
- package/dist/index.d.ts +57 -14
- package/dist/index.js +108 -23
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
+
217 endpoints across edits, releases, tracks, listings, subscriptions, in-app products, purchases, reviews, vitals, reports, users, testers, and **Managed Google Play private app publishing** (Play Custom App Publishing API, v0.9.56+ — first Android publishing SDK to support this). Built-in rate limiting, retry logic, resumable uploads, and pagination.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -192,6 +192,6 @@ import type {
|
|
|
192
192
|
- [SDK usage guide](https://yasserstudio.github.io/gpc/advanced/sdk-usage)
|
|
193
193
|
- [API coverage map](https://yasserstudio.github.io/gpc/reference/api-coverage)
|
|
194
194
|
|
|
195
|
-
##
|
|
195
|
+
## Licensing
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
Free to use. Source code is on GitHub at [yasserstudio/gpc](https://github.com/yasserstudio/gpc).
|
package/dist/index.d.ts
CHANGED
|
@@ -471,12 +471,13 @@ interface ProductPurchase {
|
|
|
471
471
|
acknowledgementState: number;
|
|
472
472
|
regionCode?: string;
|
|
473
473
|
}
|
|
474
|
+
type SubscriptionState = "SUBSCRIPTION_STATE_UNSPECIFIED" | "SUBSCRIPTION_STATE_PENDING" | "SUBSCRIPTION_STATE_ACTIVE" | "SUBSCRIPTION_STATE_PAUSED" | "SUBSCRIPTION_STATE_IN_GRACE_PERIOD" | "SUBSCRIPTION_STATE_ON_HOLD" | "SUBSCRIPTION_STATE_CANCELED" | "SUBSCRIPTION_STATE_EXPIRED" | "SUBSCRIPTION_STATE_PENDING_PURCHASE_CANCELED";
|
|
474
475
|
interface SubscriptionPurchaseV2 {
|
|
475
476
|
kind: string;
|
|
476
477
|
regionCode?: string;
|
|
477
478
|
lineItems: SubscriptionPurchaseLineItem[];
|
|
478
479
|
startTime?: string;
|
|
479
|
-
subscriptionState:
|
|
480
|
+
subscriptionState: SubscriptionState;
|
|
480
481
|
acknowledgementState?: string;
|
|
481
482
|
linkedPurchaseToken?: string;
|
|
482
483
|
/** Resubscription context when purchase originates from Play Store. (Nov 2025) */
|
|
@@ -723,15 +724,18 @@ interface ReportBucket {
|
|
|
723
724
|
interface ReportsListResponse {
|
|
724
725
|
reports: ReportBucket[];
|
|
725
726
|
}
|
|
726
|
-
type
|
|
727
|
+
type DeveloperLevelPermission = "DEVELOPER_LEVEL_PERMISSION_UNSPECIFIED" | "CAN_SEE_ALL_APPS" | "CAN_VIEW_FINANCIAL_DATA_GLOBAL" | "CAN_MANAGE_PERMISSIONS_GLOBAL" | "CAN_EDIT_GAMES_GLOBAL" | "CAN_PUBLISH_GAMES_GLOBAL" | "CAN_REPLY_TO_REVIEWS_GLOBAL" | "CAN_MANAGE_PUBLIC_APKS_GLOBAL" | "CAN_MANAGE_TRACK_APKS_GLOBAL" | "CAN_MANAGE_TRACK_USERS_GLOBAL" | "CAN_MANAGE_PUBLIC_LISTING_GLOBAL" | "CAN_MANAGE_DRAFT_APPS_GLOBAL" | "CAN_CREATE_MANAGED_PLAY_APPS_GLOBAL" | "CAN_CHANGE_MANAGED_PLAY_SETTING_GLOBAL" | "CAN_MANAGE_ORDERS_GLOBAL" | "CAN_MANAGE_APP_CONTENT_GLOBAL" | "CAN_VIEW_NON_FINANCIAL_DATA_GLOBAL" | "CAN_VIEW_APP_QUALITY_GLOBAL" | "CAN_MANAGE_DEEPLINKS_GLOBAL";
|
|
728
|
+
type AppLevelPermission = "APP_LEVEL_PERMISSION_UNSPECIFIED" | "CAN_ACCESS_APP" | "CAN_VIEW_FINANCIAL_DATA" | "CAN_MANAGE_PERMISSIONS" | "CAN_REPLY_TO_REVIEWS" | "CAN_MANAGE_PUBLIC_APKS" | "CAN_MANAGE_TRACK_APKS" | "CAN_MANAGE_TRACK_USERS" | "CAN_MANAGE_PUBLIC_LISTING" | "CAN_MANAGE_DRAFT_APPS" | "CAN_MANAGE_ORDERS" | "CAN_MANAGE_APP_CONTENT" | "CAN_VIEW_NON_FINANCIAL_DATA" | "CAN_VIEW_APP_QUALITY" | "CAN_MANAGE_DEEPLINKS";
|
|
729
|
+
/** @deprecated Use DeveloperLevelPermission instead */
|
|
730
|
+
type DeveloperPermission = DeveloperLevelPermission;
|
|
727
731
|
interface Grant {
|
|
728
732
|
packageName: string;
|
|
729
|
-
appLevelPermissions:
|
|
733
|
+
appLevelPermissions: AppLevelPermission[];
|
|
730
734
|
}
|
|
731
735
|
interface User {
|
|
732
736
|
email: string;
|
|
733
737
|
name?: string;
|
|
734
|
-
developerAccountPermission?:
|
|
738
|
+
developerAccountPermission?: DeveloperLevelPermission[];
|
|
735
739
|
grants?: Grant[];
|
|
736
740
|
expirationTime?: string;
|
|
737
741
|
}
|
|
@@ -939,12 +943,14 @@ interface TaxAndComplianceSettings {
|
|
|
939
943
|
}>;
|
|
940
944
|
isTokenizedDigitalAsset?: boolean;
|
|
941
945
|
}
|
|
946
|
+
type OneTimeOfferState = "STATE_UNSPECIFIED" | "DRAFT" | "ACTIVE" | "INACTIVE" | "INACTIVE_PUBLISHED" | "CANCELLED";
|
|
947
|
+
type OneTimeProductAvailability = "AVAILABILITY_UNSPECIFIED" | "AVAILABLE" | "NO_LONGER_AVAILABLE" | "AVAILABLE_IF_RELEASED" | "AVAILABLE_FOR_OFFERS_ONLY";
|
|
942
948
|
interface OneTimeOffer {
|
|
943
949
|
packageName: string;
|
|
944
950
|
productId: string;
|
|
945
951
|
purchaseOptionId: string;
|
|
946
952
|
offerId: string;
|
|
947
|
-
state?:
|
|
953
|
+
state?: OneTimeOfferState;
|
|
948
954
|
regionalPricingAndAvailabilityConfigs?: Record<string, OneTimeOfferRegionalConfig>;
|
|
949
955
|
/** @deprecated Use regionalPricingAndAvailabilityConfigs instead */
|
|
950
956
|
regionalConfigs?: Record<string, OneTimeOfferRegionalConfig>;
|
|
@@ -1031,6 +1037,14 @@ interface ResumableUploadOptions {
|
|
|
1031
1037
|
resumeSessionUri?: string;
|
|
1032
1038
|
/** Maximum resume attempts per chunk before giving up. Default: 5 */
|
|
1033
1039
|
maxResumeAttempts?: number;
|
|
1040
|
+
/**
|
|
1041
|
+
* Optional JSON metadata to include in the initial session-initiation POST.
|
|
1042
|
+
* When present, the initial request uses `Content-Type: application/json; charset=UTF-8`
|
|
1043
|
+
* and the serialized body. Used by APIs like Play Custom App Publishing that
|
|
1044
|
+
* accept resource metadata alongside the media upload (CustomApp.title, etc.).
|
|
1045
|
+
* When omitted, the initial request sends an empty body (default Publisher API behavior).
|
|
1046
|
+
*/
|
|
1047
|
+
initialMetadata?: object;
|
|
1034
1048
|
}
|
|
1035
1049
|
interface ReleaseSummary {
|
|
1036
1050
|
releaseName?: string;
|
|
@@ -1128,7 +1142,6 @@ interface PlayApiClient {
|
|
|
1128
1142
|
get(packageName: string, editId: string, track: string): Promise<CountryAvailability>;
|
|
1129
1143
|
};
|
|
1130
1144
|
dataSafety: {
|
|
1131
|
-
get(packageName: string): Promise<DataSafety>;
|
|
1132
1145
|
update(packageName: string, data: DataSafety): Promise<DataSafety>;
|
|
1133
1146
|
};
|
|
1134
1147
|
reviews: {
|
|
@@ -1329,6 +1342,8 @@ interface PlayApiClient {
|
|
|
1329
1342
|
}>): Promise<{
|
|
1330
1343
|
oneTimeProducts: OneTimeProduct[];
|
|
1331
1344
|
}>;
|
|
1345
|
+
activateOffer(packageName: string, productId: string, purchaseOptionId: string, offerId: string): Promise<OneTimeOffer>;
|
|
1346
|
+
deactivateOffer(packageName: string, productId: string, purchaseOptionId: string, offerId: string): Promise<OneTimeOffer>;
|
|
1332
1347
|
cancelOffer(packageName: string, productId: string, purchaseOptionId: string, offerId: string, latencyTolerance?: string): Promise<OneTimeOffer>;
|
|
1333
1348
|
batchGetOffers(packageName: string, productId: string, purchaseOptionId: string, requests: Array<{
|
|
1334
1349
|
packageName: string;
|
|
@@ -1471,23 +1486,44 @@ interface GamesApiClient {
|
|
|
1471
1486
|
}
|
|
1472
1487
|
declare function createGamesClient(options: ApiClientOptions): GamesApiClient;
|
|
1473
1488
|
|
|
1489
|
+
/**
|
|
1490
|
+
* A private ("custom") app published via the Google Play Custom App Publishing API.
|
|
1491
|
+
* Once created, these apps are PERMANENTLY private — they cannot be made public.
|
|
1492
|
+
*
|
|
1493
|
+
* Source: `https://playcustomapp.googleapis.com/$discovery/rest?version=v1`
|
|
1494
|
+
*/
|
|
1474
1495
|
interface CustomApp {
|
|
1475
|
-
|
|
1496
|
+
/** Output only. Package name Google assigns to the created custom app. */
|
|
1497
|
+
readonly packageName?: string;
|
|
1498
|
+
/** Title for the Android app. Required in practice. */
|
|
1476
1499
|
title: string;
|
|
1500
|
+
/** Default listing language in BCP 47 format (e.g. "en_US"). */
|
|
1477
1501
|
languageCode?: string;
|
|
1502
|
+
/** Organizations to which the custom app should be made available. */
|
|
1478
1503
|
organizations?: Array<{
|
|
1504
|
+
/** ID of the enterprise organization (required when included). */
|
|
1479
1505
|
organizationId: string;
|
|
1506
|
+
/** Human-readable organization name (optional). */
|
|
1480
1507
|
organizationName?: string;
|
|
1481
1508
|
}>;
|
|
1482
1509
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
nextPageToken?: string;
|
|
1486
|
-
}
|
|
1510
|
+
/** Input metadata for `apps.create` — `packageName` is output-only and excluded. */
|
|
1511
|
+
type CustomAppCreateMetadata = Omit<CustomApp, "packageName">;
|
|
1487
1512
|
interface EnterpriseApiClient {
|
|
1488
1513
|
apps: {
|
|
1489
|
-
|
|
1490
|
-
|
|
1514
|
+
/**
|
|
1515
|
+
* Create and publish a new private custom app. Performs a resumable
|
|
1516
|
+
* upload: the initial POST carries the metadata JSON, subsequent chunks
|
|
1517
|
+
* stream the bundle binary. Returns the created `CustomApp` with the
|
|
1518
|
+
* assigned `packageName`.
|
|
1519
|
+
*
|
|
1520
|
+
* The created app is permanently private and cannot be made public.
|
|
1521
|
+
*
|
|
1522
|
+
* @param accountId - Developer account ID (int64, from Play Console URL)
|
|
1523
|
+
* @param bundlePath - Path to the AAB or APK to upload
|
|
1524
|
+
* @param metadata - CustomApp metadata (title, languageCode, organizations)
|
|
1525
|
+
*/
|
|
1526
|
+
create(accountId: string, bundlePath: string, metadata: CustomAppCreateMetadata): Promise<CustomApp>;
|
|
1491
1527
|
};
|
|
1492
1528
|
}
|
|
1493
1529
|
declare function createEnterpriseClient(options: ApiClientOptions): EnterpriseApiClient;
|
|
@@ -1501,6 +1537,13 @@ interface HttpClient {
|
|
|
1501
1537
|
upload<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;
|
|
1502
1538
|
uploadResumable<T>(path: string, filePath: string, contentType: string, options?: ResumableUploadOptions): Promise<ApiResponse<T>>;
|
|
1503
1539
|
uploadInternal<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;
|
|
1540
|
+
/**
|
|
1541
|
+
* Play Custom App Publishing upload. Sends the media body AND a JSON metadata
|
|
1542
|
+
* object in a single resumable session — the initial session-initiation POST
|
|
1543
|
+
* carries the metadata (CustomApp shape), and subsequent chunks stream the
|
|
1544
|
+
* bundle binary. Used by the Play Custom App API which requires both parts.
|
|
1545
|
+
*/
|
|
1546
|
+
uploadCustomApp<T>(path: string, filePath: string, metadata: object, contentType: string): Promise<ApiResponse<T>>;
|
|
1504
1547
|
download(path: string): Promise<ArrayBuffer>;
|
|
1505
1548
|
}
|
|
1506
1549
|
declare function createHttpClient(options: ApiClientOptions): HttpClient;
|
|
@@ -1556,4 +1599,4 @@ declare class PlayApiError extends Error {
|
|
|
1556
1599
|
/** Files below this threshold use simple upload instead. */
|
|
1557
1600
|
declare const RESUMABLE_THRESHOLD: number;
|
|
1558
1601
|
|
|
1559
|
-
export { type Achievement, type AcknowledgeSubscriptionRequest, type Anomaly, type AnomalyDetectionResponse, type ApiClientOptions, type ApiResponse, type ApkInfo, type ApksListResponse, type AppDetails, type AppEdit, type AppRecoveriesListResponse, type AppRecoveryAction, type AppRecoveryTargeting, type BasePlan, type BasePlanMigratePricesRequest, type BatchGetOrdersResponse, type BatchMigratePricesRequest, type BatchMigratePricesResponse, type Bundle, type BundleListResponse, type ChangesInReviewBehavior, type ConvertRegionPricesRequest, type ConvertRegionPricesResponse, type ConvertedRegionPrice, type CountryAvailability, type CreateAppRecoveryActionRequest, type CustomApp, type
|
|
1602
|
+
export { type Achievement, type AcknowledgeSubscriptionRequest, type Anomaly, type AnomalyDetectionResponse, type ApiClientOptions, type ApiResponse, type ApkInfo, type ApksListResponse, type AppDetails, type AppEdit, type AppLevelPermission, type AppRecoveriesListResponse, type AppRecoveryAction, type AppRecoveryTargeting, type BasePlan, type BasePlanMigratePricesRequest, type BatchGetOrdersResponse, type BatchMigratePricesRequest, type BatchMigratePricesResponse, type Bundle, type BundleListResponse, type ChangesInReviewBehavior, type ConvertRegionPricesRequest, type ConvertRegionPricesResponse, type ConvertedRegionPrice, type CountryAvailability, type CreateAppRecoveryActionRequest, type CustomApp, type CustomAppCreateMetadata, type DataSafety, type DataSafetyDataType, type DataSafetyPurpose, type DeobfuscationFile, type DeobfuscationFileType, type DeobfuscationUploadResponse, type DeveloperComment, type DeveloperLevelPermission, type DeveloperPermission, type DeviceGroup, type DeviceSelector, type DeviceTier, type DeviceTierConfig, type DeviceTierConfigsListResponse, type EditCommitOptions, type EnterpriseApiClient, type ErrorIssue, type ErrorIssuesResponse, type ErrorReport, type ErrorReportsResponse, type ExpansionFile, type ExpansionFileType, type ExternalTransaction, type ExternalTransactionAmount, type ExternalTransactionRefund, type ExternallyHostedApk, type ExternallyHostedApkResponse, type GameEvent, type GamesApiClient, type GeneratedApk, type GeneratedApksPerVersion, type Grant, type GrantsListResponse, type HttpClient, type Image, type ImageType, type ImageUploadResponse, type ImagesDeleteAllResponse, type ImagesListResponse, type InAppProduct, type InAppProductListing, type InAppProductsBatchDeleteRequest, type InAppProductsBatchGetRequest, type InAppProductsBatchUpdateRequest, type InAppProductsBatchUpdateResponse, type InAppProductsListResponse, type InternalAppSharingArtifact, type Leaderboard, type LeaderboardScore, type Listing, type ListingsListResponse, type MetricRow, type MetricSetQuery, type MetricSetResponse, type Money, type MutationOptions, type OffersListResponse, type OneTimeOffer, type OneTimeOfferRegionalConfig, type OneTimeOfferState, type OneTimeOffersListResponse, type OneTimeProduct, type OneTimeProductAvailability, type OneTimeProductListing, type OneTimeProductsListResponse, type Order, type OrderLineItem, type PagedResponse, type PaginateOptions, type PlayApiClient, PlayApiError, type ProductPurchase, type ProductPurchaseLineItem, type ProductPurchaseV2, type ProductUpdateLatencyTolerance, RATE_LIMIT_BUCKETS, RESUMABLE_THRESHOLD, type RateLimitBucket, type RateLimiter, type RegionalBasePlanConfig, type Release, type ReleaseNote, type ReleaseStatus, type ReleaseSummary, type ReleasesListResponse, type ReportBucket, type ReportType, type ReportingAggregation, type ReportingApiClient, type ReportingDimension, type ReportsListResponse, type ResumableUploadOptions, type RetryLogEntry, type Review, type ReviewComment, type ReviewReplyRequest, type ReviewReplyResponse, type ReviewsListOptions, type ReviewsListResponse, type RevokeSubscriptionV2Request, type StatsDimension, type Subscription, type SubscriptionDeferRequest, type SubscriptionDeferResponse, type SubscriptionListing, type SubscriptionOffer, type SubscriptionOfferPhase, type SubscriptionPurchase, type SubscriptionPurchaseLineItem, type SubscriptionPurchaseV2, type SubscriptionState, type SubscriptionsBatchGetRequest, type SubscriptionsBatchGetResponse, type SubscriptionsBatchUpdateRequest, type SubscriptionsBatchUpdateResponse, type SubscriptionsListResponse, type SubscriptionsV2CancelRequest, type SubscriptionsV2DeferRequest, type SubscriptionsV2DeferResponse, type SystemApkDeviceSpec, type SystemApkOptions, type SystemApkVariant, type TaxAndComplianceSettings, type Testers, type TokenPagination, type Track, type TrackListResponse, type UploadProgressEvent, type UploadResponse, type User, type UserComment, type UsersApiClient, type UsersListResponse, type VitalsMetricSet, type VoidedPurchase, type VoidedPurchasesListResponse, createApiClient, createEnterpriseClient, createGamesClient, createHttpClient, createRateLimiter, createReportingClient, createUsersClient, paginate, paginateAll, paginateParallel, resolveBucket };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,9 @@ var PlayApiError = class extends Error {
|
|
|
7
7
|
this.suggestion = suggestion;
|
|
8
8
|
this.name = "PlayApiError";
|
|
9
9
|
}
|
|
10
|
+
code;
|
|
11
|
+
statusCode;
|
|
12
|
+
suggestion;
|
|
10
13
|
exitCode = 4;
|
|
11
14
|
toJSON() {
|
|
12
15
|
return {
|
|
@@ -64,7 +67,13 @@ async function resumableUpload(uploadUrl, filePath, contentType, ctx, options) {
|
|
|
64
67
|
const totalBytes = fileStats.size;
|
|
65
68
|
let sessionUri = options?.resumeSessionUri;
|
|
66
69
|
if (!sessionUri) {
|
|
67
|
-
sessionUri = await initiateSession(
|
|
70
|
+
sessionUri = await initiateSession(
|
|
71
|
+
uploadUrl,
|
|
72
|
+
contentType,
|
|
73
|
+
totalBytes,
|
|
74
|
+
ctx,
|
|
75
|
+
options?.initialMetadata
|
|
76
|
+
);
|
|
68
77
|
}
|
|
69
78
|
const startTime = Date.now();
|
|
70
79
|
let offset = 0;
|
|
@@ -170,21 +179,29 @@ async function resumableUpload(uploadUrl, filePath, contentType, ctx, options) {
|
|
|
170
179
|
await fh?.close();
|
|
171
180
|
}
|
|
172
181
|
}
|
|
173
|
-
async function initiateSession(uploadUrl, contentType, totalBytes, ctx) {
|
|
182
|
+
async function initiateSession(uploadUrl, contentType, totalBytes, ctx, initialMetadata) {
|
|
174
183
|
const token = await ctx.getAccessToken();
|
|
175
184
|
const url = uploadUrl.includes("?") ? `${uploadUrl}&uploadType=resumable` : `${uploadUrl}?uploadType=resumable`;
|
|
185
|
+
const hasMetadata = initialMetadata !== void 0;
|
|
186
|
+
const metadataBody = hasMetadata ? JSON.stringify(initialMetadata) : "";
|
|
187
|
+
const metadataBodyBytes = hasMetadata ? Buffer.byteLength(metadataBody, "utf8") : 0;
|
|
188
|
+
const headers = {
|
|
189
|
+
Authorization: `Bearer ${token}`,
|
|
190
|
+
"X-Upload-Content-Type": contentType,
|
|
191
|
+
"X-Upload-Content-Length": String(totalBytes),
|
|
192
|
+
"Content-Length": String(metadataBodyBytes)
|
|
193
|
+
};
|
|
194
|
+
if (hasMetadata) {
|
|
195
|
+
headers["Content-Type"] = "application/json; charset=UTF-8";
|
|
196
|
+
}
|
|
176
197
|
const controller = new AbortController();
|
|
177
198
|
const timer = setTimeout(() => controller.abort(), 6e4);
|
|
178
199
|
let response;
|
|
179
200
|
try {
|
|
180
201
|
response = await fetch(url, {
|
|
181
202
|
method: "POST",
|
|
182
|
-
headers
|
|
183
|
-
|
|
184
|
-
"X-Upload-Content-Type": contentType,
|
|
185
|
-
"X-Upload-Content-Length": String(totalBytes),
|
|
186
|
-
"Content-Length": "0"
|
|
187
|
-
},
|
|
203
|
+
headers,
|
|
204
|
+
body: hasMetadata ? metadataBody : void 0,
|
|
188
205
|
signal: controller.signal
|
|
189
206
|
});
|
|
190
207
|
} finally {
|
|
@@ -405,6 +422,7 @@ function validateFilePath(filePath) {
|
|
|
405
422
|
var BASE_URL = "https://androidpublisher.googleapis.com/androidpublisher/v3/applications";
|
|
406
423
|
var UPLOAD_BASE_URL = "https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications";
|
|
407
424
|
var INTERNAL_SHARING_UPLOAD_BASE_URL = "https://androidpublisher.googleapis.com/upload/internalappsharing/v3/applications";
|
|
425
|
+
var CUSTOM_APP_UPLOAD_BASE_URL = "https://playcustomapp.googleapis.com/upload/playcustomapp/v1/accounts";
|
|
408
426
|
function envInt2(name) {
|
|
409
427
|
const val = process.env[name];
|
|
410
428
|
if (val === void 0) return void 0;
|
|
@@ -938,6 +956,23 @@ function createHttpClient(options) {
|
|
|
938
956
|
uploadInternal(path, filePath, contentType) {
|
|
939
957
|
return uploadRequest(path, filePath, contentType, INTERNAL_SHARING_UPLOAD_BASE_URL);
|
|
940
958
|
},
|
|
959
|
+
async uploadCustomApp(path, filePath, metadata, contentType) {
|
|
960
|
+
const safeFilePath = validateFilePath(filePath);
|
|
961
|
+
const uploadUrl = `${CUSTOM_APP_UPLOAD_BASE_URL}${path}`;
|
|
962
|
+
return resumableUpload(
|
|
963
|
+
uploadUrl,
|
|
964
|
+
safeFilePath,
|
|
965
|
+
contentType,
|
|
966
|
+
{
|
|
967
|
+
getAccessToken: () => options.auth.getAccessToken(),
|
|
968
|
+
maxRetries,
|
|
969
|
+
baseDelay,
|
|
970
|
+
maxDelay,
|
|
971
|
+
onRetry
|
|
972
|
+
},
|
|
973
|
+
{ initialMetadata: metadata }
|
|
974
|
+
);
|
|
975
|
+
},
|
|
941
976
|
async download(path) {
|
|
942
977
|
const url = `${options.baseUrl ?? BASE_URL}${path}`;
|
|
943
978
|
const token = await options.auth.getAccessToken();
|
|
@@ -1345,12 +1380,8 @@ function createApiClient(options) {
|
|
|
1345
1380
|
}
|
|
1346
1381
|
},
|
|
1347
1382
|
dataSafety: {
|
|
1348
|
-
async get(packageName) {
|
|
1349
|
-
const { data } = await http.get(`/${packageName}/dataSafety`);
|
|
1350
|
-
return data;
|
|
1351
|
-
},
|
|
1352
1383
|
async update(packageName, body) {
|
|
1353
|
-
const { data } = await http.
|
|
1384
|
+
const { data } = await http.post(`/${packageName}/dataSafety`, body);
|
|
1354
1385
|
return data;
|
|
1355
1386
|
}
|
|
1356
1387
|
},
|
|
@@ -1788,10 +1819,10 @@ function createApiClient(options) {
|
|
|
1788
1819
|
return data.recoveryActions || [];
|
|
1789
1820
|
},
|
|
1790
1821
|
async cancel(packageName, appRecoveryId) {
|
|
1791
|
-
await http.post(`/${packageName}/
|
|
1822
|
+
await http.post(`/${packageName}/appRecoveries/${appRecoveryId}:cancel`);
|
|
1792
1823
|
},
|
|
1793
1824
|
async deploy(packageName, appRecoveryId) {
|
|
1794
|
-
await http.post(`/${packageName}/
|
|
1825
|
+
await http.post(`/${packageName}/appRecoveries/${appRecoveryId}:deploy`);
|
|
1795
1826
|
},
|
|
1796
1827
|
async create(packageName, request) {
|
|
1797
1828
|
const { data } = await http.post(
|
|
@@ -1963,6 +1994,19 @@ function createApiClient(options) {
|
|
|
1963
1994
|
);
|
|
1964
1995
|
return data;
|
|
1965
1996
|
},
|
|
1997
|
+
// Offer lifecycle
|
|
1998
|
+
async activateOffer(packageName, productId, purchaseOptionId, offerId) {
|
|
1999
|
+
const { data } = await http.post(
|
|
2000
|
+
`/${packageName}/oneTimeProducts/${productId}/purchaseOptions/${purchaseOptionId}/offers/${offerId}:activate`
|
|
2001
|
+
);
|
|
2002
|
+
return data;
|
|
2003
|
+
},
|
|
2004
|
+
async deactivateOffer(packageName, productId, purchaseOptionId, offerId) {
|
|
2005
|
+
const { data } = await http.post(
|
|
2006
|
+
`/${packageName}/oneTimeProducts/${productId}/purchaseOptions/${purchaseOptionId}/offers/${offerId}:deactivate`
|
|
2007
|
+
);
|
|
2008
|
+
return data;
|
|
2009
|
+
},
|
|
1966
2010
|
// Offer batch operations
|
|
1967
2011
|
async cancelOffer(packageName, productId, purchaseOptionId, offerId, latencyTolerance) {
|
|
1968
2012
|
const body = latencyTolerance ? { latencyTolerance } : {};
|
|
@@ -2221,17 +2265,58 @@ function createGamesClient(options) {
|
|
|
2221
2265
|
}
|
|
2222
2266
|
|
|
2223
2267
|
// src/enterprise-client.ts
|
|
2224
|
-
|
|
2268
|
+
import { stat as stat3 } from "fs/promises";
|
|
2269
|
+
function assertAccountId(accountId) {
|
|
2270
|
+
if (!/^\d+$/.test(accountId)) {
|
|
2271
|
+
throw new PlayApiError(
|
|
2272
|
+
`Developer account ID must be numeric (got "${accountId}").`,
|
|
2273
|
+
"ENTERPRISE_INVALID_ACCOUNT_ID",
|
|
2274
|
+
void 0,
|
|
2275
|
+
[
|
|
2276
|
+
"Find your developer account ID in the Play Console URL:",
|
|
2277
|
+
" https://play.google.com/console/developers/[ID]",
|
|
2278
|
+
"The ID is a long integer, not your Workspace or Cloud Identity organization ID."
|
|
2279
|
+
].join("\n")
|
|
2280
|
+
);
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
async function assertBundleExists(bundlePath) {
|
|
2284
|
+
try {
|
|
2285
|
+
await stat3(bundlePath);
|
|
2286
|
+
} catch {
|
|
2287
|
+
throw new PlayApiError(
|
|
2288
|
+
`Bundle file not found: ${bundlePath}`,
|
|
2289
|
+
"ENTERPRISE_BUNDLE_NOT_FOUND",
|
|
2290
|
+
void 0,
|
|
2291
|
+
"Verify the path to your AAB or APK is correct."
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
function detectContentType(bundlePath) {
|
|
2296
|
+
const lower = bundlePath.toLowerCase();
|
|
2297
|
+
if (lower.endsWith(".aab")) {
|
|
2298
|
+
return "application/octet-stream";
|
|
2299
|
+
}
|
|
2300
|
+
if (lower.endsWith(".apk")) {
|
|
2301
|
+
return "application/vnd.android.package-archive";
|
|
2302
|
+
}
|
|
2303
|
+
return "application/octet-stream";
|
|
2304
|
+
}
|
|
2225
2305
|
function createEnterpriseClient(options) {
|
|
2226
|
-
const http = createHttpClient(
|
|
2306
|
+
const http = createHttpClient(options);
|
|
2227
2307
|
return {
|
|
2228
2308
|
apps: {
|
|
2229
|
-
async create(
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
const { data } = await http.
|
|
2309
|
+
async create(accountId, bundlePath, metadata) {
|
|
2310
|
+
assertAccountId(accountId);
|
|
2311
|
+
await assertBundleExists(bundlePath);
|
|
2312
|
+
const contentType = detectContentType(bundlePath);
|
|
2313
|
+
const path = `/${accountId}/customApps`;
|
|
2314
|
+
const { data } = await http.uploadCustomApp(
|
|
2315
|
+
path,
|
|
2316
|
+
bundlePath,
|
|
2317
|
+
metadata,
|
|
2318
|
+
contentType
|
|
2319
|
+
);
|
|
2235
2320
|
return data;
|
|
2236
2321
|
}
|
|
2237
2322
|
}
|