@gpc-cli/core 0.9.54 → 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 CHANGED
@@ -45,23 +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) |
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
63
  | **Changelog** | `generateChangelog`, `fetchChangelog`, `formatChangelogEntry`, `buildLocaleBundle`, `renderPlayStore`, `renderMarkdown`, `renderJson`, `renderPrompt`, `translateBundle`, `resolveLocales` |
64
- | **Validation** | `validateUploadFile`, `validateImage`, `validatePreSubmission` |
64
+ | **Validation** | `validateUploadFile`, `validateImage`, `validatePreSubmission` |
65
65
 
66
66
  ## Utilities
67
67
 
package/dist/index.js CHANGED
@@ -5189,6 +5189,28 @@ var manifestScanner = {
5189
5189
  }
5190
5190
  }
5191
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
+ }
5192
5214
  const allComponents = [
5193
5215
  ...manifest.activities,
5194
5216
  ...manifest.services,
@@ -5406,6 +5428,34 @@ var permissionsScanner = {
5406
5428
  });
5407
5429
  }
5408
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
+ }
5409
5459
  const dataPermissions = [
5410
5460
  { perm: "android.permission.ACCESS_FINE_LOCATION", data: "precise location" },
5411
5461
  { perm: "android.permission.ACCESS_COARSE_LOCATION", data: "approximate location" },