@gpc-cli/core 0.9.29 → 0.9.31
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.js +101 -52
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -198,7 +198,10 @@ function formatTable(data) {
|
|
|
198
198
|
const colCount = keys.length;
|
|
199
199
|
const maxCellWidth = computeMaxCellWidth(colCount);
|
|
200
200
|
const widths = keys.map(
|
|
201
|
-
(key) => Math.max(
|
|
201
|
+
(key) => Math.max(
|
|
202
|
+
key.length,
|
|
203
|
+
...rows.map((row) => truncateCell(cellValue(row[key]), maxCellWidth).length)
|
|
204
|
+
)
|
|
202
205
|
);
|
|
203
206
|
const isNumeric = keys.map(
|
|
204
207
|
(key) => rows.every((row) => {
|
|
@@ -557,7 +560,7 @@ async function getAppInfo(client, packageName) {
|
|
|
557
560
|
|
|
558
561
|
// src/commands/releases.ts
|
|
559
562
|
import { stat as stat2 } from "fs/promises";
|
|
560
|
-
import {
|
|
563
|
+
import { PlayApiError } from "@gpc-cli/api";
|
|
561
564
|
|
|
562
565
|
// src/utils/file-validation.ts
|
|
563
566
|
import { readFile, stat } from "fs/promises";
|
|
@@ -807,12 +810,13 @@ async function updateRollout(client, packageName, track, action, userFraction) {
|
|
|
807
810
|
let newFraction;
|
|
808
811
|
switch (action) {
|
|
809
812
|
case "increase":
|
|
810
|
-
if (!userFraction)
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
813
|
+
if (!userFraction)
|
|
814
|
+
throw new GpcError(
|
|
815
|
+
"--to <percentage> is required for rollout increase",
|
|
816
|
+
"ROLLOUT_MISSING_FRACTION",
|
|
817
|
+
2,
|
|
818
|
+
"Specify the target rollout percentage with --to, e.g.: gpc rollout increase --to 0.5"
|
|
819
|
+
);
|
|
816
820
|
if (userFraction <= 0 || userFraction > 1) {
|
|
817
821
|
throw new GpcError(
|
|
818
822
|
"Rollout percentage must be between 0 and 1 (e.g., 0.1 for 10%)",
|
|
@@ -1769,9 +1773,7 @@ function generateMigrationPlan(detection) {
|
|
|
1769
1773
|
}
|
|
1770
1774
|
for (const lane of detection.lanes) {
|
|
1771
1775
|
if (lane.gpcEquivalent) {
|
|
1772
|
-
checklist.push(
|
|
1773
|
-
`Replace Fastlane lane "${lane.name}" with: ${lane.gpcEquivalent} <your.aab>`
|
|
1774
|
-
);
|
|
1776
|
+
checklist.push(`Replace Fastlane lane "${lane.name}" with: ${lane.gpcEquivalent} <your.aab>`);
|
|
1775
1777
|
}
|
|
1776
1778
|
if (lane.actions.includes("capture_android_screenshots")) {
|
|
1777
1779
|
warnings.push(
|
|
@@ -1846,7 +1848,9 @@ async function writeMigrationOutput(result, dir) {
|
|
|
1846
1848
|
lines.push("| `supply(skip_upload_aab: true)` | `gpc listings push` |");
|
|
1847
1849
|
lines.push("| `capture_android_screenshots` | No equivalent \u2014 use separate tool |");
|
|
1848
1850
|
lines.push("");
|
|
1849
|
-
lines.push(
|
|
1851
|
+
lines.push(
|
|
1852
|
+
"See the full migration guide: https://yasserstudio.github.io/gpc/migration/from-fastlane"
|
|
1853
|
+
);
|
|
1850
1854
|
lines.push("");
|
|
1851
1855
|
await writeFile2(migrationPath, lines.join("\n"), "utf-8");
|
|
1852
1856
|
files.push(migrationPath);
|
|
@@ -2250,16 +2254,16 @@ function analyzeSentiment(text) {
|
|
|
2250
2254
|
}
|
|
2251
2255
|
function clusterTopics(texts) {
|
|
2252
2256
|
const TOPIC_KEYWORDS = {
|
|
2253
|
-
|
|
2254
|
-
|
|
2257
|
+
performance: ["slow", "lag", "laggy", "freeze", "fast", "speed", "quick", "smooth"],
|
|
2258
|
+
crashes: ["crash", "crashes", "crash", "crashing", "force close", "stops", "stopped"],
|
|
2255
2259
|
"ui/ux": ["ui", "design", "interface", "layout", "button", "screen", "menu", "navigation"],
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2260
|
+
battery: ["battery", "drain", "power", "charging", "drain"],
|
|
2261
|
+
updates: ["update", "updated", "version", "new version", "after update"],
|
|
2262
|
+
notifications: ["notification", "notifications", "alert", "alerts", "push"],
|
|
2259
2263
|
"login/auth": ["login", "sign in", "logout", "password", "account", "auth"],
|
|
2260
2264
|
"feature requests": ["please add", "would be nice", "missing", "need", "wish", "want"],
|
|
2261
|
-
|
|
2262
|
-
|
|
2265
|
+
bugs: ["bug", "bugs", "issue", "error", "problem", "glitch", "broken"],
|
|
2266
|
+
pricing: ["price", "pricing", "expensive", "cheap", "subscription", "pay", "cost", "free"]
|
|
2263
2267
|
};
|
|
2264
2268
|
const clusterMap = /* @__PURE__ */ new Map();
|
|
2265
2269
|
for (const text of texts) {
|
|
@@ -2499,7 +2503,8 @@ function autoFixProrationMode(data) {
|
|
|
2499
2503
|
for (const bp of data.basePlans) {
|
|
2500
2504
|
const mode = bp.autoRenewingBasePlanType?.prorationMode;
|
|
2501
2505
|
if (mode && !mode.startsWith(PRORATION_MODE_PREFIX)) {
|
|
2502
|
-
if (bp.autoRenewingBasePlanType)
|
|
2506
|
+
if (bp.autoRenewingBasePlanType)
|
|
2507
|
+
bp.autoRenewingBasePlanType.prorationMode = `${PRORATION_MODE_PREFIX}${mode}`;
|
|
2503
2508
|
}
|
|
2504
2509
|
if (bp.autoRenewingBasePlanType?.prorationMode) {
|
|
2505
2510
|
const fullMode = bp.autoRenewingBasePlanType.prorationMode;
|
|
@@ -2637,7 +2642,13 @@ async function createOffer(client, packageName, productId, basePlanId, data) {
|
|
|
2637
2642
|
validatePackageName(packageName);
|
|
2638
2643
|
validateSku(productId);
|
|
2639
2644
|
const sanitized = sanitizeOffer(data);
|
|
2640
|
-
return client.subscriptions.createOffer(
|
|
2645
|
+
return client.subscriptions.createOffer(
|
|
2646
|
+
packageName,
|
|
2647
|
+
productId,
|
|
2648
|
+
basePlanId,
|
|
2649
|
+
sanitized,
|
|
2650
|
+
data.offerId
|
|
2651
|
+
);
|
|
2641
2652
|
}
|
|
2642
2653
|
var OFFER_ID_FIELDS = /* @__PURE__ */ new Set(["productId", "basePlanId", "offerId"]);
|
|
2643
2654
|
function deriveOfferUpdateMask(data) {
|
|
@@ -2674,7 +2685,9 @@ async function diffSubscription(client, packageName, productId, localData) {
|
|
|
2674
2685
|
const diffs = [];
|
|
2675
2686
|
const fieldsToCompare = ["listings", "basePlans", "taxAndComplianceSettings"];
|
|
2676
2687
|
for (const field of fieldsToCompare) {
|
|
2677
|
-
const localVal = JSON.stringify(
|
|
2688
|
+
const localVal = JSON.stringify(
|
|
2689
|
+
localData[field] ?? null
|
|
2690
|
+
);
|
|
2678
2691
|
const remoteVal = JSON.stringify(remote[field] ?? null);
|
|
2679
2692
|
if (localVal !== remoteVal) {
|
|
2680
2693
|
diffs.push({ field, local: localVal, remote: remoteVal });
|
|
@@ -2720,7 +2733,11 @@ async function getSubscriptionAnalytics(client, packageName) {
|
|
|
2720
2733
|
}
|
|
2721
2734
|
for (const bp of basePlans) {
|
|
2722
2735
|
try {
|
|
2723
|
-
const offersResp = await client.subscriptions.listOffers(
|
|
2736
|
+
const offersResp = await client.subscriptions.listOffers(
|
|
2737
|
+
packageName,
|
|
2738
|
+
sub.productId,
|
|
2739
|
+
bp.basePlanId
|
|
2740
|
+
);
|
|
2724
2741
|
const offers = offersResp.subscriptionOffers ?? [];
|
|
2725
2742
|
subOfferCount += offers.length;
|
|
2726
2743
|
totalOffers += offers.length;
|
|
@@ -2753,7 +2770,12 @@ var METRIC_SET_METRICS = {
|
|
|
2753
2770
|
slowStartRateMetricSet: ["slowStartRate", "distinctUsers"],
|
|
2754
2771
|
slowRenderingRateMetricSet: ["slowRenderingRate", "distinctUsers"],
|
|
2755
2772
|
excessiveWakeupRateMetricSet: ["excessiveWakeupRate", "distinctUsers"],
|
|
2756
|
-
|
|
2773
|
+
// API requires the weighted variants — base `stuckBackgroundWakelockRate` is not a valid metric
|
|
2774
|
+
stuckBackgroundWakelockRateMetricSet: [
|
|
2775
|
+
"stuckBackgroundWakelockRate7dUserWeighted",
|
|
2776
|
+
"stuckBackgroundWakelockRate28dUserWeighted",
|
|
2777
|
+
"distinctUsers"
|
|
2778
|
+
],
|
|
2757
2779
|
errorCountMetricSet: ["errorReportCount", "distinctUsers"]
|
|
2758
2780
|
};
|
|
2759
2781
|
function buildQuery(metricSet, options) {
|
|
@@ -2797,9 +2819,7 @@ async function getVitalsOverview(reporting, packageName) {
|
|
|
2797
2819
|
["stuckBackgroundWakelockRateMetricSet", "stuckWakelockRate"]
|
|
2798
2820
|
];
|
|
2799
2821
|
const results = await Promise.allSettled(
|
|
2800
|
-
metricSets.map(
|
|
2801
|
-
([metric]) => reporting.queryMetricSet(packageName, metric, buildQuery(metric))
|
|
2802
|
-
)
|
|
2822
|
+
metricSets.map(([metric]) => reporting.queryMetricSet(packageName, metric, buildQuery(metric)))
|
|
2803
2823
|
);
|
|
2804
2824
|
const overview = {};
|
|
2805
2825
|
for (let i = 0; i < metricSets.length; i++) {
|
|
@@ -3374,9 +3394,15 @@ async function createGrant(client, developerId, email, packageName, permissions)
|
|
|
3374
3394
|
});
|
|
3375
3395
|
}
|
|
3376
3396
|
async function updateGrant(client, developerId, email, packageName, permissions) {
|
|
3377
|
-
return client.grants.patch(
|
|
3378
|
-
|
|
3379
|
-
|
|
3397
|
+
return client.grants.patch(
|
|
3398
|
+
developerId,
|
|
3399
|
+
email,
|
|
3400
|
+
packageName,
|
|
3401
|
+
{
|
|
3402
|
+
appLevelPermissions: permissions
|
|
3403
|
+
},
|
|
3404
|
+
"appLevelPermissions"
|
|
3405
|
+
);
|
|
3380
3406
|
}
|
|
3381
3407
|
async function deleteGrant(client, developerId, email, packageName) {
|
|
3382
3408
|
return client.grants.delete(developerId, email, packageName);
|
|
@@ -3789,7 +3815,9 @@ async function diffOneTimeProduct(client, packageName, productId, localData) {
|
|
|
3789
3815
|
const diffs = [];
|
|
3790
3816
|
const fieldsToCompare = ["listings", "purchaseType", "taxAndComplianceSettings"];
|
|
3791
3817
|
for (const field of fieldsToCompare) {
|
|
3792
|
-
const localVal = JSON.stringify(
|
|
3818
|
+
const localVal = JSON.stringify(
|
|
3819
|
+
localData[field] ?? null
|
|
3820
|
+
);
|
|
3793
3821
|
const remoteVal = JSON.stringify(remote[field] ?? null);
|
|
3794
3822
|
if (localVal !== remoteVal) {
|
|
3795
3823
|
diffs.push({ field, local: localVal, remote: remoteVal });
|
|
@@ -4663,10 +4691,12 @@ var MODULE_SUBDIRS = /* @__PURE__ */ new Set(["dex", "manifest", "res", "assets"
|
|
|
4663
4691
|
function detectCategory(path) {
|
|
4664
4692
|
const lower = path.toLowerCase();
|
|
4665
4693
|
if (lower.endsWith(".dex") || /\/dex\/[^/]+\.dex$/.test(lower)) return "dex";
|
|
4666
|
-
if (lower === "resources.arsc" || lower.endsWith("/resources.arsc") || lower.endsWith("/resources.pb") || /^(([^/]+\/)?res\/)/.test(lower))
|
|
4694
|
+
if (lower === "resources.arsc" || lower.endsWith("/resources.arsc") || lower.endsWith("/resources.pb") || /^(([^/]+\/)?res\/)/.test(lower))
|
|
4695
|
+
return "resources";
|
|
4667
4696
|
if (/^(([^/]+\/)?assets\/)/.test(lower)) return "assets";
|
|
4668
4697
|
if (/^(([^/]+\/)?lib\/)/.test(lower)) return "native-libs";
|
|
4669
|
-
if (lower === "androidmanifest.xml" || lower.endsWith("/androidmanifest.xml") || /^(([^/]+\/)?manifest\/)/.test(lower))
|
|
4698
|
+
if (lower === "androidmanifest.xml" || lower.endsWith("/androidmanifest.xml") || /^(([^/]+\/)?manifest\/)/.test(lower))
|
|
4699
|
+
return "manifest";
|
|
4670
4700
|
if (lower.startsWith("meta-inf/") || lower === "meta-inf") return "signing";
|
|
4671
4701
|
return "other";
|
|
4672
4702
|
}
|
|
@@ -4747,7 +4777,11 @@ async function analyzeBundle(filePath) {
|
|
|
4747
4777
|
}));
|
|
4748
4778
|
const moduleMap = /* @__PURE__ */ new Map();
|
|
4749
4779
|
for (const entry of entries) {
|
|
4750
|
-
const existing = moduleMap.get(entry.module) ?? {
|
|
4780
|
+
const existing = moduleMap.get(entry.module) ?? {
|
|
4781
|
+
compressedSize: 0,
|
|
4782
|
+
uncompressedSize: 0,
|
|
4783
|
+
entries: 0
|
|
4784
|
+
};
|
|
4751
4785
|
existing.compressedSize += entry.compressedSize;
|
|
4752
4786
|
existing.uncompressedSize += entry.uncompressedSize;
|
|
4753
4787
|
existing.entries += 1;
|
|
@@ -4755,7 +4789,11 @@ async function analyzeBundle(filePath) {
|
|
|
4755
4789
|
}
|
|
4756
4790
|
const categoryMap = /* @__PURE__ */ new Map();
|
|
4757
4791
|
for (const entry of entries) {
|
|
4758
|
-
const existing = categoryMap.get(entry.category) ?? {
|
|
4792
|
+
const existing = categoryMap.get(entry.category) ?? {
|
|
4793
|
+
compressedSize: 0,
|
|
4794
|
+
uncompressedSize: 0,
|
|
4795
|
+
entries: 0
|
|
4796
|
+
};
|
|
4759
4797
|
existing.compressedSize += entry.compressedSize;
|
|
4760
4798
|
existing.uncompressedSize += entry.uncompressedSize;
|
|
4761
4799
|
existing.entries += 1;
|
|
@@ -4842,7 +4880,7 @@ async function checkBundleSize(analysis, configPath = ".bundlesize.json") {
|
|
|
4842
4880
|
|
|
4843
4881
|
// src/commands/status.ts
|
|
4844
4882
|
import { mkdir as mkdir6, readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
|
|
4845
|
-
import {
|
|
4883
|
+
import { execFile as execFile2 } from "child_process";
|
|
4846
4884
|
import { join as join8 } from "path";
|
|
4847
4885
|
import { getCacheDir as getCacheDir2 } from "@gpc-cli/config";
|
|
4848
4886
|
var DEFAULT_TTL_SECONDS = 3600;
|
|
@@ -4981,7 +5019,14 @@ async function getAppStatus(client, reporting, packageName, options = {}) {
|
|
|
4981
5019
|
slowStartRate: options.vitalThresholds?.slowStartRate ?? DEFAULT_THRESHOLDS.slowStartRate,
|
|
4982
5020
|
slowRenderingRate: options.vitalThresholds?.slowRenderingRate ?? DEFAULT_THRESHOLDS.slowRenderingRate
|
|
4983
5021
|
};
|
|
4984
|
-
const [
|
|
5022
|
+
const [
|
|
5023
|
+
releasesResult,
|
|
5024
|
+
crashesResult,
|
|
5025
|
+
anrResult,
|
|
5026
|
+
slowStartResult,
|
|
5027
|
+
slowRenderResult,
|
|
5028
|
+
reviewsResult
|
|
5029
|
+
] = await Promise.allSettled([
|
|
4985
5030
|
sections.has("releases") ? getReleasesStatus(client, packageName) : Promise.resolve([]),
|
|
4986
5031
|
sections.has("vitals") ? queryVitalWithTrend(reporting, packageName, "crashRateMetricSet", days) : Promise.resolve(SKIPPED_VITAL),
|
|
4987
5032
|
sections.has("vitals") ? queryVitalWithTrend(reporting, packageName, "anrRateMetricSet", days) : Promise.resolve(SKIPPED_VITAL),
|
|
@@ -5010,7 +5055,12 @@ async function getAppStatus(client, reporting, packageName, options = {}) {
|
|
|
5010
5055
|
releases,
|
|
5011
5056
|
vitals: {
|
|
5012
5057
|
windowDays: days,
|
|
5013
|
-
crashes: toVitalMetric(
|
|
5058
|
+
crashes: toVitalMetric(
|
|
5059
|
+
crashes.current,
|
|
5060
|
+
thresholds.crashRate,
|
|
5061
|
+
crashes.previous,
|
|
5062
|
+
crashes.trend
|
|
5063
|
+
),
|
|
5014
5064
|
anr: toVitalMetric(anr.current, thresholds.anrRate, anr.previous, anr.trend),
|
|
5015
5065
|
slowStarts: toVitalMetric(
|
|
5016
5066
|
slowStart.current,
|
|
@@ -5207,8 +5257,7 @@ function formatStatusDiff(diff, since) {
|
|
|
5207
5257
|
}
|
|
5208
5258
|
async function runWatchLoop(opts) {
|
|
5209
5259
|
if (opts.intervalSeconds < 10) {
|
|
5210
|
-
|
|
5211
|
-
process.exit(2);
|
|
5260
|
+
throw new Error("--watch interval must be at least 10 seconds");
|
|
5212
5261
|
}
|
|
5213
5262
|
let running = true;
|
|
5214
5263
|
const cleanup = () => {
|
|
@@ -5264,20 +5313,20 @@ function sendNotification(title, body) {
|
|
|
5264
5313
|
try {
|
|
5265
5314
|
const p = process.platform;
|
|
5266
5315
|
if (p === "darwin") {
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
{
|
|
5270
|
-
);
|
|
5316
|
+
execFile2("osascript", [
|
|
5317
|
+
"-e",
|
|
5318
|
+
`display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)}`
|
|
5319
|
+
]);
|
|
5271
5320
|
} else if (p === "linux") {
|
|
5272
|
-
|
|
5273
|
-
stdio: "ignore"
|
|
5274
|
-
});
|
|
5321
|
+
execFile2("notify-send", [title, body]);
|
|
5275
5322
|
} else if (p === "win32") {
|
|
5276
|
-
const
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5323
|
+
const psEscape = (s) => s.replace(/'/g, "''").replace(/[\r\n]/g, " ");
|
|
5324
|
+
execFile2("powershell", [
|
|
5325
|
+
"-NoProfile",
|
|
5326
|
+
"-NonInteractive",
|
|
5327
|
+
"-Command",
|
|
5328
|
+
`Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('${psEscape(body)}', '${psEscape(title)}')`
|
|
5329
|
+
]);
|
|
5281
5330
|
}
|
|
5282
5331
|
} catch {
|
|
5283
5332
|
}
|