@gpc-cli/core 0.9.18 → 0.9.20

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
@@ -493,8 +493,8 @@ interface ParsedMonth {
493
493
  month: number;
494
494
  }
495
495
  declare function parseMonth(monthStr: string): ParsedMonth;
496
- declare function listReports(client: PlayApiClient, packageName: string, reportType: ReportType, year: number, month: number): Promise<ReportBucket[]>;
497
- declare function downloadReport(client: PlayApiClient, packageName: string, reportType: ReportType, year: number, month: number): Promise<string>;
496
+ declare function listReports(_client: PlayApiClient, _packageName: string, reportType: ReportType, _year: number, _month: number): Promise<ReportBucket[]>;
497
+ declare function downloadReport(_client: PlayApiClient, _packageName: string, reportType: ReportType, _year: number, _month: number): Promise<string>;
498
498
 
499
499
  declare function listTesters(client: PlayApiClient, packageName: string, track: string): Promise<Testers>;
500
500
  declare function addTesters(client: PlayApiClient, packageName: string, track: string, groupEmails: string[]): Promise<Testers>;
@@ -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,4 @@ 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
- export { ApiError, type AppInfo, type AuditEntry, type BatchSyncResult, 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, batchSyncInAppProducts, cancelRecoveryAction, cancelSubscriptionPurchase, checkThreshold, 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, 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, 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 };
679
+ export { ApiError, type AppInfo, type AuditEntry, type BatchSyncResult, 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, batchSyncInAppProducts, cancelRecoveryAction, cancelSubscriptionPurchase, checkThreshold, clearAuditLog, 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
@@ -217,8 +217,8 @@ function toTestCases(data, commandName) {
217
217
  const cases = [];
218
218
  let failures = 0;
219
219
  if (Array.isArray(data)) {
220
- for (const item of data) {
221
- const tc = buildTestCase(item, commandName);
220
+ for (let i = 0; i < data.length; i++) {
221
+ const tc = buildTestCase(data[i], commandName, i);
222
222
  cases.push(tc.xml);
223
223
  if (tc.failed) failures++;
224
224
  }
@@ -233,7 +233,7 @@ function toTestCases(data, commandName) {
233
233
  }
234
234
  return { cases, failures };
235
235
  }
236
- function buildTestCase(item, commandName) {
236
+ function buildTestCase(item, commandName, index = 0) {
237
237
  if (typeof item !== "object" || item === null) {
238
238
  const text = String(item);
239
239
  return {
@@ -243,7 +243,9 @@ function buildTestCase(item, commandName) {
243
243
  }
244
244
  const record = item;
245
245
  const name = escapeXml(
246
- String(record["name"] ?? record["title"] ?? record["sku"] ?? record["id"] ?? JSON.stringify(item))
246
+ String(
247
+ record["name"] ?? record["title"] ?? record["sku"] ?? record["id"] ?? record["productId"] ?? record["packageName"] ?? record["trackId"] ?? record["region"] ?? record["languageCode"] ?? `item-${index + 1}`
248
+ )
247
249
  );
248
250
  const classname = `gpc.${escapeXml(commandName)}`;
249
251
  const breached = record["breached"];
@@ -1327,7 +1329,7 @@ var ALL_IMAGE_TYPES = [
1327
1329
  "tvBanner"
1328
1330
  ];
1329
1331
  async function exportImages(client, packageName, dir, options) {
1330
- const { mkdir: mkdir5, writeFile: writeFile6 } = await import("fs/promises");
1332
+ const { mkdir: mkdir5, writeFile: writeFile7 } = await import("fs/promises");
1331
1333
  const { join: join7 } = await import("path");
1332
1334
  const edit = await client.edits.insert(packageName);
1333
1335
  try {
@@ -1364,7 +1366,7 @@ async function exportImages(client, packageName, dir, options) {
1364
1366
  const response = await fetch(task.url);
1365
1367
  const buffer = Buffer.from(await response.arrayBuffer());
1366
1368
  const filePath = join7(dirPath, `${task.index}.png`);
1367
- await writeFile6(filePath, buffer);
1369
+ await writeFile7(filePath, buffer);
1368
1370
  return buffer.length;
1369
1371
  })
1370
1372
  );
@@ -1941,19 +1943,26 @@ function csvEscape(value) {
1941
1943
  }
1942
1944
 
1943
1945
  // src/commands/vitals.ts
1944
- function buildQuery(options) {
1946
+ var METRIC_SET_METRICS = {
1947
+ crashRateMetricSet: ["crashRate", "userPerceivedCrashRate", "distinctUsers"],
1948
+ anrRateMetricSet: ["anrRate", "userPerceivedAnrRate", "distinctUsers"],
1949
+ slowStartRateMetricSet: ["slowStartRate", "distinctUsers"],
1950
+ slowRenderingRateMetricSet: ["slowRenderingRate", "distinctUsers"],
1951
+ excessiveWakeupRateMetricSet: ["excessiveWakeupRate", "distinctUsers"],
1952
+ stuckBackgroundWakelockRateMetricSet: ["stuckBackgroundWakelockRate", "distinctUsers"],
1953
+ errorCountMetricSet: ["errorReportCount", "distinctUsers"]
1954
+ };
1955
+ function buildQuery(metricSet, options) {
1956
+ const metrics = METRIC_SET_METRICS[metricSet] ?? ["errorReportCount", "distinctUsers"];
1957
+ const days = options?.days ?? 30;
1958
+ const end = /* @__PURE__ */ new Date();
1959
+ end.setDate(end.getDate() - 1);
1960
+ const start = new Date(end);
1961
+ start.setDate(start.getDate() - days);
1945
1962
  const query = {
1946
- metrics: ["errorReportCount", "distinctUsers"]
1947
- };
1948
- if (options?.dimension) {
1949
- query.dimensions = [options.dimension];
1950
- }
1951
- if (options?.days) {
1952
- const end = /* @__PURE__ */ new Date();
1953
- const start = /* @__PURE__ */ new Date();
1954
- start.setDate(start.getDate() - options.days);
1955
- query.timelineSpec = {
1956
- aggregationPeriod: options.aggregation ?? "DAILY",
1963
+ metrics,
1964
+ timelineSpec: {
1965
+ aggregationPeriod: options?.aggregation ?? "DAILY",
1957
1966
  startTime: {
1958
1967
  year: start.getFullYear(),
1959
1968
  month: start.getMonth() + 1,
@@ -1964,12 +1973,15 @@ function buildQuery(options) {
1964
1973
  month: end.getMonth() + 1,
1965
1974
  day: end.getDate()
1966
1975
  }
1967
- };
1976
+ }
1977
+ };
1978
+ if (options?.dimension) {
1979
+ query.dimensions = [options.dimension];
1968
1980
  }
1969
1981
  return query;
1970
1982
  }
1971
1983
  async function queryMetric(reporting, packageName, metricSet, options) {
1972
- const query = buildQuery(options);
1984
+ const query = buildQuery(metricSet, options);
1973
1985
  return reporting.queryMetricSet(packageName, metricSet, query);
1974
1986
  }
1975
1987
  async function getVitalsOverview(reporting, packageName) {
@@ -1983,9 +1995,7 @@ async function getVitalsOverview(reporting, packageName) {
1983
1995
  ];
1984
1996
  const results = await Promise.allSettled(
1985
1997
  metricSets.map(
1986
- ([metric]) => reporting.queryMetricSet(packageName, metric, {
1987
- metrics: ["errorReportCount", "distinctUsers"]
1988
- })
1998
+ ([metric]) => reporting.queryMetricSet(packageName, metric, buildQuery(metric))
1989
1999
  )
1990
2000
  );
1991
2001
  const overview = {};
@@ -2027,14 +2037,16 @@ async function searchVitalsErrors(reporting, packageName, options) {
2027
2037
  }
2028
2038
  async function compareVitalsTrend(reporting, packageName, metricSet, days = 7) {
2029
2039
  const now = /* @__PURE__ */ new Date();
2040
+ now.setDate(now.getDate() - 1);
2030
2041
  const currentEnd = new Date(now);
2031
2042
  const currentStart = new Date(now);
2032
2043
  currentStart.setDate(currentStart.getDate() - days);
2033
2044
  const previousEnd = new Date(currentStart);
2034
2045
  const previousStart = new Date(previousEnd);
2035
2046
  previousStart.setDate(previousStart.getDate() - days);
2047
+ const metrics = METRIC_SET_METRICS[metricSet] ?? ["errorReportCount", "distinctUsers"];
2036
2048
  const makeQuery = (start, end) => ({
2037
- metrics: ["errorReportCount", "distinctUsers"],
2049
+ metrics,
2038
2050
  timelineSpec: {
2039
2051
  aggregationPeriod: "DAILY",
2040
2052
  startTime: { year: start.getFullYear(), month: start.getMonth() + 1, day: start.getDate() },
@@ -2610,39 +2622,21 @@ function parseMonth(monthStr) {
2610
2622
  }
2611
2623
  return { year, month };
2612
2624
  }
2613
- async function listReports(client, packageName, reportType, year, month) {
2614
- const response = await client.reports.list(packageName, reportType, year, month);
2615
- return response.reports || [];
2625
+ async function listReports(_client, _packageName, reportType, _year, _month) {
2626
+ throw new GpcError(
2627
+ `Report listing for "${reportType}" is not available through the Google Play Developer API.`,
2628
+ "REPORT_NOT_SUPPORTED",
2629
+ 1,
2630
+ isFinancialReportType(reportType) ? "Financial reports are delivered via Google Cloud Storage. Access them from Play Console \u2192 Download reports \u2192 Financial." : "Stats reports are delivered via Google Cloud Storage. For real-time metrics, use 'gpc vitals' commands."
2631
+ );
2616
2632
  }
2617
- async function downloadReport(client, packageName, reportType, year, month) {
2618
- const reports = await listReports(client, packageName, reportType, year, month);
2619
- const monthPadded = String(month).padStart(2, "0");
2620
- if (reports.length === 0) {
2621
- throw new GpcError(
2622
- `No ${reportType} reports found for ${year}-${monthPadded}.`,
2623
- "REPORT_NOT_FOUND",
2624
- 1,
2625
- `Reports may not be available yet for this period. Financial reports are typically available a few days after the month ends. Try a different month or report type.`
2626
- );
2627
- }
2628
- const bucket = reports[0];
2629
- if (!bucket) {
2630
- throw new GpcError(
2631
- `No ${reportType} reports found for ${year}-${monthPadded}.`,
2632
- "REPORT_NOT_FOUND",
2633
- 1,
2634
- `Reports may not be available yet for this period. Try a different month or report type.`
2635
- );
2636
- }
2637
- const uri = bucket.uri;
2638
- const response = await fetch(uri);
2639
- if (!response.ok) {
2640
- throw new NetworkError(
2641
- `Failed to download report from signed URI: HTTP ${response.status}`,
2642
- "The signed download URL may have expired. Retry the command to generate a fresh URL."
2643
- );
2644
- }
2645
- return response.text();
2633
+ async function downloadReport(_client, _packageName, reportType, _year, _month) {
2634
+ throw new GpcError(
2635
+ `Report download for "${reportType}" is not available through the Google Play Developer API.`,
2636
+ "REPORT_NOT_SUPPORTED",
2637
+ 1,
2638
+ isFinancialReportType(reportType) ? "Financial reports are delivered via Google Cloud Storage. Access them from Play Console \u2192 Download reports \u2192 Financial." : "Stats reports are delivered via Google Cloud Storage. For real-time metrics, use 'gpc vitals' commands."
2639
+ );
2646
2640
  }
2647
2641
 
2648
2642
  // src/commands/users.ts
@@ -3382,7 +3376,7 @@ describe("${pluginName}", () => {
3382
3376
  }
3383
3377
 
3384
3378
  // src/audit.ts
3385
- import { appendFile, chmod, mkdir as mkdir4 } from "fs/promises";
3379
+ import { appendFile, chmod, mkdir as mkdir4, readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
3386
3380
  import { join as join6 } from "path";
3387
3381
  var auditDir = null;
3388
3382
  function initAudit(configDir) {
@@ -3445,6 +3439,84 @@ function createAuditEntry(command, args, app) {
3445
3439
  args
3446
3440
  };
3447
3441
  }
3442
+ async function listAuditEvents(options) {
3443
+ if (!auditDir) return [];
3444
+ const logPath = join6(auditDir, "audit.log");
3445
+ let content;
3446
+ try {
3447
+ content = await readFile8(logPath, "utf-8");
3448
+ } catch {
3449
+ return [];
3450
+ }
3451
+ const lines = content.trim().split("\n").filter(Boolean);
3452
+ let entries = [];
3453
+ for (const line of lines) {
3454
+ try {
3455
+ entries.push(JSON.parse(line));
3456
+ } catch {
3457
+ }
3458
+ }
3459
+ if (options?.since) {
3460
+ const sinceDate = new Date(options.since).getTime();
3461
+ entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceDate);
3462
+ }
3463
+ if (options?.command) {
3464
+ const cmd = options.command.toLowerCase();
3465
+ entries = entries.filter((e) => e.command.toLowerCase().includes(cmd));
3466
+ }
3467
+ if (options?.limit) {
3468
+ entries = entries.slice(-options.limit);
3469
+ }
3470
+ return entries;
3471
+ }
3472
+ async function searchAuditEvents(query) {
3473
+ const all = await listAuditEvents();
3474
+ const q = query.toLowerCase();
3475
+ return all.filter((e) => {
3476
+ const text = JSON.stringify(e).toLowerCase();
3477
+ return text.includes(q);
3478
+ });
3479
+ }
3480
+ async function clearAuditLog(options) {
3481
+ if (!auditDir) return { deleted: 0, remaining: 0 };
3482
+ const logPath = join6(auditDir, "audit.log");
3483
+ let content;
3484
+ try {
3485
+ content = await readFile8(logPath, "utf-8");
3486
+ } catch {
3487
+ return { deleted: 0, remaining: 0 };
3488
+ }
3489
+ const lines = content.trim().split("\n").filter(Boolean);
3490
+ if (!options?.before) {
3491
+ const count = lines.length;
3492
+ if (!options?.dryRun) {
3493
+ await writeFile5(logPath, "", { encoding: "utf-8", mode: 384 });
3494
+ }
3495
+ return { deleted: count, remaining: 0 };
3496
+ }
3497
+ const beforeDate = new Date(options.before).getTime();
3498
+ const keep = [];
3499
+ const remove = [];
3500
+ for (const line of lines) {
3501
+ try {
3502
+ const entry = JSON.parse(line);
3503
+ if (new Date(entry.timestamp).getTime() < beforeDate) {
3504
+ remove.push(line);
3505
+ } else {
3506
+ keep.push(line);
3507
+ }
3508
+ } catch {
3509
+ keep.push(line);
3510
+ }
3511
+ }
3512
+ if (!options?.dryRun) {
3513
+ await writeFile5(logPath, keep.length > 0 ? keep.join("\n") + "\n" : "", {
3514
+ encoding: "utf-8",
3515
+ mode: 384
3516
+ });
3517
+ }
3518
+ return { deleted: remove.length, remaining: keep.length };
3519
+ }
3448
3520
 
3449
3521
  // src/utils/webhooks.ts
3450
3522
  function formatSlackPayload(payload) {
@@ -3591,7 +3663,7 @@ function detectFileType(filePath) {
3591
3663
  }
3592
3664
 
3593
3665
  // src/commands/generated-apks.ts
3594
- import { writeFile as writeFile5 } from "fs/promises";
3666
+ import { writeFile as writeFile6 } from "fs/promises";
3595
3667
  async function listGeneratedApks(client, packageName, versionCode) {
3596
3668
  if (!Number.isInteger(versionCode) || versionCode <= 0) {
3597
3669
  throw new GpcError(
@@ -3622,7 +3694,7 @@ async function downloadGeneratedApk(client, packageName, versionCode, apkId, out
3622
3694
  }
3623
3695
  const buffer = await client.generatedApks.download(packageName, versionCode, apkId);
3624
3696
  const bytes = new Uint8Array(buffer);
3625
- await writeFile5(outputPath, bytes);
3697
+ await writeFile6(outputPath, bytes);
3626
3698
  return { path: outputPath, sizeBytes: bytes.byteLength };
3627
3699
  }
3628
3700
 
@@ -3707,6 +3779,7 @@ export {
3707
3779
  cancelRecoveryAction,
3708
3780
  cancelSubscriptionPurchase,
3709
3781
  checkThreshold,
3782
+ clearAuditLog,
3710
3783
  compareVitalsTrend,
3711
3784
  consumeProductPurchase,
3712
3785
  convertRegionPrices,
@@ -3789,6 +3862,7 @@ export {
3789
3862
  isValidBcp47,
3790
3863
  isValidReportType,
3791
3864
  isValidStatsDimension,
3865
+ listAuditEvents,
3792
3866
  listDeviceTiers,
3793
3867
  listGeneratedApks,
3794
3868
  listImages,
@@ -3827,6 +3901,7 @@ export {
3827
3901
  safePath,
3828
3902
  safePathWithin,
3829
3903
  scaffoldPlugin,
3904
+ searchAuditEvents,
3830
3905
  searchVitalsErrors,
3831
3906
  sendWebhook,
3832
3907
  sortResults,