@gpc-cli/cli 0.9.34 → 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 +20 -15
- 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 +2 -2
- 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-5CSWPQO6.js → chunk-DDTPDKTB.js} +101 -31
- package/dist/chunk-DDTPDKTB.js.map +1 -0
- package/dist/{config-7EOY5HGL.js → config-REB7NINL.js} +4 -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-UKKOK55S.js → doctor-QDIFTXNB.js} +44 -2
- 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-6XHJV5HX.js → iap-MBDD7VWP.js} +1 -1
- package/dist/iap-MBDD7VWP.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{listings-TOYS6XBU.js → listings-7TWCGGMS.js} +90 -9
- package/dist/listings-7TWCGGMS.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-UHK4FGK6.js → reviews-NN7YQITF.js} +55 -3
- package/dist/reviews-NN7YQITF.js.map +1 -0
- package/dist/{status-DQYZ7A6Y.js → status-L5S2FGZ4.js} +13 -3
- 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-QGWOFH7E.js → vitals-LFL75LA6.js} +113 -2
- 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-5CSWPQO6.js.map +0 -1
- package/dist/config-7EOY5HGL.js.map +0 -1
- package/dist/data-safety-GDPKV5PN.js.map +0 -1
- package/dist/doctor-UKKOK55S.js.map +0 -1
- package/dist/feedback-W5MZMRF2.js.map +0 -1
- package/dist/iap-6XHJV5HX.js.map +0 -1
- package/dist/listings-TOYS6XBU.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-UHK4FGK6.js.map +0 -1
- package/dist/status-DQYZ7A6Y.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-QGWOFH7E.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig, getCacheDir, getConfigDir } from \"@gpc-cli/config\";\nimport { green, red, yellow } from \"../colors.js\";\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 green(PASS);\n case \"fail\":\n return red(FAIL);\n case \"warn\":\n return yellow(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\nasync function applyFix(check: CheckResult): Promise<string | null> {\n switch (check.name) {\n case \"config-dir\":\n case \"cache-dir\": {\n const dirMatch = check.message.match(/: (.+)$/);\n if (!dirMatch?.[1]) return null;\n const { mkdir } = await import(\"node:fs/promises\");\n await mkdir(dirMatch[1], { recursive: true, mode: check.name === \"cache-dir\" ? 0o700 : 0o755 });\n return `Created ${dirMatch[1]}`;\n }\n case \"service-account-permissions\": {\n const saPath = check.suggestion?.match(/chmod 600 (.+)$/)?.[1];\n if (!saPath) return null;\n const { chmod } = await import(\"node:fs/promises\");\n await chmod(saPath, 0o600);\n return `Fixed permissions on ${saPath}`;\n }\n case \"config\": {\n const { initConfig } = await import(\"@gpc-cli/config\");\n await initConfig({});\n return \"Initialized config file\";\n }\n default:\n return null;\n }\n}\n\nexport function registerDoctorCommand(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"Verify setup and connectivity\")\n .option(\"--fix\", \"Attempt to auto-fix failing checks\")\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 // Auto-fix failing checks if --fix was passed\n if (opts[\"fix\"]) {\n for (const r of results) {\n if (r.status === \"fail\" || r.status === \"warn\") {\n try {\n const fixMsg = await applyFix(r);\n if (fixMsg) {\n console.log(` ${green(\"→\")} Fixed: ${fixMsg}`);\n r.status = \"pass\";\n r.message += \" (fixed)\";\n }\n } catch (err) {\n console.error(` ${red(\"✗\")} Could not fix \"${r.name}\": ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n }\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(`\\n${green(\"✓\")} Ready. Try: gpc status`);\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
isDryRun,
|
|
4
|
+
printDryRun
|
|
5
|
+
} from "./chunk-Y3QZDAKS.js";
|
|
6
|
+
import {
|
|
7
|
+
getOutputFormat
|
|
8
|
+
} from "./chunk-ELXAK7GI.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/enterprise.ts
|
|
11
|
+
import { loadConfig } from "@gpc-cli/config";
|
|
12
|
+
import { resolveAuth } from "@gpc-cli/auth";
|
|
13
|
+
import { createEnterpriseClient } from "@gpc-cli/api";
|
|
14
|
+
import { listEnterpriseApps, createEnterpriseApp, formatOutput } from "@gpc-cli/core";
|
|
15
|
+
async function getClient() {
|
|
16
|
+
const config = await loadConfig();
|
|
17
|
+
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
18
|
+
return { client: createEnterpriseClient({ auth }), config };
|
|
19
|
+
}
|
|
20
|
+
function registerEnterpriseCommands(program) {
|
|
21
|
+
const enterprise = program.command("enterprise").description("Manage private enterprise apps via Managed Google Play").requiredOption("--org <id>", "Google Play organization ID");
|
|
22
|
+
enterprise.command("list").description("List private enterprise apps").action(async () => {
|
|
23
|
+
const { client, config } = await getClient();
|
|
24
|
+
const orgId = enterprise.opts()["org"];
|
|
25
|
+
const format = getOutputFormat(program, config);
|
|
26
|
+
try {
|
|
27
|
+
const result = await listEnterpriseApps(client, orgId);
|
|
28
|
+
if (result.length === 0 && format !== "json") {
|
|
29
|
+
console.log("No enterprise apps found.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
console.log(formatOutput(result, format));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
35
|
+
process.exit(4);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
enterprise.command("create").description("Create a new private enterprise app").requiredOption("--title <title>", "App title").option("--lang <code>", "Language code (default: en_US)", "en_US").action(async (options) => {
|
|
39
|
+
const { client, config } = await getClient();
|
|
40
|
+
const orgId = enterprise.opts()["org"];
|
|
41
|
+
const format = getOutputFormat(program, config);
|
|
42
|
+
if (isDryRun(program)) {
|
|
43
|
+
printDryRun(
|
|
44
|
+
{ command: "enterprise create", action: "create enterprise app", target: options.title },
|
|
45
|
+
format,
|
|
46
|
+
formatOutput
|
|
47
|
+
);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const result = await createEnterpriseApp(client, orgId, {
|
|
52
|
+
title: options.title,
|
|
53
|
+
languageCode: options.lang
|
|
54
|
+
});
|
|
55
|
+
console.log(formatOutput(result, format));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
58
|
+
process.exit(4);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
registerEnterpriseCommands
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=enterprise-IH5HXYRB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/enterprise.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createEnterpriseClient } from \"@gpc-cli/api\";\nimport { listEnterpriseApps, createEnterpriseApp, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\n\nasync function getClient() {\n const config = await loadConfig();\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return { client: createEnterpriseClient({ auth }), config };\n}\n\nexport function registerEnterpriseCommands(program: Command): void {\n const enterprise = program\n .command(\"enterprise\")\n .description(\"Manage private enterprise apps via Managed Google Play\")\n .requiredOption(\"--org <id>\", \"Google Play organization ID\");\n\n enterprise\n .command(\"list\")\n .description(\"List private enterprise apps\")\n .action(async () => {\n const { client, config } = await getClient();\n const orgId = enterprise.opts()[\"org\"] as string;\n const format = getOutputFormat(program, config);\n\n try {\n const result = await listEnterpriseApps(client, orgId);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No enterprise apps 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 enterprise\n .command(\"create\")\n .description(\"Create a new private enterprise app\")\n .requiredOption(\"--title <title>\", \"App title\")\n .option(\"--lang <code>\", \"Language code (default: en_US)\", \"en_US\")\n .action(async (options) => {\n const { client, config } = await getClient();\n const orgId = enterprise.opts()[\"org\"] as string;\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"enterprise create\", action: \"create enterprise app\", target: options.title as string },\n format,\n formatOutput,\n );\n return;\n }\n\n try {\n const result = await createEnterpriseApp(client, orgId, {\n title: options.title as string,\n languageCode: options.lang as string,\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"],"mappings":";;;;;;;;;;AACA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,8BAA8B;AACvC,SAAS,oBAAoB,qBAAqB,oBAAoB;AAItE,eAAe,YAAY;AACzB,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,EAAE,QAAQ,uBAAuB,EAAE,KAAK,CAAC,GAAG,OAAO;AAC5D;AAEO,SAAS,2BAA2B,SAAwB;AACjE,QAAM,aAAa,QAChB,QAAQ,YAAY,EACpB,YAAY,wDAAwD,EACpE,eAAe,cAAc,6BAA6B;AAE7D,aACG,QAAQ,MAAM,EACd,YAAY,8BAA8B,EAC1C,OAAO,YAAY;AAClB,UAAM,EAAE,QAAQ,OAAO,IAAI,MAAM,UAAU;AAC3C,UAAM,QAAQ,WAAW,KAAK,EAAE,KAAK;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,mBAAmB,QAAQ,KAAK;AACrD,UAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,gBAAQ,IAAI,2BAA2B;AACvC;AAAA,MACF;AACA,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;AAEH,aACG,QAAQ,QAAQ,EAChB,YAAY,qCAAqC,EACjD,eAAe,mBAAmB,WAAW,EAC7C,OAAO,iBAAiB,kCAAkC,OAAO,EACjE,OAAO,OAAO,YAAY;AACzB,UAAM,EAAE,QAAQ,OAAO,IAAI,MAAM,UAAU;AAC3C,UAAM,QAAQ,WAAW,KAAK,EAAE,KAAK;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI,SAAS,OAAO,GAAG;AACrB;AAAA,QACE,EAAE,SAAS,qBAAqB,QAAQ,yBAAyB,QAAQ,QAAQ,MAAgB;AAAA,QACjG;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,oBAAoB,QAAQ,OAAO;AAAA,QACtD,OAAO,QAAQ;AAAA,QACf,cAAc,QAAQ;AAAA,MACxB,CAAC;AACD,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;AACL;","names":[]}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
detectInstallMethod
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-43SH6XEJ.js";
|
|
5
5
|
import "./chunk-4O4D5SGL.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/feedback.ts
|
|
8
8
|
import { execFile } from "child_process";
|
|
9
9
|
function registerFeedbackCommand(program) {
|
|
10
10
|
program.command("feedback").description("Open a pre-filled GitHub issue with system diagnostics").option("--title <title>", "Issue title").action(async (opts) => {
|
|
11
|
-
const version =
|
|
11
|
+
const version = "0.9.35";
|
|
12
12
|
const body = [
|
|
13
13
|
"**GPC version:** " + version,
|
|
14
14
|
"**Node:** " + process.version,
|
|
@@ -43,4 +43,4 @@ ${url}`);
|
|
|
43
43
|
export {
|
|
44
44
|
registerFeedbackCommand
|
|
45
45
|
};
|
|
46
|
-
//# sourceMappingURL=feedback-
|
|
46
|
+
//# sourceMappingURL=feedback-NVGHRU7A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/feedback.ts"],"sourcesContent":["import type { 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;AAChB,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":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getOutputFormat
|
|
4
|
+
} from "./chunk-ELXAK7GI.js";
|
|
5
|
+
|
|
6
|
+
// src/commands/games.ts
|
|
7
|
+
import { loadConfig } from "@gpc-cli/config";
|
|
8
|
+
import { resolveAuth } from "@gpc-cli/auth";
|
|
9
|
+
import { createGamesClient } from "@gpc-cli/api";
|
|
10
|
+
import { listLeaderboards, listAchievements, listEvents, formatOutput } from "@gpc-cli/core";
|
|
11
|
+
function resolvePackageName(packageArg, config) {
|
|
12
|
+
const name = packageArg || config.app;
|
|
13
|
+
if (!name) {
|
|
14
|
+
console.error("Error: No package name. Use --app <package> or gpc config set app <package>");
|
|
15
|
+
process.exit(2);
|
|
16
|
+
}
|
|
17
|
+
return name;
|
|
18
|
+
}
|
|
19
|
+
async function getClient(config) {
|
|
20
|
+
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
21
|
+
return createGamesClient({ auth });
|
|
22
|
+
}
|
|
23
|
+
function registerGamesCommands(program) {
|
|
24
|
+
const games = program.command("games").description("Manage Play Games Services \u2014 leaderboards, achievements, events");
|
|
25
|
+
games.command("leaderboards").description("List leaderboards for the app").action(async () => {
|
|
26
|
+
const config = await loadConfig();
|
|
27
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
28
|
+
const client = await getClient(config);
|
|
29
|
+
const format = getOutputFormat(program, config);
|
|
30
|
+
try {
|
|
31
|
+
const result = await listLeaderboards(client, packageName);
|
|
32
|
+
if (result.length === 0 && format !== "json") {
|
|
33
|
+
console.log("No leaderboards found.");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(formatOutput(result, format));
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
39
|
+
process.exit(4);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
games.command("achievements").description("List achievements for the app").action(async () => {
|
|
43
|
+
const config = await loadConfig();
|
|
44
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
45
|
+
const client = await getClient(config);
|
|
46
|
+
const format = getOutputFormat(program, config);
|
|
47
|
+
try {
|
|
48
|
+
const result = await listAchievements(client, packageName);
|
|
49
|
+
if (result.length === 0 && format !== "json") {
|
|
50
|
+
console.log("No achievements found.");
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
console.log(formatOutput(result, format));
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
56
|
+
process.exit(4);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
games.command("events").description("List events for the app").action(async () => {
|
|
60
|
+
const config = await loadConfig();
|
|
61
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
62
|
+
const client = await getClient(config);
|
|
63
|
+
const format = getOutputFormat(program, config);
|
|
64
|
+
try {
|
|
65
|
+
const result = await listEvents(client, packageName);
|
|
66
|
+
if (result.length === 0 && format !== "json") {
|
|
67
|
+
console.log("No events found.");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
console.log(formatOutput(result, format));
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
73
|
+
process.exit(4);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
registerGamesCommands
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=games-X57AGM3E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/games.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 { createGamesClient } from \"@gpc-cli/api\";\nimport { listLeaderboards, listAchievements, listEvents, formatOutput } from \"@gpc-cli/core\";\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 createGamesClient({ auth });\n}\n\nexport function registerGamesCommands(program: Command): void {\n const games = program\n .command(\"games\")\n .description(\"Manage Play Games Services — leaderboards, achievements, events\");\n\n games\n .command(\"leaderboards\")\n .description(\"List leaderboards for the app\")\n .action(async () => {\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 try {\n const result = await listLeaderboards(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No leaderboards 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 games\n .command(\"achievements\")\n .description(\"List achievements for the app\")\n .action(async () => {\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 try {\n const result = await listAchievements(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No achievements 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 games\n .command(\"events\")\n .description(\"List events for the app\")\n .action(async () => {\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 try {\n const result = await listEvents(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No events 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"],"mappings":";;;;;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,kBAAkB,kBAAkB,YAAY,oBAAoB;AAG7E,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,kBAAkB,EAAE,KAAK,CAAC;AACnC;AAEO,SAAS,sBAAsB,SAAwB;AAC5D,QAAM,QAAQ,QACX,QAAQ,OAAO,EACf,YAAY,sEAAiE;AAEhF,QACG,QAAQ,cAAc,EACtB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,iBAAiB,QAAQ,WAAW;AACzD,UAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,gBAAQ,IAAI,wBAAwB;AACpC;AAAA,MACF;AACA,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;AAEH,QACG,QAAQ,cAAc,EACtB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,iBAAiB,QAAQ,WAAW;AACzD,UAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,gBAAQ,IAAI,wBAAwB;AACpC;AAAA,MACF;AACA,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;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,yBAAyB,EACrC,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,WAAW,QAAQ,WAAW;AACnD,UAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,gBAAQ,IAAI,kBAAkB;AAC9B;AAAA,MACF;AACA,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;AACL;","names":[]}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
isDryRun,
|
|
4
|
+
printDryRun
|
|
5
|
+
} from "./chunk-Y3QZDAKS.js";
|
|
6
|
+
import {
|
|
7
|
+
getOutputFormat
|
|
8
|
+
} from "./chunk-ELXAK7GI.js";
|
|
9
|
+
import {
|
|
10
|
+
requireConfirm
|
|
11
|
+
} from "./chunk-NV75I5VP.js";
|
|
12
|
+
|
|
13
|
+
// src/commands/grants.ts
|
|
14
|
+
import { loadConfig } from "@gpc-cli/config";
|
|
15
|
+
import { resolveAuth } from "@gpc-cli/auth";
|
|
16
|
+
import { createUsersClient } from "@gpc-cli/api";
|
|
17
|
+
import { listGrants, createGrant, updateGrant, deleteGrant, formatOutput } from "@gpc-cli/core";
|
|
18
|
+
function resolveDeveloperId(devIdArg, config) {
|
|
19
|
+
const id = devIdArg || config.developerId;
|
|
20
|
+
if (!id) {
|
|
21
|
+
console.error("Error: No developer ID. Use --developer-id <id> or gpc config set developerId <id>");
|
|
22
|
+
process.exit(2);
|
|
23
|
+
}
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
26
|
+
async function getClient(config) {
|
|
27
|
+
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
28
|
+
return createUsersClient({ auth });
|
|
29
|
+
}
|
|
30
|
+
function registerGrantsCommands(program) {
|
|
31
|
+
const grants = program.command("grants").description("Manage per-app permission grants for developer account users").option("--developer-id <id>", "Developer account ID");
|
|
32
|
+
grants.command("list <email>").description("List all per-app grants for a user").action(async (email) => {
|
|
33
|
+
const config = await loadConfig();
|
|
34
|
+
const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
|
|
35
|
+
const client = await getClient(config);
|
|
36
|
+
const format = getOutputFormat(program, config);
|
|
37
|
+
try {
|
|
38
|
+
const result = await listGrants(client, developerId, email);
|
|
39
|
+
if (result.length === 0) {
|
|
40
|
+
if (format === "json") {
|
|
41
|
+
console.log(formatOutput([], format));
|
|
42
|
+
} else {
|
|
43
|
+
console.log(`No grants found for ${email}.`);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
console.log(formatOutput(result, format));
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
process.exit(4);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
grants.command("create <email>").description("Grant app-level permissions to a user").requiredOption("--package <packageName>", "App package name").requiredOption("--permissions <list>", "Comma-separated permissions (e.g. CAN_MANAGE_RELEASES,VIEW_APP_INFORMATION)").action(async (email, options) => {
|
|
54
|
+
const config = await loadConfig();
|
|
55
|
+
const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
|
|
56
|
+
const format = getOutputFormat(program, config);
|
|
57
|
+
const perms = options.permissions.split(",").map((p) => p.trim());
|
|
58
|
+
if (isDryRun(program)) {
|
|
59
|
+
printDryRun(
|
|
60
|
+
{ command: "grants create", action: "grant permissions", target: `${email}/${options.package}`, details: { permissions: perms } },
|
|
61
|
+
format,
|
|
62
|
+
formatOutput
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const client = await getClient(config);
|
|
67
|
+
try {
|
|
68
|
+
const result = await createGrant(client, developerId, email, options.package, perms);
|
|
69
|
+
console.log(formatOutput(result, format));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
72
|
+
process.exit(4);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
grants.command("update <email>").description("Update app-level permissions for a user").requiredOption("--package <packageName>", "App package name").requiredOption("--permissions <list>", "New comma-separated permissions").action(async (email, options) => {
|
|
76
|
+
const config = await loadConfig();
|
|
77
|
+
const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
|
|
78
|
+
const format = getOutputFormat(program, config);
|
|
79
|
+
const perms = options.permissions.split(",").map((p) => p.trim());
|
|
80
|
+
if (isDryRun(program)) {
|
|
81
|
+
printDryRun(
|
|
82
|
+
{ command: "grants update", action: "update permissions", target: `${email}/${options.package}`, details: { permissions: perms } },
|
|
83
|
+
format,
|
|
84
|
+
formatOutput
|
|
85
|
+
);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const client = await getClient(config);
|
|
89
|
+
try {
|
|
90
|
+
const result = await updateGrant(client, developerId, email, options.package, perms);
|
|
91
|
+
console.log(formatOutput(result, format));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
94
|
+
process.exit(4);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
grants.command("delete <email>").description("Remove a per-app grant from a user").requiredOption("--package <packageName>", "App package name").action(async (email, options) => {
|
|
98
|
+
const config = await loadConfig();
|
|
99
|
+
const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
|
|
100
|
+
const format = getOutputFormat(program, config);
|
|
101
|
+
await requireConfirm(`Remove grant for "${email}" on ${options.package}?`, program);
|
|
102
|
+
if (isDryRun(program)) {
|
|
103
|
+
printDryRun(
|
|
104
|
+
{ command: "grants delete", action: "remove grant", target: `${email}/${options.package}` },
|
|
105
|
+
format,
|
|
106
|
+
formatOutput
|
|
107
|
+
);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const client = await getClient(config);
|
|
111
|
+
try {
|
|
112
|
+
await deleteGrant(client, developerId, email, options.package);
|
|
113
|
+
console.log(`Grant removed for ${email} on ${options.package}.`);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
116
|
+
process.exit(4);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
registerGrantsCommands
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=grants-CXTTYKR3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/grants.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 { createUsersClient } from \"@gpc-cli/api\";\nimport { listGrants, createGrant, updateGrant, deleteGrant, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\n\nfunction resolveDeveloperId(devIdArg: string | undefined, config: GpcConfig): string {\n const id = devIdArg || config.developerId;\n if (!id) {\n console.error(\"Error: No developer ID. Use --developer-id <id> or gpc config set developerId <id>\");\n process.exit(2);\n }\n return id;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createUsersClient({ auth });\n}\n\nexport function registerGrantsCommands(program: Command): void {\n const grants = program\n .command(\"grants\")\n .description(\"Manage per-app permission grants for developer account users\")\n .option(\"--developer-id <id>\", \"Developer account ID\");\n\n grants\n .command(\"list <email>\")\n .description(\"List all per-app grants for a user\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await listGrants(client, developerId, email);\n if (result.length === 0) {\n if (format === \"json\") {\n console.log(formatOutput([], format));\n } else {\n console.log(`No grants found for ${email}.`);\n }\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 grants\n .command(\"create <email>\")\n .description(\"Grant app-level permissions to a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\"--permissions <list>\", \"Comma-separated permissions (e.g. CAN_MANAGE_RELEASES,VIEW_APP_INFORMATION)\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"grants create\", action: \"grant permissions\", target: `${email}/${options.package}`, details: { permissions: perms } },\n format, formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await createGrant(client, developerId, email, options.package, perms);\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 grants\n .command(\"update <email>\")\n .description(\"Update app-level permissions for a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\"--permissions <list>\", \"New comma-separated permissions\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"grants update\", action: \"update permissions\", target: `${email}/${options.package}`, details: { permissions: perms } },\n format, formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await updateGrant(client, developerId, email, options.package, perms);\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 grants\n .command(\"delete <email>\")\n .description(\"Remove a per-app grant from a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n await requireConfirm(`Remove grant for \"${email}\" on ${options.package}?`, program);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"grants delete\", action: \"remove grant\", target: `${email}/${options.package}` },\n format, formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteGrant(client, developerId, email, options.package);\n console.log(`Grant removed for ${email} on ${options.package}.`);\n } catch (error) {\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":[]}
|
|
@@ -0,0 +1 @@
|
|
|
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 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 console.error(\n \"Note: The inappproducts batchGet endpoint is permanently blocked by Google Play (returns 403 PERMISSION_DENIED).\\n\" +\n \"Use `gpc iap get <sku>` for a single product, or `gpc iap list` for all products.\"\n );\n process.exit(1);\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":[]}
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,9 @@ import {
|
|
|
26
26
|
deleteListing,
|
|
27
27
|
pullListings,
|
|
28
28
|
pushListings,
|
|
29
|
-
|
|
29
|
+
diffListingsEnhanced,
|
|
30
|
+
lintLocalListings,
|
|
31
|
+
analyzeRemoteListings,
|
|
30
32
|
listImages,
|
|
31
33
|
uploadImage,
|
|
32
34
|
deleteImage,
|
|
@@ -188,7 +190,7 @@ function registerListingsCommands(program) {
|
|
|
188
190
|
process.exit(4);
|
|
189
191
|
}
|
|
190
192
|
});
|
|
191
|
-
listings.command("push").description("Upload listings from Fastlane-format directory").option("--dir <path>", "Source directory (default: metadata)", "metadata").action(async (options) => {
|
|
193
|
+
listings.command("push").description("Upload listings from Fastlane-format directory").option("--dir <path>", "Source directory (default: metadata)", "metadata").option("--force", "Push even if fields exceed character limits").action(async (options) => {
|
|
192
194
|
const config = await loadConfig();
|
|
193
195
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
194
196
|
const client = await getClient(config);
|
|
@@ -198,7 +200,8 @@ function registerListingsCommands(program) {
|
|
|
198
200
|
try {
|
|
199
201
|
const dryRun = isDryRun(program);
|
|
200
202
|
const result = await pushListings(client, packageName, options.dir, {
|
|
201
|
-
dryRun
|
|
203
|
+
dryRun,
|
|
204
|
+
force: options.force
|
|
202
205
|
});
|
|
203
206
|
spinner.stop(dryRun ? "Dry-run complete (no changes made)" : "Listings pushed");
|
|
204
207
|
console.log(formatOutput(result, format));
|
|
@@ -208,13 +211,16 @@ function registerListingsCommands(program) {
|
|
|
208
211
|
process.exit(4);
|
|
209
212
|
}
|
|
210
213
|
});
|
|
211
|
-
listings.command("diff").description("Compare local Fastlane-format metadata against remote listings").option("--dir <path>", "Local metadata directory", "metadata").action(async (options) => {
|
|
214
|
+
listings.command("diff").description("Compare local Fastlane-format metadata against remote listings").option("--dir <path>", "Local metadata directory", "metadata").option("--lang <language>", "Filter diff to a specific language").option("--word-diff", "Show word-level inline diff for fullDescription").action(async (options) => {
|
|
212
215
|
const config = await loadConfig();
|
|
213
216
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
214
217
|
const client = await getClient(config);
|
|
215
218
|
const format = getOutputFormat(program, config);
|
|
216
219
|
try {
|
|
217
|
-
const diffs = await
|
|
220
|
+
const diffs = await diffListingsEnhanced(client, packageName, options.dir, {
|
|
221
|
+
lang: options.lang,
|
|
222
|
+
wordLevel: options.wordDiff
|
|
223
|
+
});
|
|
218
224
|
if (diffs.length === 0) {
|
|
219
225
|
if (format === "json") {
|
|
220
226
|
console.log(formatOutput([], format));
|
|
@@ -227,9 +233,14 @@ function registerListingsCommands(program) {
|
|
|
227
233
|
console.log(formatOutput(diffs, format));
|
|
228
234
|
} else {
|
|
229
235
|
for (const diff of diffs) {
|
|
230
|
-
|
|
231
|
-
console.log(
|
|
232
|
-
|
|
236
|
+
const charInfo = diff["chars"] ? ` (${diff["chars"]} chars)` : "";
|
|
237
|
+
console.log(`[${diff.language}] ${diff.field}:${charInfo}`);
|
|
238
|
+
if (diff["diffSummary"]) {
|
|
239
|
+
console.log(` ${diff["diffSummary"]}`);
|
|
240
|
+
} else {
|
|
241
|
+
console.log(green(` + local: ${diff.local || "(empty)"}`));
|
|
242
|
+
console.log(red(` - remote: ${diff.remote || "(empty)"}`));
|
|
243
|
+
}
|
|
233
244
|
}
|
|
234
245
|
}
|
|
235
246
|
} catch (error) {
|
|
@@ -237,6 +248,76 @@ function registerListingsCommands(program) {
|
|
|
237
248
|
process.exit(4);
|
|
238
249
|
}
|
|
239
250
|
});
|
|
251
|
+
listings.command("lint").description("Lint local listing metadata for Play Store character limits (no API)").option("--dir <path>", "Metadata directory", "metadata").action(async (options) => {
|
|
252
|
+
const format = getOutputFormat(program, await loadConfig());
|
|
253
|
+
try {
|
|
254
|
+
const results = await lintLocalListings(options.dir);
|
|
255
|
+
if (format === "json") {
|
|
256
|
+
console.log(formatOutput(results, format));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
let exitCode = 0;
|
|
260
|
+
for (const r of results) {
|
|
261
|
+
console.log(`
|
|
262
|
+
[${r.language}] ${r.valid ? green("\u2713 valid") : red("\u2717 over limit")}`);
|
|
263
|
+
const rows = r.fields.map((f) => ({
|
|
264
|
+
field: f.field,
|
|
265
|
+
chars: f.chars,
|
|
266
|
+
limit: f.limit,
|
|
267
|
+
pct: `${f.pct}%`,
|
|
268
|
+
status: f.status === "ok" ? green("\u2713") : f.status === "warn" ? "\u26A0" : red("\u2717")
|
|
269
|
+
}));
|
|
270
|
+
console.log(formatOutput(rows, "table"));
|
|
271
|
+
if (!r.valid) exitCode = 1;
|
|
272
|
+
}
|
|
273
|
+
if (exitCode) process.exit(exitCode);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
listings.command("analyze").description("Analyze live Play Store listings for character limit compliance").option("--expected <locales>", "Comma-separated list of expected locale codes").action(async (options) => {
|
|
280
|
+
const config = await loadConfig();
|
|
281
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
282
|
+
const client = await getClient(config);
|
|
283
|
+
const format = getOutputFormat(program, config);
|
|
284
|
+
const spinner = createSpinner("Fetching remote listings...");
|
|
285
|
+
if (!program.opts()["quiet"] && process.stderr.isTTY) spinner.start();
|
|
286
|
+
try {
|
|
287
|
+
const expectedLocales = options.expected ? options.expected.split(",").map((s) => s.trim()) : void 0;
|
|
288
|
+
const { results, missingLocales } = await analyzeRemoteListings(client, packageName, {
|
|
289
|
+
expectedLocales
|
|
290
|
+
});
|
|
291
|
+
spinner.stop("Done");
|
|
292
|
+
if (format === "json") {
|
|
293
|
+
console.log(formatOutput({ results, missingLocales }, format));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
let exitCode = 0;
|
|
297
|
+
for (const r of results) {
|
|
298
|
+
console.log(`
|
|
299
|
+
[${r.language}] ${r.valid ? green("\u2713 valid") : red("\u2717 over limit")}`);
|
|
300
|
+
const rows = r.fields.map((f) => ({
|
|
301
|
+
field: f.field,
|
|
302
|
+
chars: f.chars,
|
|
303
|
+
limit: f.limit,
|
|
304
|
+
pct: `${f.pct}%`,
|
|
305
|
+
status: f.status === "ok" ? green("\u2713") : f.status === "warn" ? "\u26A0" : red("\u2717")
|
|
306
|
+
}));
|
|
307
|
+
console.log(formatOutput(rows, "table"));
|
|
308
|
+
if (!r.valid) exitCode = 1;
|
|
309
|
+
}
|
|
310
|
+
if (missingLocales && missingLocales.length > 0) {
|
|
311
|
+
console.log(`
|
|
312
|
+
Missing locales: ${missingLocales.join(", ")}`);
|
|
313
|
+
}
|
|
314
|
+
if (exitCode) process.exit(exitCode);
|
|
315
|
+
} catch (error) {
|
|
316
|
+
spinner.fail("Analysis failed");
|
|
317
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
318
|
+
process.exit(4);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
240
321
|
const images = listings.command("images").description("Manage listing images");
|
|
241
322
|
images.command("list").description("List images for a language and type").option("--lang <language>", "Language code (BCP 47)").option("--type <type>", "Image type").option("--limit <n>", "Maximum results to return").option("--next-page <token>", "Pagination token for next page").action(async (options) => {
|
|
242
323
|
const config = await loadConfig();
|
|
@@ -392,4 +473,4 @@ function registerListingsCommands(program) {
|
|
|
392
473
|
export {
|
|
393
474
|
registerListingsCommands
|
|
394
475
|
};
|
|
395
|
-
//# sourceMappingURL=listings-
|
|
476
|
+
//# sourceMappingURL=listings-7TWCGGMS.js.map
|