@gpc-cli/core 0.10.0 → 0.10.2
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 +48 -4
- package/dist/index.js +209 -31
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OutputFormat, ResolvedConfig, WebhookConfig } from '@gpc-cli/config';
|
|
2
2
|
import { AuthClient } from '@gpc-cli/auth';
|
|
3
3
|
import { GpcPlugin, PluginManifest, CommandEvent, CommandResult, PluginError, RequestEvent, ResponseEvent, PluginCommand } from '@gpc-cli/plugin-sdk';
|
|
4
|
-
import { PlayApiClient, EditCommitOptions, Track, ExternallyHostedApk, ExternallyHostedApkResponse, DeobfuscationFileType, UploadProgressEvent, ResumableUploadOptions, Listing, ImageType, CountryAvailability, Image, AppDetails, Review, ReviewReplyResponse, Subscription, SubscriptionOffer, OffersListResponse, BasePlanMigratePricesRequest, InAppProduct, Order, SubscriptionDeferResponse, SubscriptionsV2DeferResponse, ProductPurchase, ProductPurchaseV2, SubscriptionPurchaseV2, VoidedPurchase, UsersApiClient, User, DeveloperLevelPermission, Grant, MetricRow, ReportingDimension, ReportingAggregation, VitalsMetricSet, ReportingApiClient, AnomalyDetectionResponse, MetricSetResponse, ErrorIssuesResponse, ConvertRegionPricesResponse, ReportType, StatsDimension, Testers, AppRecoveryTargeting, AppRecoveryAction, CreateAppRecoveryActionRequest, DataSafetyResponse, DataSafetyRequest, ExternalTransaction, ExternalTransactionRefund, DeviceTierConfig, OneTimeOffer, OneTimeProduct, OneTimeOffersListResponse, OneTimeProductsListResponse, GamesConfigClient, AchievementConfiguration, LeaderboardConfiguration, AchievementConfigurationListResponse, GamesApiClient, Achievement, LeaderboardConfigurationListResponse, Leaderboard, ImageConfiguration, EnterpriseApiClient, CustomApp, GeneratedApksPerSigningKey, Bundle } from '@gpc-cli/api';
|
|
4
|
+
import { PlayApiClient, EditCommitOptions, Track, ExternallyHostedApk, ExternallyHostedApkResponse, DeobfuscationFileType, UploadProgressEvent, ResumableUploadOptions, Listing, ImageType, CountryAvailability, Image, AppDetails, Review, ReviewReplyResponse, Subscription, SubscriptionOffer, OffersListResponse, BasePlanMigratePricesRequest, InAppProduct, ConsumptionUsageEvent, RefundPreference, Order, SubscriptionDeferResponse, SubscriptionsV2DeferResponse, ProductPurchase, ProductPurchaseV2, SubscriptionPurchaseV2, VoidedPurchase, UsersApiClient, User, DeveloperLevelPermission, Grant, MetricRow, ReportingDimension, ReportingAggregation, VitalsMetricSet, ReportingApiClient, AnomalyDetectionResponse, MetricSetResponse, ErrorIssuesResponse, ConvertRegionPricesResponse, ReportType, StatsDimension, Testers, AppRecoveryTargeting, AppRecoveryAction, CreateAppRecoveryActionRequest, DataSafetyResponse, DataSafetyRequest, ExternalTransaction, ExternalTransactionRefund, DeviceTierConfig, OneTimeOffer, OneTimeProduct, OneTimeOffersListResponse, OneTimeProductsListResponse, GamesConfigClient, AchievementConfiguration, LeaderboardConfiguration, AchievementConfigurationListResponse, GamesApiClient, Achievement, LeaderboardConfigurationListResponse, Leaderboard, ImageConfiguration, EnterpriseApiClient, CustomApp, GeneratedApksPerSigningKey, Bundle } from '@gpc-cli/api';
|
|
5
5
|
|
|
6
6
|
declare class GpcError extends Error {
|
|
7
7
|
readonly code: string;
|
|
@@ -367,7 +367,9 @@ declare function pushListings(client: PlayApiClient, packageName: string, dir: s
|
|
|
367
367
|
commitOptions?: EditCommitOptions;
|
|
368
368
|
}): Promise<PushResult | DryRunResult>;
|
|
369
369
|
declare function listImages(client: PlayApiClient, packageName: string, language: string, imageType: ImageType): Promise<Image[]>;
|
|
370
|
-
declare function uploadImage(client: PlayApiClient, packageName: string, language: string, imageType: ImageType, filePath: string, commitOptions?: EditCommitOptions
|
|
370
|
+
declare function uploadImage(client: PlayApiClient, packageName: string, language: string, imageType: ImageType, filePath: string, commitOptions?: EditCommitOptions, uploadOptions?: {
|
|
371
|
+
aiGenerated?: boolean;
|
|
372
|
+
}): Promise<Image>;
|
|
371
373
|
declare function deleteImage(client: PlayApiClient, packageName: string, language: string, imageType: ImageType, imageId: string, commitOptions?: EditCommitOptions): Promise<void>;
|
|
372
374
|
declare function diffListingsCommand(client: PlayApiClient, packageName: string, dir: string): Promise<ListingDiff[]>;
|
|
373
375
|
declare function getCountryAvailability(client: PlayApiClient, packageName: string, track: string): Promise<CountryAvailability>;
|
|
@@ -661,6 +663,32 @@ declare function batchGetOrders(client: PlayApiClient, packageName: string, orde
|
|
|
661
663
|
declare function getProductPurchaseV2(client: PlayApiClient, packageName: string, token: string): Promise<ProductPurchaseV2>;
|
|
662
664
|
declare function cancelSubscriptionV2(client: PlayApiClient, packageName: string, token: string, cancellationType?: string): Promise<void>;
|
|
663
665
|
declare function deferSubscriptionV2(client: PlayApiClient, packageName: string, token: string, deferDuration: string, etag?: string): Promise<SubscriptionsV2DeferResponse>;
|
|
666
|
+
/** CLI-facing refund preference, mapped to the Google Play API enum. */
|
|
667
|
+
type RefundReviewPreference = "approve" | "decline" | "neutral";
|
|
668
|
+
interface ReviewOrderRefundOptions {
|
|
669
|
+
/** Token from the PendingRefundReviewNotification RTDN. */
|
|
670
|
+
pendingRefundToken: string;
|
|
671
|
+
preference: RefundReviewPreference;
|
|
672
|
+
/** Whether a free sample, trial, or functionality info was offered before purchase. */
|
|
673
|
+
sampleContentProvided: boolean;
|
|
674
|
+
consumptionPercentageMilliunits?: number;
|
|
675
|
+
consumptionUsageEvents?: ConsumptionUsageEvent[];
|
|
676
|
+
}
|
|
677
|
+
interface ReviewOrderRefundResult {
|
|
678
|
+
packageName: string;
|
|
679
|
+
orderId: string;
|
|
680
|
+
refundPreference: RefundPreference;
|
|
681
|
+
sampleContentProvided: boolean;
|
|
682
|
+
consumptionPercentageMilliunits?: number;
|
|
683
|
+
consumptionUsageEventCount: number;
|
|
684
|
+
submitted: boolean;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Respond to a chargeback review (PendingRefundReviewNotification) with a refund
|
|
688
|
+
* preference and optional purchase-usage evidence. Google Play expects a response
|
|
689
|
+
* within 24 hours of the notification.
|
|
690
|
+
*/
|
|
691
|
+
declare function reviewOrderRefund(client: PlayApiClient, packageName: string, orderId: string, options: ReviewOrderRefundOptions): Promise<ReviewOrderRefundResult>;
|
|
664
692
|
|
|
665
693
|
declare const PERMISSION_PROPAGATION_WARNING = "Note: Permission changes may take up to 48 hours to propagate.";
|
|
666
694
|
interface ListUsersOptions {
|
|
@@ -1005,7 +1033,9 @@ declare function refundExternalTransaction(client: PlayApiClient, packageName: s
|
|
|
1005
1033
|
|
|
1006
1034
|
declare function listDeviceTiers(client: PlayApiClient, packageName: string): Promise<DeviceTierConfig[]>;
|
|
1007
1035
|
declare function getDeviceTier(client: PlayApiClient, packageName: string, configId: string): Promise<DeviceTierConfig>;
|
|
1008
|
-
declare function createDeviceTier(client: PlayApiClient, packageName: string, config: DeviceTierConfig
|
|
1036
|
+
declare function createDeviceTier(client: PlayApiClient, packageName: string, config: DeviceTierConfig, options?: {
|
|
1037
|
+
allowUnknownDevices?: boolean;
|
|
1038
|
+
}): Promise<DeviceTierConfig>;
|
|
1009
1039
|
|
|
1010
1040
|
declare function listOneTimeProducts(client: PlayApiClient, packageName: string): Promise<OneTimeProductsListResponse>;
|
|
1011
1041
|
declare function getOneTimeProduct(client: PlayApiClient, packageName: string, productId: string): Promise<OneTimeProduct>;
|
|
@@ -1548,6 +1578,8 @@ interface WatchOptions {
|
|
|
1548
1578
|
render: (status: AppStatus) => string;
|
|
1549
1579
|
fetch: () => Promise<AppStatus>;
|
|
1550
1580
|
save: (status: AppStatus) => Promise<void>;
|
|
1581
|
+
/** Runs after each successful fetch+save cycle (e.g. breach notifications). */
|
|
1582
|
+
onStatus?: (status: AppStatus) => Promise<void> | void;
|
|
1551
1583
|
}
|
|
1552
1584
|
declare function loadStatusCache(packageName: string, ttlSeconds?: number): Promise<AppStatus | null>;
|
|
1553
1585
|
declare function saveStatusCache(packageName: string, data: AppStatus, ttlSeconds?: number): Promise<void>;
|
|
@@ -1769,6 +1801,16 @@ interface DecodedNotification {
|
|
|
1769
1801
|
productType: number;
|
|
1770
1802
|
refundType?: number;
|
|
1771
1803
|
};
|
|
1804
|
+
/** Chargeback review request — respond within 24h via `orders review-refund`. */
|
|
1805
|
+
pendingRefundReviewNotification?: {
|
|
1806
|
+
version: string;
|
|
1807
|
+
pendingRefundToken: string;
|
|
1808
|
+
orderId: string;
|
|
1809
|
+
/** Pending reviews currently only use CHARGEBACK (7). */
|
|
1810
|
+
refundReason?: number;
|
|
1811
|
+
obfuscatedAccountId?: string;
|
|
1812
|
+
obfuscatedProfileId?: string;
|
|
1813
|
+
};
|
|
1772
1814
|
testNotification?: {
|
|
1773
1815
|
version: string;
|
|
1774
1816
|
};
|
|
@@ -1825,6 +1867,8 @@ interface ImageSyncOptions {
|
|
|
1825
1867
|
delete?: boolean;
|
|
1826
1868
|
dryRun?: boolean;
|
|
1827
1869
|
commitOptions?: EditCommitOptions;
|
|
1870
|
+
/** Attest that the synced images were (or were not) generated by AI. */
|
|
1871
|
+
aiGenerated?: boolean;
|
|
1828
1872
|
}
|
|
1829
1873
|
interface ImageSyncDetail {
|
|
1830
1874
|
language: string;
|
|
@@ -1933,4 +1977,4 @@ declare function readinessBadgeColor(grade: ReadinessGrade): string;
|
|
|
1933
1977
|
declare function readinessBadgeUrl(score: ReadinessScore): string;
|
|
1934
1978
|
declare function readinessBadgeMarkdown(score: ReadinessScore): string;
|
|
1935
1979
|
|
|
1936
|
-
export { ApiError, type ApiSigningFingerprint, type AppInfo, type AppStatus, type ApplyReleaseNotesResult, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type BundlesWaitOptions, type ChangelogEntry, type ChecklistInput, type ChecklistItem, type ChecklistResult, type CommandContext, type CommitCluster, type CommitResult, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_MODELS, DEFAULT_PREFLIGHT_CONFIG, DEFAULT_WATCH_THRESHOLDS, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DiscoveredPlugin, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ErrorReason, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FinancialReportDownload, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GameConfigDiff, type GamesPushOptions, type GamesSyncResult, type GenerateOptions, type GeneratedChangelog, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, type GitRunner, GpcError, type ImageSyncDetail, type ImageSyncOptions, type ImageSyncResult, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type KeystoreFingerprint, type ListGamesConfigOptions, type ListIapOptions, type ListReportsResult, type ListSubscriptionsOptions, type ListUsersOptions, type ListVoidedOptions, type ListingDiff, type ListingFieldLimits, type ListingLintResult, type ListingsResult, type LoadedPlugin, type LocaleBundle, type LocaleEntry, type MigrationResult, NetworkError, type OneTimeProductDiff, type OutputMode, PERMISSION_PROPAGATION_WARNING, PLACEHOLDER_TEXT, PLAY_STORE_LIMIT, PROVIDER_WHITELIST, type ParsedCommit, type ParsedManifest, type ParsedMonth, type PlayStoreFormat, type PlayStoreRenderOptions, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type Provider, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, RENDERERS, REVIEW_SORT_PRESETS, type RawCommit, type ReadinessBreakdownEntry, type ReadinessGrade, type ReadinessScore, type ReadinessSignal, type ReadinessSignalStatus, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type Renderer, type ReportObject, type ReportsAuth, type ResolveAiConfigOptions, type ResolveLocalesOptions, type ReviewAnalysis, type ReviewExportOptions, type ReviewSortPreset, type ReviewsFilterOptions, type RevocationRefundType, type RtdnStatus, SECTION_ORDER, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type SigningConsistencyResult, type SigningKeyComparison, type Spinner, type StatsReportDownload, type StatusDiff, type StatusRelease, type StatusReviews, type StatusVitalMetric, type SubscriptionAnalytics, type SubscriptionDiff, type SyncResult, type ThresholdResult, type TrainConfig, type TrainState, type TranslateBundleOptions, type TranslatedBundle, type TranslationFailure, type TranslationPath, type TranslationResult, type Translator, type TranslatorConfig, type UploadResult, VALID_WATCH_METRICS, type ValidateCheck, type ValidateOptions, type ValidateResult, type ValidatedPluginApproval, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchAction, type WatchCallbacks, type WatchConfig, type WatchEvent, type WatchMetric, type WatchOptions, type WatchRollout, type WatchSummary, type WatchVitalReading, type WatchVitalsOptions, type WebhookPayload, type ZipCsvEntry, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, annotateListResult, applyReleaseNotes, assignRelease, batchGetOrders, batchSyncInAppProducts, buildChecklist, buildLocaleBundle, bundleToReleaseNotes, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkSigningConsistency, checkThreshold, classifyError, clearAuditLog, commitWithRescue, compareBundles, compareFingerprints, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAchievementConfig, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createLeaderboardConfig, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, createTranslator, deactivateBasePlan, deactivateOffer, decodeCsvText, decodeNotification, decodeStatsCsv, defaultGitRunner, deferSubscriptionPurchase, deferSubscriptionV2, deleteAchievementConfig, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteLeaderboardConfig, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffAchievementConfig, diffLeaderboardConfig, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPluginEntries, discoverPlugins, dispatchWebhook, downloadFinancialReport, downloadGeneratedApk, downloadReportObject, downloadStatsReport, exportImages, exportReviews, extractCsvEntriesFromZip, fetchAggregateCost, fetchChangelog, fetchReleaseNotes, findBundle, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatMoney, formatNotification, formatOutput, formatPathLabel, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateChangelog, generateMigrationPlan, generateNotesFromGit, getAchievementConfig, getAllScannerNames, getApiSigningFingerprint, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, getKeystoreFingerprint, getLeaderboardConfig, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getOrderDetails, getProductPurchase, getProductPurchaseV2, getQuotaUsage, getReleasesStatus, getReview, getRtdnStatus, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsErrorCount, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, gradeFromPercent, gunzipIfNeeded, handleBreach, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isGzip, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, isVersionedNotesDir, isZip, lintListing, lintListings, lintLocalListings, listAchievementConfigs, listAchievements, listAuditEvents, listBundles, listDeviceTiers, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboardConfigs, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReportObjects, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, monthToken, moreResultsFooter, normalizeFingerprint, parseAppfile, parseCommit, parseFastfile, parseGrantArg, parseKeytoolOutput, parseMonth, parseRemoteUrl, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullAchievementConfigs, pullLeaderboardConfigs, pullListings, pushAchievementConfigs, pushLeaderboardConfigs, pushListings, readListingsFromDir, readReleaseNotesForVersion, readReleaseNotesFromDir, readinessBadgeColor, readinessBadgeMarkdown, readinessBadgeUrl, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, renderChecklistMarkdown, renderJson, renderMarkdown, renderPlayStore, renderPlayStoreJson, renderPlayStoreMd, renderPlayStorePrompt, renderPrompt, replyToReview, reportAccessDeniedError, reportBucketNotFoundError, reportObjectNotFoundError, reportPrefix, resolveAiConfig, resolveLocales, resolveReportsBucket, retryOnUploadNotComplete, revokeSubscriptionPurchase, runPreflight, runWatch, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, scoreReadiness, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, setAchievementIcon, setLeaderboardIcon, sha256File, sortResults, sortReviews, startTrain, statusHasBreach, syncImages, syncInAppProducts, topFiles, trackBreachState, translateBundle, updateAchievementConfig, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateLeaderboardConfig, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateAndCommit, validateBundleForApply, validateImage, validateLanguageCode, validatePackageName, validatePluginForApproval, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, waitForBundle, waitForBundleProcessing, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
|
1980
|
+
export { ApiError, type ApiSigningFingerprint, type AppInfo, type AppStatus, type ApplyReleaseNotesResult, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type BundlesWaitOptions, type ChangelogEntry, type ChecklistInput, type ChecklistItem, type ChecklistResult, type CommandContext, type CommitCluster, type CommitResult, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_MODELS, DEFAULT_PREFLIGHT_CONFIG, DEFAULT_WATCH_THRESHOLDS, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DiscoveredPlugin, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ErrorReason, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FinancialReportDownload, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GameConfigDiff, type GamesPushOptions, type GamesSyncResult, type GenerateOptions, type GeneratedChangelog, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, type GitRunner, GpcError, type ImageSyncDetail, type ImageSyncOptions, type ImageSyncResult, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type KeystoreFingerprint, type ListGamesConfigOptions, type ListIapOptions, type ListReportsResult, type ListSubscriptionsOptions, type ListUsersOptions, type ListVoidedOptions, type ListingDiff, type ListingFieldLimits, type ListingLintResult, type ListingsResult, type LoadedPlugin, type LocaleBundle, type LocaleEntry, type MigrationResult, NetworkError, type OneTimeProductDiff, type OutputMode, PERMISSION_PROPAGATION_WARNING, PLACEHOLDER_TEXT, PLAY_STORE_LIMIT, PROVIDER_WHITELIST, type ParsedCommit, type ParsedManifest, type ParsedMonth, type PlayStoreFormat, type PlayStoreRenderOptions, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type Provider, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, RENDERERS, REVIEW_SORT_PRESETS, type RawCommit, type ReadinessBreakdownEntry, type ReadinessGrade, type ReadinessScore, type ReadinessSignal, type ReadinessSignalStatus, type RefundReviewPreference, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type Renderer, type ReportObject, type ReportsAuth, type ResolveAiConfigOptions, type ResolveLocalesOptions, type ReviewAnalysis, type ReviewExportOptions, type ReviewOrderRefundOptions, type ReviewOrderRefundResult, type ReviewSortPreset, type ReviewsFilterOptions, type RevocationRefundType, type RtdnStatus, SECTION_ORDER, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type SigningConsistencyResult, type SigningKeyComparison, type Spinner, type StatsReportDownload, type StatusDiff, type StatusRelease, type StatusReviews, type StatusVitalMetric, type SubscriptionAnalytics, type SubscriptionDiff, type SyncResult, type ThresholdResult, type TrainConfig, type TrainState, type TranslateBundleOptions, type TranslatedBundle, type TranslationFailure, type TranslationPath, type TranslationResult, type Translator, type TranslatorConfig, type UploadResult, VALID_WATCH_METRICS, type ValidateCheck, type ValidateOptions, type ValidateResult, type ValidatedPluginApproval, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchAction, type WatchCallbacks, type WatchConfig, type WatchEvent, type WatchMetric, type WatchOptions, type WatchRollout, type WatchSummary, type WatchVitalReading, type WatchVitalsOptions, type WebhookPayload, type ZipCsvEntry, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, annotateListResult, applyReleaseNotes, assignRelease, batchGetOrders, batchSyncInAppProducts, buildChecklist, buildLocaleBundle, bundleToReleaseNotes, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkSigningConsistency, checkThreshold, classifyError, clearAuditLog, commitWithRescue, compareBundles, compareFingerprints, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAchievementConfig, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createLeaderboardConfig, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, createTranslator, deactivateBasePlan, deactivateOffer, decodeCsvText, decodeNotification, decodeStatsCsv, defaultGitRunner, deferSubscriptionPurchase, deferSubscriptionV2, deleteAchievementConfig, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteLeaderboardConfig, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffAchievementConfig, diffLeaderboardConfig, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPluginEntries, discoverPlugins, dispatchWebhook, downloadFinancialReport, downloadGeneratedApk, downloadReportObject, downloadStatsReport, exportImages, exportReviews, extractCsvEntriesFromZip, fetchAggregateCost, fetchChangelog, fetchReleaseNotes, findBundle, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatMoney, formatNotification, formatOutput, formatPathLabel, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateChangelog, generateMigrationPlan, generateNotesFromGit, getAchievementConfig, getAllScannerNames, getApiSigningFingerprint, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, getKeystoreFingerprint, getLeaderboardConfig, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getOrderDetails, getProductPurchase, getProductPurchaseV2, getQuotaUsage, getReleasesStatus, getReview, getRtdnStatus, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsErrorCount, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, gradeFromPercent, gunzipIfNeeded, handleBreach, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isGzip, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, isVersionedNotesDir, isZip, lintListing, lintListings, lintLocalListings, listAchievementConfigs, listAchievements, listAuditEvents, listBundles, listDeviceTiers, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboardConfigs, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReportObjects, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, monthToken, moreResultsFooter, normalizeFingerprint, parseAppfile, parseCommit, parseFastfile, parseGrantArg, parseKeytoolOutput, parseMonth, parseRemoteUrl, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullAchievementConfigs, pullLeaderboardConfigs, pullListings, pushAchievementConfigs, pushLeaderboardConfigs, pushListings, readListingsFromDir, readReleaseNotesForVersion, readReleaseNotesFromDir, readinessBadgeColor, readinessBadgeMarkdown, readinessBadgeUrl, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, renderChecklistMarkdown, renderJson, renderMarkdown, renderPlayStore, renderPlayStoreJson, renderPlayStoreMd, renderPlayStorePrompt, renderPrompt, replyToReview, reportAccessDeniedError, reportBucketNotFoundError, reportObjectNotFoundError, reportPrefix, resolveAiConfig, resolveLocales, resolveReportsBucket, retryOnUploadNotComplete, reviewOrderRefund, revokeSubscriptionPurchase, runPreflight, runWatch, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, scoreReadiness, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, setAchievementIcon, setLeaderboardIcon, sha256File, sortResults, sortReviews, startTrain, statusHasBreach, syncImages, syncInAppProducts, topFiles, trackBreachState, translateBundle, updateAchievementConfig, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateLeaderboardConfig, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateAndCommit, validateBundleForApply, validateImage, validateLanguageCode, validatePackageName, validatePluginForApproval, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, waitForBundle, waitForBundleProcessing, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
package/dist/index.js
CHANGED
|
@@ -1324,7 +1324,7 @@ async function listImages(client, packageName, language, imageType) {
|
|
|
1324
1324
|
throw error;
|
|
1325
1325
|
}
|
|
1326
1326
|
}
|
|
1327
|
-
async function uploadImage(client, packageName, language, imageType, filePath, commitOptions) {
|
|
1327
|
+
async function uploadImage(client, packageName, language, imageType, filePath, commitOptions, uploadOptions) {
|
|
1328
1328
|
validateLanguage(language);
|
|
1329
1329
|
const imageCheck = await validateImage(filePath, imageType);
|
|
1330
1330
|
if (!imageCheck.valid) {
|
|
@@ -1340,7 +1340,14 @@ async function uploadImage(client, packageName, language, imageType, filePath, c
|
|
|
1340
1340
|
}
|
|
1341
1341
|
const edit = await client.edits.insert(packageName);
|
|
1342
1342
|
try {
|
|
1343
|
-
const image = await client.images.upload(
|
|
1343
|
+
const image = await client.images.upload(
|
|
1344
|
+
packageName,
|
|
1345
|
+
edit.id,
|
|
1346
|
+
language,
|
|
1347
|
+
imageType,
|
|
1348
|
+
filePath,
|
|
1349
|
+
uploadOptions
|
|
1350
|
+
);
|
|
1344
1351
|
await validateAndCommit(client, packageName, edit.id, commitOptions);
|
|
1345
1352
|
return image;
|
|
1346
1353
|
} catch (error) {
|
|
@@ -3401,6 +3408,7 @@ async function runWatchLoop(opts) {
|
|
|
3401
3408
|
const status = await opts.fetch();
|
|
3402
3409
|
await opts.save(status);
|
|
3403
3410
|
console.log(opts.render(status));
|
|
3411
|
+
await opts.onStatus?.(status);
|
|
3404
3412
|
} catch (err) {
|
|
3405
3413
|
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
3406
3414
|
}
|
|
@@ -3978,6 +3986,87 @@ async function deferSubscriptionV2(client, packageName, token, deferDuration, et
|
|
|
3978
3986
|
deferralContext: { etag: resolvedEtag, deferDuration }
|
|
3979
3987
|
});
|
|
3980
3988
|
}
|
|
3989
|
+
var REFUND_PREFERENCES = {
|
|
3990
|
+
approve: "APPROVE",
|
|
3991
|
+
decline: "DECLINE",
|
|
3992
|
+
neutral: "NEUTRAL"
|
|
3993
|
+
};
|
|
3994
|
+
var MAX_CONSUMPTION_USAGE_EVENTS = 1e3;
|
|
3995
|
+
var MAX_CONSUMPTION_MILLIUNITS = 1e5;
|
|
3996
|
+
var RFC3339 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
3997
|
+
function invalidReviewRefund(message, suggestion) {
|
|
3998
|
+
return new GpcError(message, "ORDER_REVIEW_REFUND_INVALID", 2, suggestion);
|
|
3999
|
+
}
|
|
4000
|
+
async function reviewOrderRefund(client, packageName, orderId, options) {
|
|
4001
|
+
validatePackageName(packageName);
|
|
4002
|
+
if (!orderId.trim()) {
|
|
4003
|
+
throw invalidReviewRefund(
|
|
4004
|
+
"orderId is required",
|
|
4005
|
+
"Pass the order ID from the pending refund review notification"
|
|
4006
|
+
);
|
|
4007
|
+
}
|
|
4008
|
+
const pendingRefundToken = options.pendingRefundToken.trim();
|
|
4009
|
+
if (!pendingRefundToken) {
|
|
4010
|
+
throw invalidReviewRefund(
|
|
4011
|
+
"pendingRefundToken is required and cannot be empty",
|
|
4012
|
+
"Pass --pending-refund-token with the token from the PendingRefundReviewNotification"
|
|
4013
|
+
);
|
|
4014
|
+
}
|
|
4015
|
+
const refundPreference = REFUND_PREFERENCES[options.preference];
|
|
4016
|
+
if (!refundPreference) {
|
|
4017
|
+
throw invalidReviewRefund(
|
|
4018
|
+
`Invalid refund preference "${options.preference}"`,
|
|
4019
|
+
"Use --preference with one of: approve, decline, neutral"
|
|
4020
|
+
);
|
|
4021
|
+
}
|
|
4022
|
+
const milliunits = options.consumptionPercentageMilliunits;
|
|
4023
|
+
if (milliunits !== void 0) {
|
|
4024
|
+
if (!Number.isInteger(milliunits) || milliunits < 0 || milliunits > MAX_CONSUMPTION_MILLIUNITS) {
|
|
4025
|
+
throw invalidReviewRefund(
|
|
4026
|
+
`consumptionPercentageMilliunits must be an integer between 0 and ${MAX_CONSUMPTION_MILLIUNITS}, got ${milliunits}`,
|
|
4027
|
+
"Pass --consumption-percent with a value between 0 and 100"
|
|
4028
|
+
);
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
const events = options.consumptionUsageEvents ?? [];
|
|
4032
|
+
if (events.length > MAX_CONSUMPTION_USAGE_EVENTS) {
|
|
4033
|
+
throw invalidReviewRefund(
|
|
4034
|
+
`consumptionUsageEvents has ${events.length} entries; Google Play rejects lists over ${MAX_CONSUMPTION_USAGE_EVENTS}`,
|
|
4035
|
+
`Trim the usage-events file to at most ${MAX_CONSUMPTION_USAGE_EVENTS} events`
|
|
4036
|
+
);
|
|
4037
|
+
}
|
|
4038
|
+
events.forEach((event, index) => {
|
|
4039
|
+
const time = event.consumptionTime;
|
|
4040
|
+
if (time !== void 0 && (!RFC3339.test(time) || Number.isNaN(Date.parse(time)))) {
|
|
4041
|
+
throw invalidReviewRefund(
|
|
4042
|
+
`consumptionUsageEvents[${index}].consumptionTime "${time}" is not an RFC 3339 timestamp`,
|
|
4043
|
+
"Use a timestamp like 2026-08-30T10:15:00Z"
|
|
4044
|
+
);
|
|
4045
|
+
}
|
|
4046
|
+
if (event.location && !event.location.regionCode?.trim()) {
|
|
4047
|
+
throw invalidReviewRefund(
|
|
4048
|
+
`consumptionUsageEvents[${index}].location.regionCode is required when a location is supplied`,
|
|
4049
|
+
'Set a CLDR region code such as "US" on each location'
|
|
4050
|
+
);
|
|
4051
|
+
}
|
|
4052
|
+
});
|
|
4053
|
+
await client.orders.reviewRefund(packageName, orderId, {
|
|
4054
|
+
pendingRefundToken,
|
|
4055
|
+
refundPreference,
|
|
4056
|
+
sampleContentProvided: options.sampleContentProvided,
|
|
4057
|
+
...milliunits !== void 0 ? { consumptionPercentageMilliunits: milliunits } : {},
|
|
4058
|
+
...events.length > 0 ? { consumptionUsageEvents: events } : {}
|
|
4059
|
+
});
|
|
4060
|
+
return {
|
|
4061
|
+
packageName,
|
|
4062
|
+
orderId,
|
|
4063
|
+
refundPreference,
|
|
4064
|
+
sampleContentProvided: options.sampleContentProvided,
|
|
4065
|
+
...milliunits !== void 0 ? { consumptionPercentageMilliunits: milliunits } : {},
|
|
4066
|
+
consumptionUsageEventCount: events.length,
|
|
4067
|
+
submitted: true
|
|
4068
|
+
};
|
|
4069
|
+
}
|
|
3981
4070
|
|
|
3982
4071
|
// src/commands/pricing.ts
|
|
3983
4072
|
async function convertRegionPrices(client, packageName, currencyCode, amount) {
|
|
@@ -4795,7 +4884,7 @@ async function getDeviceTier(client, packageName, configId) {
|
|
|
4795
4884
|
}
|
|
4796
4885
|
return client.deviceTiers.get(packageName, configId);
|
|
4797
4886
|
}
|
|
4798
|
-
async function createDeviceTier(client, packageName, config) {
|
|
4887
|
+
async function createDeviceTier(client, packageName, config, options) {
|
|
4799
4888
|
if (!packageName) {
|
|
4800
4889
|
throw new GpcError(
|
|
4801
4890
|
"Package name is required",
|
|
@@ -4812,7 +4901,7 @@ async function createDeviceTier(client, packageName, config) {
|
|
|
4812
4901
|
"Provide a valid config with deviceGroups."
|
|
4813
4902
|
);
|
|
4814
4903
|
}
|
|
4815
|
-
return client.deviceTiers.create(packageName, config);
|
|
4904
|
+
return client.deviceTiers.create(packageName, config, options);
|
|
4816
4905
|
}
|
|
4817
4906
|
|
|
4818
4907
|
// src/commands/one-time-products.ts
|
|
@@ -4856,7 +4945,14 @@ var OTP_ID_FIELDS = /* @__PURE__ */ new Set(["productId", "packageName"]);
|
|
|
4856
4945
|
function deriveOtpUpdateMask(data) {
|
|
4857
4946
|
return Object.keys(data).filter((k) => !OTP_ID_FIELDS.has(k)).join(",");
|
|
4858
4947
|
}
|
|
4859
|
-
var OTP_OFFER_ID_FIELDS = /* @__PURE__ */ new Set([
|
|
4948
|
+
var OTP_OFFER_ID_FIELDS = /* @__PURE__ */ new Set([
|
|
4949
|
+
"packageName",
|
|
4950
|
+
"productId",
|
|
4951
|
+
"purchaseOptionId",
|
|
4952
|
+
"offerId",
|
|
4953
|
+
"state",
|
|
4954
|
+
"regionsVersion"
|
|
4955
|
+
]);
|
|
4860
4956
|
function deriveOtpOfferUpdateMask(data) {
|
|
4861
4957
|
return Object.keys(data).filter((k) => !OTP_OFFER_ID_FIELDS.has(k)).join(",");
|
|
4862
4958
|
}
|
|
@@ -4929,7 +5025,7 @@ async function createOneTimeOffer(client, packageName, productId, data, purchase
|
|
|
4929
5025
|
}
|
|
4930
5026
|
async function updateOneTimeOffer(client, packageName, productId, offerId, data, updateMask, purchaseOptionId = "-", regionsVersion) {
|
|
4931
5027
|
try {
|
|
4932
|
-
const mask = updateMask || deriveOtpOfferUpdateMask(data);
|
|
5028
|
+
const mask = updateMask || deriveOtpOfferUpdateMask(data) || void 0;
|
|
4933
5029
|
return await client.oneTimeProducts.updateOffer(
|
|
4934
5030
|
packageName,
|
|
4935
5031
|
productId,
|
|
@@ -6253,6 +6349,9 @@ var manifestScanner = {
|
|
|
6253
6349
|
requires: ["manifest"],
|
|
6254
6350
|
async scan(ctx) {
|
|
6255
6351
|
const manifest = ctx.manifest;
|
|
6352
|
+
if (!manifest) {
|
|
6353
|
+
throw new Error('The "manifest" scanner requires manifest in the preflight context');
|
|
6354
|
+
}
|
|
6256
6355
|
const findings = [];
|
|
6257
6356
|
const minTargetSdk = ctx.config.targetSdkMinimum;
|
|
6258
6357
|
if (manifest.targetSdk < minTargetSdk) {
|
|
@@ -6568,6 +6667,9 @@ var permissionsScanner = {
|
|
|
6568
6667
|
requires: ["manifest"],
|
|
6569
6668
|
async scan(ctx) {
|
|
6570
6669
|
const manifest = ctx.manifest;
|
|
6670
|
+
if (!manifest) {
|
|
6671
|
+
throw new Error('The "permissions" scanner requires manifest in the preflight context');
|
|
6672
|
+
}
|
|
6571
6673
|
const findings = [];
|
|
6572
6674
|
const allowed = new Set(ctx.config.allowedPermissions);
|
|
6573
6675
|
for (const perm of manifest.permissions) {
|
|
@@ -6711,13 +6813,16 @@ var nativeLibsScanner = {
|
|
|
6711
6813
|
requires: ["zipEntries"],
|
|
6712
6814
|
async scan(ctx) {
|
|
6713
6815
|
const entries = ctx.zipEntries;
|
|
6816
|
+
if (!entries) {
|
|
6817
|
+
throw new Error('The "native-libs" scanner requires zipEntries in the preflight context');
|
|
6818
|
+
}
|
|
6714
6819
|
const findings = [];
|
|
6715
6820
|
const abisFound = /* @__PURE__ */ new Set();
|
|
6716
6821
|
let totalNativeSize = 0;
|
|
6717
6822
|
for (const entry of entries) {
|
|
6718
|
-
const
|
|
6719
|
-
if (
|
|
6720
|
-
abisFound.add(
|
|
6823
|
+
const abi = LIB_PATH_RE.exec(entry.path)?.[1];
|
|
6824
|
+
if (abi) {
|
|
6825
|
+
abisFound.add(abi);
|
|
6721
6826
|
totalNativeSize += entry.uncompressedSize;
|
|
6722
6827
|
}
|
|
6723
6828
|
}
|
|
@@ -6830,6 +6935,9 @@ var metadataScanner = {
|
|
|
6830
6935
|
requires: ["metadataDir"],
|
|
6831
6936
|
async scan(ctx) {
|
|
6832
6937
|
const dir = ctx.metadataDir;
|
|
6938
|
+
if (!dir) {
|
|
6939
|
+
throw new Error('The "metadata" scanner requires metadataDir in the preflight context');
|
|
6940
|
+
}
|
|
6833
6941
|
const findings = [];
|
|
6834
6942
|
let entries;
|
|
6835
6943
|
try {
|
|
@@ -6935,7 +7043,7 @@ var metadataScanner = {
|
|
|
6935
7043
|
});
|
|
6936
7044
|
}
|
|
6937
7045
|
}
|
|
6938
|
-
const defaultLang = locales.includes("en-US") ? "en-US" : locales[0];
|
|
7046
|
+
const defaultLang = locales.includes("en-US") ? "en-US" : locales[0] ?? "en-US";
|
|
6939
7047
|
const privacyPath = join10(dir, defaultLang, "privacy_policy_url.txt");
|
|
6940
7048
|
try {
|
|
6941
7049
|
const url = await readFile13(privacyPath, "utf-8");
|
|
@@ -7078,6 +7186,7 @@ var secretsScanner = {
|
|
|
7078
7186
|
requires: ["sourceDir"],
|
|
7079
7187
|
async scan(ctx) {
|
|
7080
7188
|
const dir = ctx.sourceDir;
|
|
7189
|
+
if (!dir) throw new Error('The "secrets" scanner requires sourceDir in the preflight context');
|
|
7081
7190
|
const findings = [];
|
|
7082
7191
|
const files = await collectSourceFiles(dir, SCAN_EXTENSIONS);
|
|
7083
7192
|
for (const filePath of files) {
|
|
@@ -7090,6 +7199,7 @@ var secretsScanner = {
|
|
|
7090
7199
|
const lines = content.split("\n");
|
|
7091
7200
|
for (let i = 0; i < lines.length; i++) {
|
|
7092
7201
|
const line = lines[i];
|
|
7202
|
+
if (line === void 0) continue;
|
|
7093
7203
|
for (const pattern of SECRET_PATTERNS) {
|
|
7094
7204
|
if (pattern.pattern.test(line)) {
|
|
7095
7205
|
const relativePath = filePath.startsWith(dir) ? filePath.slice(dir.length + 1) : filePath;
|
|
@@ -7166,6 +7276,7 @@ var billingScanner = {
|
|
|
7166
7276
|
requires: ["sourceDir"],
|
|
7167
7277
|
async scan(ctx) {
|
|
7168
7278
|
const dir = ctx.sourceDir;
|
|
7279
|
+
if (!dir) throw new Error('The "billing" scanner requires sourceDir in the preflight context');
|
|
7169
7280
|
const findings = [];
|
|
7170
7281
|
const detectedSdks = /* @__PURE__ */ new Set();
|
|
7171
7282
|
const files = await collectSourceFiles(dir, SCAN_EXTENSIONS2);
|
|
@@ -7232,6 +7343,7 @@ var privacyScanner = {
|
|
|
7232
7343
|
requires: ["sourceDir"],
|
|
7233
7344
|
async scan(ctx) {
|
|
7234
7345
|
const dir = ctx.sourceDir;
|
|
7346
|
+
if (!dir) throw new Error('The "privacy" scanner requires sourceDir in the preflight context');
|
|
7235
7347
|
const findings = [];
|
|
7236
7348
|
const detectedSdks = /* @__PURE__ */ new Set();
|
|
7237
7349
|
const files = await collectSourceFiles(dir, SCAN_EXTENSIONS3);
|
|
@@ -7313,6 +7425,9 @@ var policyScanner = {
|
|
|
7313
7425
|
requires: ["manifest"],
|
|
7314
7426
|
async scan(ctx) {
|
|
7315
7427
|
const manifest = ctx.manifest;
|
|
7428
|
+
if (!manifest) {
|
|
7429
|
+
throw new Error('The "policy" scanner requires manifest in the preflight context');
|
|
7430
|
+
}
|
|
7316
7431
|
const findings = [];
|
|
7317
7432
|
const perms = new Set(manifest.permissions);
|
|
7318
7433
|
if (manifest.targetSdk >= 28) {
|
|
@@ -7422,6 +7537,9 @@ var sizeScanner = {
|
|
|
7422
7537
|
requires: ["zipEntries"],
|
|
7423
7538
|
async scan(ctx) {
|
|
7424
7539
|
const entries = ctx.zipEntries;
|
|
7540
|
+
if (!entries) {
|
|
7541
|
+
throw new Error('The "size" scanner requires zipEntries in the preflight context');
|
|
7542
|
+
}
|
|
7425
7543
|
const findings = [];
|
|
7426
7544
|
const maxMb = ctx.config.maxDownloadSizeMb;
|
|
7427
7545
|
const totalCompressed = entries.reduce((sum, e) => sum + e.compressedSize, 0);
|
|
@@ -7570,12 +7688,12 @@ async function runPreflight(options) {
|
|
|
7570
7688
|
}
|
|
7571
7689
|
const settled = await Promise.allSettled(applicableScanners.map((scanner) => scanner.scan(ctx)));
|
|
7572
7690
|
let findings = [...earlyFindings];
|
|
7573
|
-
for (
|
|
7691
|
+
for (const [i, scanner] of applicableScanners.entries()) {
|
|
7574
7692
|
const result = settled[i];
|
|
7693
|
+
if (!result) continue;
|
|
7575
7694
|
if (result.status === "fulfilled") {
|
|
7576
7695
|
findings.push(...result.value);
|
|
7577
7696
|
} else {
|
|
7578
|
-
const scanner = applicableScanners[i];
|
|
7579
7697
|
findings.push({
|
|
7580
7698
|
scanner: scanner.name,
|
|
7581
7699
|
ruleId: "scanner-error",
|
|
@@ -8166,7 +8284,7 @@ async function fetchChangelog(options) {
|
|
|
8166
8284
|
return releases.filter((r) => r.tag_name.startsWith("v")).map((r) => ({
|
|
8167
8285
|
version: r.tag_name,
|
|
8168
8286
|
title: r.name || r.tag_name,
|
|
8169
|
-
date: r.published_at ? r.published_at.split("T")[0] : "unknown",
|
|
8287
|
+
date: r.published_at ? r.published_at.split("T")[0] ?? "unknown" : "unknown",
|
|
8170
8288
|
body: r.body || "No release notes.",
|
|
8171
8289
|
url: r.html_url
|
|
8172
8290
|
}));
|
|
@@ -8456,12 +8574,14 @@ var TYPE_PRIORITY = {
|
|
|
8456
8574
|
function clusterCommits(commits) {
|
|
8457
8575
|
const n = commits.length;
|
|
8458
8576
|
const parent = Array.from({ length: n }, (_, i) => i);
|
|
8577
|
+
const parentOf = (i) => parent[i] ?? i;
|
|
8459
8578
|
const find = (i) => {
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8579
|
+
let cur = i;
|
|
8580
|
+
while (parentOf(cur) !== cur) {
|
|
8581
|
+
parent[cur] = parentOf(parentOf(cur));
|
|
8582
|
+
cur = parentOf(cur);
|
|
8463
8583
|
}
|
|
8464
|
-
return
|
|
8584
|
+
return cur;
|
|
8465
8585
|
};
|
|
8466
8586
|
const union = (i, j) => {
|
|
8467
8587
|
const ri = find(i);
|
|
@@ -8470,20 +8590,32 @@ function clusterCommits(commits) {
|
|
|
8470
8590
|
};
|
|
8471
8591
|
const tokens = commits.map((c) => tokenize2(c.subject));
|
|
8472
8592
|
for (let i = 0; i < n; i++) {
|
|
8593
|
+
const ci = commits[i];
|
|
8594
|
+
const ti = tokens[i];
|
|
8595
|
+
if (ci === void 0 || ti === void 0) continue;
|
|
8473
8596
|
for (let j = i + 1; j < n; j++) {
|
|
8474
|
-
|
|
8597
|
+
const cj = commits[j];
|
|
8598
|
+
const tj = tokens[j];
|
|
8599
|
+
if (cj === void 0 || tj === void 0) continue;
|
|
8600
|
+
if (shouldCluster(ci, cj, ti, tj)) union(i, j);
|
|
8475
8601
|
}
|
|
8476
8602
|
}
|
|
8477
8603
|
const groups = /* @__PURE__ */ new Map();
|
|
8478
8604
|
for (let i = 0; i < n; i++) {
|
|
8605
|
+
const commit = commits[i];
|
|
8606
|
+
if (commit === void 0) continue;
|
|
8479
8607
|
const root = find(i);
|
|
8480
|
-
|
|
8481
|
-
|
|
8608
|
+
let group = groups.get(root);
|
|
8609
|
+
if (!group) {
|
|
8610
|
+
group = [];
|
|
8611
|
+
groups.set(root, group);
|
|
8612
|
+
}
|
|
8613
|
+
group.push(commit);
|
|
8482
8614
|
}
|
|
8483
8615
|
const clusters = [];
|
|
8484
8616
|
for (const [, members] of groups) {
|
|
8485
8617
|
const weight = members.reduce((s, m) => s + m.weight, 0);
|
|
8486
|
-
const primaryType = members.map((m) => m.type).sort((a, b) => (TYPE_PRIORITY[a] ?? 99) - (TYPE_PRIORITY[b] ?? 99))[0];
|
|
8618
|
+
const primaryType = members.map((m) => m.type).sort((a, b) => (TYPE_PRIORITY[a] ?? 99) - (TYPE_PRIORITY[b] ?? 99))[0] ?? "other";
|
|
8487
8619
|
const label = clusterLabel(members);
|
|
8488
8620
|
clusters.push({
|
|
8489
8621
|
id: label.toLowerCase().replace(/\s+/g, "-"),
|
|
@@ -8526,7 +8658,7 @@ function clusterLabel(members) {
|
|
|
8526
8658
|
bestTokenCount = c;
|
|
8527
8659
|
}
|
|
8528
8660
|
}
|
|
8529
|
-
return bestToken ?? members[0]
|
|
8661
|
+
return bestToken ?? members[0]?.subject.slice(0, 30) ?? "changes";
|
|
8530
8662
|
}
|
|
8531
8663
|
function scoreHeadlines(clusters) {
|
|
8532
8664
|
return [...clusters].sort((a, b) => {
|
|
@@ -8595,8 +8727,8 @@ async function generateChangelog(opts = {}, runner = defaultGitRunner) {
|
|
|
8595
8727
|
const headlineCandidates = scoreHeadlines(clusters);
|
|
8596
8728
|
const grouped = {};
|
|
8597
8729
|
for (const c of visible) {
|
|
8598
|
-
|
|
8599
|
-
|
|
8730
|
+
const bucket = grouped[c.type] ??= [];
|
|
8731
|
+
bucket.push(c);
|
|
8600
8732
|
}
|
|
8601
8733
|
warnings.push(...lintJargon(visible));
|
|
8602
8734
|
return {
|
|
@@ -9242,6 +9374,9 @@ var OTP_NOTIFICATION_TYPES = {
|
|
|
9242
9374
|
1: "ONE_TIME_PRODUCT_PURCHASED",
|
|
9243
9375
|
2: "ONE_TIME_PRODUCT_CANCELED"
|
|
9244
9376
|
};
|
|
9377
|
+
var REFUND_REASONS = {
|
|
9378
|
+
7: "CHARGEBACK"
|
|
9379
|
+
};
|
|
9245
9380
|
async function getRtdnStatus(client, packageName) {
|
|
9246
9381
|
try {
|
|
9247
9382
|
const edit = await client.edits.insert(packageName);
|
|
@@ -9308,6 +9443,20 @@ function formatNotification(notification) {
|
|
|
9308
9443
|
purchaseToken: n.purchaseToken.slice(0, 16) + "..."
|
|
9309
9444
|
};
|
|
9310
9445
|
}
|
|
9446
|
+
if (notification.pendingRefundReviewNotification) {
|
|
9447
|
+
const n = notification.pendingRefundReviewNotification;
|
|
9448
|
+
return {
|
|
9449
|
+
...base,
|
|
9450
|
+
type: "pending-refund-review",
|
|
9451
|
+
event: "PENDING_REFUND_REVIEW",
|
|
9452
|
+
orderId: n.orderId,
|
|
9453
|
+
// An absent reason is plain "UNKNOWN"; only an unrecognised value is worth echoing.
|
|
9454
|
+
refundReason: n.refundReason == null ? "UNKNOWN" : REFUND_REASONS[n.refundReason] ?? `UNKNOWN(${n.refundReason})`,
|
|
9455
|
+
// A partial notification (hand-crafted, or a Google field we have not seen
|
|
9456
|
+
// yet) must not crash the decoder.
|
|
9457
|
+
pendingRefundToken: typeof n.pendingRefundToken === "string" ? n.pendingRefundToken.slice(0, 16) + "..." : "(missing)"
|
|
9458
|
+
};
|
|
9459
|
+
}
|
|
9311
9460
|
if (notification.testNotification) {
|
|
9312
9461
|
return { ...base, type: "test", event: "TEST_NOTIFICATION" };
|
|
9313
9462
|
}
|
|
@@ -9537,7 +9686,14 @@ async function syncImages(client, packageName, dir, options) {
|
|
|
9537
9686
|
"Check image dimensions, file size, and format."
|
|
9538
9687
|
);
|
|
9539
9688
|
}
|
|
9540
|
-
await client.images.upload(
|
|
9689
|
+
await client.images.upload(
|
|
9690
|
+
packageName,
|
|
9691
|
+
edit.id,
|
|
9692
|
+
language,
|
|
9693
|
+
imageType,
|
|
9694
|
+
filePath,
|
|
9695
|
+
options?.aiGenerated === void 0 ? void 0 : { aiGenerated: options.aiGenerated }
|
|
9696
|
+
);
|
|
9541
9697
|
}
|
|
9542
9698
|
uploaded++;
|
|
9543
9699
|
details.push({ language, imageType, file, action: "upload", reason });
|
|
@@ -9555,7 +9711,7 @@ async function syncImages(client, packageName, dir, options) {
|
|
|
9555
9711
|
}
|
|
9556
9712
|
continue;
|
|
9557
9713
|
}
|
|
9558
|
-
const localSeq = localFiles.map((file) => localHashes.get(file));
|
|
9714
|
+
const localSeq = localFiles.map((file) => localHashes.get(file) ?? "");
|
|
9559
9715
|
const remoteSeq = remoteImages.map((img) => img.sha256.toLowerCase());
|
|
9560
9716
|
const inOrder = localSeq.length === remoteSeq.length && localSeq.every((hash, i) => hash === remoteSeq[i]);
|
|
9561
9717
|
if (inOrder) {
|
|
@@ -9593,7 +9749,7 @@ async function syncImages(client, packageName, dir, options) {
|
|
|
9593
9749
|
}
|
|
9594
9750
|
for (const file of localFiles) {
|
|
9595
9751
|
const hash = localHashes.get(file);
|
|
9596
|
-
if (remoteSha256Set.has(hash)) {
|
|
9752
|
+
if (hash !== void 0 && remoteSha256Set.has(hash)) {
|
|
9597
9753
|
skipped++;
|
|
9598
9754
|
details.push({ language, imageType, file, action: "skip", reason: "sha256 match" });
|
|
9599
9755
|
} else {
|
|
@@ -9656,7 +9812,8 @@ async function checkSigningConsistency(accessToken, packageName, apiHost = "andr
|
|
|
9656
9812
|
}
|
|
9657
9813
|
const bundlesData = await bundlesResp.json();
|
|
9658
9814
|
const bundles = (bundlesData.bundles ?? []).sort((a, b) => b.versionCode - a.versionCode);
|
|
9659
|
-
|
|
9815
|
+
const [current, previous] = bundles;
|
|
9816
|
+
if (!current) {
|
|
9660
9817
|
throw new GpcError(
|
|
9661
9818
|
"No bundles found for this app",
|
|
9662
9819
|
"NO_BUNDLES",
|
|
@@ -9664,9 +9821,9 @@ async function checkSigningConsistency(accessToken, packageName, apiHost = "andr
|
|
|
9664
9821
|
"Upload at least one AAB with 'gpc publish' before checking signing consistency"
|
|
9665
9822
|
);
|
|
9666
9823
|
}
|
|
9667
|
-
const currentVc =
|
|
9824
|
+
const currentVc = current.versionCode;
|
|
9668
9825
|
const currentFp = await fetchFingerprint(baseUrl, accessToken, currentVc);
|
|
9669
|
-
if (
|
|
9826
|
+
if (!previous) {
|
|
9670
9827
|
return {
|
|
9671
9828
|
currentVersionCode: currentVc,
|
|
9672
9829
|
currentFingerprint: currentFp,
|
|
@@ -9674,7 +9831,7 @@ async function checkSigningConsistency(accessToken, packageName, apiHost = "andr
|
|
|
9674
9831
|
firstRelease: true
|
|
9675
9832
|
};
|
|
9676
9833
|
}
|
|
9677
|
-
const previousVc =
|
|
9834
|
+
const previousVc = previous.versionCode;
|
|
9678
9835
|
const previousFp = await fetchFingerprint(baseUrl, accessToken, previousVc);
|
|
9679
9836
|
const consistent = normalizeFingerprint(currentFp) === normalizeFingerprint(previousFp);
|
|
9680
9837
|
return {
|
|
@@ -9724,6 +9881,8 @@ async function fetchFingerprint(baseUrl, accessToken, versionCode) {
|
|
|
9724
9881
|
var PLAY_CONSOLE_SETTINGS = "https://play.google.com/console/developers/settings";
|
|
9725
9882
|
var VERIFICATION_PAGE = "https://developer.android.com/developer-verification";
|
|
9726
9883
|
var PLAY_APP_SIGNING = "https://support.google.com/googleplay/android-developer/answer/9842756";
|
|
9884
|
+
var QUALITY_REQUIREMENTS_ANNOUNCEMENT = "https://android-developers.googleblog.com/2026/08/app-quality-memory-optimization-secure-onboarding.html";
|
|
9885
|
+
var RESTORE_CREDENTIALS_DOCS = "https://developer.android.com/identity/sign-in/restore-credentials";
|
|
9727
9886
|
function buildChecklist(input) {
|
|
9728
9887
|
const items = [];
|
|
9729
9888
|
const answers = input.interactiveAnswers ?? {};
|
|
@@ -9770,6 +9929,24 @@ function buildChecklist(input) {
|
|
|
9770
9929
|
answers
|
|
9771
9930
|
)
|
|
9772
9931
|
);
|
|
9932
|
+
items.push(
|
|
9933
|
+
resolveManualStep(
|
|
9934
|
+
"memory-quality-thresholds",
|
|
9935
|
+
"Memory quality requirements reviewed",
|
|
9936
|
+
"Starting February 2027, apps and games must meet Google Play's dynamic memory, bitmap memory, and DEX code optimization thresholds (at least 25% coverage using R8 or another shrinking tool); apps that miss them may see reduced visibility and publishing capabilities. Review the dynamic memory metrics, out of memory crash filters, and DEX optimization insights in Play Console under Android vitals. Source: " + QUALITY_REQUIREMENTS_ANNOUNCEMENT,
|
|
9937
|
+
QUALITY_REQUIREMENTS_ANNOUNCEMENT,
|
|
9938
|
+
answers
|
|
9939
|
+
)
|
|
9940
|
+
);
|
|
9941
|
+
items.push(
|
|
9942
|
+
resolveManualStep(
|
|
9943
|
+
"restore-credentials",
|
|
9944
|
+
"Zero-Tap Sign-In (Restore Credentials API) implemented",
|
|
9945
|
+
"Starting April 2027, apps that support user sign-in must restore the signed-in state when a user moves to a new Android device, using the Android Restore Credentials API, to keep full publishing capabilities and optimal Play Store visibility. Games are currently exempt. Adopt the Restore Credentials API in your sign-in flow. Source: " + QUALITY_REQUIREMENTS_ANNOUNCEMENT,
|
|
9946
|
+
RESTORE_CREDENTIALS_DOCS,
|
|
9947
|
+
answers
|
|
9948
|
+
)
|
|
9949
|
+
);
|
|
9773
9950
|
if (input.appAccessible !== void 0) {
|
|
9774
9951
|
items.push({
|
|
9775
9952
|
id: "app-accessible",
|
|
@@ -10173,6 +10350,7 @@ export {
|
|
|
10173
10350
|
resolveLocales,
|
|
10174
10351
|
resolveReportsBucket,
|
|
10175
10352
|
retryOnUploadNotComplete,
|
|
10353
|
+
reviewOrderRefund,
|
|
10176
10354
|
revokeSubscriptionPurchase,
|
|
10177
10355
|
runPreflight,
|
|
10178
10356
|
runWatch,
|