@gpc-cli/cli 0.9.33 → 0.9.35
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/README.md +21 -16
- package/dist/anomalies-QZJGQXTZ.js +59 -0
- package/dist/anomalies-QZJGQXTZ.js.map +1 -0
- package/dist/{apps-CVBURB5V.js → apps-J2446UDA.js} +2 -2
- package/dist/{apps-CVBURB5V.js.map → apps-J2446UDA.js.map} +1 -1
- package/dist/{audit-A4BP27DN.js → audit-4UPTLW37.js} +2 -3
- package/dist/{audit-A4BP27DN.js.map → audit-4UPTLW37.js.map} +1 -1
- package/dist/{auth-QSDK7NUO.js → auth-KPVEGAWV.js} +101 -9
- package/dist/auth-KPVEGAWV.js.map +1 -0
- package/dist/bin.js +14 -3
- package/dist/bin.js.map +1 -1
- package/dist/{bundle-7IF5FIB4.js → bundle-7XYHNVNF.js} +27 -2
- package/dist/bundle-7XYHNVNF.js.map +1 -0
- package/dist/{cache-SHWAVON6.js → cache-K23N6GJR.js} +1 -1
- package/dist/cache-K23N6GJR.js.map +1 -0
- package/dist/{chunk-UH3TMIAL.js → chunk-43SH6XEJ.js} +5 -5
- package/dist/{chunk-UH3TMIAL.js.map → chunk-43SH6XEJ.js.map} +1 -1
- package/dist/chunk-7BXCQKJG.js +37 -0
- package/dist/chunk-7BXCQKJG.js.map +1 -0
- package/dist/{chunk-DMMFPBYF.js → chunk-DDTPDKTB.js} +116 -31
- package/dist/chunk-DDTPDKTB.js.map +1 -0
- package/dist/{config-2L7QUYWP.js → config-REB7NINL.js} +14 -4
- package/dist/config-REB7NINL.js.map +1 -0
- package/dist/{data-safety-GDPKV5PN.js → data-safety-GN5VBKAK.js} +1 -1
- package/dist/data-safety-GN5VBKAK.js.map +1 -0
- package/dist/{doctor-UZB2UB5X.js → doctor-QDIFTXNB.js} +54 -6
- package/dist/doctor-QDIFTXNB.js.map +1 -0
- package/dist/enterprise-IH5HXYRB.js +65 -0
- package/dist/enterprise-IH5HXYRB.js.map +1 -0
- package/dist/{feedback-W5MZMRF2.js → feedback-NVGHRU7A.js} +3 -3
- package/dist/feedback-NVGHRU7A.js.map +1 -0
- package/dist/games-X57AGM3E.js +80 -0
- package/dist/games-X57AGM3E.js.map +1 -0
- package/dist/grants-CXTTYKR3.js +123 -0
- package/dist/grants-CXTTYKR3.js.map +1 -0
- package/dist/{iap-BBHF7BLZ.js → iap-MBDD7VWP.js} +6 -38
- package/dist/iap-MBDD7VWP.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{listings-VSBHQY5H.js → listings-7TWCGGMS.js} +94 -9
- package/dist/listings-7TWCGGMS.js.map +1 -0
- package/dist/{migrate-XQV7P4R7.js → migrate-OHN2FDY6.js} +13 -3
- package/dist/migrate-OHN2FDY6.js.map +1 -0
- package/dist/{publish-I6WJGR4S.js → publish-XM43UA5R.js} +2 -1
- package/dist/publish-XM43UA5R.js.map +1 -0
- package/dist/{purchases-YRO6B7M6.js → purchases-WIDU3FDQ.js} +28 -1
- package/dist/purchases-WIDU3FDQ.js.map +1 -0
- package/dist/quickstart-N7FXM5RQ.js +87 -0
- package/dist/quickstart-N7FXM5RQ.js.map +1 -0
- package/dist/quota-SNUI75NM.js +53 -0
- package/dist/quota-SNUI75NM.js.map +1 -0
- package/dist/{releases-ANC54YWF.js → releases-YRYM7JXC.js} +5 -1
- package/dist/releases-YRYM7JXC.js.map +1 -0
- package/dist/{reports-N5X66IUN.js → reports-YOT4DQGL.js} +1 -1
- package/dist/reports-YOT4DQGL.js.map +1 -0
- package/dist/{reviews-GJAQ5OVC.js → reviews-NN7YQITF.js} +59 -3
- package/dist/reviews-NN7YQITF.js.map +1 -0
- package/dist/{status-6Y2CHHVD.js → status-L5S2FGZ4.js} +45 -5
- package/dist/status-L5S2FGZ4.js.map +1 -0
- package/dist/{subscriptions-Z5ZPVUFM.js → subscriptions-OXAE7SNS.js} +32 -1
- package/dist/subscriptions-OXAE7SNS.js.map +1 -0
- package/dist/{testers-UWSUGGVT.js → testers-SDLVWQ2Z.js} +1 -1
- package/dist/testers-SDLVWQ2Z.js.map +1 -0
- package/dist/{tracks-XFUN7JJX.js → tracks-NERFFEDT.js} +2 -2
- package/dist/tracks-NERFFEDT.js.map +1 -0
- package/dist/train-PX5Z26PQ.js +150 -0
- package/dist/train-PX5Z26PQ.js.map +1 -0
- package/dist/{update-NIVJLUNH.js → update-6XSZRXSU.js} +3 -3
- package/dist/{update-NIVJLUNH.js.map → update-6XSZRXSU.js.map} +1 -1
- package/dist/{validate-MHLPENCM.js → validate-NC4MWKOB.js} +9 -4
- package/dist/validate-NC4MWKOB.js.map +1 -0
- package/dist/{version-7AI5IHVK.js → version-2X32UAAE.js} +3 -3
- package/dist/version-2X32UAAE.js.map +1 -0
- package/dist/{vitals-KSNAVN5F.js → vitals-LFL75LA6.js} +135 -4
- package/dist/vitals-LFL75LA6.js.map +1 -0
- package/package.json +8 -4
- package/dist/auth-QSDK7NUO.js.map +0 -1
- package/dist/bundle-7IF5FIB4.js.map +0 -1
- package/dist/cache-SHWAVON6.js.map +0 -1
- package/dist/chunk-DMMFPBYF.js.map +0 -1
- package/dist/config-2L7QUYWP.js.map +0 -1
- package/dist/data-safety-GDPKV5PN.js.map +0 -1
- package/dist/doctor-UZB2UB5X.js.map +0 -1
- package/dist/feedback-W5MZMRF2.js.map +0 -1
- package/dist/iap-BBHF7BLZ.js.map +0 -1
- package/dist/listings-VSBHQY5H.js.map +0 -1
- package/dist/migrate-XQV7P4R7.js.map +0 -1
- package/dist/publish-I6WJGR4S.js.map +0 -1
- package/dist/purchases-YRO6B7M6.js.map +0 -1
- package/dist/releases-ANC54YWF.js.map +0 -1
- package/dist/reports-N5X66IUN.js.map +0 -1
- package/dist/reviews-GJAQ5OVC.js.map +0 -1
- package/dist/status-6Y2CHHVD.js.map +0 -1
- package/dist/subscriptions-Z5ZPVUFM.js.map +0 -1
- package/dist/testers-UWSUGGVT.js.map +0 -1
- package/dist/tracks-XFUN7JJX.js.map +0 -1
- package/dist/validate-MHLPENCM.js.map +0 -1
- package/dist/version-7AI5IHVK.js.map +0 -1
- package/dist/vitals-KSNAVN5F.js.map +0 -1
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
green,
|
|
4
|
+
red,
|
|
5
|
+
yellow
|
|
6
|
+
} from "./chunk-7BXCQKJG.js";
|
|
2
7
|
import {
|
|
3
8
|
getOutputFormat
|
|
4
9
|
} from "./chunk-ELXAK7GI.js";
|
|
@@ -15,9 +20,12 @@ import {
|
|
|
15
20
|
getVitalsRendering,
|
|
16
21
|
getVitalsBattery,
|
|
17
22
|
getVitalsMemory,
|
|
23
|
+
getVitalsLmk,
|
|
18
24
|
getVitalsAnomalies,
|
|
19
25
|
searchVitalsErrors,
|
|
20
26
|
compareVitalsTrend,
|
|
27
|
+
compareVersionVitals,
|
|
28
|
+
watchVitalsWithAutoHalt,
|
|
21
29
|
checkThreshold,
|
|
22
30
|
formatOutput
|
|
23
31
|
} from "@gpc-cli/core";
|
|
@@ -53,7 +61,9 @@ var THRESHOLD_CONFIG_KEYS = {
|
|
|
53
61
|
startup: "slowStartRate",
|
|
54
62
|
rendering: "slowRenderingRate",
|
|
55
63
|
battery: "excessiveWakeupRate",
|
|
56
|
-
memory: "stuckWakelockRate"
|
|
64
|
+
memory: "stuckWakelockRate",
|
|
65
|
+
wakeup: "excessiveWakeupRate",
|
|
66
|
+
lmk: "stuckWakelockRate"
|
|
57
67
|
};
|
|
58
68
|
function validateDimension(dim) {
|
|
59
69
|
if (!VALID_DIMENSIONS.includes(dim)) {
|
|
@@ -75,7 +85,7 @@ function registerMetricCommand(parent, name, description, fn, program) {
|
|
|
75
85
|
days: options.days
|
|
76
86
|
});
|
|
77
87
|
if (format !== "json" && (!result.rows || result.rows.length === 0)) {
|
|
78
|
-
console.log("No vitals data available
|
|
88
|
+
console.log(`${yellow("\u26A0")} No vitals data available.`);
|
|
79
89
|
return;
|
|
80
90
|
}
|
|
81
91
|
if (format !== "json" && result.rows) {
|
|
@@ -112,7 +122,7 @@ function registerMetricCommand(parent, name, description, fn, program) {
|
|
|
112
122
|
const value = firstMetric ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value) : void 0;
|
|
113
123
|
const check = checkThreshold(value, threshold);
|
|
114
124
|
if (check.breached) {
|
|
115
|
-
console.error(
|
|
125
|
+
console.error(`${red("\u2717")} Threshold breached: ${check.value} > ${check.threshold}`);
|
|
116
126
|
process.exit(6);
|
|
117
127
|
}
|
|
118
128
|
}
|
|
@@ -180,6 +190,20 @@ function registerVitalsCommands(program) {
|
|
|
180
190
|
program
|
|
181
191
|
);
|
|
182
192
|
registerMetricCommand(vitals, "memory", "Query stuck wakelock metrics", getVitalsMemory, program);
|
|
193
|
+
registerMetricCommand(
|
|
194
|
+
vitals,
|
|
195
|
+
"wakeup",
|
|
196
|
+
"Query excessive wakeup rate metrics",
|
|
197
|
+
getVitalsBattery,
|
|
198
|
+
program
|
|
199
|
+
);
|
|
200
|
+
registerMetricCommand(
|
|
201
|
+
vitals,
|
|
202
|
+
"lmk",
|
|
203
|
+
"Query low-memory kill (stuck wakelock) metrics",
|
|
204
|
+
getVitalsLmk,
|
|
205
|
+
program
|
|
206
|
+
);
|
|
183
207
|
vitals.command("anomalies").description("Detect anomalies in app vitals").action(async () => {
|
|
184
208
|
const config = await loadConfig();
|
|
185
209
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
@@ -243,8 +267,115 @@ function registerVitalsCommands(program) {
|
|
|
243
267
|
process.exit(4);
|
|
244
268
|
}
|
|
245
269
|
});
|
|
270
|
+
vitals.command("compare-versions <v1> <v2>").description("Compare vitals side-by-side for two version codes").option("--days <n>", "Number of days to query", (v) => parseInt(v, 10), 30).action(async (v1, v2, options) => {
|
|
271
|
+
const config = await loadConfig();
|
|
272
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
273
|
+
const reporting = await getReportingClient(config);
|
|
274
|
+
const format = getOutputFormat(program, config);
|
|
275
|
+
try {
|
|
276
|
+
const result = await compareVersionVitals(reporting, packageName, v1, v2, {
|
|
277
|
+
days: options.days
|
|
278
|
+
});
|
|
279
|
+
if (format === "json") {
|
|
280
|
+
console.log(formatOutput(result, format));
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const metrics = [
|
|
284
|
+
["crashRate", "Crash Rate"],
|
|
285
|
+
["anrRate", "ANR Rate"],
|
|
286
|
+
["slowStartRate", "Slow Start Rate"],
|
|
287
|
+
["slowRenderingRate", "Slow Rendering Rate"]
|
|
288
|
+
];
|
|
289
|
+
console.log(`
|
|
290
|
+
Version Comparison \u2014 ${packageName}`);
|
|
291
|
+
console.log(`${"\u2500".repeat(60)}`);
|
|
292
|
+
console.log(`${"Metric".padEnd(22)} ${"v" + v1.padEnd(14)} ${"v" + v2.padEnd(14)} Change`);
|
|
293
|
+
console.log(`${"\u2500".repeat(60)}`);
|
|
294
|
+
for (const [key, label] of metrics) {
|
|
295
|
+
const val1 = result.v1[key];
|
|
296
|
+
const val2 = result.v2[key];
|
|
297
|
+
const s1 = val1 !== void 0 ? (val1 * 100).toFixed(3) + "%" : "N/A";
|
|
298
|
+
const s2 = val2 !== void 0 ? (val2 * 100).toFixed(3) + "%" : "N/A";
|
|
299
|
+
const isRegression = result.regressions.includes(key);
|
|
300
|
+
const change = val1 !== void 0 && val2 !== void 0 ? (val2 - val1) / val1 * 100 : void 0;
|
|
301
|
+
const changeStr = change !== void 0 ? (change > 0 ? "+" : "") + change.toFixed(1) + "%" : "N/A";
|
|
302
|
+
const colorFn = isRegression ? red : change !== void 0 && change < -1 ? green : (s) => s;
|
|
303
|
+
console.log(
|
|
304
|
+
`${label.padEnd(22)} ${s1.padEnd(15)} ${colorFn(s2.padEnd(15))} ${colorFn(changeStr)}`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
if (result.regressions.length > 0) {
|
|
308
|
+
console.log(`
|
|
309
|
+
${red("\u2717")} Regressions detected: ${result.regressions.join(", ")}`);
|
|
310
|
+
} else {
|
|
311
|
+
console.log(`
|
|
312
|
+
${green("\u2713")} No regressions detected.`);
|
|
313
|
+
}
|
|
314
|
+
} catch (error) {
|
|
315
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
316
|
+
process.exit(4);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
vitals.command("watch").description("Monitor vitals continuously and optionally auto-halt rollout on breach").requiredOption("--threshold <value>", "Breach threshold value", parseFloat).option("--metric <name>", "Metric to monitor (crashes, anr, startup, rendering, battery, memory)", "crashes").option("--interval <seconds>", "Polling interval in seconds", (v) => parseInt(v, 10), 300).option("--auto-halt-rollout", "Automatically halt rollout if threshold is breached").option("--track <name>", "Track to halt rollout on (required with --auto-halt-rollout)").action(async (options) => {
|
|
320
|
+
const metricSet = METRIC_MAP[options.metric];
|
|
321
|
+
if (!metricSet) {
|
|
322
|
+
console.error(
|
|
323
|
+
`Error: Unknown metric "${options.metric}". Use: ${Object.keys(METRIC_MAP).join(", ")}`
|
|
324
|
+
);
|
|
325
|
+
process.exit(2);
|
|
326
|
+
}
|
|
327
|
+
if (options.autoHaltRollout && !options.track) {
|
|
328
|
+
console.error("Error: --track <name> is required when using --auto-halt-rollout");
|
|
329
|
+
process.exit(2);
|
|
330
|
+
}
|
|
331
|
+
const config = await loadConfig();
|
|
332
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
333
|
+
const reporting = await getReportingClient(config);
|
|
334
|
+
const intervalMs = options.interval * 1e3;
|
|
335
|
+
console.log(`Watching ${options.metric} for ${packageName}`);
|
|
336
|
+
console.log(`Threshold: ${options.threshold} Interval: ${options.interval}s`);
|
|
337
|
+
if (options.autoHaltRollout) {
|
|
338
|
+
console.log(`Auto-halt enabled on track: ${options.track}`);
|
|
339
|
+
}
|
|
340
|
+
console.log("Press Ctrl+C to stop.\n");
|
|
341
|
+
const stop = watchVitalsWithAutoHalt(reporting, packageName, {
|
|
342
|
+
intervalMs,
|
|
343
|
+
threshold: options.threshold,
|
|
344
|
+
metricSet,
|
|
345
|
+
onPoll: (value, breached) => {
|
|
346
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
347
|
+
const valStr = value !== void 0 ? (value * 100).toFixed(3) + "%" : "N/A";
|
|
348
|
+
const indicator = breached ? red("\u2717 BREACH") : green("\u2713 OK");
|
|
349
|
+
console.log(`[${ts}] ${options.metric}: ${valStr} \u2014 ${indicator}`);
|
|
350
|
+
},
|
|
351
|
+
onHalt: options.autoHaltRollout ? async (value) => {
|
|
352
|
+
console.error(
|
|
353
|
+
`
|
|
354
|
+
${red("\u2717")} Threshold breached (${(value * 100).toFixed(3)}% > ${options.threshold}%). Halting rollout on track "${options.track}"...`
|
|
355
|
+
);
|
|
356
|
+
try {
|
|
357
|
+
const { resolveAuth: resolveAuth2 } = await import("@gpc-cli/auth");
|
|
358
|
+
const { createApiClient } = await import("@gpc-cli/api");
|
|
359
|
+
const { updateRollout } = await import("@gpc-cli/core");
|
|
360
|
+
const auth = await resolveAuth2({ serviceAccountPath: config.auth?.serviceAccount });
|
|
361
|
+
const apiClient = createApiClient({ auth });
|
|
362
|
+
await updateRollout(apiClient, packageName, options.track, 0);
|
|
363
|
+
console.error(`${red("\u26A0")} Rollout halted on track "${options.track}".`);
|
|
364
|
+
} catch (err) {
|
|
365
|
+
console.error(`Failed to halt rollout: ${err instanceof Error ? err.message : String(err)}`);
|
|
366
|
+
}
|
|
367
|
+
stop();
|
|
368
|
+
process.exit(6);
|
|
369
|
+
} : void 0
|
|
370
|
+
});
|
|
371
|
+
process.on("SIGINT", () => {
|
|
372
|
+
stop();
|
|
373
|
+
console.log("\nWatch stopped.");
|
|
374
|
+
process.exit(0);
|
|
375
|
+
});
|
|
376
|
+
});
|
|
246
377
|
}
|
|
247
378
|
export {
|
|
248
379
|
registerVitalsCommands
|
|
249
380
|
};
|
|
250
|
-
//# sourceMappingURL=vitals-
|
|
381
|
+
//# sourceMappingURL=vitals-LFL75LA6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/vitals.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createReportingClient } from \"@gpc-cli/api\";\nimport type { ReportingDimension } from \"@gpc-cli/api\";\nimport type { VitalsMetricSet } from \"@gpc-cli/api\";\nimport {\n getVitalsOverview,\n getVitalsCrashes,\n getVitalsAnr,\n getVitalsStartup,\n getVitalsRendering,\n getVitalsBattery,\n getVitalsMemory,\n getVitalsLmk,\n getVitalsAnomalies,\n searchVitalsErrors,\n compareVitalsTrend,\n compareVersionVitals,\n watchVitalsWithAutoHalt,\n checkThreshold,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { red, yellow, green } from \"../colors.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getReportingClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createReportingClient({ auth });\n}\n\nconst VALID_DIMENSIONS: ReportingDimension[] = [\n \"apiLevel\",\n \"versionCode\",\n \"deviceModel\",\n \"deviceType\",\n \"countryCode\",\n \"deviceRamBucket\",\n \"deviceSocName\",\n \"deviceCpuMakeModel\",\n \"deviceGlEsVersion\",\n \"deviceVulkanVersion\",\n \"deviceOpenGlVersion\",\n \"deviceBrand\",\n];\n\nconst THRESHOLD_CONFIG_KEYS: Record<string, string> = {\n crashes: \"crashRate\",\n anr: \"anrRate\",\n startup: \"slowStartRate\",\n rendering: \"slowRenderingRate\",\n battery: \"excessiveWakeupRate\",\n memory: \"stuckWakelockRate\",\n wakeup: \"excessiveWakeupRate\",\n lmk: \"stuckWakelockRate\",\n};\n\nfunction validateDimension(dim: string): ReportingDimension {\n if (!VALID_DIMENSIONS.includes(dim as ReportingDimension)) {\n console.error(`Error: Invalid dimension \"${dim}\".`);\n console.error(`Valid dimensions: ${VALID_DIMENSIONS.join(\", \")}`);\n process.exit(2);\n }\n return dim as ReportingDimension;\n}\n\ntype MetricFn = typeof getVitalsCrashes;\n\nfunction registerMetricCommand(\n parent: Command,\n name: string,\n description: string,\n fn: MetricFn,\n program: Command,\n): void {\n parent\n .command(name)\n .description(description)\n .option(\"--dim <dimension>\", \"Group by dimension\")\n .option(\"--days <n>\", \"Number of days to query\", parseInt)\n .option(\"--threshold <value>\", \"Threshold value for CI alerting\", parseFloat)\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await fn(reporting, packageName, {\n dimension: options.dim ? validateDimension(options.dim) : undefined,\n days: options.days,\n });\n if (format !== \"json\" && (!result.rows || result.rows.length === 0)) {\n console.log(`${yellow(\"⚠\")} No vitals data available.`);\n return;\n }\n if (format !== \"json\" && result.rows) {\n const rows = result.rows.map((row: Record<string, unknown>) => {\n const startTime = row[\"startTime\"] as Record<string, unknown> | undefined;\n const metrics = row[\"metrics\"] as Record<string, Record<string, unknown>> | undefined;\n const flat: Record<string, unknown> = {\n date: startTime ? `${startTime[\"year\"]}-${String(startTime[\"month\"]).padStart(2, \"0\")}-${String(startTime[\"day\"]).padStart(2, \"0\")}` : \"-\",\n };\n if (metrics) {\n for (const [key, val] of Object.entries(metrics)) {\n flat[key] = val?.[\"decimalValue\"]?.[\"value\"] ?? \"-\";\n }\n }\n const dims = row[\"dimensions\"] as Record<string, unknown> | undefined;\n if (dims) {\n for (const [key, val] of Object.entries(dims)) {\n flat[key] = (val as Record<string, unknown>)?.[\"stringValue\"] ?? \"-\";\n }\n }\n return flat;\n });\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(result, format));\n }\n\n // Check threshold from flag or config\n const configKey = THRESHOLD_CONFIG_KEYS[name];\n const configThreshold = configKey\n ? (config as Record<string, unknown>)[\"vitals\"]\n ? ((config as Record<string, unknown>)[\"vitals\"] as Record<string, unknown>)[\"thresholds\"]\n ? (((config as Record<string, unknown>)[\"vitals\"] as Record<string, unknown>)[\"thresholds\"] as Record<string, unknown>)[configKey]\n : undefined\n : undefined\n : undefined;\n const threshold = options.threshold ?? (configThreshold !== undefined ? Number(configThreshold) : undefined);\n if (threshold !== undefined) {\n const latestRow = result.rows?.[result.rows.length - 1];\n const metricKeys = latestRow?.metrics ? Object.keys(latestRow.metrics) : [];\n const firstMetric = metricKeys[0];\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n const check = checkThreshold(value, threshold);\n if (check.breached) {\n console.error(`${red(\"✗\")} Threshold breached: ${check.value} > ${check.threshold}`);\n process.exit(6);\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n\nexport function registerVitalsCommands(program: Command): void {\n const vitals = program\n .command(\"vitals\")\n .description(\"Monitor app vitals, crash rates, and performance metrics\");\n\n vitals\n .command(\"overview\")\n .description(\"Dashboard summary of all vital metrics\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await getVitalsOverview(reporting, packageName);\n if (Object.keys(result).length === 0) {\n if (format === \"json\") {\n console.log(formatOutput({ vitals: [], message: \"No vitals data available\" }, format));\n } else {\n console.log(\"No vitals data available.\");\n }\n return;\n }\n if (format !== \"json\") {\n const overview = result as Record<string, unknown>;\n const rows = Object.entries(overview).map(([metric, data]) => {\n const metricRows = data as Record<string, unknown>[] | undefined;\n const latest = metricRows?.[metricRows.length - 1];\n const metrics = latest?.[\"metrics\"] as Record<string, Record<string, unknown>> | undefined;\n const firstKey = metrics ? Object.keys(metrics)[0] : undefined;\n const value = firstKey ? metrics?.[firstKey]?.[\"decimalValue\"]?.[\"value\"] : undefined;\n return {\n metric,\n dataPoints: metricRows?.length || 0,\n latestValue: value ?? \"-\",\n };\n });\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n registerMetricCommand(vitals, \"crashes\", \"Query crash rate metrics\", getVitalsCrashes, program);\n registerMetricCommand(vitals, \"anr\", \"Query ANR rate metrics\", getVitalsAnr, program);\n registerMetricCommand(vitals, \"startup\", \"Query slow startup metrics\", getVitalsStartup, program);\n registerMetricCommand(\n vitals,\n \"rendering\",\n \"Query slow rendering metrics\",\n getVitalsRendering,\n program,\n );\n registerMetricCommand(\n vitals,\n \"battery\",\n \"Query excessive wakeup metrics\",\n getVitalsBattery,\n program,\n );\n registerMetricCommand(vitals, \"memory\", \"Query stuck wakelock metrics\", getVitalsMemory, program);\n registerMetricCommand(\n vitals,\n \"wakeup\",\n \"Query excessive wakeup rate metrics\",\n getVitalsBattery,\n program,\n );\n registerMetricCommand(\n vitals,\n \"lmk\",\n \"Query low-memory kill (stuck wakelock) metrics\",\n getVitalsLmk,\n program,\n );\n\n vitals\n .command(\"anomalies\")\n .description(\"Detect anomalies in app vitals\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await getVitalsAnomalies(reporting, packageName);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n const errors = vitals.command(\"errors\").description(\"Search and view error issues\");\n\n errors\n .command(\"search\")\n .description(\"Search error issues\")\n .option(\"--filter <text>\", \"Filter expression\")\n .option(\"--max <n>\", \"Maximum results\", parseInt)\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await searchVitalsErrors(reporting, packageName, {\n filter: options.filter,\n maxResults: options.max,\n });\n const issues = (result as Record<string, unknown>)[\"errorIssues\"] as unknown[] | undefined;\n if (format !== \"json\" && (!issues || issues.length === 0)) {\n console.log(\"No error issues found.\");\n return;\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n const METRIC_MAP: Record<string, VitalsMetricSet> = {\n crashes: \"crashRateMetricSet\",\n anr: \"anrRateMetricSet\",\n startup: \"slowStartRateMetricSet\",\n rendering: \"slowRenderingRateMetricSet\",\n battery: \"excessiveWakeupRateMetricSet\",\n memory: \"stuckBackgroundWakelockRateMetricSet\",\n };\n\n vitals\n .command(\"compare <metric>\")\n .description(\"Compare metric trend: this period vs previous period\")\n .option(\"--days <n>\", \"Period length in days\", (v) => parseInt(v, 10), 7)\n .action(async (metric: string, options) => {\n const metricSet = METRIC_MAP[metric];\n if (!metricSet) {\n console.error(\n `Error: Unknown metric \"${metric}\". Use: ${Object.keys(METRIC_MAP).join(\", \")}`,\n );\n process.exit(2);\n }\n\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await compareVitalsTrend(reporting, packageName, metricSet, options.days);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n vitals\n .command(\"compare-versions <v1> <v2>\")\n .description(\"Compare vitals side-by-side for two version codes\")\n .option(\"--days <n>\", \"Number of days to query\", (v) => parseInt(v, 10), 30)\n .action(async (v1: string, v2: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await compareVersionVitals(reporting, packageName, v1, v2, {\n days: options.days,\n });\n\n if (format === \"json\") {\n console.log(formatOutput(result, format));\n return;\n }\n\n const metrics: [keyof typeof result.v1, string][] = [\n [\"crashRate\", \"Crash Rate\"],\n [\"anrRate\", \"ANR Rate\"],\n [\"slowStartRate\", \"Slow Start Rate\"],\n [\"slowRenderingRate\", \"Slow Rendering Rate\"],\n ];\n\n console.log(`\\nVersion Comparison — ${packageName}`);\n console.log(`${\"─\".repeat(60)}`);\n console.log(`${\"Metric\".padEnd(22)} ${\"v\" + v1.padEnd(14)} ${\"v\" + v2.padEnd(14)} Change`);\n console.log(`${\"─\".repeat(60)}`);\n\n for (const [key, label] of metrics) {\n const val1 = result.v1[key];\n const val2 = result.v2[key];\n const s1 = val1 !== undefined ? (val1 * 100).toFixed(3) + \"%\" : \"N/A\";\n const s2 = val2 !== undefined ? (val2 * 100).toFixed(3) + \"%\" : \"N/A\";\n const isRegression = result.regressions.includes(key as string);\n const change =\n val1 !== undefined && val2 !== undefined\n ? ((val2 - val1) / val1) * 100\n : undefined;\n const changeStr =\n change !== undefined\n ? (change > 0 ? \"+\" : \"\") + change.toFixed(1) + \"%\"\n : \"N/A\";\n const colorFn = isRegression ? red : change !== undefined && change < -1 ? green : (s: string) => s;\n console.log(\n `${label.padEnd(22)} ${s1.padEnd(15)} ${colorFn(s2.padEnd(15))} ${colorFn(changeStr)}`,\n );\n }\n\n if (result.regressions.length > 0) {\n console.log(`\\n${red(\"✗\")} Regressions detected: ${result.regressions.join(\", \")}`);\n } else {\n console.log(`\\n${green(\"✓\")} No regressions detected.`);\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n vitals\n .command(\"watch\")\n .description(\"Monitor vitals continuously and optionally auto-halt rollout on breach\")\n .requiredOption(\"--threshold <value>\", \"Breach threshold value\", parseFloat)\n .option(\"--metric <name>\", \"Metric to monitor (crashes, anr, startup, rendering, battery, memory)\", \"crashes\")\n .option(\"--interval <seconds>\", \"Polling interval in seconds\", (v) => parseInt(v, 10), 300)\n .option(\"--auto-halt-rollout\", \"Automatically halt rollout if threshold is breached\")\n .option(\"--track <name>\", \"Track to halt rollout on (required with --auto-halt-rollout)\")\n .action(async (options) => {\n const metricSet = METRIC_MAP[options.metric as string];\n if (!metricSet) {\n console.error(\n `Error: Unknown metric \"${options.metric}\". Use: ${Object.keys(METRIC_MAP).join(\", \")}`,\n );\n process.exit(2);\n }\n\n if (options.autoHaltRollout && !options.track) {\n console.error(\"Error: --track <name> is required when using --auto-halt-rollout\");\n process.exit(2);\n }\n\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const intervalMs = (options.interval as number) * 1000;\n\n console.log(`Watching ${options.metric} for ${packageName}`);\n console.log(`Threshold: ${options.threshold} Interval: ${options.interval}s`);\n if (options.autoHaltRollout) {\n console.log(`Auto-halt enabled on track: ${options.track}`);\n }\n console.log(\"Press Ctrl+C to stop.\\n\");\n\n const stop = watchVitalsWithAutoHalt(reporting, packageName, {\n intervalMs,\n threshold: options.threshold as number,\n metricSet,\n onPoll: (value, breached) => {\n const ts = new Date().toISOString();\n const valStr = value !== undefined ? (value * 100).toFixed(3) + \"%\" : \"N/A\";\n const indicator = breached ? red(\"✗ BREACH\") : green(\"✓ OK\");\n console.log(`[${ts}] ${options.metric}: ${valStr} — ${indicator}`);\n },\n onHalt: options.autoHaltRollout\n ? async (value: number) => {\n console.error(\n `\\n${red(\"✗\")} Threshold breached (${(value * 100).toFixed(3)}% > ${options.threshold}%). Halting rollout on track \"${options.track}\"...`,\n );\n try {\n const { resolveAuth } = await import(\"@gpc-cli/auth\");\n const { createApiClient } = await import(\"@gpc-cli/api\");\n const { updateRollout } = await import(\"@gpc-cli/core\");\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const apiClient = createApiClient({ auth });\n await updateRollout(apiClient, packageName, options.track as string, 0);\n console.error(`${red(\"⚠\")} Rollout halted on track \"${options.track}\".`);\n } catch (err) {\n console.error(`Failed to halt rollout: ${err instanceof Error ? err.message : String(err)}`);\n }\n stop();\n process.exit(6);\n }\n : undefined,\n });\n\n process.on(\"SIGINT\", () => {\n stop();\n console.log(\"\\nWatch stopped.\");\n process.exit(0);\n });\n });\n}\n"],"mappings":"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","names":["resolveAuth"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gpc-cli/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.35",
|
|
4
4
|
"description": "GPC — Google Play Console CLI. 187 API endpoints, one tool.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"commander": "^14.0.3",
|
|
22
|
-
"@gpc-cli/api": "1.0.
|
|
23
|
-
"@gpc-cli/plugin-sdk": "0.9.7",
|
|
22
|
+
"@gpc-cli/api": "1.0.19",
|
|
24
23
|
"@gpc-cli/auth": "^0.9.10",
|
|
25
24
|
"@gpc-cli/config": "0.9.9",
|
|
26
|
-
"@gpc-cli/core": "0.9.
|
|
25
|
+
"@gpc-cli/core": "0.9.29",
|
|
26
|
+
"@gpc-cli/plugin-sdk": "0.9.7"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"google-play",
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^25.3.5"
|
|
50
50
|
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://github.com/yasserstudio/gpc"
|
|
54
|
+
},
|
|
51
55
|
"scripts": {
|
|
52
56
|
"build": "tsup",
|
|
53
57
|
"dev": "tsup --watch",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/auth.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { resolveAuth, loadServiceAccountKey, clearTokenCache, AuthError } from \"@gpc-cli/auth\";\nimport { loadConfig, getCacheDir } from \"@gpc-cli/config\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\nexport function registerAuthCommands(program: Command): void {\n const auth = program.command(\"auth\").description(\"Manage authentication\");\n\n auth\n .command(\"login\")\n .description(\"Authenticate with Google Play Developer API\")\n .option(\"--service-account <path>\", \"Path to service account JSON key file\")\n .option(\"--adc\", \"Use Application Default Credentials\")\n .option(\"--profile <name>\", \"Store credentials under a named profile\")\n .action(async (options: { serviceAccount?: string; adc?: boolean; profile?: string }) => {\n try {\n if (options.serviceAccount) {\n const key = await loadServiceAccountKey(options.serviceAccount);\n\n if (options.profile) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(options.profile, {\n auth: { serviceAccount: options.serviceAccount },\n });\n console.log(`Profile \"${options.profile}\" configured with ${key.client_email}`);\n } else {\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", options.serviceAccount);\n console.log(`Authenticated as ${key.client_email}`);\n }\n console.log(`Project: ${key.project_id}`);\n } else if (options.adc) {\n const client = await resolveAuth();\n console.log(`Authenticated via Application Default Credentials`);\n console.log(`Account: ${client.getClientEmail()}`);\n } else {\n console.log(\"Usage: gpc auth login --service-account <path>\");\n console.log(\"\");\n console.log(\"Authentication methods:\");\n console.log(\" --service-account <path> Service account JSON key file\");\n console.log(\" --adc Application Default Credentials\");\n console.log(\"\");\n console.log(\"Options:\");\n console.log(\" --profile <name> Store under a named profile\");\n }\n } catch (error) {\n if (error instanceof AuthError) {\n console.error(`Error: ${error.message}`);\n if (error.suggestion) console.error(`Suggestion: ${error.suggestion}`);\n process.exit(3);\n }\n throw error;\n }\n });\n\n auth\n .command(\"status\")\n .description(\"Show current authentication status\")\n .action(async () => {\n const config = await loadConfig();\n try {\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\n const format = getOutputFormat(program, config);\n const data = {\n authenticated: true,\n account: client.getClientEmail(),\n project: client.getProjectId(),\n ...(config.profile && { profile: config.profile }),\n };\n console.log(formatOutput(data, format));\n } catch (error) {\n if (error instanceof AuthError) {\n const format = getOutputFormat(program, config);\n const data = {\n authenticated: false,\n error: error.message,\n suggestion: error.suggestion,\n };\n console.log(formatOutput(data, format));\n process.exit(3);\n }\n throw error;\n }\n });\n\n auth\n .command(\"logout\")\n .description(\"Clear stored credentials and token cache\")\n .action(async () => {\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", \"\");\n await clearTokenCache(getCacheDir());\n console.log(\"Credentials and token cache cleared.\");\n });\n\n auth\n .command(\"whoami\")\n .description(\"Show current authenticated identity\")\n .action(async () => {\n try {\n const config = await loadConfig();\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\n console.log(client.getClientEmail());\n } catch {\n console.error(\"Not authenticated. Run: gpc auth login\");\n process.exit(3);\n }\n });\n\n auth\n .command(\"switch <profile>\")\n .description(\"Switch to a named profile\")\n .action(async (profile: string) => {\n try {\n // Verify profile exists\n const config = await loadConfig({ profile });\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"profile\", profile);\n console.log(`Switched to profile \"${profile}\"`);\n if (config.auth?.serviceAccount) {\n console.log(`Service account: ${config.auth.serviceAccount}`);\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(2);\n }\n });\n\n auth\n .command(\"token\")\n .description(\"Print the current access token (useful for manual API calls)\")\n .action(async () => {\n try {\n const config = await loadConfig();\n const authClient = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\n const token = await authClient.getAccessToken();\n console.log(token);\n } catch (error) {\n if (error instanceof AuthError) {\n console.error(`Error: ${error.message}`);\n process.exit(3);\n }\n throw error;\n }\n });\n\n auth\n .command(\"profiles\")\n .description(\"List configured profiles\")\n .action(async () => {\n const { listProfiles } = await import(\"@gpc-cli/config\");\n const config = await loadConfig();\n const profiles = await listProfiles();\n const format = getOutputFormat(program, config);\n\n if (profiles.length === 0) {\n console.log(\n \"No profiles configured. Use: gpc auth login --service-account <path> --profile <name>\",\n );\n return;\n }\n\n const data = profiles.map((name) => ({\n name,\n active: name === config.profile,\n }));\n console.log(formatOutput(data, format));\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/bundle.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport {\n analyzeBundle,\n compareBundles,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\nfunction formatSize(bytes: number): string {\n const abs = Math.abs(bytes);\n const sign = bytes < 0 ? \"-\" : \"\";\n if (abs < 1024) return `${sign}${abs} B`;\n if (abs < 1024 * 1024) return `${sign}${(abs / 1024).toFixed(1)} KB`;\n return `${sign}${(abs / (1024 * 1024)).toFixed(2)} MB`;\n}\n\nfunction formatDelta(delta: number): string {\n const prefix = delta > 0 ? \"+\" : \"\";\n return `${prefix}${formatSize(delta)}`;\n}\n\nexport function registerBundleCommands(program: Command): void {\n const bundle = program.command(\"bundle\").description(\"Analyze app bundles and APKs\");\n\n bundle\n .command(\"analyze <file>\")\n .description(\"Analyze size breakdown of an AAB or APK\")\n .option(\"--threshold <mb>\", \"Fail if compressed size exceeds threshold (MB)\", parseFloat)\n .action(async (file: string, opts: { threshold?: number }) => {\n const format = getOutputFormat(program, await getConfig());\n\n try {\n const analysis = await analyzeBundle(file);\n\n if (format === \"json\") {\n console.log(formatOutput(analysis, format));\n } else if (format === \"markdown\") {\n const moduleRows = analysis.modules.map((m) => ({\n module: m.name,\n compressed: formatSize(m.compressedSize),\n uncompressed: formatSize(m.uncompressedSize),\n entries: m.entries,\n }));\n const categoryRows = analysis.categories.map((c) => ({\n category: c.name,\n compressed: formatSize(c.compressedSize),\n uncompressed: formatSize(c.uncompressedSize),\n entries: c.entries,\n }));\n console.log(`## Bundle Analysis: \\`${analysis.filePath}\\``);\n console.log();\n console.log(`| Property | Value |`);\n console.log(`| --- | --- |`);\n console.log(`| Type | ${analysis.fileType.toUpperCase()} |`);\n console.log(`| Total compressed | ${formatSize(analysis.totalCompressed)} |`);\n console.log(`| Total uncompressed | ${formatSize(analysis.totalUncompressed)} |`);\n console.log(`| Entries | ${analysis.entryCount} |`);\n console.log();\n console.log(`### Modules`);\n console.log();\n console.log(formatOutput(moduleRows, \"markdown\"));\n console.log();\n console.log(`### Categories`);\n console.log();\n console.log(formatOutput(categoryRows, \"markdown\"));\n } else {\n console.log(`\\nFile: ${analysis.filePath}`);\n console.log(`Type: ${analysis.fileType.toUpperCase()}`);\n console.log(`Total compressed: ${formatSize(analysis.totalCompressed)}`);\n console.log(`Total uncompressed: ${formatSize(analysis.totalUncompressed)}`);\n console.log(`Entries: ${analysis.entryCount}\\n`);\n\n // Modules table\n const moduleRows = analysis.modules.map((m) => ({\n module: m.name,\n compressed: formatSize(m.compressedSize),\n uncompressed: formatSize(m.uncompressedSize),\n entries: m.entries,\n }));\n console.log(\"Modules:\");\n console.log(formatOutput(moduleRows, \"table\"));\n\n // Categories table\n const categoryRows = analysis.categories.map((c) => ({\n category: c.name,\n compressed: formatSize(c.compressedSize),\n uncompressed: formatSize(c.uncompressedSize),\n entries: c.entries,\n }));\n console.log(\"\\nCategories:\");\n console.log(formatOutput(categoryRows, \"table\"));\n }\n\n // Threshold check\n if (opts.threshold !== undefined) {\n const thresholdBytes = opts.threshold * 1024 * 1024;\n if (analysis.totalCompressed > thresholdBytes) {\n console.error(\n `\\nThreshold breached: ${formatSize(analysis.totalCompressed)} > ${opts.threshold} MB`,\n );\n process.exit(6);\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n\n bundle\n .command(\"compare <file1> <file2>\")\n .description(\"Compare size differences between two bundles or APKs\")\n .action(async (file1: string, file2: string) => {\n const format = getOutputFormat(program, await getConfig());\n\n try {\n const [before, after] = await Promise.all([\n analyzeBundle(file1),\n analyzeBundle(file2),\n ]);\n const comparison = compareBundles(before, after);\n\n if (format === \"json\") {\n console.log(formatOutput(comparison, format));\n } else if (format === \"markdown\") {\n const sign = comparison.sizeDelta >= 0 ? \"+\" : \"\";\n const moduleRows = comparison.moduleDeltas\n .filter((m) => m.delta !== 0)\n .map((m) => ({\n module: m.module,\n before: formatSize(m.before),\n after: formatSize(m.after),\n delta: formatDelta(m.delta),\n }));\n const categoryRows = comparison.categoryDeltas\n .filter((c) => c.delta !== 0)\n .map((c) => ({\n category: c.category,\n before: formatSize(c.before),\n after: formatSize(c.after),\n delta: formatDelta(c.delta),\n }));\n console.log(`## Bundle Comparison`);\n console.log();\n console.log(`| | Path | Size |`);\n console.log(`| --- | --- | --- |`);\n console.log(`| Before | \\`${comparison.before.path}\\` | ${formatSize(comparison.before.totalCompressed)} |`);\n console.log(`| After | \\`${comparison.after.path}\\` | ${formatSize(comparison.after.totalCompressed)} |`);\n console.log(`| **Delta** | | **${sign}${formatSize(comparison.sizeDelta)} (${sign}${comparison.sizeDeltaPercent}%)** |`);\n if (moduleRows.length > 0) {\n console.log();\n console.log(`### Module Changes`);\n console.log();\n console.log(formatOutput(moduleRows, \"markdown\"));\n }\n if (categoryRows.length > 0) {\n console.log();\n console.log(`### Category Changes`);\n console.log();\n console.log(formatOutput(categoryRows, \"markdown\"));\n }\n } else {\n const sign = comparison.sizeDelta >= 0 ? \"+\" : \"\";\n console.log(`\\nBefore: ${comparison.before.path} (${formatSize(comparison.before.totalCompressed)})`);\n console.log(`After: ${comparison.after.path} (${formatSize(comparison.after.totalCompressed)})`);\n console.log(`Delta: ${sign}${formatSize(comparison.sizeDelta)} (${sign}${comparison.sizeDeltaPercent}%)\\n`);\n\n // Module deltas\n const moduleRows = comparison.moduleDeltas\n .filter((m) => m.delta !== 0)\n .map((m) => ({\n module: m.module,\n before: formatSize(m.before),\n after: formatSize(m.after),\n delta: formatDelta(m.delta),\n }));\n if (moduleRows.length > 0) {\n console.log(\"Module changes:\");\n console.log(formatOutput(moduleRows, \"table\"));\n }\n\n // Category deltas\n const categoryRows = comparison.categoryDeltas\n .filter((c) => c.delta !== 0)\n .map((c) => ({\n category: c.category,\n before: formatSize(c.before),\n after: formatSize(c.after),\n delta: formatDelta(c.delta),\n }));\n if (categoryRows.length > 0) {\n console.log(\"\\nCategory changes:\");\n console.log(formatOutput(categoryRows, \"table\"));\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n}\n\nasync function getConfig() {\n const { loadConfig } = await import(\"@gpc-cli/config\");\n return loadConfig();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/cache.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { readdir, stat, unlink, rm } from \"node:fs/promises\";\nimport { join, extname, basename } from \"node:path\";\nimport { getCacheDir } from \"@gpc-cli/config\";\n\nconst FILE_TYPES: Record<string, (name: string) => boolean> = {\n status: (name) => name.startsWith(\"status-\") && name.endsWith(\".json\"),\n token: (name) => name === \"token-cache.json\",\n update: (name) => name === \"update-check.json\",\n};\n\nasync function getCacheFiles(cacheDir: string): Promise<{ name: string; path: string; size: number; mtime: Date }[]> {\n let entries: string[];\n try {\n entries = await readdir(cacheDir);\n } catch {\n return [];\n }\n\n const files: { name: string; path: string; size: number; mtime: Date }[] = [];\n for (const entry of entries) {\n if (!entry.endsWith(\".json\")) continue;\n const filePath = join(cacheDir, entry);\n try {\n const info = await stat(filePath);\n if (info.isFile()) {\n files.push({ name: entry, path: filePath, size: info.size, mtime: info.mtime });\n }\n } catch { /* ignore */ }\n }\n return files;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction fileType(name: string): string {\n for (const [type, matcher] of Object.entries(FILE_TYPES)) {\n if (matcher(name)) return type;\n }\n return \"other\";\n}\n\nexport function registerCacheCommand(program: Command): void {\n const cache = program.command(\"cache\").description(\"Manage local cache files\");\n\n cache\n .command(\"info\")\n .description(\"Show cache directory and total size\")\n .action(async () => {\n const cacheDir = getCacheDir();\n const files = await getCacheFiles(cacheDir);\n const totalSize = files.reduce((sum, f) => sum + f.size, 0);\n console.log(`Cache directory: ${cacheDir}`);\n console.log(`Files: ${files.length}`);\n console.log(`Total size: ${formatBytes(totalSize)}`);\n });\n\n cache\n .command(\"list\")\n .description(\"List all cache files with size and age\")\n .action(async () => {\n const cacheDir = getCacheDir();\n const files = await getCacheFiles(cacheDir);\n if (files.length === 0) {\n console.log(\"No cache files found.\");\n return;\n }\n const now = Date.now();\n for (const f of files) {\n const ageMs = now - f.mtime.getTime();\n const ageMins = Math.floor(ageMs / 60000);\n const ageStr = ageMins < 60\n ? `${ageMins}m ago`\n : ageMins < 1440\n ? `${Math.floor(ageMins / 60)}h ago`\n : `${Math.floor(ageMins / 1440)}d ago`;\n const type = fileType(f.name);\n console.log(` ${f.name} [${type}] ${formatBytes(f.size)} ${ageStr}`);\n }\n });\n\n cache\n .command(\"clear\")\n .description(\"Remove cache files\")\n .option(\"--force\", \"Skip confirmation prompt\")\n .option(\"--type <type>\", \"Remove only files of this type (status|token|update)\")\n .action(async (opts) => {\n const cacheDir = getCacheDir();\n const allFiles = await getCacheFiles(cacheDir);\n\n let toDelete = allFiles;\n if (opts.type) {\n const matcher = FILE_TYPES[opts.type];\n if (!matcher) {\n console.error(`Error: Unknown cache type \"${opts.type}\". Valid types: ${Object.keys(FILE_TYPES).join(\", \")}`);\n process.exit(2);\n }\n toDelete = allFiles.filter((f) => matcher(f.name));\n }\n\n if (toDelete.length === 0) {\n console.log(\"No cache files to remove.\");\n return;\n }\n\n if (!opts.force) {\n console.log(`About to remove ${toDelete.length} file(s) from ${cacheDir}:`);\n for (const f of toDelete) {\n console.log(` ${f.name} (${formatBytes(f.size)})`);\n }\n const { createInterface } = await import(\"node:readline\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => rl.question(\"Proceed? [y/N] \", resolve));\n rl.close();\n if (answer.toLowerCase() !== \"y\") {\n console.log(\"Aborted.\");\n return;\n }\n }\n\n let removed = 0;\n for (const f of toDelete) {\n try {\n await unlink(f.path);\n removed++;\n } catch { /* ignore */ }\n }\n console.log(`Removed ${removed} file(s).`);\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugins.ts","../src/program.ts","../src/error-handler.ts"],"sourcesContent":["import { PluginManager, discoverPlugins } from \"@gpc-cli/core\";\nimport type { Command } from \"commander\";\n\n/**\n * Load and initialize all plugins.\n * First-party plugins (@gpc-cli/*) are auto-trusted.\n * Third-party plugins require prior approval stored in config.\n * Plugin loading is disabled in standalone binary mode.\n */\nexport async function loadPlugins(): Promise<PluginManager> {\n const manager = new PluginManager();\n\n // Standalone binary cannot resolve external npm packages at runtime\n if (process.env[\"__GPC_BINARY\"] === \"1\") {\n return manager;\n }\n\n try {\n const { loadConfig } = await import(\"@gpc-cli/config\");\n const config = await loadConfig();\n const plugins = await discoverPlugins({ configPlugins: config.plugins });\n const approved = new Set(config.approvedPlugins ?? []);\n\n for (const plugin of plugins) {\n const isTrusted = plugin.name.startsWith(\"@gpc-cli/\");\n\n if (!isTrusted && !approved.has(plugin.name)) {\n // Skip unapproved third-party plugins silently in non-interactive mode\n // In interactive mode, the user would run `gpc plugins approve <name>` first\n const isQuiet = process.argv.includes(\"--quiet\") || process.argv.includes(\"-q\");\n if (!isQuiet) {\n console.error(\n `Plugin \"${plugin.name}\" is not approved. Run: gpc plugins approve ${plugin.name}`,\n );\n }\n continue;\n }\n\n try {\n await manager.load(plugin);\n } catch {\n // Skip plugins that fail to load — don't block the CLI\n }\n }\n } catch {\n // Config loading failure shouldn't block plugin-free commands\n }\n\n return manager;\n}\n\n/**\n * Register plugin-defined commands with the Commander program.\n */\nexport function registerPluginCommands(program: Command, manager: PluginManager): void {\n for (const def of manager.getRegisteredCommands()) {\n const cmd = program.command(def.name).description(def.description);\n\n if (def.arguments) {\n for (const arg of def.arguments) {\n const syntax = arg.required ? `<${arg.name}>` : `[${arg.name}]`;\n cmd.argument(syntax, arg.description);\n }\n }\n\n if (def.options) {\n for (const opt of def.options) {\n cmd.option(\n opt.flags,\n opt.description,\n opt.defaultValue as string | boolean | string[] | undefined,\n );\n }\n }\n\n cmd.action(async (...rawArgs: unknown[]) => {\n const opts = rawArgs[rawArgs.length - 2] as Record<string, unknown>;\n const args: Record<string, unknown> = {};\n\n if (def.arguments) {\n def.arguments.forEach((argDef, i) => {\n args[argDef.name] = rawArgs[i];\n });\n }\n\n await def.action(args, opts);\n });\n }\n}\n","import { Command } from \"commander\";\nimport type { PluginManager } from \"@gpc-cli/core\";\nimport type { CommandEvent, CommandResult } from \"@gpc-cli/plugin-sdk\";\nimport { registerPluginCommands } from \"./plugins.js\";\n\nexport async function createProgram(pluginManager?: PluginManager): Promise<Command> {\n const program = new Command();\n\n program\n .name(\"gpc\")\n .description(\"GPC — Google Play Console CLI\")\n .version(process.env[\"__GPC_VERSION\"] || \"0.0.0\", \"-V, --version\")\n .option(\"-o, --output <format>\", \"Output format: table, json, yaml, markdown, junit\")\n .option(\"-v, --verbose\", \"Enable debug logging\")\n .option(\"-q, --quiet\", \"Suppress non-essential output\")\n .option(\"-a, --app <package>\", \"App package name\")\n .option(\"-p, --profile <name>\", \"Auth profile name\")\n .option(\"--no-color\", \"Disable colored output\")\n .option(\"--no-interactive\", \"Disable interactive prompts\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"--dry-run\", \"Preview changes without executing\")\n .option(\"--notify [target]\", \"Send webhook notification on completion (slack, discord, custom)\")\n .option(\"--ci\", \"Force CI mode (JSON output, no prompts, strict exit codes)\")\n .option(\"-j, --json\", \"Shorthand for --output json\")\n .showSuggestionAfterError(false);\n\n const commandLoaders: Record<string, () => Promise<void>> = {\n auth: async () => {\n (await import(\"./commands/auth.js\")).registerAuthCommands(program);\n },\n config: async () => {\n (await import(\"./commands/config.js\")).registerConfigCommands(program);\n },\n doctor: async () => {\n (await import(\"./commands/doctor.js\")).registerDoctorCommand(program);\n },\n update: async () => {\n (await import(\"./commands/update.js\")).registerUpdateCommand(program);\n },\n docs: async () => {\n (await import(\"./commands/docs.js\")).registerDocsCommand(program);\n },\n completion: async () => {\n (await import(\"./commands/completion.js\")).registerCompletionCommand(program);\n },\n apps: async () => {\n (await import(\"./commands/apps.js\")).registerAppsCommands(program);\n },\n releases: async () => {\n (await import(\"./commands/releases.js\")).registerReleasesCommands(program);\n },\n tracks: async () => {\n (await import(\"./commands/tracks.js\")).registerTracksCommands(program);\n },\n status: async () => {\n (await import(\"./commands/status.js\")).registerStatusCommand(program);\n },\n listings: async () => {\n (await import(\"./commands/listings.js\")).registerListingsCommands(program);\n },\n reviews: async () => {\n (await import(\"./commands/reviews.js\")).registerReviewsCommands(program);\n },\n vitals: async () => {\n (await import(\"./commands/vitals.js\")).registerVitalsCommands(program);\n },\n subscriptions: async () => {\n (await import(\"./commands/subscriptions.js\")).registerSubscriptionsCommands(program);\n },\n iap: async () => {\n (await import(\"./commands/iap.js\")).registerIapCommands(program);\n },\n purchases: async () => {\n (await import(\"./commands/purchases.js\")).registerPurchasesCommands(program);\n },\n pricing: async () => {\n (await import(\"./commands/pricing.js\")).registerPricingCommands(program);\n },\n reports: async () => {\n (await import(\"./commands/reports.js\")).registerReportsCommands(program);\n },\n users: async () => {\n (await import(\"./commands/users.js\")).registerUsersCommands(program);\n },\n testers: async () => {\n (await import(\"./commands/testers.js\")).registerTestersCommands(program);\n },\n validate: async () => {\n (await import(\"./commands/validate.js\")).registerValidateCommand(program);\n },\n publish: async () => {\n (await import(\"./commands/publish.js\")).registerPublishCommand(program);\n },\n recovery: async () => {\n (await import(\"./commands/recovery.js\")).registerRecoveryCommands(program);\n },\n \"data-safety\": async () => {\n (await import(\"./commands/data-safety.js\")).registerDataSafetyCommands(program);\n },\n \"external-transactions\": async () => {\n (await import(\"./commands/external-transactions.js\")).registerExternalTransactionsCommands(\n program,\n );\n },\n \"device-tiers\": async () => {\n (await import(\"./commands/device-tiers.js\")).registerDeviceTiersCommands(program);\n },\n \"one-time-products\": async () => {\n (await import(\"./commands/one-time-products.js\")).registerOneTimeProductsCommands(program);\n },\n \"internal-sharing\": async () => {\n (await import(\"./commands/internal-sharing.js\")).registerInternalSharingCommands(program);\n },\n \"generated-apks\": async () => {\n (await import(\"./commands/generated-apks.js\")).registerGeneratedApksCommands(program);\n },\n \"purchase-options\": async () => {\n (await import(\"./commands/purchase-options.js\")).registerPurchaseOptionsCommands(program);\n },\n bundle: async () => {\n (await import(\"./commands/bundle.js\")).registerBundleCommands(program);\n },\n audit: async () => {\n (await import(\"./commands/audit.js\")).registerAuditCommands(program);\n },\n migrate: async () => {\n (await import(\"./commands/migrate.js\")).registerMigrateCommands(program);\n },\n \"install-skills\": async () => {\n (await import(\"./commands/install-skills.js\")).registerInstallSkillsCommand(program);\n },\n version: async () => {\n (await import(\"./commands/version.js\")).registerVersionCommand(program);\n },\n cache: async () => {\n (await import(\"./commands/cache.js\")).registerCacheCommand(program);\n },\n feedback: async () => {\n (await import(\"./commands/feedback.js\")).registerFeedbackCommand(program);\n },\n plugins: async () => {\n registerPluginsCommand(program, pluginManager);\n },\n };\n\n // \"Did you mean?\" suggestions for unknown commands\n function levenshtein(a: string, b: string): number {\n const m = a.length, n = b.length;\n const dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>\n Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0))\n );\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n const row = dp[i]!;\n const prevRow = dp[i - 1]!;\n row[j] = a[i - 1] === b[j - 1]\n ? prevRow[j - 1]!\n : 1 + Math.min(prevRow[j]!, row[j - 1]!, prevRow[j - 1]!);\n }\n }\n return dp[m]![n]!;\n }\n\n program.on(\"command:*\", (operands: string[]) => {\n const cmd = operands[0] ?? \"\";\n const names = Object.keys(commandLoaders);\n const best = names.map(name => ({ name, d: levenshtein(cmd, name) })).sort((a, b) => a.d - b.d)[0];\n console.error(`Error: Unknown command \"${cmd}\".`);\n if (best && best.d <= 3) console.error(`Did you mean: gpc ${best.name}?`);\n console.error(`Run \"gpc --help\" to see all commands.`);\n process.exit(2);\n });\n\n // Resolve command aliases for lazy loading\n const commandAliases: Record<string, string> = {\n \"ext-txn\": \"external-transactions\",\n otp: \"one-time-products\",\n };\n\n const rawTarget = process.argv[2];\n const target = rawTarget ? (commandAliases[rawTarget] ?? rawTarget) : undefined;\n\n const loader = target ? commandLoaders[target] : undefined;\n if (loader) {\n await loader();\n } else {\n await Promise.all(Object.values(commandLoaders).map((loader) => loader()));\n }\n\n // Register plugin-defined commands\n if (pluginManager) {\n registerPluginCommands(program, pluginManager);\n }\n\n // Wire plugin lifecycle hooks around command execution\n if (pluginManager) {\n wrapCommandHooks(program, pluginManager);\n }\n\n return program;\n}\n\n/**\n * `gpc plugins` — manage plugins.\n */\nfunction registerPluginsCommand(program: Command, manager?: PluginManager): void {\n const cmd = program.command(\"plugins\").description(\"Manage plugins\");\n\n cmd\n .command(\"list\")\n .description(\"List loaded plugins\")\n .action(() => {\n const plugins = manager?.getLoadedPlugins() ?? [];\n const opts = program.opts();\n\n if (opts[\"output\"] === \"json\") {\n console.log(JSON.stringify(plugins, null, 2));\n return;\n }\n\n if (plugins.length === 0) {\n console.log(\"No plugins loaded.\");\n console.log('\\nConfigure plugins in .gpcrc.json: { \"plugins\": [\"@gpc-cli/plugin-ci\"] }');\n return;\n }\n\n console.log(\"Loaded plugins:\\n\");\n for (const p of plugins) {\n const trust = p.trusted ? \"trusted\" : \"third-party\";\n console.log(` ${p.name}@${p.version} (${trust})`);\n }\n\n const commands = manager?.getRegisteredCommands() ?? [];\n if (commands.length > 0) {\n console.log(\"\\nPlugin commands:\\n\");\n for (const c of commands) {\n console.log(` gpc ${c.name} — ${c.description}`);\n }\n }\n });\n\n cmd\n .command(\"init <name>\")\n .description(\"Scaffold a new plugin project\")\n .option(\"-d, --dir <path>\", \"Output directory (defaults to ./gpc-plugin-<name>)\")\n .option(\"--description <text>\", \"Plugin description\")\n .action(async (name: string, opts: { dir?: string; description?: string }) => {\n const { scaffoldPlugin } = await import(\"@gpc-cli/core\");\n const pluginName = name.startsWith(\"gpc-plugin-\") ? name : `gpc-plugin-${name}`;\n const dir = opts.dir ?? `./${pluginName}`;\n\n const result = await scaffoldPlugin({ name, dir, description: opts.description });\n\n console.log(`Plugin scaffolded at ${result.dir}/\\n`);\n console.log(\"Files created:\");\n for (const f of result.files) {\n console.log(` ${f}`);\n }\n console.log(`\\nNext steps:`);\n console.log(` cd ${pluginName}`);\n console.log(` npm install`);\n console.log(` npm run build`);\n console.log(` npm test`);\n });\n\n cmd\n .command(\"approve <name>\")\n .description(\"Approve a third-party plugin for loading\")\n .action(async (name: string) => {\n const { approvePlugin } = await import(\"@gpc-cli/config\");\n await approvePlugin(name);\n console.log(`Plugin \"${name}\" approved. It will be loaded on next run.`);\n });\n\n cmd\n .command(\"revoke <name>\")\n .description(\"Revoke approval for a third-party plugin\")\n .action(async (name: string) => {\n const { revokePluginApproval } = await import(\"@gpc-cli/config\");\n const removed = await revokePluginApproval(name);\n if (removed) {\n console.log(`Plugin \"${name}\" approval revoked.`);\n } else {\n console.log(`Plugin \"${name}\" was not in the approved list.`);\n }\n });\n}\n\n/**\n * Wrap all registered commands so plugin hooks fire before/after each command.\n */\nfunction wrapCommandHooks(program: Command, manager: PluginManager): void {\n program.hook(\"preAction\", async (thisCommand) => {\n const event: CommandEvent = {\n command: getFullCommandName(thisCommand),\n args: thisCommand.opts(),\n app: program.opts()[\"app\"] as string | undefined,\n startedAt: new Date(),\n };\n\n // Store on the command for afterCommand/onError\n (thisCommand as unknown as Record<string, unknown>)[\"__pluginEvent\"] = event;\n\n await manager.runBeforeCommand(event);\n });\n\n program.hook(\"postAction\", async (thisCommand) => {\n const event: CommandEvent = (thisCommand as unknown as Record<string, unknown>)[\n \"__pluginEvent\"\n ] as CommandEvent;\n if (!event) return;\n\n const result: CommandResult = {\n success: true,\n durationMs: Date.now() - event.startedAt.getTime(),\n exitCode: 0,\n };\n\n await manager.runAfterCommand(event, result);\n });\n}\n\nfunction getFullCommandName(cmd: Command): string {\n const parts: string[] = [];\n let current: Command | null = cmd;\n while (current && current.name() !== \"gpc\") {\n parts.unshift(current.name());\n current = current.parent;\n }\n return parts.join(\" \");\n}\n","/**\n * Shared error formatting for CLI output.\n * Extracts error code, message, and suggestion from typed errors (GpcError, AuthError, ApiError, ConfigError).\n */\n\ninterface TypedError {\n message: string;\n code?: string;\n suggestion?: string;\n exitCode?: number;\n}\n\nfunction isTypedError(error: unknown): error is Error & TypedError {\n return error instanceof Error && \"code\" in error && typeof (error as TypedError).code === \"string\";\n}\n\n/**\n * Format an error for CLI output. Prints:\n * Error [CODE]: message\n * Suggestion: suggestion (if available)\n *\n * Returns the appropriate exit code.\n */\nexport function handleCliError(error: unknown): number {\n if (isTypedError(error)) {\n console.error(`Error [${error.code}]: ${error.message}`);\n if (error.suggestion) {\n console.error(`Suggestion: ${error.suggestion}`);\n }\n return error.exitCode ?? 1;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${message}`);\n return 1;\n}\n"],"mappings":"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","names":["_","loader"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/config.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig, setConfigValue, getUserConfigPath, initConfig } from \"@gpc-cli/config\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { formatOutput, writeAuditLog, createAuditEntry } from \"@gpc-cli/core\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isInteractive, promptInput, promptSelect, promptConfirm } from \"../prompt.js\";\n\nconst ANDROID_PACKAGE_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)+$/;\n\nexport function registerConfigCommands(program: Command): void {\n const config = program.command(\"config\").description(\"Manage configuration\");\n\n config\n .command(\"init\")\n .description(\"Create a configuration file\")\n .option(\"--global\", \"Create in user config directory (~/.config/gpc/)\")\n .action(async (_options: { global?: boolean }) => {\n const initialConfig: Record<string, unknown> = {};\n\n if (isInteractive(program)) {\n console.log(\"\\nGPC Setup Wizard\\n\");\n\n // Package name\n let app = await promptInput(\"Default package name (e.g. com.example.app, blank to skip)\");\n if (app) {\n if (!ANDROID_PACKAGE_RE.test(app)) {\n console.error(\n ` Warning: \"${app}\" doesn't look like a valid Android package name — continuing anyway`,\n );\n }\n initialConfig[\"app\"] = app;\n }\n\n // Auth method\n const authMethod = await promptSelect(\n \"Authentication method:\",\n [\"service-account\", \"adc\", \"skip\"],\n \"service-account\",\n );\n\n if (authMethod === \"service-account\") {\n let saPath = \"\";\n while (true) {\n saPath = await promptInput(\"Path to service account JSON key file\");\n if (!saPath) {\n console.log(\" Skipping service account setup.\");\n break;\n }\n const resolved = resolve(saPath);\n if (existsSync(resolved)) {\n initialConfig[\"auth\"] = { serviceAccount: saPath };\n break;\n }\n console.error(` File not found: ${resolved}`);\n const retry = await promptConfirm(\"Try a different path?\");\n if (!retry) break;\n }\n } else if (authMethod === \"adc\") {\n console.log(\n \" Using Application Default Credentials — run `gcloud auth application-default login` if not already set up.\",\n );\n }\n\n // Output format\n const output = await promptSelect(\n \"Default output format:\",\n [\"table\", \"json\", \"yaml\", \"markdown\"],\n \"table\",\n );\n if (output !== \"table\") initialConfig[\"output\"] = output;\n }\n\n const path = await initConfig(initialConfig as GpcConfig);\n\n // Summary\n const configured: string[] = [];\n if (initialConfig[\"app\"]) configured.push(`app: ${initialConfig[\"app\"]}`);\n if (initialConfig[\"auth\"]) configured.push(\"auth: service account\");\n if (initialConfig[\"output\"]) configured.push(`output: ${initialConfig[\"output\"]}`);\n\n console.log(`\\nConfiguration file created: ${path}`);\n if (configured.length > 0) {\n console.log(` ${configured.join(\" · \")}`);\n }\n console.log(\"\\nRun `gpc doctor` to verify your setup.\");\n\n writeAuditLog(createAuditEntry(\"config init\", { path })).catch(() => {});\n });\n\n config\n .command(\"show\")\n .description(\"Display resolved configuration\")\n .action(async () => {\n const resolved = await loadConfig();\n const format = getOutputFormat(program, resolved);\n console.log(formatOutput(resolved, format));\n });\n\n config\n .command(\"set <key> <value>\")\n .description(\"Set a configuration value\")\n .action(async (key: string, value: string) => {\n await setConfigValue(key, value);\n console.log(`Set ${key} = ${value}`);\n });\n\n config\n .command(\"path\")\n .description(\"Show configuration file path\")\n .action(() => {\n console.log(getUserConfigPath());\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/data-safety.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport {\n getDataSafety,\n updateDataSafety,\n exportDataSafety,\n importDataSafety,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { getOutputFormat } from \"../format.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerDataSafetyCommands(program: Command): void {\n const dataSafety = program\n .command(\"data-safety\")\n .description(\"Manage data safety declarations\");\n\n // Get — not supported by Google Play API (no GET endpoint for data safety)\n dataSafety\n .command(\"get\")\n .description(\"Get the current data safety declaration\")\n .action(async () => {\n console.error(\"Error: The Google Play Developer API does not provide a GET endpoint for data safety declarations.\");\n console.error(\"\");\n console.error(\"Data safety labels can only be updated (not read) via the API.\");\n console.error(\"To view your current data safety declaration, use the Google Play Console:\");\n console.error(\" https://play.google.com/console → App content → Data safety\");\n console.error(\"\");\n console.error(\"To update data safety via the API, use: gpc data-safety update --file <csv-file>\");\n process.exit(2);\n });\n\n // Update\n dataSafety\n .command(\"update\")\n .description(\"Update data safety declaration from a JSON file\")\n .requiredOption(\"--file <path>\", \"Path to data safety JSON file\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"data-safety update\",\n action: \"update data safety from\",\n target: options.file,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await importDataSafety(client, packageName, options.file);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Export — not supported (no GET endpoint)\n dataSafety\n .command(\"export\")\n .description(\"Export data safety declaration to a JSON file\")\n .option(\"--output <path>\", \"Output file path\", \"data-safety.json\")\n .action(async () => {\n console.error(\"Error: The Google Play Developer API does not provide a GET endpoint for data safety declarations.\");\n console.error(\"Data safety labels cannot be exported via the API.\");\n console.error(\"\");\n console.error(\"To export your data safety declaration, use the Google Play Console:\");\n console.error(\" App content → Data safety → Export to CSV\");\n process.exit(2);\n });\n}\n"],"mappings":";;;;;;;;;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC;AAAA,EAIE;AAAA,EACA;AAAA,OACK;AAIP,SAAS,mBAAmB,YAAgC,QAA2B;AACrF,QAAM,OAAO,cAAc,OAAO;AAClC,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,UAAU,QAAmB;AAC1C,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,gBAAgB,EAAE,KAAK,CAAC;AACjC;AAEO,SAAS,2BAA2B,SAAwB;AACjE,QAAM,aAAa,QAChB,QAAQ,aAAa,EACrB,YAAY,iCAAiC;AAGhD,aACG,QAAQ,KAAK,EACb,YAAY,yCAAyC,EACrD,OAAO,YAAY;AAClB,YAAQ,MAAM,oGAAoG;AAClH,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,gEAAgE;AAC9E,YAAQ,MAAM,4EAA4E;AAC1F,YAAQ,MAAM,yEAA+D;AAC7E,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,kFAAkF;AAChG,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAGH,aACG,QAAQ,QAAQ,EAChB,YAAY,iDAAiD,EAC7D,eAAe,iBAAiB,+BAA+B,EAC/D,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI,SAAS,OAAO,GAAG;AACrB;AAAA,QACE;AAAA,UACE,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ,QAAQ;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,QAAI;AACF,YAAM,SAAS,MAAM,iBAAiB,QAAQ,aAAa,QAAQ,IAAI;AACvE,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,aACG,QAAQ,QAAQ,EAChB,YAAY,+CAA+C,EAC3D,OAAO,mBAAmB,oBAAoB,kBAAkB,EAChE,OAAO,YAAY;AAClB,YAAQ,MAAM,oGAAoG;AAClH,YAAQ,MAAM,oDAAoD;AAClE,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,sEAAsE;AACpF,YAAQ,MAAM,uDAA6C;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACL;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig, getCacheDir, getConfigDir } from \"@gpc-cli/config\";\nimport { resolveAuth, AuthError } from \"@gpc-cli/auth\";\nimport { existsSync, accessSync, statSync, constants } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { lookup } from \"node:dns/promises\";\n\nexport interface CheckResult {\n name: string;\n status: \"pass\" | \"fail\" | \"warn\" | \"info\";\n message: string;\n suggestion?: string;\n}\n\nconst PASS = \"\\u2713\";\nconst FAIL = \"\\u2717\";\nconst WARN = \"\\u26A0\";\nconst INFO = \"-\";\n\nfunction icon(status: CheckResult[\"status\"]): string {\n switch (status) {\n case \"pass\":\n return PASS;\n case \"fail\":\n return FAIL;\n case \"warn\":\n return WARN;\n case \"info\":\n return INFO;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Pure, testable check helpers\n// ---------------------------------------------------------------------------\n\nconst ANDROID_PACKAGE_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)+$/;\n\nexport function checkNodeVersion(nodeVersion: string): CheckResult {\n const major = parseInt(nodeVersion.split(\".\")[0] ?? \"0\", 10);\n return major >= 20\n ? { name: \"node\", status: \"pass\", message: `Node.js ${nodeVersion}` }\n : {\n name: \"node\",\n status: \"fail\",\n message: `Node.js ${nodeVersion} (requires >=20)`,\n suggestion: \"Upgrade Node.js to v20 or later: https://nodejs.org\",\n };\n}\n\nexport function checkPackageName(app: string | undefined): CheckResult | null {\n if (!app) return null;\n return ANDROID_PACKAGE_RE.test(app)\n ? { name: \"package-name\", status: \"pass\", message: `Package name format OK: ${app}` }\n : {\n name: \"package-name\",\n status: \"warn\",\n message: `Package name may be invalid: ${app}`,\n suggestion:\n \"Android package names must have 2+ dot-separated segments, each starting with a letter (e.g. com.example.app)\",\n };\n}\n\nexport function checkProxy(url: string | undefined): CheckResult | null {\n if (!url) return null;\n try {\n new URL(url);\n return { name: \"proxy\", status: \"pass\", message: `Proxy configured: ${url}` };\n } catch {\n return {\n name: \"proxy\",\n status: \"warn\",\n message: `Invalid proxy URL: ${url}`,\n suggestion: \"Set HTTPS_PROXY to a valid URL (e.g. http://proxy.example.com:8080)\",\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\n// ---------------------------------------------------------------------------\n\nexport function registerDoctorCommand(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"Verify setup and connectivity\")\n .action(async (_opts, cmd) => {\n const results: CheckResult[] = [];\n const parentOpts = cmd.parent?.opts() ?? {};\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n\n // 1. Node.js version\n results.push(checkNodeVersion(process.versions.node));\n\n // 2. Config file\n let config;\n try {\n config = await loadConfig();\n results.push({ name: \"config\", status: \"pass\", message: \"Configuration loaded\" });\n if (config.app) {\n results.push({\n name: \"default-app\",\n status: \"pass\",\n message: `Default app: ${config.app}`,\n });\n // 2b. Package name format\n const pkgCheck = checkPackageName(config.app);\n if (pkgCheck) results.push(pkgCheck);\n } else {\n results.push({\n name: \"default-app\",\n status: \"info\",\n message: \"No default app configured\",\n suggestion: \"Use --app flag or run: gpc config set app <package>\",\n });\n }\n } catch {\n results.push({\n name: \"config\",\n status: \"fail\",\n message: \"Configuration could not be loaded\",\n suggestion: \"Run gpc config init to create a config file, or check .gpcrc.json for syntax errors\",\n });\n }\n\n // 3. Config directory permissions\n const configDir = getConfigDir();\n try {\n if (existsSync(configDir)) {\n accessSync(configDir, constants.R_OK | constants.W_OK);\n results.push({\n name: \"config-dir\",\n status: \"pass\",\n message: `Config directory: ${configDir}`,\n });\n } else {\n results.push({\n name: \"config-dir\",\n status: \"info\",\n message: `Config directory does not exist yet: ${configDir}`,\n });\n }\n } catch {\n results.push({\n name: \"config-dir\",\n status: \"warn\",\n message: `Config directory not writable: ${configDir}`,\n suggestion: `Fix permissions: chmod 755 ${configDir}`,\n });\n }\n\n // 4. Cache directory permissions\n const cacheDir = getCacheDir();\n try {\n if (existsSync(cacheDir)) {\n accessSync(cacheDir, constants.R_OK | constants.W_OK);\n results.push({\n name: \"cache-dir\",\n status: \"pass\",\n message: `Cache directory: ${cacheDir}`,\n });\n } else {\n results.push({\n name: \"cache-dir\",\n status: \"info\",\n message: `Cache directory does not exist yet: ${cacheDir}`,\n });\n }\n } catch {\n results.push({\n name: \"cache-dir\",\n status: \"warn\",\n message: `Cache directory not writable: ${cacheDir}`,\n suggestion: `Fix permissions: chmod 700 ${cacheDir}`,\n });\n }\n\n // 5. Service account file existence + permissions\n if (config?.auth?.serviceAccount) {\n const saValue = config.auth.serviceAccount;\n const looksLikePath = !saValue.trim().startsWith(\"{\");\n if (looksLikePath) {\n const saPath = resolve(saValue);\n if (existsSync(saPath)) {\n try {\n accessSync(saPath, constants.R_OK);\n results.push({\n name: \"service-account-file\",\n status: \"pass\",\n message: `Service account file: ${saPath}`,\n });\n } catch {\n results.push({\n name: \"service-account-file\",\n status: \"fail\",\n message: `Service account file not readable: ${saPath}`,\n suggestion: `Fix permissions: chmod 600 ${saPath}`,\n });\n }\n\n // 5b. SA key file permissions (Unix only)\n if (process.platform !== \"win32\") {\n try {\n const mode = statSync(saPath).mode;\n const groupRead = (mode & 0o040) !== 0;\n const worldRead = (mode & 0o004) !== 0;\n if (groupRead || worldRead) {\n results.push({\n name: \"service-account-permissions\",\n status: \"warn\",\n message: `Service account file is group/world-readable (mode: ${(mode & 0o777).toString(8)})`,\n suggestion: `Restrict permissions: chmod 600 ${saPath}`,\n });\n } else {\n results.push({\n name: \"service-account-permissions\",\n status: \"pass\",\n message: `Service account file permissions OK (mode: ${(mode & 0o777).toString(8)})`,\n });\n }\n } catch {\n // stat failed — skip permission check\n }\n }\n } else {\n results.push({\n name: \"service-account-file\",\n status: \"fail\",\n message: `Service account file not found: ${saPath}`,\n suggestion: \"Check the path in your config or GPC_SERVICE_ACCOUNT env var\",\n });\n }\n }\n }\n\n // 6. Profile validation\n const gpcProfile = process.env[\"GPC_PROFILE\"];\n if (gpcProfile && config) {\n if (config.profiles && gpcProfile in config.profiles) {\n results.push({\n name: \"profile\",\n status: \"pass\",\n message: `Profile \"${gpcProfile}\" found`,\n });\n } else {\n const available = config.profiles ? Object.keys(config.profiles).join(\", \") : \"\";\n results.push({\n name: \"profile\",\n status: \"fail\",\n message: `Profile \"${gpcProfile}\" not found`,\n suggestion: available\n ? `Available profiles: ${available}. Create with: gpc auth login --profile ${gpcProfile}`\n : `No profiles defined. Create one with: gpc auth login --profile ${gpcProfile}`,\n });\n }\n }\n\n // 7. Proxy configuration\n const proxyUrl =\n process.env[\"HTTPS_PROXY\"] ||\n process.env[\"https_proxy\"] ||\n process.env[\"HTTP_PROXY\"] ||\n process.env[\"http_proxy\"];\n const proxyCheck = checkProxy(proxyUrl);\n if (proxyCheck) results.push(proxyCheck);\n\n // 8. CA certificate\n const caCert = process.env[\"GPC_CA_CERT\"] || process.env[\"NODE_EXTRA_CA_CERTS\"];\n if (caCert) {\n if (existsSync(caCert)) {\n results.push({\n name: \"ca-cert\",\n status: \"pass\",\n message: `CA certificate: ${caCert}`,\n });\n } else {\n results.push({\n name: \"ca-cert\",\n status: \"warn\",\n message: `CA certificate file not found: ${caCert}`,\n suggestion: \"Check that GPC_CA_CERT points to an existing PEM file\",\n });\n }\n }\n\n // 9. DNS resolution — both API endpoints\n const dnsHosts = [\n \"androidpublisher.googleapis.com\",\n \"playdeveloperreporting.googleapis.com\",\n ];\n for (const host of dnsHosts) {\n try {\n await lookup(host);\n results.push({\n name: \"dns\",\n status: \"pass\",\n message: `DNS: ${host}`,\n });\n } catch {\n results.push({\n name: \"dns\",\n status: \"fail\",\n message: `Cannot resolve ${host}`,\n suggestion: \"Check your DNS settings and network connection\",\n });\n }\n }\n\n // 10. Authentication + API connectivity\n try {\n const authConfig = config ?? (await loadConfig());\n const client = await resolveAuth({\n serviceAccountPath: authConfig.auth?.serviceAccount,\n });\n results.push({\n name: \"auth\",\n status: \"pass\",\n message: `Authenticated as ${client.getClientEmail()}`,\n });\n\n await client.getAccessToken();\n results.push({\n name: \"api-connectivity\",\n status: \"pass\",\n message: \"API connectivity verified\",\n });\n } catch (error) {\n if (error instanceof AuthError) {\n results.push({\n name: \"auth\",\n status: \"fail\",\n message: `Authentication: ${error.message}`,\n suggestion: error.suggestion,\n });\n } else {\n results.push({\n name: \"api-connectivity\",\n status: \"fail\",\n message: \"API connectivity failed\",\n suggestion: \"Check your network connection and credentials\",\n });\n }\n }\n\n // ---------------------------------------------------------------------------\n // Output\n // ---------------------------------------------------------------------------\n\n const errors = results.filter((r) => r.status === \"fail\").length;\n const warnings = results.filter((r) => r.status === \"warn\").length;\n const passed = results.filter((r) => r.status === \"pass\").length;\n\n if (jsonMode) {\n console.log(\n JSON.stringify({ success: errors === 0, errors, warnings, checks: results }, null, 2),\n );\n if (errors > 0) process.exit(1);\n return;\n }\n\n console.log(\"GPC Doctor\\n\");\n for (const r of results) {\n console.log(` ${icon(r.status)} ${r.message}`);\n if (r.suggestion && r.status !== \"pass\") {\n console.log(` ${r.suggestion}`);\n }\n }\n\n console.log(\n `\\n ${PASS} ${passed} passed ${WARN} ${warnings} warning${warnings !== 1 ? \"s\" : \"\"} ${FAIL} ${errors} failed`,\n );\n\n if (errors > 0) {\n console.log(\"\\nSome checks failed. Fix the issues above and run again.\");\n process.exit(1);\n } else if (warnings > 0) {\n console.log(\"\\nAll checks passed with warnings.\");\n } else {\n console.log(\"\\nAll checks passed!\");\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/feedback.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { execFile } from \"node:child_process\";\nimport { detectInstallMethod } from \"../updater.js\";\n\nexport function registerFeedbackCommand(program: Command): void {\n program\n .command(\"feedback\")\n .description(\"Open a pre-filled GitHub issue with system diagnostics\")\n .option(\"--title <title>\", \"Issue title\")\n .action(async (opts) => {\n const version = process.env[\"__GPC_VERSION\"] || \"0.0.0\";\n const body = [\n \"**GPC version:** \" + version,\n \"**Node:** \" + process.version,\n \"**Platform:** \" + process.platform + \"/\" + process.arch,\n \"**Install method:** \" + detectInstallMethod(),\n \"\",\n \"**Describe the issue:**\",\n \"<!-- Replace this with your bug description -->\",\n ].join(\"\\n\");\n const params = new URLSearchParams({\n title: opts.title ?? \"Bug report\",\n body,\n labels: \"bug\",\n });\n const url = `https://github.com/yasserstudio/gpc/issues/new?${params}`;\n if (process.platform === \"win32\") {\n execFile(\"cmd\", [\"/c\", \"start\", \"\", url], (err) => {\n if (err) console.log(`Open in your browser:\\n${url}`);\n else console.log(\"Opened GitHub issue form in your browser.\");\n });\n } else {\n const cmd = process.platform === \"darwin\" ? \"open\" : \"xdg-open\";\n execFile(cmd, [url], (err) => {\n if (err) console.log(`Open in your browser:\\n${url}`);\n else console.log(\"Opened GitHub issue form in your browser.\");\n });\n }\n });\n}\n"],"mappings":";;;;;;;AACA,SAAS,gBAAgB;AAGlB,SAAS,wBAAwB,SAAwB;AAC9D,UACG,QAAQ,UAAU,EAClB,YAAY,wDAAwD,EACpE,OAAO,mBAAmB,aAAa,EACvC,OAAO,OAAO,SAAS;AACtB,UAAM,UAAU,QAAQ,IAAI,eAAe,KAAK;AAChD,UAAM,OAAO;AAAA,MACX,sBAAsB;AAAA,MACtB,eAAe,QAAQ;AAAA,MACvB,mBAAmB,QAAQ,WAAW,MAAM,QAAQ;AAAA,MACpD,yBAAyB,oBAAoB;AAAA,MAC7C;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AACX,UAAM,SAAS,IAAI,gBAAgB;AAAA,MACjC,OAAO,KAAK,SAAS;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,MAAM,kDAAkD,MAAM;AACpE,QAAI,QAAQ,aAAa,SAAS;AAChC,eAAS,OAAO,CAAC,MAAM,SAAS,IAAI,GAAG,GAAG,CAAC,QAAQ;AACjD,YAAI,IAAK,SAAQ,IAAI;AAAA,EAA0B,GAAG,EAAE;AAAA,YAC/C,SAAQ,IAAI,2CAA2C;AAAA,MAC9D,CAAC;AAAA,IACH,OAAO;AACL,YAAM,MAAM,QAAQ,aAAa,WAAW,SAAS;AACrD,eAAS,KAAK,CAAC,GAAG,GAAG,CAAC,QAAQ;AAC5B,YAAI,IAAK,SAAQ,IAAI;AAAA,EAA0B,GAAG,EAAE;AAAA,YAC/C,SAAQ,IAAI,2CAA2C;AAAA,MAC9D,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACL;","names":[]}
|
package/dist/iap-BBHF7BLZ.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/iap.ts"],"sourcesContent":["import type { GpcConfig } from \"@gpc-cli/config\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport {\n listOneTimeProducts,\n getOneTimeProduct,\n createInAppProduct,\n updateInAppProduct,\n deleteInAppProduct,\n syncInAppProducts,\n listInAppProducts,\n batchSyncInAppProducts,\n formatOutput,\n sortResults,\n createSpinner,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { getOutputFormat } from \"../format.js\";\nimport { requireConfirm } from \"../prompt.js\";\nimport { readJsonFile } from \"../json.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerIapCommands(program: Command): void {\n const iap = program.command(\"iap\").description(\"Manage in-app products (uses one-time products API)\");\n\n iap\n .command(\"list\")\n .description(\"List in-app products\")\n .option(\"--max <n>\", \"Maximum results per page\", parseInt)\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n console.error(\"Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)\");\n\n try {\n const result = await listOneTimeProducts(client, packageName);\n let products = result.oneTimeProducts || [];\n if (options.sort) {\n products = sortResults(products, options.sort);\n }\n console.log(formatOutput(products, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"get <sku>\")\n .description(\"Get an in-app product\")\n .action(async (sku: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n console.error(\"Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)\");\n\n try {\n const result = await getOneTimeProduct(client, packageName, sku);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"create\")\n .description(\"Create an in-app product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"iap create\",\n action: \"create\",\n target: `in-app product from ${options.file}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await createInAppProduct(client, packageName, data as any);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"update <sku>\")\n .description(\"Update an in-app product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .action(async (sku: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"iap update\",\n action: \"update\",\n target: sku,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await updateInAppProduct(client, packageName, sku, data as any);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"delete <sku>\")\n .description(\"Delete an in-app product\")\n .action(async (sku: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete in-app product \"${sku}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"iap delete\",\n action: \"delete\",\n target: sku,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteInAppProduct(client, packageName, sku);\n console.log(`In-app product ${sku} deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"sync\")\n .description(\"Sync in-app products from a directory of JSON files\")\n .requiredOption(\"--dir <path>\", \"Directory containing product JSON files\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n const dryRun = isDryRun(program);\n\n const spinner = createSpinner(\"Syncing in-app products...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const result = await syncInAppProducts(client, packageName, options.dir, {\n dryRun,\n });\n spinner.stop(\"Sync complete\");\n if (dryRun) {\n console.log(`[dry-run] Would create: ${result.created}, update: ${result.updated}`);\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Sync failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"batch-get\")\n .description(\"Batch get multiple in-app products\")\n .option(\"--skus <skus>\", \"Comma-separated list of SKUs\")\n .option(\"--file <path>\", \"JSON file with array of SKUs\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n let skus: string[];\n if (options.file) {\n const data = await readJsonFile(options.file);\n skus = Array.isArray(data) ? data : (data as Record<string, unknown>)[\"skus\"] as string[] || [];\n } else if (options.skus) {\n skus = options.skus.split(\",\").map((s: string) => s.trim());\n } else {\n console.error(\"Error: Provide --skus <sku1,sku2,...> or --file <path>\");\n process.exit(2);\n return;\n }\n\n console.error(\"Note: Using inappproducts batch API\");\n\n try {\n const products = await client.inappproducts.batchGet(packageName, skus);\n if (format !== \"json\") {\n const rows = products.map((p: Record<string, unknown>) => ({\n sku: p[\"sku\"] || \"-\",\n status: p[\"status\"] || \"-\",\n purchaseType: p[\"purchaseType\"] || \"-\",\n defaultPrice: (() => {\n const price = p[\"defaultPrice\"] as Record<string, unknown> | undefined;\n return price ? `${price[\"priceMicros\"] ? Number(price[\"priceMicros\"]) / 1_000_000 : \"-\"} ${price[\"currency\"] || \"\"}` : \"-\";\n })(),\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(products, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"batch-update\")\n .description(\"Batch update multiple in-app products from a JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with array of product objects\")\n .option(\"--dry-run\", \"Preview changes without executing\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (options.dryRun || isDryRun(program)) {\n const data = await readJsonFile(options.file);\n const products = Array.isArray(data) ? data : [];\n console.log(`[dry-run] Would batch update ${products.length} product(s)`);\n if (format !== \"json\") {\n const rows = products.map((p: Record<string, unknown>) => ({\n sku: p[\"sku\"] || \"-\",\n action: \"update\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(products, format));\n }\n return;\n }\n\n const client = await getClient(config);\n console.error(\"Note: Using inappproducts batch API\");\n\n const spinner = createSpinner(\"Batch updating products...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const data = await readJsonFile(options.file);\n const products = Array.isArray(data) ? data : [];\n const request = {\n requests: products.map((p: Record<string, unknown>) => ({\n inappproduct: p,\n packageName,\n sku: p[\"sku\"] as string,\n })),\n };\n const result = await client.inappproducts.batchUpdate(packageName, request as any);\n spinner.stop(\"Batch update complete\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Batch update failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
|