@gpc-cli/core 0.9.19 → 0.9.21
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 +68 -1
- package/dist/index.js +244 -6
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -629,6 +629,19 @@ declare function redactAuditArgs(entry: AuditEntry): AuditEntry;
|
|
|
629
629
|
* Convenience: create an audit entry for a write command.
|
|
630
630
|
*/
|
|
631
631
|
declare function createAuditEntry(command: string, args: Record<string, unknown>, app?: string): AuditEntry;
|
|
632
|
+
declare function listAuditEvents(options?: {
|
|
633
|
+
limit?: number;
|
|
634
|
+
since?: string;
|
|
635
|
+
command?: string;
|
|
636
|
+
}): Promise<AuditEntry[]>;
|
|
637
|
+
declare function searchAuditEvents(query: string): Promise<AuditEntry[]>;
|
|
638
|
+
declare function clearAuditLog(options?: {
|
|
639
|
+
before?: string;
|
|
640
|
+
dryRun?: boolean;
|
|
641
|
+
}): Promise<{
|
|
642
|
+
deleted: number;
|
|
643
|
+
remaining: number;
|
|
644
|
+
}>;
|
|
632
645
|
|
|
633
646
|
interface WebhookPayload {
|
|
634
647
|
command: string;
|
|
@@ -663,4 +676,58 @@ declare function createPurchaseOption(client: PlayApiClient, packageName: string
|
|
|
663
676
|
declare function activatePurchaseOption(client: PlayApiClient, packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;
|
|
664
677
|
declare function deactivatePurchaseOption(client: PlayApiClient, packageName: string, purchaseOptionId: string): Promise<PurchaseOption>;
|
|
665
678
|
|
|
666
|
-
|
|
679
|
+
interface BundleEntry {
|
|
680
|
+
path: string;
|
|
681
|
+
module: string;
|
|
682
|
+
category: string;
|
|
683
|
+
compressedSize: number;
|
|
684
|
+
uncompressedSize: number;
|
|
685
|
+
}
|
|
686
|
+
interface BundleAnalysis {
|
|
687
|
+
filePath: string;
|
|
688
|
+
fileType: "aab" | "apk";
|
|
689
|
+
totalCompressed: number;
|
|
690
|
+
totalUncompressed: number;
|
|
691
|
+
entryCount: number;
|
|
692
|
+
modules: {
|
|
693
|
+
name: string;
|
|
694
|
+
compressedSize: number;
|
|
695
|
+
uncompressedSize: number;
|
|
696
|
+
entries: number;
|
|
697
|
+
}[];
|
|
698
|
+
categories: {
|
|
699
|
+
name: string;
|
|
700
|
+
compressedSize: number;
|
|
701
|
+
uncompressedSize: number;
|
|
702
|
+
entries: number;
|
|
703
|
+
}[];
|
|
704
|
+
entries: BundleEntry[];
|
|
705
|
+
}
|
|
706
|
+
interface BundleComparison {
|
|
707
|
+
before: {
|
|
708
|
+
path: string;
|
|
709
|
+
totalCompressed: number;
|
|
710
|
+
};
|
|
711
|
+
after: {
|
|
712
|
+
path: string;
|
|
713
|
+
totalCompressed: number;
|
|
714
|
+
};
|
|
715
|
+
sizeDelta: number;
|
|
716
|
+
sizeDeltaPercent: number;
|
|
717
|
+
moduleDeltas: {
|
|
718
|
+
module: string;
|
|
719
|
+
before: number;
|
|
720
|
+
after: number;
|
|
721
|
+
delta: number;
|
|
722
|
+
}[];
|
|
723
|
+
categoryDeltas: {
|
|
724
|
+
category: string;
|
|
725
|
+
before: number;
|
|
726
|
+
after: number;
|
|
727
|
+
delta: number;
|
|
728
|
+
}[];
|
|
729
|
+
}
|
|
730
|
+
declare function analyzeBundle(filePath: string): Promise<BundleAnalysis>;
|
|
731
|
+
declare function compareBundles(before: BundleAnalysis, after: BundleAnalysis): BundleComparison;
|
|
732
|
+
|
|
733
|
+
export { ApiError, type AppInfo, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type CommandContext, ConfigError, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FileValidationResult, GOOGLE_PLAY_LANGUAGES, type GitNotesOptions, type GitReleaseNotes, GpcError, type ImageValidationResult, type InternalSharingUploadResult, type ListIapOptions, type ListSubscriptionsOptions, type ListUsersOptions, type ListVoidedOptions, type ListingDiff, type ListingsResult, type LoadedPlugin, type MigrationResult, NetworkError, type OneTimeProductDiff, PERMISSION_PROPAGATION_WARNING, type ParsedMonth, PluginManager, type PublishOptions, type PublishResult, type PushResult, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type ReviewExportOptions, type ReviewsFilterOptions, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, type ScaffoldOptions, type ScaffoldResult, type Spinner, type SubscriptionDiff, type SyncResult, type ThresholdResult, type UploadResult, type ValidateCheck, type ValidateOptions, type ValidateResult, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WebhookPayload, acknowledgeProductPurchase, activateBasePlan, activateOffer, activatePurchaseOption, addRecoveryTargeting, addTesters, analyzeBundle, batchSyncInAppProducts, cancelRecoveryAction, cancelSubscriptionPurchase, checkThreshold, clearAuditLog, compareBundles, compareVitalsTrend, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createExternalTransaction, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createPurchaseOption, createRecoveryAction, createSpinner, createSubscription, createTrack, deactivateBasePlan, deactivateOffer, deactivatePurchaseOption, deferSubscriptionPurchase, deleteBasePlan, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportDataSafety, exportImages, exportReviews, formatCustomPayload, formatDiscordPayload, formatJunit, formatOutput, formatSlackPayload, generateMigrationPlan, generateNotesFromGit, getAppInfo, getCountryAvailability, getDataSafety, getDeviceTier, getExternalTransaction, getInAppProduct, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getProductPurchase, getPurchaseOption, getReleasesStatus, getReview, getSubscription, getSubscriptionPurchase, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, importDataSafety, importTestersFromCsv, initAudit, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, listAuditEvents, listDeviceTiers, listGeneratedApks, listImages, listInAppProducts, listOffers, listOneTimeOffers, listOneTimeProducts, listPurchaseOptions, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, migratePrices, parseAppfile, parseFastfile, parseGrantArg, parseMonth, promoteRelease, publish, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, removeTesters, removeUser, replyToReview, revokeSubscriptionPurchase, safePath, safePathWithin, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendWebhook, sortResults, syncInAppProducts, updateAppDetails, updateDataSafety, updateInAppProduct, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateImage, validateLanguageCode, validatePackageName, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
package/dist/index.js
CHANGED
|
@@ -1329,7 +1329,7 @@ var ALL_IMAGE_TYPES = [
|
|
|
1329
1329
|
"tvBanner"
|
|
1330
1330
|
];
|
|
1331
1331
|
async function exportImages(client, packageName, dir, options) {
|
|
1332
|
-
const { mkdir: mkdir5, writeFile:
|
|
1332
|
+
const { mkdir: mkdir5, writeFile: writeFile7 } = await import("fs/promises");
|
|
1333
1333
|
const { join: join7 } = await import("path");
|
|
1334
1334
|
const edit = await client.edits.insert(packageName);
|
|
1335
1335
|
try {
|
|
@@ -1366,7 +1366,7 @@ async function exportImages(client, packageName, dir, options) {
|
|
|
1366
1366
|
const response = await fetch(task.url);
|
|
1367
1367
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
1368
1368
|
const filePath = join7(dirPath, `${task.index}.png`);
|
|
1369
|
-
await
|
|
1369
|
+
await writeFile7(filePath, buffer);
|
|
1370
1370
|
return buffer.length;
|
|
1371
1371
|
})
|
|
1372
1372
|
);
|
|
@@ -1956,7 +1956,8 @@ function buildQuery(metricSet, options) {
|
|
|
1956
1956
|
const metrics = METRIC_SET_METRICS[metricSet] ?? ["errorReportCount", "distinctUsers"];
|
|
1957
1957
|
const days = options?.days ?? 30;
|
|
1958
1958
|
const end = /* @__PURE__ */ new Date();
|
|
1959
|
-
|
|
1959
|
+
end.setDate(end.getDate() - 1);
|
|
1960
|
+
const start = new Date(end);
|
|
1960
1961
|
start.setDate(start.getDate() - days);
|
|
1961
1962
|
const query = {
|
|
1962
1963
|
metrics,
|
|
@@ -2036,10 +2037,12 @@ async function searchVitalsErrors(reporting, packageName, options) {
|
|
|
2036
2037
|
}
|
|
2037
2038
|
async function compareVitalsTrend(reporting, packageName, metricSet, days = 7) {
|
|
2038
2039
|
const now = /* @__PURE__ */ new Date();
|
|
2040
|
+
now.setDate(now.getDate() - 1);
|
|
2039
2041
|
const currentEnd = new Date(now);
|
|
2040
2042
|
const currentStart = new Date(now);
|
|
2041
2043
|
currentStart.setDate(currentStart.getDate() - days);
|
|
2042
2044
|
const previousEnd = new Date(currentStart);
|
|
2045
|
+
previousEnd.setDate(previousEnd.getDate() - 1);
|
|
2043
2046
|
const previousStart = new Date(previousEnd);
|
|
2044
2047
|
previousStart.setDate(previousStart.getDate() - days);
|
|
2045
2048
|
const metrics = METRIC_SET_METRICS[metricSet] ?? ["errorReportCount", "distinctUsers"];
|
|
@@ -3374,7 +3377,7 @@ describe("${pluginName}", () => {
|
|
|
3374
3377
|
}
|
|
3375
3378
|
|
|
3376
3379
|
// src/audit.ts
|
|
3377
|
-
import { appendFile, chmod, mkdir as mkdir4 } from "fs/promises";
|
|
3380
|
+
import { appendFile, chmod, mkdir as mkdir4, readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
|
|
3378
3381
|
import { join as join6 } from "path";
|
|
3379
3382
|
var auditDir = null;
|
|
3380
3383
|
function initAudit(configDir) {
|
|
@@ -3437,6 +3440,84 @@ function createAuditEntry(command, args, app) {
|
|
|
3437
3440
|
args
|
|
3438
3441
|
};
|
|
3439
3442
|
}
|
|
3443
|
+
async function listAuditEvents(options) {
|
|
3444
|
+
if (!auditDir) return [];
|
|
3445
|
+
const logPath = join6(auditDir, "audit.log");
|
|
3446
|
+
let content;
|
|
3447
|
+
try {
|
|
3448
|
+
content = await readFile8(logPath, "utf-8");
|
|
3449
|
+
} catch {
|
|
3450
|
+
return [];
|
|
3451
|
+
}
|
|
3452
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
3453
|
+
let entries = [];
|
|
3454
|
+
for (const line of lines) {
|
|
3455
|
+
try {
|
|
3456
|
+
entries.push(JSON.parse(line));
|
|
3457
|
+
} catch {
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
if (options?.since) {
|
|
3461
|
+
const sinceDate = new Date(options.since).getTime();
|
|
3462
|
+
entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceDate);
|
|
3463
|
+
}
|
|
3464
|
+
if (options?.command) {
|
|
3465
|
+
const cmd = options.command.toLowerCase();
|
|
3466
|
+
entries = entries.filter((e) => e.command.toLowerCase().includes(cmd));
|
|
3467
|
+
}
|
|
3468
|
+
if (options?.limit) {
|
|
3469
|
+
entries = entries.slice(-options.limit);
|
|
3470
|
+
}
|
|
3471
|
+
return entries;
|
|
3472
|
+
}
|
|
3473
|
+
async function searchAuditEvents(query) {
|
|
3474
|
+
const all = await listAuditEvents();
|
|
3475
|
+
const q = query.toLowerCase();
|
|
3476
|
+
return all.filter((e) => {
|
|
3477
|
+
const text = JSON.stringify(e).toLowerCase();
|
|
3478
|
+
return text.includes(q);
|
|
3479
|
+
});
|
|
3480
|
+
}
|
|
3481
|
+
async function clearAuditLog(options) {
|
|
3482
|
+
if (!auditDir) return { deleted: 0, remaining: 0 };
|
|
3483
|
+
const logPath = join6(auditDir, "audit.log");
|
|
3484
|
+
let content;
|
|
3485
|
+
try {
|
|
3486
|
+
content = await readFile8(logPath, "utf-8");
|
|
3487
|
+
} catch {
|
|
3488
|
+
return { deleted: 0, remaining: 0 };
|
|
3489
|
+
}
|
|
3490
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
3491
|
+
if (!options?.before) {
|
|
3492
|
+
const count = lines.length;
|
|
3493
|
+
if (!options?.dryRun) {
|
|
3494
|
+
await writeFile5(logPath, "", { encoding: "utf-8", mode: 384 });
|
|
3495
|
+
}
|
|
3496
|
+
return { deleted: count, remaining: 0 };
|
|
3497
|
+
}
|
|
3498
|
+
const beforeDate = new Date(options.before).getTime();
|
|
3499
|
+
const keep = [];
|
|
3500
|
+
const remove = [];
|
|
3501
|
+
for (const line of lines) {
|
|
3502
|
+
try {
|
|
3503
|
+
const entry = JSON.parse(line);
|
|
3504
|
+
if (new Date(entry.timestamp).getTime() < beforeDate) {
|
|
3505
|
+
remove.push(line);
|
|
3506
|
+
} else {
|
|
3507
|
+
keep.push(line);
|
|
3508
|
+
}
|
|
3509
|
+
} catch {
|
|
3510
|
+
keep.push(line);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
if (!options?.dryRun) {
|
|
3514
|
+
await writeFile5(logPath, keep.length > 0 ? keep.join("\n") + "\n" : "", {
|
|
3515
|
+
encoding: "utf-8",
|
|
3516
|
+
mode: 384
|
|
3517
|
+
});
|
|
3518
|
+
}
|
|
3519
|
+
return { deleted: remove.length, remaining: keep.length };
|
|
3520
|
+
}
|
|
3440
3521
|
|
|
3441
3522
|
// src/utils/webhooks.ts
|
|
3442
3523
|
function formatSlackPayload(payload) {
|
|
@@ -3583,7 +3664,7 @@ function detectFileType(filePath) {
|
|
|
3583
3664
|
}
|
|
3584
3665
|
|
|
3585
3666
|
// src/commands/generated-apks.ts
|
|
3586
|
-
import { writeFile as
|
|
3667
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
3587
3668
|
async function listGeneratedApks(client, packageName, versionCode) {
|
|
3588
3669
|
if (!Number.isInteger(versionCode) || versionCode <= 0) {
|
|
3589
3670
|
throw new GpcError(
|
|
@@ -3614,7 +3695,7 @@ async function downloadGeneratedApk(client, packageName, versionCode, apkId, out
|
|
|
3614
3695
|
}
|
|
3615
3696
|
const buffer = await client.generatedApks.download(packageName, versionCode, apkId);
|
|
3616
3697
|
const bytes = new Uint8Array(buffer);
|
|
3617
|
-
await
|
|
3698
|
+
await writeFile6(outputPath, bytes);
|
|
3618
3699
|
return { path: outputPath, sizeBytes: bytes.byteLength };
|
|
3619
3700
|
}
|
|
3620
3701
|
|
|
@@ -3679,6 +3760,158 @@ async function deactivatePurchaseOption(client, packageName, purchaseOptionId) {
|
|
|
3679
3760
|
);
|
|
3680
3761
|
}
|
|
3681
3762
|
}
|
|
3763
|
+
|
|
3764
|
+
// src/commands/bundle-analysis.ts
|
|
3765
|
+
import { readFile as readFile9, stat as stat6 } from "fs/promises";
|
|
3766
|
+
var EOCD_SIGNATURE = 101010256;
|
|
3767
|
+
var CD_SIGNATURE = 33639248;
|
|
3768
|
+
var MODULE_SUBDIRS = /* @__PURE__ */ new Set(["dex", "manifest", "res", "assets", "lib", "resources.pb", "root"]);
|
|
3769
|
+
function detectCategory(path) {
|
|
3770
|
+
const lower = path.toLowerCase();
|
|
3771
|
+
if (lower.endsWith(".dex") || /\/dex\/[^/]+\.dex$/.test(lower)) return "dex";
|
|
3772
|
+
if (lower === "resources.arsc" || lower.endsWith("/resources.arsc") || lower.endsWith("/resources.pb") || /^(([^/]+\/)?res\/)/.test(lower)) return "resources";
|
|
3773
|
+
if (/^(([^/]+\/)?assets\/)/.test(lower)) return "assets";
|
|
3774
|
+
if (/^(([^/]+\/)?lib\/)/.test(lower)) return "native-libs";
|
|
3775
|
+
if (lower === "androidmanifest.xml" || lower.endsWith("/androidmanifest.xml") || /^(([^/]+\/)?manifest\/)/.test(lower)) return "manifest";
|
|
3776
|
+
if (lower.startsWith("meta-inf/") || lower === "meta-inf") return "signing";
|
|
3777
|
+
return "other";
|
|
3778
|
+
}
|
|
3779
|
+
function detectModule(path, isAab) {
|
|
3780
|
+
if (!isAab) return "(root)";
|
|
3781
|
+
const slashIdx = path.indexOf("/");
|
|
3782
|
+
if (slashIdx === -1) return "(root)";
|
|
3783
|
+
const topDir = path.substring(0, slashIdx);
|
|
3784
|
+
const rest = path.substring(slashIdx + 1);
|
|
3785
|
+
if (topDir === "base") return "base";
|
|
3786
|
+
if (topDir === "BUNDLE-METADATA" || topDir === "META-INF") return "(root)";
|
|
3787
|
+
if (path === "BundleConfig.pb") return "(root)";
|
|
3788
|
+
const subDir = rest.split("/")[0] || "";
|
|
3789
|
+
if (MODULE_SUBDIRS.has(subDir)) return topDir;
|
|
3790
|
+
return "(root)";
|
|
3791
|
+
}
|
|
3792
|
+
function parseCentralDirectory(buf) {
|
|
3793
|
+
let eocdOffset = -1;
|
|
3794
|
+
for (let i = buf.length - 22; i >= 0 && i >= buf.length - 65557; i--) {
|
|
3795
|
+
if (buf.readUInt32LE(i) === EOCD_SIGNATURE) {
|
|
3796
|
+
eocdOffset = i;
|
|
3797
|
+
break;
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
if (eocdOffset === -1) {
|
|
3801
|
+
throw new Error("Not a valid ZIP file: EOCD signature not found");
|
|
3802
|
+
}
|
|
3803
|
+
const cdSize = buf.readUInt32LE(eocdOffset + 12);
|
|
3804
|
+
let cdOffset = buf.readUInt32LE(eocdOffset + 16);
|
|
3805
|
+
if (cdOffset === 4294967295) {
|
|
3806
|
+
const zip64LocatorOffset = eocdOffset - 20;
|
|
3807
|
+
if (zip64LocatorOffset >= 0 && buf.readUInt32LE(zip64LocatorOffset) === 117853008) {
|
|
3808
|
+
const zip64EocdOffset = Number(buf.readBigUInt64LE(zip64LocatorOffset + 8));
|
|
3809
|
+
if (zip64EocdOffset >= 0 && zip64EocdOffset < buf.length) {
|
|
3810
|
+
cdOffset = Number(buf.readBigUInt64LE(zip64EocdOffset + 48));
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
const entries = [];
|
|
3815
|
+
let pos = cdOffset;
|
|
3816
|
+
const end = cdOffset + cdSize;
|
|
3817
|
+
while (pos < end && pos + 46 <= buf.length) {
|
|
3818
|
+
const sig = buf.readUInt32LE(pos);
|
|
3819
|
+
if (sig !== CD_SIGNATURE) break;
|
|
3820
|
+
const compressedSize = buf.readUInt32LE(pos + 20);
|
|
3821
|
+
const uncompressedSize = buf.readUInt32LE(pos + 24);
|
|
3822
|
+
const filenameLen = buf.readUInt16LE(pos + 28);
|
|
3823
|
+
const extraLen = buf.readUInt16LE(pos + 30);
|
|
3824
|
+
const commentLen = buf.readUInt16LE(pos + 32);
|
|
3825
|
+
const filename = buf.toString("utf-8", pos + 46, pos + 46 + filenameLen);
|
|
3826
|
+
if (!filename.endsWith("/")) {
|
|
3827
|
+
entries.push({ filename, compressedSize, uncompressedSize });
|
|
3828
|
+
}
|
|
3829
|
+
pos += 46 + filenameLen + extraLen + commentLen;
|
|
3830
|
+
}
|
|
3831
|
+
return entries;
|
|
3832
|
+
}
|
|
3833
|
+
function detectFileType2(filePath) {
|
|
3834
|
+
const lower = filePath.toLowerCase();
|
|
3835
|
+
if (lower.endsWith(".aab")) return "aab";
|
|
3836
|
+
return "apk";
|
|
3837
|
+
}
|
|
3838
|
+
async function analyzeBundle(filePath) {
|
|
3839
|
+
const fileInfo = await stat6(filePath).catch(() => null);
|
|
3840
|
+
if (!fileInfo || !fileInfo.isFile()) {
|
|
3841
|
+
throw new Error(`File not found: ${filePath}`);
|
|
3842
|
+
}
|
|
3843
|
+
const buf = await readFile9(filePath);
|
|
3844
|
+
const cdEntries = parseCentralDirectory(buf);
|
|
3845
|
+
const fileType = detectFileType2(filePath);
|
|
3846
|
+
const isAab = fileType === "aab";
|
|
3847
|
+
const entries = cdEntries.map((e) => ({
|
|
3848
|
+
path: e.filename,
|
|
3849
|
+
module: detectModule(e.filename, isAab),
|
|
3850
|
+
category: detectCategory(e.filename),
|
|
3851
|
+
compressedSize: e.compressedSize,
|
|
3852
|
+
uncompressedSize: e.uncompressedSize
|
|
3853
|
+
}));
|
|
3854
|
+
const moduleMap = /* @__PURE__ */ new Map();
|
|
3855
|
+
for (const entry of entries) {
|
|
3856
|
+
const existing = moduleMap.get(entry.module) ?? { compressedSize: 0, uncompressedSize: 0, entries: 0 };
|
|
3857
|
+
existing.compressedSize += entry.compressedSize;
|
|
3858
|
+
existing.uncompressedSize += entry.uncompressedSize;
|
|
3859
|
+
existing.entries += 1;
|
|
3860
|
+
moduleMap.set(entry.module, existing);
|
|
3861
|
+
}
|
|
3862
|
+
const categoryMap = /* @__PURE__ */ new Map();
|
|
3863
|
+
for (const entry of entries) {
|
|
3864
|
+
const existing = categoryMap.get(entry.category) ?? { compressedSize: 0, uncompressedSize: 0, entries: 0 };
|
|
3865
|
+
existing.compressedSize += entry.compressedSize;
|
|
3866
|
+
existing.uncompressedSize += entry.uncompressedSize;
|
|
3867
|
+
existing.entries += 1;
|
|
3868
|
+
categoryMap.set(entry.category, existing);
|
|
3869
|
+
}
|
|
3870
|
+
const modules = [...moduleMap.entries()].map(([name, data]) => ({ name, ...data })).sort((a, b) => b.compressedSize - a.compressedSize);
|
|
3871
|
+
const categories = [...categoryMap.entries()].map(([name, data]) => ({ name, ...data })).sort((a, b) => b.compressedSize - a.compressedSize);
|
|
3872
|
+
const totalCompressed = entries.reduce((sum, e) => sum + e.compressedSize, 0);
|
|
3873
|
+
const totalUncompressed = entries.reduce((sum, e) => sum + e.uncompressedSize, 0);
|
|
3874
|
+
return {
|
|
3875
|
+
filePath,
|
|
3876
|
+
fileType,
|
|
3877
|
+
totalCompressed,
|
|
3878
|
+
totalUncompressed,
|
|
3879
|
+
entryCount: entries.length,
|
|
3880
|
+
modules,
|
|
3881
|
+
categories,
|
|
3882
|
+
entries
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
function compareBundles(before, after) {
|
|
3886
|
+
const sizeDelta = after.totalCompressed - before.totalCompressed;
|
|
3887
|
+
const sizeDeltaPercent = before.totalCompressed > 0 ? Math.round(sizeDelta / before.totalCompressed * 100 * 10) / 10 : 0;
|
|
3888
|
+
const allModules = /* @__PURE__ */ new Set([
|
|
3889
|
+
...before.modules.map((m) => m.name),
|
|
3890
|
+
...after.modules.map((m) => m.name)
|
|
3891
|
+
]);
|
|
3892
|
+
const moduleDeltas = [...allModules].map((module) => {
|
|
3893
|
+
const b = before.modules.find((m) => m.name === module)?.compressedSize ?? 0;
|
|
3894
|
+
const a = after.modules.find((m) => m.name === module)?.compressedSize ?? 0;
|
|
3895
|
+
return { module, before: b, after: a, delta: a - b };
|
|
3896
|
+
}).sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));
|
|
3897
|
+
const allCategories = /* @__PURE__ */ new Set([
|
|
3898
|
+
...before.categories.map((c) => c.name),
|
|
3899
|
+
...after.categories.map((c) => c.name)
|
|
3900
|
+
]);
|
|
3901
|
+
const categoryDeltas = [...allCategories].map((category) => {
|
|
3902
|
+
const b = before.categories.find((c) => c.name === category)?.compressedSize ?? 0;
|
|
3903
|
+
const a = after.categories.find((c) => c.name === category)?.compressedSize ?? 0;
|
|
3904
|
+
return { category, before: b, after: a, delta: a - b };
|
|
3905
|
+
}).sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));
|
|
3906
|
+
return {
|
|
3907
|
+
before: { path: before.filePath, totalCompressed: before.totalCompressed },
|
|
3908
|
+
after: { path: after.filePath, totalCompressed: after.totalCompressed },
|
|
3909
|
+
sizeDelta,
|
|
3910
|
+
sizeDeltaPercent,
|
|
3911
|
+
moduleDeltas,
|
|
3912
|
+
categoryDeltas
|
|
3913
|
+
};
|
|
3914
|
+
}
|
|
3682
3915
|
export {
|
|
3683
3916
|
ApiError,
|
|
3684
3917
|
ConfigError,
|
|
@@ -3695,10 +3928,13 @@ export {
|
|
|
3695
3928
|
activatePurchaseOption,
|
|
3696
3929
|
addRecoveryTargeting,
|
|
3697
3930
|
addTesters,
|
|
3931
|
+
analyzeBundle,
|
|
3698
3932
|
batchSyncInAppProducts,
|
|
3699
3933
|
cancelRecoveryAction,
|
|
3700
3934
|
cancelSubscriptionPurchase,
|
|
3701
3935
|
checkThreshold,
|
|
3936
|
+
clearAuditLog,
|
|
3937
|
+
compareBundles,
|
|
3702
3938
|
compareVitalsTrend,
|
|
3703
3939
|
consumeProductPurchase,
|
|
3704
3940
|
convertRegionPrices,
|
|
@@ -3781,6 +4017,7 @@ export {
|
|
|
3781
4017
|
isValidBcp47,
|
|
3782
4018
|
isValidReportType,
|
|
3783
4019
|
isValidStatsDimension,
|
|
4020
|
+
listAuditEvents,
|
|
3784
4021
|
listDeviceTiers,
|
|
3785
4022
|
listGeneratedApks,
|
|
3786
4023
|
listImages,
|
|
@@ -3819,6 +4056,7 @@ export {
|
|
|
3819
4056
|
safePath,
|
|
3820
4057
|
safePathWithin,
|
|
3821
4058
|
scaffoldPlugin,
|
|
4059
|
+
searchAuditEvents,
|
|
3822
4060
|
searchVitalsErrors,
|
|
3823
4061
|
sendWebhook,
|
|
3824
4062
|
sortResults,
|