@gpc-cli/core 0.9.35 → 0.9.37

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 CHANGED
@@ -885,6 +885,8 @@ interface ParsedManifest {
885
885
  services: ManifestComponent[];
886
886
  receivers: ManifestComponent[];
887
887
  providers: ManifestComponent[];
888
+ /** Set when the manifest could not be fully parsed — manifest-dependent scanners should skip. */
889
+ _parseError?: string;
888
890
  }
889
891
  interface ManifestFeature {
890
892
  name: string;
@@ -1174,4 +1176,26 @@ declare function trackBreachState(packageName: string, isBreaching: boolean): Pr
1174
1176
  declare function sendNotification(title: string, body: string): void;
1175
1177
  declare function statusHasBreach(status: AppStatus): boolean;
1176
1178
 
1177
- export { ApiError, type AppInfo, type AppStatus, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type CommandContext, ConfigError, DEFAULT_LIMITS, DEFAULT_PREFLIGHT_CONFIG, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, 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 MigrationResult, NetworkError, type OneTimeProductDiff, PERMISSION_PROPAGATION_WARNING, type ParsedManifest, type ParsedMonth, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, 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 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, activatePurchaseOption, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, batchSyncInAppProducts, cancelRecoveryAction, cancelSubscriptionPurchase, checkBundleSize, checkThreshold, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createPurchaseOption, createRecoveryAction, createSpinner, createSubscription, createTrack, deactivateBasePlan, deactivateOffer, deactivatePurchaseOption, deferSubscriptionPurchase, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportDataSafety, exportImages, exportReviews, fetchReleaseNotes, formatCustomPayload, formatDiscordPayload, formatJunit, formatOutput, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDataSafety, getDeviceTier, getExternalTransaction, getInAppProduct, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getProductPurchase, getPurchaseOption, getQuotaUsage, getReleasesStatus, getReview, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEnterpriseApps, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listPurchaseOptions, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseFastfile, parseGrantArg, parseMonth, pauseTrain, promoteRelease, publish, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, refundSubscriptionV2, removeTesters, removeUser, replyToReview, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, 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 };
1179
+ interface ChangelogEntry {
1180
+ version: string;
1181
+ title: string;
1182
+ date: string;
1183
+ body: string;
1184
+ url: string;
1185
+ }
1186
+ interface FetchChangelogOptions {
1187
+ limit?: number;
1188
+ version?: string;
1189
+ }
1190
+ /**
1191
+ * Fetch release history from GitHub Releases API.
1192
+ * Public endpoint — no auth required (60 req/hour rate limit).
1193
+ */
1194
+ declare function fetchChangelog(options?: FetchChangelogOptions): Promise<ChangelogEntry[]>;
1195
+ /**
1196
+ * Format a changelog entry as readable terminal text.
1197
+ * Strips markdown formatting for clean terminal output.
1198
+ */
1199
+ declare function formatChangelogEntry(entry: ChangelogEntry): string;
1200
+
1201
+ export { ApiError, type AppInfo, type AppStatus, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type ChangelogEntry, type CommandContext, ConfigError, DEFAULT_LIMITS, DEFAULT_PREFLIGHT_CONFIG, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, 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 MigrationResult, NetworkError, type OneTimeProductDiff, PERMISSION_PROPAGATION_WARNING, type ParsedManifest, type ParsedMonth, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, 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 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, activatePurchaseOption, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, batchSyncInAppProducts, cancelRecoveryAction, cancelSubscriptionPurchase, checkBundleSize, checkThreshold, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createPurchaseOption, createRecoveryAction, createSpinner, createSubscription, createTrack, deactivateBasePlan, deactivateOffer, deactivatePurchaseOption, deferSubscriptionPurchase, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportDataSafety, exportImages, exportReviews, fetchChangelog, fetchReleaseNotes, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatOutput, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDataSafety, getDeviceTier, getExternalTransaction, getInAppProduct, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getProductPurchase, getPurchaseOption, getQuotaUsage, getReleasesStatus, getReview, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEnterpriseApps, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listPurchaseOptions, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseFastfile, parseGrantArg, parseMonth, pauseTrain, promoteRelease, publish, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, refundSubscriptionV2, removeTesters, removeUser, replyToReview, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, 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 };
package/dist/index.js CHANGED
@@ -4717,9 +4717,39 @@ async function readAab(aabPath) {
4717
4717
  `AAB is missing ${MANIFEST_PATH}. This does not appear to be a valid Android App Bundle.`
4718
4718
  );
4719
4719
  }
4720
- const manifest = decodeManifest(manifestBuf);
4720
+ let manifest;
4721
+ try {
4722
+ manifest = decodeManifest(manifestBuf);
4723
+ } catch (err) {
4724
+ const errMsg = err instanceof Error ? err.message : String(err);
4725
+ if (errMsg.includes("index out of range") || errMsg.includes("invalid wire type")) {
4726
+ manifest = createFallbackManifest();
4727
+ manifest._parseError = `Manifest could not be fully parsed: ${errMsg}. Manifest-dependent checks will be skipped.`;
4728
+ } else {
4729
+ throw err;
4730
+ }
4731
+ }
4721
4732
  return { manifest, entries };
4722
4733
  }
4734
+ function createFallbackManifest() {
4735
+ return {
4736
+ packageName: "",
4737
+ versionCode: 0,
4738
+ versionName: "",
4739
+ minSdk: 0,
4740
+ targetSdk: 0,
4741
+ debuggable: false,
4742
+ testOnly: false,
4743
+ usesCleartextTraffic: false,
4744
+ extractNativeLibs: true,
4745
+ permissions: [],
4746
+ features: [],
4747
+ activities: [],
4748
+ services: [],
4749
+ receivers: [],
4750
+ providers: []
4751
+ };
4752
+ }
4723
4753
  function openAndScan(aabPath) {
4724
4754
  return new Promise((resolve2, reject) => {
4725
4755
  yauzlOpen(aabPath, { lazyEntries: true, autoClose: false }, (err, zipfile) => {
@@ -5868,11 +5898,23 @@ async function runPreflight(options) {
5868
5898
  failOn: options.failOn ?? fileConfig.failOn ?? DEFAULT_PREFLIGHT_CONFIG.failOn
5869
5899
  };
5870
5900
  const ctx = { config };
5901
+ const earlyFindings = [];
5871
5902
  if (options.aabPath) {
5872
5903
  ctx.aabPath = options.aabPath;
5873
5904
  const aab = await readAab(options.aabPath);
5874
5905
  ctx.manifest = aab.manifest;
5875
5906
  ctx.zipEntries = aab.entries;
5907
+ if (aab.manifest._parseError) {
5908
+ earlyFindings.push({
5909
+ scanner: "manifest-parser",
5910
+ ruleId: "manifest-parse-error",
5911
+ severity: "warning",
5912
+ title: "Manifest could not be fully parsed",
5913
+ message: aab.manifest._parseError,
5914
+ suggestion: "Manifest-dependent scanners (manifest, permissions, policy, privacy) were skipped. Other scanners (native-libs, size, secrets, billing) still ran."
5915
+ });
5916
+ ctx.manifest = void 0;
5917
+ }
5876
5918
  }
5877
5919
  if (options.metadataDir) ctx.metadataDir = options.metadataDir;
5878
5920
  if (options.sourceDir) ctx.sourceDir = options.sourceDir;
@@ -5888,7 +5930,7 @@ async function runPreflight(options) {
5888
5930
  return true;
5889
5931
  });
5890
5932
  const settled = await Promise.allSettled(applicableScanners.map((scanner) => scanner.scan(ctx)));
5891
- let findings = [];
5933
+ let findings = [...earlyFindings];
5892
5934
  for (let i = 0; i < settled.length; i++) {
5893
5935
  const result = settled[i];
5894
5936
  if (result.status === "fulfilled") {
@@ -6990,6 +7032,62 @@ function sendNotification(title, body) {
6990
7032
  function statusHasBreach(status) {
6991
7033
  return status.vitals.crashes.status === "breach" || status.vitals.anr.status === "breach" || status.vitals.slowStarts.status === "breach" || status.vitals.slowRender.status === "breach";
6992
7034
  }
7035
+
7036
+ // src/commands/changelog.ts
7037
+ var GITHUB_RELEASES_URL = "https://api.github.com/repos/yasserstudio/gpc/releases";
7038
+ var DOCS_CHANGELOG_URL = "https://yasserstudio.github.io/gpc/reference/changelog";
7039
+ async function fetchChangelog(options) {
7040
+ const limit = options?.limit ?? 5;
7041
+ const url = options?.version ? `${GITHUB_RELEASES_URL}/tags/${options.version.startsWith("v") ? options.version : `v${options.version}`}` : `${GITHUB_RELEASES_URL}?per_page=${Math.min(limit, 100)}`;
7042
+ const controller = new AbortController();
7043
+ const timer = setTimeout(() => controller.abort(), 1e4);
7044
+ let response;
7045
+ try {
7046
+ response = await fetch(url, {
7047
+ headers: {
7048
+ Accept: "application/vnd.github+json",
7049
+ "User-Agent": "gpc-cli"
7050
+ },
7051
+ signal: controller.signal
7052
+ });
7053
+ } catch {
7054
+ throw new Error(
7055
+ `Could not fetch changelog. View online: ${DOCS_CHANGELOG_URL}`
7056
+ );
7057
+ } finally {
7058
+ clearTimeout(timer);
7059
+ }
7060
+ if (!response.ok) {
7061
+ if (response.status === 404 && options?.version) {
7062
+ throw new Error(
7063
+ `Version ${options.version} not found. Run: gpc changelog --limit 10`
7064
+ );
7065
+ }
7066
+ throw new Error(
7067
+ `GitHub API returned ${response.status}. View online: ${DOCS_CHANGELOG_URL}`
7068
+ );
7069
+ }
7070
+ const data = await response.json();
7071
+ const releases = Array.isArray(data) ? data : [data];
7072
+ return releases.filter((r) => r.tag_name.startsWith("v")).map((r) => ({
7073
+ version: r.tag_name,
7074
+ title: r.name || r.tag_name,
7075
+ date: r.published_at ? r.published_at.split("T")[0] : "unknown",
7076
+ body: r.body || "No release notes.",
7077
+ url: r.html_url
7078
+ }));
7079
+ }
7080
+ function formatChangelogEntry(entry) {
7081
+ const lines = [];
7082
+ lines.push(`${entry.version} \u2014 ${entry.title}`);
7083
+ lines.push(`Released: ${entry.date}`);
7084
+ lines.push("");
7085
+ const body = entry.body.replace(/^### /gm, "").replace(/^## /gm, "").replace(/^# /gm, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").trim();
7086
+ lines.push(body);
7087
+ lines.push("");
7088
+ lines.push(`Full notes: ${entry.url}`);
7089
+ return lines.join("\n");
7090
+ }
6993
7091
  export {
6994
7092
  ApiError,
6995
7093
  ConfigError,
@@ -7068,7 +7166,9 @@ export {
7068
7166
  exportDataSafety,
7069
7167
  exportImages,
7070
7168
  exportReviews,
7169
+ fetchChangelog,
7071
7170
  fetchReleaseNotes,
7171
+ formatChangelogEntry,
7072
7172
  formatCustomPayload,
7073
7173
  formatDiscordPayload,
7074
7174
  formatJunit,