@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 +16 -3
- package/dist/index.js +134 -59
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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(
|
|
497
|
-
declare function downloadReport(
|
|
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 (
|
|
221
|
-
const tc = buildTestCase(
|
|
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(
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
|
1947
|
-
|
|
1948
|
-
|
|
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
|
|
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(
|
|
2614
|
-
|
|
2615
|
-
|
|
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(
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
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
|
|
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
|
|
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,
|