@gpc-cli/api 1.0.6 → 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/dist/index.d.ts +153 -1
- package/dist/index.js +163 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -511,6 +511,27 @@ interface AppRecoveryAction {
|
|
|
511
511
|
interface AppRecoveriesListResponse {
|
|
512
512
|
recoveryActions: AppRecoveryAction[];
|
|
513
513
|
}
|
|
514
|
+
interface AppRecoveryTargeting {
|
|
515
|
+
allUsers?: {
|
|
516
|
+
inScopeVersionCodes?: string[];
|
|
517
|
+
};
|
|
518
|
+
androidSdks?: {
|
|
519
|
+
sdkLevels: string[];
|
|
520
|
+
};
|
|
521
|
+
regions?: {
|
|
522
|
+
regionCodes: string[];
|
|
523
|
+
};
|
|
524
|
+
versionList?: {
|
|
525
|
+
versionCodes: string[];
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
interface CreateAppRecoveryActionRequest {
|
|
529
|
+
remoteInAppUpdateData?: Record<string, unknown>;
|
|
530
|
+
appRecoveryAction?: {
|
|
531
|
+
targeting?: AppRecoveryTargeting;
|
|
532
|
+
status?: string;
|
|
533
|
+
};
|
|
534
|
+
}
|
|
514
535
|
interface ExternalTransactionAmount {
|
|
515
536
|
priceMicros?: string;
|
|
516
537
|
currency?: string;
|
|
@@ -572,6 +593,108 @@ interface Testers {
|
|
|
572
593
|
googleGroups?: string[];
|
|
573
594
|
googleGroupsCount?: number;
|
|
574
595
|
}
|
|
596
|
+
interface DeviceTier {
|
|
597
|
+
deviceTierConfigId: string;
|
|
598
|
+
deviceGroups: DeviceGroup[];
|
|
599
|
+
}
|
|
600
|
+
interface DeviceGroup {
|
|
601
|
+
name: string;
|
|
602
|
+
deviceSelectors: DeviceSelector[];
|
|
603
|
+
}
|
|
604
|
+
interface DeviceSelector {
|
|
605
|
+
deviceRam?: {
|
|
606
|
+
minBytes?: string;
|
|
607
|
+
maxBytes?: string;
|
|
608
|
+
};
|
|
609
|
+
includedDeviceIds?: {
|
|
610
|
+
buildBrand: string;
|
|
611
|
+
buildDevice: string;
|
|
612
|
+
}[];
|
|
613
|
+
excludedDeviceIds?: {
|
|
614
|
+
buildBrand: string;
|
|
615
|
+
buildDevice: string;
|
|
616
|
+
}[];
|
|
617
|
+
requiredSystemFeatures?: {
|
|
618
|
+
name: string;
|
|
619
|
+
}[];
|
|
620
|
+
forbiddenSystemFeatures?: {
|
|
621
|
+
name: string;
|
|
622
|
+
}[];
|
|
623
|
+
}
|
|
624
|
+
interface DeviceTierConfig {
|
|
625
|
+
deviceTierConfigId: string;
|
|
626
|
+
deviceGroups: DeviceGroup[];
|
|
627
|
+
userCountryTargeting?: {
|
|
628
|
+
countryCodes: string[];
|
|
629
|
+
exclude?: boolean;
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
interface DeviceTierConfigsListResponse {
|
|
633
|
+
deviceTierConfigs: DeviceTierConfig[];
|
|
634
|
+
}
|
|
635
|
+
interface InternalAppSharingArtifact {
|
|
636
|
+
certificateFingerprint: string;
|
|
637
|
+
downloadUrl: string;
|
|
638
|
+
sha256: string;
|
|
639
|
+
}
|
|
640
|
+
interface GeneratedApk {
|
|
641
|
+
generatedApkId: string;
|
|
642
|
+
variantId: number;
|
|
643
|
+
moduleName: string;
|
|
644
|
+
apkDescription?: string;
|
|
645
|
+
certificateSha256Fingerprint: string;
|
|
646
|
+
}
|
|
647
|
+
interface GeneratedApksPerVersion {
|
|
648
|
+
generatedApks: GeneratedApk[];
|
|
649
|
+
}
|
|
650
|
+
interface OneTimeProduct {
|
|
651
|
+
packageName: string;
|
|
652
|
+
productId: string;
|
|
653
|
+
purchaseType: "managedUser" | "subscription";
|
|
654
|
+
listings: Record<string, OneTimeProductListing>;
|
|
655
|
+
taxAndComplianceSettings?: TaxAndComplianceSettings;
|
|
656
|
+
}
|
|
657
|
+
interface OneTimeProductListing {
|
|
658
|
+
title: string;
|
|
659
|
+
description?: string;
|
|
660
|
+
benefits?: string[];
|
|
661
|
+
}
|
|
662
|
+
interface TaxAndComplianceSettings {
|
|
663
|
+
eeaWithdrawalRightType?: "WITHDRAWAL_RIGHT_DIGITAL_CONTENT" | "WITHDRAWAL_RIGHT_SERVICE";
|
|
664
|
+
taxRateInfoByRegionCode?: Record<string, {
|
|
665
|
+
streamingTaxType?: string;
|
|
666
|
+
taxTier?: string;
|
|
667
|
+
}>;
|
|
668
|
+
isTokenizedDigitalAsset?: boolean;
|
|
669
|
+
}
|
|
670
|
+
interface OneTimeOffer {
|
|
671
|
+
packageName: string;
|
|
672
|
+
productId: string;
|
|
673
|
+
offerId: string;
|
|
674
|
+
regionalConfigs: Record<string, OneTimeOfferRegionalConfig>;
|
|
675
|
+
otherRegionsConfig?: {
|
|
676
|
+
usdPrice: {
|
|
677
|
+
units: string;
|
|
678
|
+
nanos?: number;
|
|
679
|
+
};
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
interface OneTimeOfferRegionalConfig {
|
|
683
|
+
price: {
|
|
684
|
+
currencyCode: string;
|
|
685
|
+
units: string;
|
|
686
|
+
nanos?: number;
|
|
687
|
+
};
|
|
688
|
+
newSubscriberAvailability?: boolean;
|
|
689
|
+
}
|
|
690
|
+
interface OneTimeProductsListResponse {
|
|
691
|
+
oneTimeProducts: OneTimeProduct[];
|
|
692
|
+
nextPageToken?: string;
|
|
693
|
+
}
|
|
694
|
+
interface OneTimeOffersListResponse {
|
|
695
|
+
oneTimeOffers: OneTimeOffer[];
|
|
696
|
+
nextPageToken?: string;
|
|
697
|
+
}
|
|
575
698
|
|
|
576
699
|
interface PlayApiClient {
|
|
577
700
|
edits: {
|
|
@@ -693,12 +816,39 @@ interface PlayApiClient {
|
|
|
693
816
|
list(packageName: string): Promise<AppRecoveryAction[]>;
|
|
694
817
|
cancel(packageName: string, appRecoveryId: string): Promise<void>;
|
|
695
818
|
deploy(packageName: string, appRecoveryId: string): Promise<void>;
|
|
819
|
+
create(packageName: string, request: CreateAppRecoveryActionRequest): Promise<AppRecoveryAction>;
|
|
820
|
+
addTargeting(packageName: string, appRecoveryId: string, targeting: AppRecoveryTargeting): Promise<AppRecoveryAction>;
|
|
696
821
|
};
|
|
697
822
|
externalTransactions: {
|
|
698
823
|
create(packageName: string, data: ExternalTransaction): Promise<ExternalTransaction>;
|
|
699
824
|
get(packageName: string, transactionId: string): Promise<ExternalTransaction>;
|
|
700
825
|
refund(packageName: string, transactionId: string, refundData: ExternalTransactionRefund): Promise<ExternalTransaction>;
|
|
701
826
|
};
|
|
827
|
+
deviceTiers: {
|
|
828
|
+
list(packageName: string): Promise<DeviceTierConfig[]>;
|
|
829
|
+
get(packageName: string, configId: string): Promise<DeviceTierConfig>;
|
|
830
|
+
create(packageName: string, config: DeviceTierConfig): Promise<DeviceTierConfig>;
|
|
831
|
+
};
|
|
832
|
+
oneTimeProducts: {
|
|
833
|
+
list(packageName: string): Promise<OneTimeProductsListResponse>;
|
|
834
|
+
get(packageName: string, productId: string): Promise<OneTimeProduct>;
|
|
835
|
+
create(packageName: string, product: OneTimeProduct): Promise<OneTimeProduct>;
|
|
836
|
+
update(packageName: string, productId: string, product: Partial<OneTimeProduct>): Promise<OneTimeProduct>;
|
|
837
|
+
delete(packageName: string, productId: string): Promise<void>;
|
|
838
|
+
listOffers(packageName: string, productId: string): Promise<OneTimeOffersListResponse>;
|
|
839
|
+
getOffer(packageName: string, productId: string, offerId: string): Promise<OneTimeOffer>;
|
|
840
|
+
createOffer(packageName: string, productId: string, offer: OneTimeOffer): Promise<OneTimeOffer>;
|
|
841
|
+
updateOffer(packageName: string, productId: string, offerId: string, offer: Partial<OneTimeOffer>): Promise<OneTimeOffer>;
|
|
842
|
+
deleteOffer(packageName: string, productId: string, offerId: string): Promise<void>;
|
|
843
|
+
};
|
|
844
|
+
internalAppSharing: {
|
|
845
|
+
uploadBundle(packageName: string, bundlePath: string): Promise<InternalAppSharingArtifact>;
|
|
846
|
+
uploadApk(packageName: string, apkPath: string): Promise<InternalAppSharingArtifact>;
|
|
847
|
+
};
|
|
848
|
+
generatedApks: {
|
|
849
|
+
list(packageName: string, versionCode: number): Promise<GeneratedApk[]>;
|
|
850
|
+
download(packageName: string, versionCode: number, id: string): Promise<ArrayBuffer>;
|
|
851
|
+
};
|
|
702
852
|
}
|
|
703
853
|
declare function createApiClient(options: ApiClientOptions): PlayApiClient;
|
|
704
854
|
|
|
@@ -729,6 +879,8 @@ interface HttpClient {
|
|
|
729
879
|
patch<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;
|
|
730
880
|
delete<T>(path: string): Promise<ApiResponse<T>>;
|
|
731
881
|
upload<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;
|
|
882
|
+
uploadInternal<T>(path: string, filePath: string, contentType: string): Promise<ApiResponse<T>>;
|
|
883
|
+
download(path: string): Promise<ArrayBuffer>;
|
|
732
884
|
}
|
|
733
885
|
declare function createHttpClient(options: ApiClientOptions): HttpClient;
|
|
734
886
|
|
|
@@ -780,4 +932,4 @@ declare class ApiError extends Error {
|
|
|
780
932
|
};
|
|
781
933
|
}
|
|
782
934
|
|
|
783
|
-
export { type Anomaly, type AnomalyDetectionResponse, type ApiClientOptions, ApiError, type ApiResponse, type ApkInfo, type AppDetails, type AppEdit, type AppRecoveriesListResponse, type AppRecoveryAction, type BasePlan, type BasePlanMigratePricesRequest, type Bundle, type BundleListResponse, type ConvertRegionPricesRequest, type ConvertRegionPricesResponse, type ConvertedRegionPrice, type CountryAvailability, type DataSafety, type DataSafetyDataType, type DataSafetyPurpose, type DeobfuscationFile, type DeobfuscationUploadResponse, type DeveloperComment, type DeveloperPermission, type ErrorIssue, type ErrorIssuesResponse, type ErrorReport, type ErrorReportsResponse, type ExternalTransaction, type ExternalTransactionAmount, type ExternalTransactionRefund, type Grant, type HttpClient, type Image, type ImageType, type ImageUploadResponse, type ImagesDeleteAllResponse, type ImagesListResponse, type InAppProduct, type InAppProductListing, type InAppProductsListResponse, type Listing, type ListingsListResponse, type MetricRow, type MetricSetQuery, type MetricSetResponse, type Money, type OffersListResponse, type PagedResponse, type PaginateOptions, type PlayApiClient, type ProductPurchase, 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 Testers, type TokenPagination, type Track, type TrackListResponse, type UploadResponse, type User, type UserComment, type UsersApiClient, type UsersListResponse, type VitalsMetricSet, type VoidedPurchase, type VoidedPurchasesListResponse, createApiClient, createHttpClient, createRateLimiter, createReportingClient, createUsersClient, paginate, paginateAll, paginateParallel };
|
|
935
|
+
export { type Anomaly, type AnomalyDetectionResponse, type ApiClientOptions, ApiError, 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 DataSafety, type DataSafetyDataType, type DataSafetyPurpose, type DeobfuscationFile, type DeobfuscationUploadResponse, type DeveloperComment, type DeveloperPermission, type DeviceGroup, type DeviceSelector, type DeviceTier, type DeviceTierConfig, type DeviceTierConfigsListResponse, type ErrorIssue, type ErrorIssuesResponse, type ErrorReport, type ErrorReportsResponse, type ExternalTransaction, type ExternalTransactionAmount, type ExternalTransactionRefund, type GeneratedApk, type GeneratedApksPerVersion, type Grant, type HttpClient, type Image, type ImageType, type ImageUploadResponse, type ImagesDeleteAllResponse, type ImagesListResponse, type InAppProduct, type InAppProductListing, type InAppProductsListResponse, type InternalAppSharingArtifact, 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, type ProductPurchase, 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, createHttpClient, createRateLimiter, createReportingClient, createUsersClient, paginate, paginateAll, paginateParallel };
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,7 @@ function validateFilePath(filePath) {
|
|
|
50
50
|
}
|
|
51
51
|
var BASE_URL = "https://androidpublisher.googleapis.com/androidpublisher/v3/applications";
|
|
52
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";
|
|
53
54
|
function envInt(name) {
|
|
54
55
|
const val = process.env[name];
|
|
55
56
|
if (val === void 0) return void 0;
|
|
@@ -225,8 +226,8 @@ function createHttpClient(options) {
|
|
|
225
226
|
}
|
|
226
227
|
throw lastError ?? new ApiError("Request failed", "API_NETWORK_ERROR");
|
|
227
228
|
}
|
|
228
|
-
async function uploadRequest(path, filePath, contentType) {
|
|
229
|
-
const url = `${
|
|
229
|
+
async function uploadRequest(path, filePath, contentType, baseUrl = UPLOAD_BASE_URL) {
|
|
230
|
+
const url = `${baseUrl}${path}`;
|
|
230
231
|
const safeFilePath = validateFilePath(filePath);
|
|
231
232
|
const fileBuffer = await readFile(safeFilePath);
|
|
232
233
|
let token = await options.auth.getAccessToken();
|
|
@@ -353,6 +354,40 @@ function createHttpClient(options) {
|
|
|
353
354
|
},
|
|
354
355
|
upload(path, filePath, contentType) {
|
|
355
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
|
+
}
|
|
356
391
|
}
|
|
357
392
|
};
|
|
358
393
|
}
|
|
@@ -837,6 +872,20 @@ function createApiClient(options) {
|
|
|
837
872
|
},
|
|
838
873
|
async deploy(packageName, appRecoveryId) {
|
|
839
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;
|
|
840
889
|
}
|
|
841
890
|
},
|
|
842
891
|
externalTransactions: {
|
|
@@ -860,6 +909,118 @@ function createApiClient(options) {
|
|
|
860
909
|
);
|
|
861
910
|
return data;
|
|
862
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
|
+
}
|
|
863
1024
|
}
|
|
864
1025
|
};
|
|
865
1026
|
}
|
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/** 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\n }\n // Truncate raw body to prevent leaking large payloads\n return body.length > 200 ? body.slice(0, 200) + \"...\" : body;\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\");\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\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}\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 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\");\n }\n\n async function uploadRequest<T>(\n path: string,\n filePath: string,\n contentType: string,\n ): Promise<ApiResponse<T>> {\n const url = `${UPLOAD_BASE_URL}${path}`;\n const safeFilePath = validateFilePath(filePath);\n const fileBuffer = await readFile(safeFilePath);\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(), timeout);\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 timeoutErr = new ApiError(\n `POST upload ${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: \"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\");\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 };\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 BasePlanMigratePricesRequest,\n Bundle,\n BundleListResponse,\n ConvertRegionPricesRequest,\n ConvertRegionPricesResponse,\n CountryAvailability,\n DataSafety,\n DeobfuscationFile,\n DeobfuscationUploadResponse,\n ExternalTransaction,\n ExternalTransactionRefund,\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 UploadResponse,\n VoidedPurchasesListResponse,\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 update(packageName: string, editId: string, track: string, release: Release): Promise<Track>;\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, editId: string): Promise<DataSafety>;\n update(packageName: string, editId: 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): Promise<Subscription>;\n update(\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: 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 ): Promise<SubscriptionOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: 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): Promise<InAppProduct>;\n update(packageName: string, sku: string, data: InAppProduct): Promise<InAppProduct>;\n delete(packageName: string, sku: string): Promise<void>;\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): Promise<AppRecoveryAction[]>;\n cancel(packageName: string, appRecoveryId: string): Promise<void>;\n deploy(packageName: string, appRecoveryId: string): Promise<void>;\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\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<UploadResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data.bundle) {\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.bundle;\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 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 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, editId) {\n const { data } = await http.get<DataSafety>(\n `/${packageName}/edits/${editId}/dataSafety`,\n );\n return data;\n },\n\n async update(packageName, editId, body) {\n const { data } = await http.put<DataSafety>(\n `/${packageName}/edits/${editId}/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}/monetization/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}/monetization/subscriptions/${productId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions`,\n body,\n );\n return data;\n },\n\n async update(packageName, productId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}`;\n if (updateMask) {\n path += `?${new URLSearchParams({ updateMask }).toString()}`;\n }\n const { data } = await http.patch<Subscription>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/monetization/subscriptions/${productId}`);\n },\n\n async activateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/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}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:deactivate`,\n );\n return data;\n },\n\n async deleteBasePlan(packageName, productId, basePlanId) {\n await http.delete(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}`,\n );\n },\n\n async migratePrices(packageName, productId, basePlanId, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/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}/monetization/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}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, basePlanId, body) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n body,\n );\n return data;\n },\n\n async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`;\n if (updateMask) {\n path += `?${new URLSearchParams({ updateMask }).toString()}`;\n }\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}/monetization/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}/monetization/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}/monetization/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) {\n const { data } = await http.post<InAppProduct>(`/${packageName}/inappproducts`, body);\n return data;\n },\n\n async update(packageName, sku, body) {\n const { data } = await http.put<InAppProduct>(`/${packageName}/inappproducts/${sku}`, body);\n return data;\n },\n\n async delete(packageName, sku) {\n await http.delete(`/${packageName}/inappproducts/${sku}`);\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}/monetization/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) {\n const { data } = await http.post<AppRecoveriesListResponse>(\n `/${packageName}/appRecoveries`,\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\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}\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/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/** 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\n }\n // Truncate raw body to prevent leaking large payloads\n return body.length > 200 ? body.slice(0, 200) + \"...\" : body;\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\");\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 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\");\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\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(), timeout);\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 timeoutErr = new ApiError(\n `POST upload ${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: \"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\");\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 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 UploadResponse,\n VoidedPurchasesListResponse,\n OneTimeProduct,\n OneTimeProductsListResponse,\n OneTimeOffer,\n OneTimeOffersListResponse,\n InternalAppSharingArtifact,\n GeneratedApk,\n GeneratedApksPerVersion,\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 update(packageName: string, editId: string, track: string, release: Release): Promise<Track>;\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, editId: string): Promise<DataSafety>;\n update(packageName: string, editId: 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): Promise<Subscription>;\n update(\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: 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 ): Promise<SubscriptionOffer>;\n updateOffer(\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: 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): Promise<InAppProduct>;\n update(packageName: string, sku: string, data: InAppProduct): Promise<InAppProduct>;\n delete(packageName: string, sku: string): Promise<void>;\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): 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 ): 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 ): Promise<OneTimeOffer>;\n deleteOffer(\n packageName: string,\n productId: string,\n offerId: string,\n ): Promise<void>;\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<UploadResponse>(\n `/${packageName}/edits/${editId}/bundles`,\n filePath,\n \"application/octet-stream\",\n );\n if (!data.bundle) {\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.bundle;\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 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 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, editId) {\n const { data } = await http.get<DataSafety>(\n `/${packageName}/edits/${editId}/dataSafety`,\n );\n return data;\n },\n\n async update(packageName, editId, body) {\n const { data } = await http.put<DataSafety>(\n `/${packageName}/edits/${editId}/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}/monetization/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}/monetization/subscriptions/${productId}`,\n );\n return data;\n },\n\n async create(packageName, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/subscriptions`,\n body,\n );\n return data;\n },\n\n async update(packageName, productId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}`;\n if (updateMask) {\n path += `?${new URLSearchParams({ updateMask }).toString()}`;\n }\n const { data } = await http.patch<Subscription>(path, body);\n return data;\n },\n\n async delete(packageName, productId) {\n await http.delete(`/${packageName}/monetization/subscriptions/${productId}`);\n },\n\n async activateBasePlan(packageName, productId, basePlanId) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/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}/monetization/subscriptions/${productId}/basePlans/${basePlanId}:deactivate`,\n );\n return data;\n },\n\n async deleteBasePlan(packageName, productId, basePlanId) {\n await http.delete(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}`,\n );\n },\n\n async migratePrices(packageName, productId, basePlanId, body) {\n const { data } = await http.post<Subscription>(\n `/${packageName}/monetization/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}/monetization/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}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`,\n );\n return data;\n },\n\n async createOffer(packageName, productId, basePlanId, body) {\n const { data } = await http.post<SubscriptionOffer>(\n `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers`,\n body,\n );\n return data;\n },\n\n async updateOffer(packageName, productId, basePlanId, offerId, body, updateMask?) {\n let path = `/${packageName}/monetization/subscriptions/${productId}/basePlans/${basePlanId}/offers/${offerId}`;\n if (updateMask) {\n path += `?${new URLSearchParams({ updateMask }).toString()}`;\n }\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}/monetization/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}/monetization/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}/monetization/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) {\n const { data } = await http.post<InAppProduct>(`/${packageName}/inappproducts`, body);\n return data;\n },\n\n async update(packageName, sku, body) {\n const { data } = await http.put<InAppProduct>(`/${packageName}/inappproducts/${sku}`, body);\n return data;\n },\n\n async delete(packageName, sku) {\n await http.delete(`/${packageName}/inappproducts/${sku}`);\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}/monetization/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) {\n const { data } = await http.post<AppRecoveriesListResponse>(\n `/${packageName}/appRecoveries`,\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 { data } = await http.post<OneTimeProduct>(\n `/${packageName}/oneTimeProducts`,\n body,\n );\n return data;\n },\n\n async update(packageName, productId, body) {\n const { data } = await http.patch<OneTimeProduct>(\n `/${packageName}/oneTimeProducts/${productId}`,\n body,\n );\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) {\n const { data } = await http.patch<OneTimeOffer>(\n `/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`,\n body,\n );\n return data;\n },\n\n async deleteOffer(packageName, productId, offerId) {\n await http.delete(`/${packageName}/oneTimeProducts/${productId}/offers/${offerId}`);\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"]}
|