@gpc-cli/core 0.9.53 → 0.9.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -16
- package/dist/index.d.ts +20 -1
- package/dist/index.js +137 -5
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -45,22 +45,23 @@ const analysis = await analyzeBundle("./app.aab");
|
|
|
45
45
|
|
|
46
46
|
## Command Groups
|
|
47
47
|
|
|
48
|
-
| Group | Functions
|
|
49
|
-
| ----------------- |
|
|
50
|
-
| **Releases** | `uploadRelease`, `promoteRelease`, `updateRollout`, `getReleasesStatus`, `listTracks`
|
|
51
|
-
| **Listings** | `getListings`, `updateListing`, `pullListings`, `pushListings`, `diffListings`
|
|
52
|
-
| **Images** | `listImages`, `uploadImage`, `deleteImage`
|
|
53
|
-
| **Reviews** | `listReviews`, `getReview`, `replyToReview`, `exportReviews`
|
|
54
|
-
| **Vitals** | `getVitalsOverview`, `getVitalsCrashes`, `getVitalsAnr`, `getVitalsStartup`, `compareVitalsTrend`, `checkThreshold`
|
|
55
|
-
| **Subscriptions** | `listSubscriptions`, `createSubscription`, `updateSubscription`, `deleteSubscription`, `listOffers`, `createOffer`
|
|
56
|
-
| **IAP** | `listInAppProducts`, `createInAppProduct`, `syncInAppProducts`
|
|
57
|
-
| **Purchases** | `getProductPurchase`, `acknowledgeProductPurchase`, `refundOrder`
|
|
58
|
-
| **Reports** | `listReports`, `downloadReport`
|
|
59
|
-
| **Users** | `listUsers`, `inviteUser`, `updateUser`, `removeUser`
|
|
60
|
-
| **Testers** | `listTesters`, `addTesters`, `removeTesters`, `importTestersFromCsv`
|
|
61
|
-
| **Bundle** | `analyzeBundle`, `compareBundles` (zero-dependency AAB/APK size analysis)
|
|
62
|
-
| **Publishing** | `publish` (end-to-end: upload + track + notes + commit)
|
|
63
|
-
| **
|
|
48
|
+
| Group | Functions |
|
|
49
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
50
|
+
| **Releases** | `uploadRelease`, `promoteRelease`, `updateRollout`, `getReleasesStatus`, `listTracks` |
|
|
51
|
+
| **Listings** | `getListings`, `updateListing`, `pullListings`, `pushListings`, `diffListings` |
|
|
52
|
+
| **Images** | `listImages`, `uploadImage`, `deleteImage` |
|
|
53
|
+
| **Reviews** | `listReviews`, `getReview`, `replyToReview`, `exportReviews` |
|
|
54
|
+
| **Vitals** | `getVitalsOverview`, `getVitalsCrashes`, `getVitalsAnr`, `getVitalsStartup`, `compareVitalsTrend`, `checkThreshold` |
|
|
55
|
+
| **Subscriptions** | `listSubscriptions`, `createSubscription`, `updateSubscription`, `deleteSubscription`, `listOffers`, `createOffer` |
|
|
56
|
+
| **IAP** | `listInAppProducts`, `createInAppProduct`, `syncInAppProducts` |
|
|
57
|
+
| **Purchases** | `getProductPurchase`, `acknowledgeProductPurchase`, `refundOrder` |
|
|
58
|
+
| **Reports** | `listReports`, `downloadReport` |
|
|
59
|
+
| **Users** | `listUsers`, `inviteUser`, `updateUser`, `removeUser` |
|
|
60
|
+
| **Testers** | `listTesters`, `addTesters`, `removeTesters`, `importTestersFromCsv` |
|
|
61
|
+
| **Bundle** | `analyzeBundle`, `compareBundles` (zero-dependency AAB/APK size analysis) |
|
|
62
|
+
| **Publishing** | `publish` (end-to-end: upload + track + notes + commit) |
|
|
63
|
+
| **Changelog** | `generateChangelog`, `fetchChangelog`, `formatChangelogEntry`, `buildLocaleBundle`, `renderPlayStore`, `renderMarkdown`, `renderJson`, `renderPrompt`, `translateBundle`, `resolveLocales` |
|
|
64
|
+
| **Validation** | `validateUploadFile`, `validateImage`, `validatePreSubmission` |
|
|
64
65
|
|
|
65
66
|
## Utilities
|
|
66
67
|
|
package/dist/index.d.ts
CHANGED
|
@@ -109,6 +109,7 @@ interface AppInfo {
|
|
|
109
109
|
}
|
|
110
110
|
declare function getAppInfo(client: PlayApiClient, packageName: string): Promise<AppInfo>;
|
|
111
111
|
|
|
112
|
+
declare function waitForBundleProcessing(client: PlayApiClient, packageName: string, editId: string, versionCode: number, backoff?: number[]): Promise<void>;
|
|
112
113
|
interface UploadResult {
|
|
113
114
|
versionCode: number;
|
|
114
115
|
track: string;
|
|
@@ -183,6 +184,19 @@ declare function fetchReleaseNotes(client: PlayApiClient, packageName: string, t
|
|
|
183
184
|
language: string;
|
|
184
185
|
text: string;
|
|
185
186
|
}[]>;
|
|
187
|
+
interface ApplyReleaseNotesResult {
|
|
188
|
+
track: string;
|
|
189
|
+
versionCodes: string[];
|
|
190
|
+
localeCount: number;
|
|
191
|
+
releaseNotes: {
|
|
192
|
+
language: string;
|
|
193
|
+
text: string;
|
|
194
|
+
}[];
|
|
195
|
+
}
|
|
196
|
+
declare function applyReleaseNotes(client: PlayApiClient, packageName: string, track: string, releaseNotes: {
|
|
197
|
+
language: string;
|
|
198
|
+
text: string;
|
|
199
|
+
}[], commitOptions?: EditCommitOptions): Promise<ApplyReleaseNotesResult>;
|
|
186
200
|
interface ReleaseDiff {
|
|
187
201
|
field: string;
|
|
188
202
|
track1Value: string;
|
|
@@ -1398,6 +1412,11 @@ interface TranslatedBundle extends LocaleBundle {
|
|
|
1398
1412
|
failures: TranslationFailure[];
|
|
1399
1413
|
}
|
|
1400
1414
|
declare function translateBundle(bundle: LocaleBundle, options: TranslateBundleOptions): Promise<TranslatedBundle>;
|
|
1415
|
+
declare function validateBundleForApply(bundle: LocaleBundle): string[];
|
|
1416
|
+
declare function bundleToReleaseNotes(bundle: LocaleBundle): {
|
|
1417
|
+
language: string;
|
|
1418
|
+
text: string;
|
|
1419
|
+
}[];
|
|
1401
1420
|
|
|
1402
1421
|
type Renderer = (g: GeneratedChangelog) => string;
|
|
1403
1422
|
declare const RENDERERS: Record<OutputMode, Renderer>;
|
|
@@ -1453,4 +1472,4 @@ declare function decodeNotification(base64Payload: string): DecodedNotification;
|
|
|
1453
1472
|
*/
|
|
1454
1473
|
declare function formatNotification(notification: DecodedNotification): Record<string, unknown>;
|
|
1455
1474
|
|
|
1456
|
-
export { ApiError, type AppInfo, type AppStatus, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type ChangelogEntry, type CommandContext, type CommitCluster, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_MODELS, DEFAULT_PREFLIGHT_CONFIG, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ErrorReason, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GenerateOptions, type GeneratedChangelog, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, type GitRunner, GpcError, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type ListIapOptions, 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, type RawCommit, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type Renderer, type ResolveAiConfigOptions, type ResolveLocalesOptions, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, type RtdnStatus, SECTION_ORDER, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type Spinner, 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, type ValidateCheck, type ValidateOptions, type ValidateResult, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchOptions, type WatchVitalsOptions, type WebhookPayload, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, batchGetOrders, batchSyncInAppProducts, buildLocaleBundle, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkThreshold, classifyError, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, createTranslator, deactivateBasePlan, deactivateOffer, decodeNotification, defaultGitRunner, deferSubscriptionPurchase, deferSubscriptionV2, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportImages, exportReviews, fetchAggregateCost, fetchChangelog, fetchReleaseNotes, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatNotification, formatOutput, formatPathLabel, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateChangelog, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, 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, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseCommit, parseFastfile, parseGrantArg, parseMonth, parseRemoteUrl, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, renderJson, renderMarkdown, renderPlayStore, renderPlayStoreJson, renderPlayStoreMd, renderPlayStorePrompt, renderPrompt, replyToReview, resolveAiConfig, resolveLocales, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, translateBundle, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateImage, validateLanguageCode, validatePackageName, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
|
1475
|
+
export { ApiError, type AppInfo, type AppStatus, type ApplyReleaseNotesResult, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type ChangelogEntry, type CommandContext, type CommitCluster, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_MODELS, DEFAULT_PREFLIGHT_CONFIG, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ErrorReason, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GenerateOptions, type GeneratedChangelog, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, type GitRunner, GpcError, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type ListIapOptions, 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, type RawCommit, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type Renderer, type ResolveAiConfigOptions, type ResolveLocalesOptions, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, type RtdnStatus, SECTION_ORDER, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type Spinner, 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, type ValidateCheck, type ValidateOptions, type ValidateResult, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchOptions, type WatchVitalsOptions, type WebhookPayload, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, applyReleaseNotes, batchGetOrders, batchSyncInAppProducts, buildLocaleBundle, bundleToReleaseNotes, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkThreshold, classifyError, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, createTranslator, deactivateBasePlan, deactivateOffer, decodeNotification, defaultGitRunner, deferSubscriptionPurchase, deferSubscriptionV2, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportImages, exportReviews, fetchAggregateCost, fetchChangelog, fetchReleaseNotes, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatNotification, formatOutput, formatPathLabel, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateChangelog, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, 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, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseCommit, parseFastfile, parseGrantArg, parseMonth, parseRemoteUrl, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, renderJson, renderMarkdown, renderPlayStore, renderPlayStoreJson, renderPlayStoreMd, renderPlayStorePrompt, renderPrompt, replyToReview, resolveAiConfig, resolveLocales, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, translateBundle, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateBundleForApply, validateImage, validateLanguageCode, validatePackageName, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, waitForBundleProcessing, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
package/dist/index.js
CHANGED
|
@@ -650,6 +650,20 @@ function formatSize(bytes) {
|
|
|
650
650
|
}
|
|
651
651
|
|
|
652
652
|
// src/commands/releases.ts
|
|
653
|
+
var BUNDLE_POLL_BACKOFF = [2e3, 3e3, 5e3, 8e3, 13e3];
|
|
654
|
+
async function waitForBundleProcessing(client, packageName, editId, versionCode, backoff = BUNDLE_POLL_BACKOFF) {
|
|
655
|
+
for (let i = 0; i < backoff.length; i++) {
|
|
656
|
+
const bundles = await client.bundles.list(packageName, editId);
|
|
657
|
+
if (bundles.some((b) => b.versionCode === versionCode)) return;
|
|
658
|
+
await new Promise((r) => setTimeout(r, backoff[i]));
|
|
659
|
+
}
|
|
660
|
+
throw new GpcError(
|
|
661
|
+
`Bundle versionCode ${versionCode} not ready after ${backoff.length} poll attempts (~${Math.round(backoff.reduce((a, b) => a + b, 0) / 1e3)}s)`,
|
|
662
|
+
"BUNDLE_PROCESSING_TIMEOUT",
|
|
663
|
+
4,
|
|
664
|
+
"The AAB is still being processed by Google. Retry the upload, or use --status draft and commit later."
|
|
665
|
+
);
|
|
666
|
+
}
|
|
653
667
|
async function withRetryOnConflict(client, packageName, operation) {
|
|
654
668
|
const edit = await client.edits.insert(packageName);
|
|
655
669
|
try {
|
|
@@ -763,6 +777,9 @@ ${validation.errors.join("\n")}`,
|
|
|
763
777
|
uploadOpts,
|
|
764
778
|
options.deviceTierConfigId
|
|
765
779
|
);
|
|
780
|
+
if (!isApk) {
|
|
781
|
+
await waitForBundleProcessing(client, packageName, edit.id, bundle.versionCode);
|
|
782
|
+
}
|
|
766
783
|
if (options.mappingFile) {
|
|
767
784
|
await client.deobfuscation.upload(
|
|
768
785
|
packageName,
|
|
@@ -1023,6 +1040,35 @@ async function fetchReleaseNotes(client, packageName, track) {
|
|
|
1023
1040
|
});
|
|
1024
1041
|
}
|
|
1025
1042
|
}
|
|
1043
|
+
async function applyReleaseNotes(client, packageName, track, releaseNotes, commitOptions) {
|
|
1044
|
+
return withRetryOnConflict(client, packageName, async (edit) => {
|
|
1045
|
+
const trackData = await client.tracks.get(packageName, edit.id, track);
|
|
1046
|
+
const draft = trackData.releases?.find((r) => r.status === "draft");
|
|
1047
|
+
if (!draft) {
|
|
1048
|
+
throw new GpcError(
|
|
1049
|
+
`No draft release found on track "${track}"`,
|
|
1050
|
+
"RELEASE_NO_DRAFT",
|
|
1051
|
+
1,
|
|
1052
|
+
`Upload an AAB/APK first to create a draft, or check the --track value. Current track: "${track}".`
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
const patched = {
|
|
1056
|
+
...draft,
|
|
1057
|
+
releaseNotes
|
|
1058
|
+
};
|
|
1059
|
+
await client.tracks.update(packageName, edit.id, track, patched);
|
|
1060
|
+
if (!commitOptions?.changesNotSentForReview) {
|
|
1061
|
+
await client.edits.validate(packageName, edit.id);
|
|
1062
|
+
}
|
|
1063
|
+
await client.edits.commit(packageName, edit.id, commitOptions);
|
|
1064
|
+
return {
|
|
1065
|
+
track,
|
|
1066
|
+
versionCodes: draft.versionCodes || [],
|
|
1067
|
+
localeCount: releaseNotes.length,
|
|
1068
|
+
releaseNotes
|
|
1069
|
+
};
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1026
1072
|
async function diffReleases(client, packageName, fromTrack, toTrack) {
|
|
1027
1073
|
const edit = await client.edits.insert(packageName);
|
|
1028
1074
|
try {
|
|
@@ -5143,6 +5189,28 @@ var manifestScanner = {
|
|
|
5143
5189
|
}
|
|
5144
5190
|
}
|
|
5145
5191
|
}
|
|
5192
|
+
const hasBackgroundLocation = manifest.permissions.includes(
|
|
5193
|
+
"android.permission.ACCESS_BACKGROUND_LOCATION"
|
|
5194
|
+
);
|
|
5195
|
+
if (hasBackgroundLocation) {
|
|
5196
|
+
for (const service of manifest.services) {
|
|
5197
|
+
const fst = service.foregroundServiceType;
|
|
5198
|
+
if (!fst) continue;
|
|
5199
|
+
const num = Number(fst);
|
|
5200
|
+
const hasLocation = fst.split("|").some((t) => t.trim() === "location") || !isNaN(num) && (num & 8) !== 0;
|
|
5201
|
+
if (hasLocation) {
|
|
5202
|
+
findings.push({
|
|
5203
|
+
scanner: "manifest",
|
|
5204
|
+
ruleId: "geofencing-foreground-service",
|
|
5205
|
+
severity: "warning",
|
|
5206
|
+
title: `Possible geofencing via foreground service "${service.name}"`,
|
|
5207
|
+
message: `Service "${service.name}" uses foregroundServiceType "location" and the app declares ACCESS_BACKGROUND_LOCATION. Google Play no longer approves geofencing as a foreground service use case (April 2026 policy). Compliance deadline: May 15, 2026.`,
|
|
5208
|
+
suggestion: 'If this service performs geofencing, migrate to WorkManager or AlarmManager. If this is legitimate background location tracking (navigation, fitness), suppress this rule via .preflightrc.json: "disabledRules": ["geofencing-foreground-service"].',
|
|
5209
|
+
policyUrl: "https://support.google.com/googleplay/android-developer/answer/16926792"
|
|
5210
|
+
});
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
5213
|
+
}
|
|
5146
5214
|
const allComponents = [
|
|
5147
5215
|
...manifest.activities,
|
|
5148
5216
|
...manifest.services,
|
|
@@ -5360,6 +5428,34 @@ var permissionsScanner = {
|
|
|
5360
5428
|
});
|
|
5361
5429
|
}
|
|
5362
5430
|
}
|
|
5431
|
+
const contactsPerms = [
|
|
5432
|
+
"android.permission.READ_CONTACTS",
|
|
5433
|
+
"android.permission.WRITE_CONTACTS"
|
|
5434
|
+
].filter((p) => manifest.permissions.includes(p) && !allowed.has(p));
|
|
5435
|
+
if (contactsPerms.length > 0) {
|
|
5436
|
+
const names = contactsPerms.map((p) => p.split(".").pop()).join(", ");
|
|
5437
|
+
findings.push({
|
|
5438
|
+
scanner: "permissions",
|
|
5439
|
+
ruleId: "contacts-permission-broad",
|
|
5440
|
+
severity: "warning",
|
|
5441
|
+
title: "Broad contacts access requires migration to Contact Picker",
|
|
5442
|
+
message: `Your app declares ${names}. Google Play now requires the Android Contact Picker instead of broad contacts access. Compliance deadline: May 15, 2026.`,
|
|
5443
|
+
suggestion: "Migrate to the Android Contact Picker API for user-initiated contact selection. Remove READ_CONTACTS/WRITE_CONTACTS unless your app is a dialer, messaging, or contacts management app.",
|
|
5444
|
+
policyUrl: "https://support.google.com/googleplay/android-developer/answer/16926792"
|
|
5445
|
+
});
|
|
5446
|
+
}
|
|
5447
|
+
const broadHealthPerm = "android.permission.health.READ_ALL_HEALTH_DATA";
|
|
5448
|
+
if (manifest.permissions.includes(broadHealthPerm) && !allowed.has(broadHealthPerm)) {
|
|
5449
|
+
findings.push({
|
|
5450
|
+
scanner: "permissions",
|
|
5451
|
+
ruleId: "health-connect-granular",
|
|
5452
|
+
severity: manifest.targetSdk >= 36 ? "warning" : "info",
|
|
5453
|
+
title: "Broad Health Connect permission \u2014 use granular permissions",
|
|
5454
|
+
message: `Your app declares READ_ALL_HEALTH_DATA. Android 16 requires granular Health Connect permissions for individual data types (e.g., steps, heart rate, sleep).${manifest.targetSdk >= 36 ? " Your targetSdk >= 36 makes this a policy requirement." : " This will become required when you target API 36+."}`,
|
|
5455
|
+
suggestion: "Replace READ_ALL_HEALTH_DATA with individual permissions like health.READ_STEPS, health.READ_HEART_RATE, etc. Only request the data types your app actually uses.",
|
|
5456
|
+
policyUrl: "https://developer.android.com/health-and-fitness/guides/health-connect/plan/data-types"
|
|
5457
|
+
});
|
|
5458
|
+
}
|
|
5363
5459
|
const dataPermissions = [
|
|
5364
5460
|
{ perm: "android.permission.ACCESS_FINE_LOCATION", data: "precise location" },
|
|
5365
5461
|
{ perm: "android.permission.ACCESS_COARSE_LOCATION", data: "approximate location" },
|
|
@@ -7377,7 +7473,16 @@ var KNOWN_TYPES = /* @__PURE__ */ new Set([
|
|
|
7377
7473
|
"release"
|
|
7378
7474
|
]);
|
|
7379
7475
|
var FILTERED_TYPES = /* @__PURE__ */ new Set(["chore", "refactor", "test", "build", "style", "merge"]);
|
|
7380
|
-
var SECTION_ORDER = [
|
|
7476
|
+
var SECTION_ORDER = [
|
|
7477
|
+
"breaking",
|
|
7478
|
+
"feat",
|
|
7479
|
+
"fix",
|
|
7480
|
+
"perf",
|
|
7481
|
+
"docs",
|
|
7482
|
+
"ci",
|
|
7483
|
+
"release",
|
|
7484
|
+
"other"
|
|
7485
|
+
];
|
|
7381
7486
|
var FIXUP_PATTERNS = [
|
|
7382
7487
|
/^wip\b/i,
|
|
7383
7488
|
/^fix\s+typo\b/i,
|
|
@@ -7841,14 +7946,18 @@ function renderPrompt(g) {
|
|
|
7841
7946
|
if (g.headlineCandidates.length > 0) {
|
|
7842
7947
|
lines.push("HEADLINE CANDIDATES (largest first):");
|
|
7843
7948
|
for (const c of g.headlineCandidates) {
|
|
7844
|
-
lines.push(
|
|
7949
|
+
lines.push(
|
|
7950
|
+
` ${c.label} (weight ${c.weight}, ${c.commits.length} commits, primary ${c.primaryType})`
|
|
7951
|
+
);
|
|
7845
7952
|
}
|
|
7846
7953
|
lines.push("");
|
|
7847
7954
|
}
|
|
7848
7955
|
lines.push("CLUSTERED COMMITS:");
|
|
7849
7956
|
lines.push("");
|
|
7850
7957
|
for (const cluster of g.clusters) {
|
|
7851
|
-
lines.push(
|
|
7958
|
+
lines.push(
|
|
7959
|
+
`[cluster: ${cluster.label}, weight ${cluster.weight}, ${cluster.commits.length} commits, primary ${cluster.primaryType}]`
|
|
7960
|
+
);
|
|
7852
7961
|
for (const commit of cluster.commits) {
|
|
7853
7962
|
lines.push(`- ${commit.type}: ${safeLine(commit.subject)} (${commit.sha.slice(0, 7)})`);
|
|
7854
7963
|
if (commit.files.length > 0) {
|
|
@@ -8159,7 +8268,9 @@ function renderPlayStorePrompt(bundle, g) {
|
|
|
8159
8268
|
const source = bundle.locales.find((e) => e.language === bundle.sourceLanguage);
|
|
8160
8269
|
const targets = bundle.locales.filter((e) => e.language !== bundle.sourceLanguage);
|
|
8161
8270
|
const lines = [];
|
|
8162
|
-
lines.push(
|
|
8271
|
+
lines.push(
|
|
8272
|
+
`You are translating Play Store "What's new" release notes from ${bundle.sourceLanguage}.`
|
|
8273
|
+
);
|
|
8163
8274
|
lines.push("");
|
|
8164
8275
|
lines.push("TARGETS:");
|
|
8165
8276
|
for (const t of targets) lines.push(` - ${t.language}`);
|
|
@@ -8170,7 +8281,9 @@ function renderPlayStorePrompt(bundle, g) {
|
|
|
8170
8281
|
lines.push('- Preserve the bullet format (one item per line, starts with "- ")');
|
|
8171
8282
|
lines.push("- Keep a user-facing tone (no internal jargon)");
|
|
8172
8283
|
lines.push('- Do not translate technical names (package names, CLI flags, "GPC")');
|
|
8173
|
-
lines.push(
|
|
8284
|
+
lines.push(
|
|
8285
|
+
"- Drop the conventional-commit prefix (feat:/fix:) if it feels unnatural in the target language"
|
|
8286
|
+
);
|
|
8174
8287
|
lines.push("");
|
|
8175
8288
|
lines.push(`SOURCE (${bundle.sourceLanguage}, ${source?.chars ?? 0}/${bundle.limit} chars):`);
|
|
8176
8289
|
lines.push("```");
|
|
@@ -8290,6 +8403,21 @@ async function translateBundle(bundle, options) {
|
|
|
8290
8403
|
}
|
|
8291
8404
|
return translated;
|
|
8292
8405
|
}
|
|
8406
|
+
function validateBundleForApply(bundle) {
|
|
8407
|
+
const errors = [];
|
|
8408
|
+
for (const entry of bundle.locales) {
|
|
8409
|
+
if (entry.status === "placeholder") {
|
|
8410
|
+
errors.push(`${entry.language}: untranslated placeholder \u2014 use --ai or remove this locale`);
|
|
8411
|
+
}
|
|
8412
|
+
if (entry.status === "failed") {
|
|
8413
|
+
errors.push(`${entry.language}: translation failed \u2014 retry or remove this locale`);
|
|
8414
|
+
}
|
|
8415
|
+
}
|
|
8416
|
+
return errors;
|
|
8417
|
+
}
|
|
8418
|
+
function bundleToReleaseNotes(bundle) {
|
|
8419
|
+
return bundle.locales.filter((e) => e.status !== "placeholder" && e.status !== "failed").map((e) => ({ language: e.language, text: e.text }));
|
|
8420
|
+
}
|
|
8293
8421
|
|
|
8294
8422
|
// src/commands/changelog-renderers/index.ts
|
|
8295
8423
|
var RENDERERS = {
|
|
@@ -8481,9 +8609,11 @@ export {
|
|
|
8481
8609
|
analyzeBundle,
|
|
8482
8610
|
analyzeRemoteListings,
|
|
8483
8611
|
analyzeReviews2 as analyzeReviews,
|
|
8612
|
+
applyReleaseNotes,
|
|
8484
8613
|
batchGetOrders,
|
|
8485
8614
|
batchSyncInAppProducts,
|
|
8486
8615
|
buildLocaleBundle,
|
|
8616
|
+
bundleToReleaseNotes,
|
|
8487
8617
|
cancelRecoveryAction,
|
|
8488
8618
|
cancelSubscriptionPurchase,
|
|
8489
8619
|
cancelSubscriptionV2,
|
|
@@ -8693,6 +8823,7 @@ export {
|
|
|
8693
8823
|
uploadImage,
|
|
8694
8824
|
uploadInternalSharing,
|
|
8695
8825
|
uploadRelease,
|
|
8826
|
+
validateBundleForApply,
|
|
8696
8827
|
validateImage,
|
|
8697
8828
|
validateLanguageCode,
|
|
8698
8829
|
validatePackageName,
|
|
@@ -8702,6 +8833,7 @@ export {
|
|
|
8702
8833
|
validateTrackName,
|
|
8703
8834
|
validateUploadFile,
|
|
8704
8835
|
validateVersionCode,
|
|
8836
|
+
waitForBundleProcessing,
|
|
8705
8837
|
watchVitalsWithAutoHalt,
|
|
8706
8838
|
wordDiff,
|
|
8707
8839
|
writeAuditLog,
|