@gpc-cli/cli 0.9.79 → 0.9.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{auth-4DRT7ZH2.js → auth-C6K563I5.js} +4 -3
- package/dist/auth-C6K563I5.js.map +1 -0
- package/dist/bin.js +2 -2
- package/dist/{bundles-6F3AD4QM.js → bundles-6NNRCBQE.js} +2 -2
- package/dist/bundles-6NNRCBQE.js.map +1 -0
- package/dist/{chunk-TPSF4BAR.js → chunk-LKI2MVT4.js} +13 -13
- package/dist/{config-WSKL2CK6.js → config-3GHC45S5.js} +2 -2
- package/dist/{doctor-JGJO52HH.js → doctor-AO52FMY4.js} +2 -2
- package/dist/{enterprise-NP3EVLCN.js → enterprise-T5NWQS2R.js} +2 -2
- package/dist/{enterprise-NP3EVLCN.js.map → enterprise-T5NWQS2R.js.map} +1 -1
- package/dist/{feedback-56LWTSEP.js → feedback-OT4VK7B6.js} +2 -2
- package/dist/generated/docs-bundle.json +1 -1
- package/dist/index.js +1 -1
- package/dist/{purchases-LHGBIZNF.js → purchases-3KUR5YR3.js} +3 -4
- package/dist/purchases-3KUR5YR3.js.map +1 -0
- package/dist/{setup-IKHZQJIH.js → setup-XC4X323X.js} +4 -3
- package/dist/setup-XC4X323X.js.map +1 -0
- package/dist/{update-4SKKZHXQ.js → update-TXLKZ6JD.js} +2 -2
- package/dist/{users-CJ23I3IS.js → users-HJAXLZPM.js} +2 -2
- package/dist/users-HJAXLZPM.js.map +1 -0
- package/dist/{version-YJSTOXO5.js → version-BHRQPXO6.js} +2 -2
- package/package.json +1 -1
- package/dist/auth-4DRT7ZH2.js.map +0 -1
- package/dist/bundles-6F3AD4QM.js.map +0 -1
- package/dist/purchases-LHGBIZNF.js.map +0 -1
- package/dist/setup-IKHZQJIH.js.map +0 -1
- package/dist/users-CJ23I3IS.js.map +0 -1
- /package/dist/{chunk-TPSF4BAR.js.map → chunk-LKI2MVT4.js.map} +0 -0
- /package/dist/{config-WSKL2CK6.js.map → config-3GHC45S5.js.map} +0 -0
- /package/dist/{doctor-JGJO52HH.js.map → doctor-AO52FMY4.js.map} +0 -0
- /package/dist/{feedback-56LWTSEP.js.map → feedback-OT4VK7B6.js.map} +0 -0
- /package/dist/{update-4SKKZHXQ.js.map → update-TXLKZ6JD.js.map} +0 -0
- /package/dist/{version-YJSTOXO5.js.map → version-BHRQPXO6.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -197,7 +197,7 @@ Use one of these instead:
|
|
|
197
197
|
gpc purchases subscription revoke <token> Revoke + refund via v2 API
|
|
198
198
|
`
|
|
199
199
|
);
|
|
200
|
-
|
|
200
|
+
throw new Error("subscriptionsv2 refund is not a valid API endpoint");
|
|
201
201
|
});
|
|
202
202
|
sub.command("revoke <token>").description("Revoke a subscription (v2)").option("--refund-type <type>", "Refund type: full, prorated, or item (default: prorated)").option(
|
|
203
203
|
"--product-id <id>",
|
|
@@ -207,8 +207,7 @@ Use one of these instead:
|
|
|
207
207
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
208
208
|
const refundType = opts.refundType ?? "prorated";
|
|
209
209
|
if (!["full", "prorated", "item"].includes(refundType)) {
|
|
210
|
-
|
|
211
|
-
process.exit(2);
|
|
210
|
+
throw new Error(`Invalid --refund-type "${refundType}". Use: full, prorated, or item`);
|
|
212
211
|
}
|
|
213
212
|
if (isDryRun(program)) {
|
|
214
213
|
const format = getOutputFormat(program, config);
|
|
@@ -424,4 +423,4 @@ Use one of these instead:
|
|
|
424
423
|
export {
|
|
425
424
|
registerPurchasesCommands
|
|
426
425
|
};
|
|
427
|
-
//# sourceMappingURL=purchases-
|
|
426
|
+
//# sourceMappingURL=purchases-3KUR5YR3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/purchases.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { Option } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport {\n getProductPurchase,\n getProductPurchaseV2,\n acknowledgeProductPurchase,\n consumeProductPurchase,\n getSubscriptionPurchase,\n cancelSubscriptionPurchase,\n cancelSubscriptionV2,\n deferSubscriptionPurchase,\n deferSubscriptionV2,\n revokeSubscriptionPurchase,\n listVoidedPurchases,\n refundOrder,\n getOrderDetails,\n batchGetOrders,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\n\nexport function registerPurchasesCommands(program: Command): void {\n const purchases = program.command(\"purchases\").description(\"Manage purchases and orders\");\n\n purchases\n .command(\"get <product-id> <token>\")\n .description(\"Get a product purchase\")\n .action(async (productId: string, token: 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 const result = await getProductPurchase(client, packageName, productId, token);\n if (format !== \"json\") {\n const r = result as unknown as Record<string, unknown>;\n const row = {\n orderId: r[\"orderId\"] || \"-\",\n purchaseState: r[\"purchaseState\"] ?? \"-\",\n consumptionState: r[\"consumptionState\"] ?? \"-\",\n purchaseTime: r[\"purchaseTimeMillis\"]\n ? new Date(Number(r[\"purchaseTimeMillis\"])).toISOString()\n : \"-\",\n acknowledged: r[\"acknowledgementState\"] ?? \"-\",\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n purchases\n .command(\"acknowledge <product-id> <token>\")\n .description(\"Acknowledge a product purchase\")\n .option(\"--payload <text>\", \"Developer payload\")\n .action(async (productId: string, token: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases acknowledge\",\n action: \"acknowledge\",\n target: `${productId}/${token}`,\n details: { payload: options.payload },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await acknowledgeProductPurchase(client, packageName, productId, token, options.payload);\n console.log(`Purchase acknowledged.`);\n });\n\n purchases\n .command(\"consume <product-id> <token>\")\n .description(\"Consume a product purchase\")\n .action(async (productId: string, token: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases consume\",\n action: \"consume\",\n target: `${productId}/${token}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await consumeProductPurchase(client, packageName, productId, token);\n console.log(`Purchase consumed.`);\n });\n\n // --- Subscription purchases ---\n const sub = purchases.command(\"subscription\").description(\"Manage subscription purchases\");\n\n sub\n .command(\"get <token>\")\n .description(\"Get a subscription purchase (v2)\")\n .action(async (token: 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 const result = await getSubscriptionPurchase(client, packageName, token);\n if (format !== \"json\") {\n const r = result as unknown as Record<string, unknown>;\n const lineItems = r[\"lineItems\"] as Record<string, unknown>[] | undefined;\n const onHold = r[\"onHoldStateContext\"] as Record<string, unknown> | undefined;\n const inGrace = r[\"inGracePeriodStateContext\"] as Record<string, unknown> | undefined;\n const onHoldPending = (\n onHold?.[\"renewalDeclined\"] as Record<string, unknown> | undefined\n )?.[\"pendingOrderId\"] as string | undefined;\n const inGracePending = (\n inGrace?.[\"renewalDeclined\"] as Record<string, unknown> | undefined\n )?.[\"pendingOrderId\"] as string | undefined;\n const row: Record<string, unknown> = {\n subscriptionState: r[\"subscriptionState\"] || \"-\",\n startTime: r[\"startTime\"] || \"-\",\n expiryTime: r[\"expiryTime\"] || \"-\",\n linkedPurchaseToken: r[\"linkedPurchaseToken\"] ? \"yes\" : \"no\",\n lineItems: lineItems?.length || 0,\n acknowledgement: r[\"acknowledgementState\"] || \"-\",\n ...(onHoldPending && { onHoldPendingOrderId: onHoldPending }),\n ...(inGracePending && { gracePeriodPendingOrderId: inGracePending }),\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n sub\n .command(\"cancel <subscription-id> <token>\")\n .description(\"Cancel a subscription (v1)\")\n .action(async (subscriptionId: string, token: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription cancel\",\n action: \"cancel subscription\",\n target: `${subscriptionId}/${token}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n await requireConfirm(\n `Cancel subscription ${subscriptionId}? This cannot be undone.`,\n program,\n );\n\n const client = await getClient(config);\n\n await cancelSubscriptionPurchase(client, packageName, subscriptionId, token);\n console.log(`Subscription cancelled.`);\n });\n\n sub\n .command(\"defer <subscription-id> <token>\")\n .description(\"Defer a subscription expiry\")\n .option(\"--expiry <iso-date>\", \"Desired new expiry date (ISO 8601)\")\n .action(async (subscriptionId: string, token: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\n options.expiry = await requireOption(\n \"expiry\",\n options.expiry,\n {\n message: \"New expiry date (ISO 8601, e.g. 2026-12-31T23:59:59Z):\",\n },\n interactive,\n );\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"purchases subscription defer\",\n action: \"defer subscription\",\n target: `${subscriptionId}/${token}`,\n details: { expiry: options.expiry },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await deferSubscriptionPurchase(\n client,\n packageName,\n subscriptionId,\n token,\n options.expiry,\n );\n console.log(formatOutput(result, format));\n });\n\n sub\n .command(\"refund <token>\")\n .description(\"Refund a subscription purchase (use 'orders refund' instead)\")\n .action(async () => {\n console.error(\n `The subscriptionsv2 refund endpoint does not exist in the Google Play API.\\n\\n` +\n `Use one of these instead:\\n` +\n ` gpc purchases orders refund <order-id> Refund via orders API\\n` +\n ` gpc purchases subscription revoke <token> Revoke + refund via v2 API\\n`,\n );\n throw new Error(\"subscriptionsv2 refund is not a valid API endpoint\");\n });\n\n sub\n .command(\"revoke <token>\")\n .description(\"Revoke a subscription (v2)\")\n .option(\"--refund-type <type>\", \"Refund type: full, prorated, or item (default: prorated)\")\n .option(\n \"--product-id <id>\",\n \"Product ID for item-based refund (required with --refund-type item)\",\n )\n .action(async (token: string, opts: { refundType?: string; productId?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const refundType = (opts.refundType ?? \"prorated\") as \"full\" | \"prorated\" | \"item\";\n\n if (![\"full\", \"prorated\", \"item\"].includes(refundType)) {\n throw new Error(`Invalid --refund-type \"${refundType}\". Use: full, prorated, or item`);\n }\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription revoke\",\n action: \"revoke subscription\",\n target: token,\n details: {\n refundType,\n ...(opts.productId && { productId: opts.productId }),\n },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n await requireConfirm(\n `Revoke subscription (${refundType} refund)? This cannot be undone.`,\n program,\n );\n\n const client = await getClient(config);\n\n await revokeSubscriptionPurchase(client, packageName, token, refundType, opts.productId);\n console.log(`Subscription revoked (${refundType} refund).`);\n });\n\n // --- Voided purchases ---\n purchases\n .command(\"voided\")\n .description(\"List voided purchases\")\n .option(\"--start-time <time>\", \"Start time (milliseconds)\")\n .option(\"--end-time <time>\", \"End time (milliseconds)\")\n .option(\n \"--type <n>\",\n \"Purchase type: 0=in-app only (default), 1=in-app + subscriptions\",\n parseInt,\n )\n .option(\"--include-partial-refunds\", \"Include quantity-based partial refunds\")\n .addOption(\n new Option(\"--max-results <n>\", \"Maximum results per page\").argParser(parseInt).hideHelp(),\n )\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\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 const result = await listVoidedPurchases(client, packageName, {\n startTime: options.startTime,\n endTime: options.endTime,\n type: options.type,\n includeQuantityBasedPartialRefund: options.includePartialRefunds,\n maxResults: options.maxResults,\n limit: options.limit,\n nextPage: options.nextPage,\n });\n if (format !== \"json\") {\n const purchases = (result as Record<string, unknown>)[\"voidedPurchases\"] as\n | Record<string, unknown>[]\n | undefined;\n if (purchases && purchases.length > 0) {\n const rows = purchases.map((p) => ({\n orderId: p[\"orderId\"] || \"-\",\n purchaseToken: String(p[\"purchaseToken\"] || \"-\").slice(0, 16) + \"...\",\n voidedTime: p[\"voidedTimeMillis\"]\n ? new Date(Number(p[\"voidedTimeMillis\"])).toISOString()\n : \"-\",\n voidedSource: p[\"voidedSource\"] ?? \"-\",\n voidedReason: p[\"voidedReason\"] ?? \"-\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(\"No voided purchases found.\");\n }\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n // --- Orders ---\n const orders = purchases.command(\"orders\").description(\"Manage orders\");\n\n orders\n .command(\"refund <order-id>\")\n .description(\"Refund an order\")\n .option(\"--revoke\", \"Revoke the order (remove entitlement)\")\n .action(async (orderId: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Refund order \"${orderId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases orders refund\",\n action: \"refund\",\n target: orderId,\n details: { revoke: options.revoke },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await refundOrder(client, packageName, orderId, {\n revoke: options.revoke,\n });\n console.log(`Order ${orderId} refunded.`);\n });\n\n orders\n .command(\"get <order-id>\")\n .description(\"Get order details\")\n .action(async (orderId: 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 const result = await getOrderDetails(client, packageName, orderId);\n if (format !== \"json\") {\n const row = {\n orderId: result.orderId,\n state: result.state,\n purchaseToken: result.purchaseToken ? result.purchaseToken.slice(0, 16) + \"...\" : \"-\",\n createTime: result.createTime || \"-\",\n total: result.total\n ? `${result.total.units || \"0\"}.${String(result.total.nanos || 0)\n .padStart(9, \"0\")\n .slice(0, 2)} ${result.total.currencyCode}`\n : \"-\",\n lineItems: result.lineItems?.length || 0,\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n orders\n .command(\"batch-get\")\n .description(\"Get multiple orders at once\")\n .requiredOption(\"--ids <order-ids>\", \"Comma-separated order IDs (max 1000)\")\n .action(async (options: { ids: 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 const orderIds = options.ids\n .split(\",\")\n .map((id) => id.trim())\n .filter(Boolean);\n\n const result = await batchGetOrders(client, packageName, orderIds);\n if (format !== \"json\") {\n if (result.length === 0) {\n console.log(\"No orders found.\");\n } else {\n const rows = result.map((o) => ({\n orderId: o.orderId,\n state: o.state,\n createTime: o.createTime || \"-\",\n lineItems: o.lineItems?.length || 0,\n }));\n console.log(formatOutput(rows, format));\n }\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n // --- Product purchases V2 (Jun 2025) ---\n const product = purchases.command(\"product\").description(\"Product purchase operations\");\n\n product\n .command(\"get-v2 <token>\")\n .description(\"Get product purchase details (v2 — supports multi-offer OTPs)\")\n .action(async (token: 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 const result = await getProductPurchaseV2(client, packageName, token);\n if (format !== \"json\") {\n const row = {\n orderId: result.orderId || \"-\",\n state: result.purchaseStateContext?.purchaseState || \"-\",\n regionCode: result.regionCode || \"-\",\n completionTime: result.purchaseCompletionTime || \"-\",\n acknowledgement: result.acknowledgementState || \"-\",\n lineItems: result.productLineItem?.length || 0,\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n // --- Subscription V2 cancel/defer (Sep 2025 / Jan 2026) ---\n // Added to existing `sub` group alongside v1 cancel/defer\n\n sub\n .command(\"cancel-v2 <token>\")\n .description(\"Cancel a subscription (v2 -- supports cancellation types)\")\n .option(\n \"--type <cancellationType>\",\n \"USER_REQUESTED_STOP_RENEWALS (default) or DEVELOPER_REQUESTED_STOP_PAYMENTS\",\n )\n .action(async (token: string, options: { type?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription cancel-v2\",\n action: \"cancel\",\n target: token.slice(0, 16) + \"...\",\n details: { cancellationType: options.type },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n await requireConfirm(\n `Cancel subscription (token: ${token.slice(0, 16)}...)? This cannot be undone.`,\n program,\n );\n\n const client = await getClient(config);\n\n await cancelSubscriptionV2(client, packageName, token, options.type);\n console.log(\"Subscription cancelled.\");\n });\n\n sub\n .command(\"defer-v2 <token>\")\n .description(\"Defer a subscription renewal (v2 -- supports add-on subscriptions)\")\n .requiredOption(\"--duration <seconds>\", \"Duration to defer by (e.g. '2592000s' for 30 days)\")\n .option(\"--etag <etag>\", \"Subscription etag (fetched automatically if omitted)\")\n .action(async (token: string, options: { duration: string; etag?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Defer subscription renewal by ${options.duration}?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription defer-v2\",\n action: \"defer\",\n target: token.slice(0, 16) + \"...\",\n details: { deferDuration: options.duration },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await deferSubscriptionV2(\n client,\n packageName,\n token,\n options.duration,\n options.etag,\n );\n for (const item of result.itemExpiryTimeDetails) {\n console.log(`${item.productId}: new expiry ${item.expiryTime}`);\n }\n });\n}\n"],"mappings":"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","names":["purchases"]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/commands/setup.ts
|
|
4
4
|
import { existsSync } from "fs";
|
|
5
|
+
import { homedir } from "os";
|
|
5
6
|
import { resolve } from "path";
|
|
6
7
|
var ANDROID_PACKAGE_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9_]*)+$/;
|
|
7
8
|
function step(n, total, label, status) {
|
|
@@ -80,7 +81,7 @@ function registerSetupCommand(program) {
|
|
|
80
81
|
"./service-account.json",
|
|
81
82
|
"./gpc-service-account.json",
|
|
82
83
|
"~/.config/gpc/service-account.json"
|
|
83
|
-
].map((p) => resolve(p.replace("~",
|
|
84
|
+
].map((p) => resolve(p.replace("~", homedir())));
|
|
84
85
|
const autoDetected = commonPaths.find((p) => existsSync(p));
|
|
85
86
|
const defaultHint = autoDetected ? ` (found: ${autoDetected})` : "";
|
|
86
87
|
let attempts = 0;
|
|
@@ -93,7 +94,7 @@ function registerSetupCommand(program) {
|
|
|
93
94
|
step(1, total, "Authenticate", "\u2014 skipped");
|
|
94
95
|
break;
|
|
95
96
|
}
|
|
96
|
-
const absPath = resolve(input.replace("~",
|
|
97
|
+
const absPath = resolve(input.replace("~", homedir()));
|
|
97
98
|
if (!existsSync(absPath)) {
|
|
98
99
|
console.log(` File not found: ${absPath}`);
|
|
99
100
|
attempts++;
|
|
@@ -258,4 +259,4 @@ function registerSetupCommand(program) {
|
|
|
258
259
|
export {
|
|
259
260
|
registerSetupCommand
|
|
260
261
|
};
|
|
261
|
-
//# sourceMappingURL=setup-
|
|
262
|
+
//# sourceMappingURL=setup-XC4X323X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/setup.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { resolve } from \"node:path\";\n\nconst ANDROID_PACKAGE_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)+$/;\n\nfunction step(n: number, total: number, label: string, status: string): void {\n const padded = `Step ${n}/${total} ${label}`.padEnd(50);\n console.log(`${padded}${status}`);\n}\n\nexport function registerSetupCommand(program: Command): void {\n program\n .command(\"setup\")\n .description(\"Guided first-time setup: auth, config, verification, and shell completion\")\n .option(\"--auto\", \"Non-interactive setup from env vars and auto-detected credentials\")\n .action(async (options: { auto?: boolean }) => {\n const { isInteractive, promptInput, promptSelect, promptConfirm } =\n await import(\"../prompt.js\");\n const { loadConfig, initConfig, setConfigValue, getUserConfigPath } =\n await import(\"@gpc-cli/config\");\n const { resolveAuth, loadServiceAccountKey } = await import(\"@gpc-cli/auth\");\n\n const interactive = !options.auto && isInteractive(program);\n const total = 5;\n\n console.log(\"\\nGPC — Setup\");\n console.log(\"═\".repeat(50));\n\n if (options.auto) {\n console.log(\"Running in auto mode (non-interactive)\\n\");\n }\n\n // ---------------------------------------------------------------\n // Step 1: Credentials\n // ---------------------------------------------------------------\n let saPath: string | undefined;\n let authOk = false;\n let email: string;\n\n if (options.auto) {\n // Auto mode: try env vars, existing config, then ADC\n try {\n const auth = await resolveAuth();\n email = auth.getClientEmail();\n await auth.getAccessToken();\n authOk = true;\n const method =\n process.env[\"GPC_SERVICE_ACCOUNT\"] || process.env[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n ? \"env\"\n : \"adc\";\n step(1, total, \"Authenticate\", `✓ ${email} (${method})`);\n } catch {\n step(1, total, \"Authenticate\", \"✗ No credentials found\");\n console.log(\"\\n Set GPC_SERVICE_ACCOUNT or GOOGLE_APPLICATION_CREDENTIALS,\");\n console.log(\" or run `gpc setup` interactively.\\n\");\n process.exitCode = 1;\n return;\n }\n } else if (interactive) {\n // Check for existing credentials first\n try {\n const existing = await loadConfig();\n if (existing.auth?.serviceAccount) {\n const auth = await resolveAuth({\n serviceAccountPath: existing.auth.serviceAccount,\n });\n email = auth.getClientEmail();\n await auth.getAccessToken();\n authOk = true;\n step(1, total, \"Authenticate\", `✓ ${email} (existing config)`);\n }\n } catch {\n // No existing config or invalid credentials\n }\n\n if (!authOk) {\n const method = await promptSelect(\n \"\\nAuthentication method:\",\n [\"service-account\", \"adc\"],\n \"service-account\",\n );\n\n if (method === \"adc\") {\n try {\n const auth = await resolveAuth();\n email = auth.getClientEmail();\n await auth.getAccessToken();\n authOk = true;\n step(1, total, \"Authenticate\", `✓ ${email} (ADC)`);\n } catch (err) {\n step(\n 1,\n total,\n \"Authenticate\",\n `✗ ADC failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n console.log(\" Run: gcloud auth application-default login\");\n }\n } else {\n // Service account with retry loop\n const commonPaths = [\n \"~/gpc-service-account.json\",\n \"./service-account.json\",\n \"./gpc-service-account.json\",\n \"~/.config/gpc/service-account.json\",\n ].map((p) => resolve(p.replace(\"~\", homedir())));\n\n const autoDetected = commonPaths.find((p) => existsSync(p));\n const defaultHint = autoDetected ? ` (found: ${autoDetected})` : \"\";\n\n let attempts = 0;\n while (!authOk && attempts < 3) {\n const input = await promptInput(\n `Path to service account JSON key${defaultHint}`,\n autoDetected,\n );\n if (!input) {\n step(1, total, \"Authenticate\", \"— skipped\");\n break;\n }\n\n const absPath = resolve(input.replace(\"~\", homedir()));\n if (!existsSync(absPath)) {\n console.log(` File not found: ${absPath}`);\n attempts++;\n continue;\n }\n\n try {\n const key = await loadServiceAccountKey(absPath);\n const auth = await resolveAuth({ serviceAccountPath: absPath });\n await auth.getAccessToken();\n saPath = absPath;\n email = key.client_email;\n authOk = true;\n step(1, total, \"Authenticate\", `✓ ${email}`);\n } catch (err) {\n console.log(` Auth failed: ${err instanceof Error ? err.message : String(err)}`);\n attempts++;\n }\n }\n\n if (!authOk && attempts >= 3) {\n step(1, total, \"Authenticate\", \"✗ Failed after 3 attempts\");\n }\n }\n }\n } else {\n step(1, total, \"Authenticate\", \"— non-interactive, skipped\");\n }\n\n // ---------------------------------------------------------------\n // Step 2: Package name\n // ---------------------------------------------------------------\n let packageName: string | undefined;\n\n if (options.auto) {\n packageName = process.env[\"GPC_APP\"];\n if (packageName) {\n step(2, total, \"Default app\", `✓ ${packageName}`);\n } else {\n step(2, total, \"Default app\", \"— GPC_APP not set (optional)\");\n }\n } else if (interactive) {\n // Check existing config\n try {\n const existing = await loadConfig();\n if (existing.app) {\n const keep = await promptConfirm(`Keep existing app: ${existing.app}?`, true);\n if (keep) {\n packageName = existing.app;\n }\n }\n } catch {\n // No existing config\n }\n\n if (!packageName) {\n const input = await promptInput(\n \"Default package name (e.g. com.example.app, blank to skip)\",\n );\n if (input) {\n if (!ANDROID_PACKAGE_RE.test(input)) {\n console.log(` Warning: \"${input}\" doesn't look like a valid Android package name`);\n }\n packageName = input;\n }\n }\n\n if (packageName) {\n step(2, total, \"Default app\", `✓ ${packageName}`);\n } else {\n step(2, total, \"Default app\", \"— skipped (set later with: gpc config set app <pkg>)\");\n }\n } else {\n step(2, total, \"Default app\", \"— non-interactive, skipped\");\n }\n\n // ---------------------------------------------------------------\n // Step 3: Write config\n // ---------------------------------------------------------------\n const configPayload: Record<string, unknown> = {};\n if (saPath) configPayload[\"auth\"] = { serviceAccount: saPath };\n if (packageName) configPayload[\"app\"] = packageName;\n\n const configPath = getUserConfigPath();\n const configExists = existsSync(configPath);\n\n if (Object.keys(configPayload).length > 0) {\n try {\n if (configExists) {\n if (saPath) await setConfigValue(\"auth.serviceAccount\", saPath);\n if (packageName) await setConfigValue(\"app\", packageName);\n step(3, total, \"Save config\", `✓ Updated ${configPath}`);\n } else {\n await initConfig(configPayload);\n step(3, total, \"Save config\", `✓ Created ${configPath}`);\n }\n } catch (err) {\n step(\n 3,\n total,\n \"Save config\",\n `✗ Failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else if (configExists) {\n step(3, total, \"Save config\", `✓ Existing config at ${configPath}`);\n } else if (options.auto) {\n step(3, total, \"Save config\", \"— using env vars only\");\n } else {\n step(3, total, \"Save config\", \"— nothing to save\");\n }\n\n // ---------------------------------------------------------------\n // Step 4: Shell completion\n // ---------------------------------------------------------------\n if (interactive) {\n const installCompletion = await promptConfirm(\"Install shell completions?\", true);\n if (installCompletion) {\n const shell = process.env[\"SHELL\"] || \"\";\n let completionHint = \"\";\n if (shell.includes(\"zsh\")) {\n completionHint = \"gpc completion zsh > ~/.zsh/completions/_gpc && compinit\";\n } else if (shell.includes(\"bash\")) {\n completionHint = \"gpc completion bash >> ~/.bashrc && source ~/.bashrc\";\n } else if (shell.includes(\"fish\")) {\n completionHint = \"gpc completion fish > ~/.config/fish/completions/gpc.fish\";\n }\n\n if (completionHint) {\n console.log(`\\n Run: ${completionHint}\\n`);\n } else {\n console.log(\"\\n Run: gpc completion --help\\n\");\n }\n step(4, total, \"Shell completion\", \"✓ Instructions printed\");\n } else {\n step(4, total, \"Shell completion\", \"— skipped\");\n }\n } else {\n step(4, total, \"Shell completion\", \"— skipped (non-interactive)\");\n }\n\n // ---------------------------------------------------------------\n // Step 5: Doctor verification\n // ---------------------------------------------------------------\n console.log(\"\");\n try {\n const { spawnSync } = await import(\"node:child_process\");\n const result = spawnSync(\"gpc\", [\"doctor\"], {\n stdio: \"pipe\",\n encoding: \"utf-8\",\n });\n\n if (result.error) {\n step(5, total, \"Verify (doctor)\", \"— gpc not in PATH, run: gpc doctor\");\n } else if (result.status === 0) {\n step(5, total, \"Verify (doctor)\", \"✓ All checks passed\");\n } else {\n step(5, total, \"Verify (doctor)\", \"⚠ Some checks need attention\");\n if (result.stdout) {\n const lines = result.stdout.split(\"\\n\").filter((l: string) => l.includes(\"✗\"));\n for (const line of lines.slice(0, 5)) {\n console.log(` ${line.trim()}`);\n }\n }\n console.log(\" Run: gpc doctor --fix\");\n }\n } catch {\n step(5, total, \"Verify (doctor)\", \"— run: gpc doctor\");\n }\n\n // ---------------------------------------------------------------\n // Summary\n // ---------------------------------------------------------------\n console.log(\"\\n\" + \"═\".repeat(50));\n\n if (authOk) {\n console.log(\"\\nReady! Here's what you can do next:\\n\");\n console.log(\" gpc status → app health snapshot\");\n console.log(\" gpc releases list → current tracks and versions\");\n console.log(\" gpc reviews list → recent user reviews\");\n console.log(\" gpc vitals overview → crash and ANR rates\");\n console.log(\" gpc publish app.aab → end-to-end upload and release\");\n console.log(\"\\nDocs: https://yasserstudio.github.io/gpc/\");\n } else {\n console.log(\"\\nSetup incomplete. Fix the issues above, then run `gpc setup` again.\");\n console.log(\"Need help? Run `gpc doctor` for detailed diagnostics.\");\n console.log(\"Full guide: https://yasserstudio.github.io/gpc/guide/authentication\");\n process.exitCode = 1;\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -17,7 +17,7 @@ function registerUpdateCommand(program) {
|
|
|
17
17
|
program.command("update").description("Update gpc to the latest version").option("--check", "Check for updates without installing (exits 0 always)").option("--force", "Update even if already on the latest version").action(async (opts, cmd) => {
|
|
18
18
|
const parentOpts = cmd.parent?.opts() ?? {};
|
|
19
19
|
const jsonMode = !!(parentOpts["json"] || parentOpts["output"] === "json");
|
|
20
|
-
const currentVersion = "0.9.
|
|
20
|
+
const currentVersion = "0.9.81";
|
|
21
21
|
if (currentVersion === "0.0.0") {
|
|
22
22
|
if (jsonMode) {
|
|
23
23
|
console.log(
|
|
@@ -172,4 +172,4 @@ Run: gpc update`);
|
|
|
172
172
|
export {
|
|
173
173
|
registerUpdateCommand
|
|
174
174
|
};
|
|
175
|
-
//# sourceMappingURL=update-
|
|
175
|
+
//# sourceMappingURL=update-TXLKZ6JD.js.map
|
|
@@ -66,7 +66,7 @@ function registerUsersCommands(program) {
|
|
|
66
66
|
name: u["name"] || "-",
|
|
67
67
|
accessState: u["accessState"] || "-",
|
|
68
68
|
grants: Array.isArray(u["grants"]) ? u["grants"].length : 0,
|
|
69
|
-
permissions: Array.isArray(u["developerAccountPermission"]) ? u["developerAccountPermission"].length : 0
|
|
69
|
+
permissions: Array.isArray(u["developerAccountPermissions"]) ? u["developerAccountPermissions"].length : Array.isArray(u["developerAccountPermission"]) ? u["developerAccountPermission"].length : 0
|
|
70
70
|
}));
|
|
71
71
|
console.log(formatOutput(rows, format));
|
|
72
72
|
}
|
|
@@ -162,4 +162,4 @@ function registerUsersCommands(program) {
|
|
|
162
162
|
export {
|
|
163
163
|
registerUsersCommands
|
|
164
164
|
};
|
|
165
|
-
//# sourceMappingURL=users-
|
|
165
|
+
//# sourceMappingURL=users-HJAXLZPM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/users.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 type { DeveloperPermission } from \"@gpc-cli/api\";\nimport {\n listUsers,\n getUser,\n inviteUser,\n updateUser,\n removeUser,\n parseGrantArg,\n PERMISSION_PROPAGATION_WARNING,\n formatOutput,\n sortResults,\n GpcError,\n} 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 throw new GpcError(\n \"No developer ID. Use --developer-id <id> or gpc config set developerId <id>\",\n \"MISSING_DEVELOPER_ID\",\n 2,\n \"gpc config set developerId <id>\",\n );\n }\n return id;\n}\n\nasync function getUsersClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createUsersClient({ auth });\n}\n\nexport function registerUsersCommands(program: Command): void {\n const users = program\n .command(\"users\")\n .description(\"Manage developer account users and permissions\")\n .option(\"--developer-id <id>\", \"Developer account ID\");\n\n users\n .command(\"list\")\n .description(\"List all users in the developer account\")\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 developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const client = await getUsersClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listUsers(client, developerId, {\n limit: options.limit,\n nextPage: options.nextPage,\n });\n if (options.sort) {\n result.users = sortResults(result.users, options.sort);\n }\n if (format !== \"json\") {\n const users = (result.users || []) as unknown as Record<string, unknown>[];\n if (users.length === 0) {\n console.log(\"No users found.\");\n } else {\n const rows = users.map((u) => ({\n email: u[\"email\"] || \"-\",\n name: u[\"name\"] || \"-\",\n accessState: u[\"accessState\"] || \"-\",\n grants: Array.isArray(u[\"grants\"]) ? (u[\"grants\"] as unknown[]).length : 0,\n permissions: Array.isArray(u[\"developerAccountPermissions\"])\n ? (u[\"developerAccountPermissions\"] as unknown[]).length\n : Array.isArray(u[\"developerAccountPermission\"])\n ? (u[\"developerAccountPermission\"] as unknown[]).length\n : 0,\n }));\n console.log(formatOutput(rows, format));\n }\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n users\n .command(\"get <email>\")\n .description(\"Get user details\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const client = await getUsersClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await getUser(client, developerId, email);\n console.log(formatOutput(result, format));\n });\n\n users\n .command(\"invite <email>\")\n .description(\"Invite a user to the developer account\")\n .option(\"--role <permissions...>\", \"Developer-level permissions\")\n .option(\n \"--grant <grants...>\",\n \"Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"users invite\",\n action: \"invite\",\n target: email,\n details: { role: options.role, grant: options.grant },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n const permissions = options.role as DeveloperPermission[] | undefined;\n const grants = options.grant?.map((g: string) => parseGrantArg(g));\n const result = await inviteUser(client, developerId, email, permissions, grants);\n console.log(formatOutput(result, format));\n console.error(PERMISSION_PROPAGATION_WARNING);\n });\n\n users\n .command(\"update <email>\")\n .description(\"Update user permissions\")\n .option(\"--role <permissions...>\", \"Developer-level permissions\")\n .option(\n \"--grant <grants...>\",\n \"Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"users update\",\n action: \"update\",\n target: email,\n details: { role: options.role, grant: options.grant },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n const permissions = options.role as DeveloperPermission[] | undefined;\n const grants = options.grant?.map((g: string) => parseGrantArg(g));\n const result = await updateUser(client, developerId, email, permissions, grants);\n console.log(formatOutput(result, format));\n console.error(PERMISSION_PROPAGATION_WARNING);\n });\n\n users\n .command(\"remove <email>\")\n .description(\"Remove a user from the developer account\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n\n await requireConfirm(`Remove user \"${email}\" from developer account?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"users remove\",\n action: \"remove\",\n target: email,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n await removeUser(client, developerId, email);\n console.log(`User ${email} removed.`);\n console.error(PERMISSION_PROPAGATION_WARNING);\n });\n}\n"],"mappings":"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","names":["users"]}
|
|
@@ -7,7 +7,7 @@ import "./chunk-3SJ6OXCZ.js";
|
|
|
7
7
|
// src/commands/version.ts
|
|
8
8
|
function registerVersionCommand(program) {
|
|
9
9
|
program.command("version").description("Show version information").action(() => {
|
|
10
|
-
const version = "0.9.
|
|
10
|
+
const version = "0.9.81";
|
|
11
11
|
if (program.opts()["output"] === "json") {
|
|
12
12
|
console.log(
|
|
13
13
|
JSON.stringify({
|
|
@@ -25,4 +25,4 @@ function registerVersionCommand(program) {
|
|
|
25
25
|
export {
|
|
26
26
|
registerVersionCommand
|
|
27
27
|
};
|
|
28
|
-
//# sourceMappingURL=version-
|
|
28
|
+
//# sourceMappingURL=version-BHRQPXO6.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gpc-cli/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.81",
|
|
4
4
|
"description": "GPC — Google Play Console CLI. 217 API endpoints including Managed Google Play. Upload AABs, manage releases, monitor vitals, publish private enterprise apps. Fastlane alternative for Android.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/auth.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { createInterface } from \"node:readline\";\nimport { access } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { resolveAuth, loadServiceAccountKey, clearTokenCache, AuthError } from \"@gpc-cli/auth\";\nimport { loadConfig, getCacheDir, deleteConfigValue, setConfigValue } from \"@gpc-cli/config\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function askQuestion(\n rl: ReturnType<typeof createInterface>,\n question: string,\n): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n}\n\n/** Resolve a path to absolute (prevents CWD-dependent config). */\nfunction toAbsolutePath(pathStr: string): string {\n return resolve(pathStr);\n}\n\n/** Verify that the saved credentials can acquire a token. */\nasync function verifyToken(\n serviceAccountPath?: string,\n): Promise<{ email: string; ok: boolean; error?: string }> {\n try {\n const client = await resolveAuth({ serviceAccountPath });\n const email = client.getClientEmail();\n await client.getAccessToken();\n return { email, ok: true };\n } catch (err) {\n const email = \"unknown\";\n const msg = err instanceof Error ? err.message : String(err);\n return { email, ok: false, error: msg };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Interactive login wizard\n// ---------------------------------------------------------------------------\n\nasync function runLoginWizard(program: Command): Promise<void> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n try {\n console.log(\"\\nGPC Authentication Setup\");\n console.log(\n \"\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\\u2500\",\n );\n\n // Step 1: auth method\n console.log(\"\\nAuthentication methods:\");\n console.log(\" 1. Service account key file (recommended)\");\n console.log(\" 2. Application Default Credentials (ADC)\");\n const method = await askQuestion(rl, \"\\nSelect method [1]: \");\n const useAdc = method === \"2\";\n\n if (useAdc) {\n const client = await resolveAuth();\n const email = client.getClientEmail();\n // Verify token works\n await client.getAccessToken();\n outputLoginResult(program, { account: email, method: \"adc\", verified: true });\n return;\n }\n\n // Step 2: credentials path with validation loop\n let saPath = \"\";\n while (!saPath) {\n const input = await askQuestion(rl, \"\\nPath to service account JSON key: \");\n if (!input) {\n console.log(\" Path is required.\");\n continue;\n }\n try {\n await access(input);\n saPath = toAbsolutePath(input);\n } catch {\n console.log(` File not found: ${input}`);\n }\n }\n\n // Step 3: optional profile name\n const profileName = await askQuestion(rl, \"\\nProfile name (optional, press Enter to skip): \");\n\n // Step 4: default package name\n const packageName = await askQuestion(\n rl,\n \"Default package name (optional, e.g. com.example.app): \",\n );\n\n // Apply settings\n const key = await loadServiceAccountKey(saPath);\n\n if (profileName) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(profileName, {\n auth: { serviceAccount: saPath },\n ...(packageName && { app: packageName }),\n });\n } else {\n await setConfigValue(\"auth.serviceAccount\", saPath);\n if (packageName) await setConfigValue(\"app\", packageName);\n }\n\n // Verify token\n const verification = await verifyToken(saPath);\n\n outputLoginResult(program, {\n account: key.client_email,\n project: key.project_id,\n method: \"service-account\",\n profile: profileName || undefined,\n verified: verification.ok,\n verifyError: verification.error,\n });\n } finally {\n rl.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Structured login output\n// ---------------------------------------------------------------------------\n\ninterface LoginResult {\n account: string;\n project?: string;\n method: string;\n profile?: string;\n verified: boolean;\n verifyError?: string;\n}\n\nfunction outputLoginResult(program: Command, result: LoginResult): void {\n const parentOpts = program.opts() ?? {};\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n account: result.account,\n project: result.project,\n method: result.method,\n profile: result.profile,\n verified: result.verified,\n ...(result.verifyError && { verifyError: result.verifyError }),\n }),\n );\n return;\n }\n\n if (result.profile) {\n console.log(`\\nProfile \"${result.profile}\" configured with ${result.account}`);\n } else if (result.method === \"adc\") {\n console.log(`\\nAuthenticated via Application Default Credentials`);\n console.log(`Account: ${result.account}`);\n } else {\n console.log(`\\nAuthenticated as ${result.account}`);\n }\n if (result.project) console.log(`Project: ${result.project}`);\n\n if (result.verified) {\n console.log(\"Verified: token acquired successfully\");\n } else if (result.verifyError) {\n console.log(`Warning: token verification failed: ${result.verifyError}`);\n console.log(\"Credentials saved, but check your setup with: gpc doctor\");\n }\n\n if (!result.verifyError) {\n console.log(\"\\nRun 'gpc doctor' to verify your full setup.\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\n// ---------------------------------------------------------------------------\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 if (options.serviceAccount) {\n const absolutePath = toAbsolutePath(options.serviceAccount);\n const key = await loadServiceAccountKey(absolutePath);\n\n if (options.profile) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(options.profile, {\n auth: { serviceAccount: absolutePath },\n });\n } else {\n await setConfigValue(\"auth.serviceAccount\", absolutePath);\n }\n\n // Verify token works\n const verification = await verifyToken(absolutePath);\n\n outputLoginResult(program, {\n account: key.client_email,\n project: key.project_id,\n method: \"service-account\",\n profile: options.profile,\n verified: verification.ok,\n verifyError: verification.error,\n });\n } else if (options.adc) {\n const client = await resolveAuth();\n const email = client.getClientEmail();\n await client.getAccessToken();\n outputLoginResult(program, { account: email, method: \"adc\", verified: true });\n } else {\n // Interactive wizard when no flags provided and in interactive mode\n const opts = program.opts();\n const interactive =\n opts[\"interactive\"] !== false && opts[\"ci\"] !== true && process.stdin.isTTY;\n if (interactive) {\n await runLoginWizard(program);\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 }\n });\n\n auth\n .command(\"status\")\n .description(\"Show current authentication status\")\n .action(async () => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n try {\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\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 data = {\n authenticated: false,\n error: error.message,\n suggestion: error.suggestion,\n };\n console.log(formatOutput(data, format));\n }\n throw error; // Let error handler set exit code 3\n }\n });\n\n auth\n .command(\"logout\")\n .description(\"Clear stored credentials and token cache\")\n .option(\"--profile <name>\", \"Clear credentials for a specific profile\")\n .action(async (options: { profile?: string }) => {\n if (options.profile) {\n const { deleteProfile } = await import(\"@gpc-cli/config\");\n const deleted = await deleteProfile(options.profile);\n if (deleted) {\n console.log(`Profile \"${options.profile}\" removed.`);\n } else {\n console.log(`Profile \"${options.profile}\" not found.`);\n }\n } else {\n await deleteConfigValue(\"auth.serviceAccount\");\n console.log(\"Credentials cleared.\");\n }\n await clearTokenCache(getCacheDir());\n console.log(\"Token cache cleared.\");\n });\n\n auth\n .command(\"whoami\")\n .description(\"Show current authenticated identity\")\n .action(async () => {\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 });\n\n auth\n .command(\"switch <profile>\")\n .description(\"Switch to a named profile\")\n .action(async (profile: string) => {\n // loadConfig with the profile will throw ConfigError if profile doesn't exist\n const config = await loadConfig({ profile });\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 });\n\n auth\n .command(\"token\")\n .description(\"Print the current access token (useful for manual API calls)\")\n .action(async () => {\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 });\n\n auth\n .command(\"setup-gcp\")\n .description(\"Step-by-step guide to create a Google Cloud service account\")\n .option(\"--key <path>\", \"Path to an already-downloaded service account JSON key\")\n .action(async (options: { key?: string }) => {\n const { existsSync, readFileSync } = await import(\"node:fs\");\n const { resolve } = await import(\"node:path\");\n\n console.log(\"\\nGPC \\u2014 Google Cloud Service Account Setup\");\n console.log(\"\\u2550\".repeat(50));\n\n // If key path provided or user already has one, skip to validation\n let keyPath = options.key;\n\n if (!keyPath) {\n console.log(\"\\nStep 1: Open the Google Cloud Console\");\n console.log(\" https://console.cloud.google.com/iam-admin/serviceaccounts\");\n console.log(\"\\nStep 2: Create a service account\");\n console.log(\" \\u2022 Click 'Create Service Account'\");\n console.log(\" \\u2022 Name it: gpc-deploy (or any name you like)\");\n console.log(\" \\u2022 Description: GPC Google Play Console access\");\n console.log(\"\\nStep 3: Grant roles\");\n console.log(\" No GCP roles needed \\u2014 permissions are managed in Google Play Console.\");\n console.log(\"\\nStep 4: Download the JSON key\");\n console.log(\n \" \\u2022 Click your new service account \\u2192 Keys \\u2192 Add Key \\u2192 Create new key \\u2192 JSON\",\n );\n console.log(\" \\u2022 Save as: ~/gpc-service-account.json\");\n console.log(\"\\nStep 5: Add to Google Play Console\");\n console.log(\" https://play.google.com/console/developers\");\n console.log(\" \\u2022 Users and Permissions \\u2192 Invite new users\");\n console.log(\" \\u2022 Paste the service account email (ends with @...gserviceaccount.com)\");\n console.log(\" \\u2022 Grant: Release manager + View app info + Reply to reviews\");\n\n // Try to auto-detect a key file\n const commonPaths = [\n \"~/gpc-service-account.json\",\n \"./service-account.json\",\n \"./gpc-service-account.json\",\n \"~/.config/gpc/service-account.json\",\n ].map((p) => resolve(p.replace(\"~\", process.env[\"HOME\"] || \"\")));\n\n for (const p of commonPaths) {\n if (existsSync(p)) {\n console.log(`\\n\\u2713 Found key file: ${p}`);\n keyPath = p;\n break;\n }\n }\n\n if (!keyPath) {\n console.log(\"\\nOnce you've downloaded the key, run:\");\n console.log(\" gpc auth setup-gcp --key <path/to/key.json>\");\n console.log(\"\\nOr authenticate directly:\");\n console.log(\" gpc auth login --service-account <path/to/key.json>\");\n console.log(\"\\nSee full docs: https://yasserstudio.github.io/gpc/guide/authentication\");\n return;\n }\n }\n\n // Validate the key file\n const absPath = resolve(keyPath.replace(\"~\", process.env[\"HOME\"] || \"\"));\n if (!existsSync(absPath)) {\n console.error(`\\n\\u2717 File not found: ${absPath}`);\n return;\n }\n\n try {\n const content = JSON.parse(readFileSync(absPath, \"utf-8\"));\n if (content.type !== \"service_account\") {\n console.error(`\\n\\u2717 Not a service account key (type: ${content.type})`);\n return;\n }\n console.log(`\\n\\u2713 Valid service account key`);\n console.log(` Email: ${content.client_email}`);\n console.log(` Project: ${content.project_id}`);\n } catch {\n console.error(`\\n\\u2717 Invalid JSON file: ${absPath}`);\n return;\n }\n\n // Auto-login\n console.log(`\\nStep 6: Authenticating...`);\n try {\n const auth = await resolveAuth({ serviceAccountPath: absPath });\n await auth.getAccessToken();\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", absPath);\n console.log(`\\u2713 Authenticated and saved to config`);\n } catch (err) {\n console.error(\n `\\u2717 Authentication failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n console.log(`\\nTry manually: gpc auth login --service-account ${absPath}`);\n return;\n }\n\n // Auto-run doctor\n console.log(`\\nStep 7: Verifying setup...`);\n console.log(` Run: gpc doctor`);\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":["resolve","auth","setConfigValue"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/bundles.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { listBundles, findBundle, waitForBundle, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { resolvePackageName, getClient } from \"../resolve.js\";\n\nexport function registerBundlesCommands(program: Command): void {\n const bundles = program.command(\"bundles\").description(\"Manage uploaded app bundles (API)\");\n\n bundles\n .command(\"list\")\n .description(\"List all processed bundles\")\n .action(async () => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n\n const result = await listBundles(client, packageName);\n\n if (format === \"json\") {\n console.log(formatOutput(result, \"json\"));\n } else {\n if (result.length === 0) {\n console.log(\"No bundles found.\");\n return;\n }\n console.log(\n formatOutput(\n result.map((b) => ({\n versionCode: b.versionCode,\n sha256: b.sha256.slice(0, 12) + \"...\",\n })),\n format,\n ),\n );\n }\n });\n\n bundles\n .command(\"find\")\n .description(\"Find a specific bundle by version code\")\n .requiredOption(\"--version-code <n>\", \"Version code to find\", (v) => parseInt(v, 10))\n .action(async (options: { versionCode: number }) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n\n const result = await findBundle(client, packageName, options.versionCode);\n\n if (!result) {\n if (format === \"json\") {\n console.log(formatOutput(null, \"json\"));\n } else {\n console.error(`Bundle with version code ${options.versionCode} not found.`);\n }\n process.exit(1);\n }\n\n console.log(formatOutput(result, format));\n });\n\n bundles\n .command(\"wait\")\n .description(\"Wait for a bundle to finish server-side processing\")\n .requiredOption(\"--version-code <n>\", \"Version code to wait for\", (v) => parseInt(v, 10))\n .option(\"--timeout <seconds>\", \"Timeout in seconds (default: 600)\", (v) => parseInt(v, 10))\n .option(\"--interval <seconds>\", \"Poll interval in seconds (default: 15)\", (v) =>\n parseInt(v, 10),\n )\n .action(async (options: { versionCode: number; timeout?: number; interval?: number }) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n\n if (format !== \"json\") {\n process.stderr.write(`Waiting for bundle ${options.versionCode} to finish processing...\\n`);\n }\n\n const result = await waitForBundle(client, packageName, options.versionCode, {\n timeout: options.timeout ? options.timeout * 1000 : undefined,\n interval: options.interval ? options.interval * 1000 : undefined,\n });\n\n if (format !== \"json\") {\n process.stderr.write(`Bundle ${result.versionCode} is ready.\\n`);\n }\n console.log(formatOutput(result, format));\n });\n}\n"],"mappings":";;;;;;;;;;AACA,SAAS,kBAAkB;AAC3B,SAAS,aAAa,YAAY,eAAe,oBAAoB;AAI9D,SAAS,wBAAwB,SAAwB;AAC9D,QAAM,UAAU,QAAQ,QAAQ,SAAS,EAAE,YAAY,mCAAmC;AAE1F,UACG,QAAQ,MAAM,EACd,YAAY,4BAA4B,EACxC,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAC9C,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,UAAM,SAAS,MAAM,YAAY,QAAQ,WAAW;AAEpD,QAAI,WAAW,QAAQ;AACrB,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,OAAO;AACL,UAAI,OAAO,WAAW,GAAG;AACvB,gBAAQ,IAAI,mBAAmB;AAC/B;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,UACE,OAAO,IAAI,CAAC,OAAO;AAAA,YACjB,aAAa,EAAE;AAAA,YACf,QAAQ,EAAE,OAAO,MAAM,GAAG,EAAE,IAAI;AAAA,UAClC,EAAE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAEH,UACG,QAAQ,MAAM,EACd,YAAY,wCAAwC,EACpD,eAAe,sBAAsB,wBAAwB,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,EACnF,OAAO,OAAO,YAAqC;AAClD,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAC9C,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,UAAM,SAAS,MAAM,WAAW,QAAQ,aAAa,QAAQ,WAAW;AAExE,QAAI,CAAC,QAAQ;AACX,UAAI,WAAW,QAAQ;AACrB,gBAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AAAA,MACxC,OAAO;AACL,gBAAQ,MAAM,4BAA4B,QAAQ,WAAW,aAAa;AAAA,MAC5E;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,YAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,EAC1C,CAAC;AAEH,UACG,QAAQ,MAAM,EACd,YAAY,oDAAoD,EAChE,eAAe,sBAAsB,4BAA4B,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,EACvF,OAAO,uBAAuB,qCAAqC,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,EACzF;AAAA,IAAO;AAAA,IAAwB;AAAA,IAA0C,CAAC,MACzE,SAAS,GAAG,EAAE;AAAA,EAChB,EACC,OAAO,OAAO,YAA0E;AACvF,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAC9C,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,QAAI,WAAW,QAAQ;AACrB,cAAQ,OAAO,MAAM,sBAAsB,QAAQ,WAAW;AAAA,CAA4B;AAAA,IAC5F;AAEA,UAAM,SAAS,MAAM,cAAc,QAAQ,aAAa,QAAQ,aAAa;AAAA,MAC3E,SAAS,QAAQ,UAAU,QAAQ,UAAU,MAAO;AAAA,MACpD,UAAU,QAAQ,WAAW,QAAQ,WAAW,MAAO;AAAA,IACzD,CAAC;AAED,QAAI,WAAW,QAAQ;AACrB,cAAQ,OAAO,MAAM,UAAU,OAAO,WAAW;AAAA,CAAc;AAAA,IACjE;AACA,YAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,EAC1C,CAAC;AACL;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/purchases.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { Option } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport {\n getProductPurchase,\n getProductPurchaseV2,\n acknowledgeProductPurchase,\n consumeProductPurchase,\n getSubscriptionPurchase,\n cancelSubscriptionPurchase,\n cancelSubscriptionV2,\n deferSubscriptionPurchase,\n deferSubscriptionV2,\n revokeSubscriptionPurchase,\n listVoidedPurchases,\n refundOrder,\n getOrderDetails,\n batchGetOrders,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\n\nexport function registerPurchasesCommands(program: Command): void {\n const purchases = program.command(\"purchases\").description(\"Manage purchases and orders\");\n\n purchases\n .command(\"get <product-id> <token>\")\n .description(\"Get a product purchase\")\n .action(async (productId: string, token: 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 const result = await getProductPurchase(client, packageName, productId, token);\n if (format !== \"json\") {\n const r = result as unknown as Record<string, unknown>;\n const row = {\n orderId: r[\"orderId\"] || \"-\",\n purchaseState: r[\"purchaseState\"] ?? \"-\",\n consumptionState: r[\"consumptionState\"] ?? \"-\",\n purchaseTime: r[\"purchaseTimeMillis\"]\n ? new Date(Number(r[\"purchaseTimeMillis\"])).toISOString()\n : \"-\",\n acknowledged: r[\"acknowledgementState\"] ?? \"-\",\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n purchases\n .command(\"acknowledge <product-id> <token>\")\n .description(\"Acknowledge a product purchase\")\n .option(\"--payload <text>\", \"Developer payload\")\n .action(async (productId: string, token: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases acknowledge\",\n action: \"acknowledge\",\n target: `${productId}/${token}`,\n details: { payload: options.payload },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await acknowledgeProductPurchase(client, packageName, productId, token, options.payload);\n console.log(`Purchase acknowledged.`);\n });\n\n purchases\n .command(\"consume <product-id> <token>\")\n .description(\"Consume a product purchase\")\n .action(async (productId: string, token: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases consume\",\n action: \"consume\",\n target: `${productId}/${token}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await consumeProductPurchase(client, packageName, productId, token);\n console.log(`Purchase consumed.`);\n });\n\n // --- Subscription purchases ---\n const sub = purchases.command(\"subscription\").description(\"Manage subscription purchases\");\n\n sub\n .command(\"get <token>\")\n .description(\"Get a subscription purchase (v2)\")\n .action(async (token: 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 const result = await getSubscriptionPurchase(client, packageName, token);\n if (format !== \"json\") {\n const r = result as unknown as Record<string, unknown>;\n const lineItems = r[\"lineItems\"] as Record<string, unknown>[] | undefined;\n const onHold = r[\"onHoldStateContext\"] as Record<string, unknown> | undefined;\n const inGrace = r[\"inGracePeriodStateContext\"] as Record<string, unknown> | undefined;\n const onHoldPending = (\n onHold?.[\"renewalDeclined\"] as Record<string, unknown> | undefined\n )?.[\"pendingOrderId\"];\n const inGracePending = (\n inGrace?.[\"renewalDeclined\"] as Record<string, unknown> | undefined\n )?.[\"pendingOrderId\"];\n const row: Record<string, unknown> = {\n subscriptionState: r[\"subscriptionState\"] || \"-\",\n startTime: r[\"startTime\"] || \"-\",\n expiryTime: r[\"expiryTime\"] || \"-\",\n linkedPurchaseToken: r[\"linkedPurchaseToken\"] ? \"yes\" : \"no\",\n lineItems: lineItems?.length || 0,\n acknowledgement: r[\"acknowledgementState\"] || \"-\",\n ...(onHoldPending && { onHoldPendingOrderId: onHoldPending }),\n ...(inGracePending && { gracePeriodPendingOrderId: inGracePending }),\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n sub\n .command(\"cancel <subscription-id> <token>\")\n .description(\"Cancel a subscription (v1)\")\n .action(async (subscriptionId: string, token: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription cancel\",\n action: \"cancel subscription\",\n target: `${subscriptionId}/${token}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n await requireConfirm(\n `Cancel subscription ${subscriptionId}? This cannot be undone.`,\n program,\n );\n\n const client = await getClient(config);\n\n await cancelSubscriptionPurchase(client, packageName, subscriptionId, token);\n console.log(`Subscription cancelled.`);\n });\n\n sub\n .command(\"defer <subscription-id> <token>\")\n .description(\"Defer a subscription expiry\")\n .option(\"--expiry <iso-date>\", \"Desired new expiry date (ISO 8601)\")\n .action(async (subscriptionId: string, token: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\n options.expiry = await requireOption(\n \"expiry\",\n options.expiry,\n {\n message: \"New expiry date (ISO 8601, e.g. 2026-12-31T23:59:59Z):\",\n },\n interactive,\n );\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"purchases subscription defer\",\n action: \"defer subscription\",\n target: `${subscriptionId}/${token}`,\n details: { expiry: options.expiry },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await deferSubscriptionPurchase(\n client,\n packageName,\n subscriptionId,\n token,\n options.expiry,\n );\n console.log(formatOutput(result, format));\n });\n\n sub\n .command(\"refund <token>\")\n .description(\"Refund a subscription purchase (use 'orders refund' instead)\")\n .action(async () => {\n console.error(\n `The subscriptionsv2 refund endpoint does not exist in the Google Play API.\\n\\n` +\n `Use one of these instead:\\n` +\n ` gpc purchases orders refund <order-id> Refund via orders API\\n` +\n ` gpc purchases subscription revoke <token> Revoke + refund via v2 API\\n`,\n );\n process.exit(2);\n });\n\n sub\n .command(\"revoke <token>\")\n .description(\"Revoke a subscription (v2)\")\n .option(\"--refund-type <type>\", \"Refund type: full, prorated, or item (default: prorated)\")\n .option(\n \"--product-id <id>\",\n \"Product ID for item-based refund (required with --refund-type item)\",\n )\n .action(async (token: string, opts: { refundType?: string; productId?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const refundType = (opts.refundType ?? \"prorated\") as \"full\" | \"prorated\" | \"item\";\n\n if (![\"full\", \"prorated\", \"item\"].includes(refundType)) {\n console.error(`Invalid --refund-type \"${refundType}\". Use: full, prorated, or item`);\n process.exit(2);\n }\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription revoke\",\n action: \"revoke subscription\",\n target: token,\n details: {\n refundType,\n ...(opts.productId && { productId: opts.productId }),\n },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n await requireConfirm(\n `Revoke subscription (${refundType} refund)? This cannot be undone.`,\n program,\n );\n\n const client = await getClient(config);\n\n await revokeSubscriptionPurchase(client, packageName, token, refundType, opts.productId);\n console.log(`Subscription revoked (${refundType} refund).`);\n });\n\n // --- Voided purchases ---\n purchases\n .command(\"voided\")\n .description(\"List voided purchases\")\n .option(\"--start-time <time>\", \"Start time (milliseconds)\")\n .option(\"--end-time <time>\", \"End time (milliseconds)\")\n .option(\n \"--type <n>\",\n \"Purchase type: 0=in-app only (default), 1=in-app + subscriptions\",\n parseInt,\n )\n .option(\"--include-partial-refunds\", \"Include quantity-based partial refunds\")\n .addOption(\n new Option(\"--max-results <n>\", \"Maximum results per page\").argParser(parseInt).hideHelp(),\n )\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\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 const result = await listVoidedPurchases(client, packageName, {\n startTime: options.startTime,\n endTime: options.endTime,\n type: options.type,\n includeQuantityBasedPartialRefund: options.includePartialRefunds,\n maxResults: options.maxResults,\n limit: options.limit,\n nextPage: options.nextPage,\n });\n if (format !== \"json\") {\n const purchases = (result as Record<string, unknown>)[\"voidedPurchases\"] as\n | Record<string, unknown>[]\n | undefined;\n if (purchases && purchases.length > 0) {\n const rows = purchases.map((p) => ({\n orderId: p[\"orderId\"] || \"-\",\n purchaseToken: String(p[\"purchaseToken\"] || \"-\").slice(0, 16) + \"...\",\n voidedTime: p[\"voidedTimeMillis\"]\n ? new Date(Number(p[\"voidedTimeMillis\"])).toISOString()\n : \"-\",\n voidedSource: p[\"voidedSource\"] ?? \"-\",\n voidedReason: p[\"voidedReason\"] ?? \"-\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(\"No voided purchases found.\");\n }\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n // --- Orders ---\n const orders = purchases.command(\"orders\").description(\"Manage orders\");\n\n orders\n .command(\"refund <order-id>\")\n .description(\"Refund an order\")\n .option(\"--revoke\", \"Revoke the order (remove entitlement)\")\n .action(async (orderId: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Refund order \"${orderId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases orders refund\",\n action: \"refund\",\n target: orderId,\n details: { revoke: options.revoke },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await refundOrder(client, packageName, orderId, {\n revoke: options.revoke,\n });\n console.log(`Order ${orderId} refunded.`);\n });\n\n orders\n .command(\"get <order-id>\")\n .description(\"Get order details\")\n .action(async (orderId: 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 const result = await getOrderDetails(client, packageName, orderId);\n if (format !== \"json\") {\n const row = {\n orderId: result.orderId,\n state: result.state,\n purchaseToken: result.purchaseToken ? result.purchaseToken.slice(0, 16) + \"...\" : \"-\",\n createTime: result.createTime || \"-\",\n total: result.total\n ? `${result.total.units || \"0\"}.${String(result.total.nanos || 0)\n .padStart(9, \"0\")\n .slice(0, 2)} ${result.total.currencyCode}`\n : \"-\",\n lineItems: result.lineItems?.length || 0,\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n orders\n .command(\"batch-get\")\n .description(\"Get multiple orders at once\")\n .requiredOption(\"--ids <order-ids>\", \"Comma-separated order IDs (max 1000)\")\n .action(async (options: { ids: 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 const orderIds = options.ids\n .split(\",\")\n .map((id) => id.trim())\n .filter(Boolean);\n\n const result = await batchGetOrders(client, packageName, orderIds);\n if (format !== \"json\") {\n if (result.length === 0) {\n console.log(\"No orders found.\");\n } else {\n const rows = result.map((o) => ({\n orderId: o.orderId,\n state: o.state,\n createTime: o.createTime || \"-\",\n lineItems: o.lineItems?.length || 0,\n }));\n console.log(formatOutput(rows, format));\n }\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n // --- Product purchases V2 (Jun 2025) ---\n const product = purchases.command(\"product\").description(\"Product purchase operations\");\n\n product\n .command(\"get-v2 <token>\")\n .description(\"Get product purchase details (v2 — supports multi-offer OTPs)\")\n .action(async (token: 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 const result = await getProductPurchaseV2(client, packageName, token);\n if (format !== \"json\") {\n const row = {\n orderId: result.orderId || \"-\",\n state: result.purchaseStateContext?.purchaseState || \"-\",\n regionCode: result.regionCode || \"-\",\n completionTime: result.purchaseCompletionTime || \"-\",\n acknowledgement: result.acknowledgementState || \"-\",\n lineItems: result.productLineItem?.length || 0,\n };\n console.log(formatOutput(row, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n // --- Subscription V2 cancel/defer (Sep 2025 / Jan 2026) ---\n // Added to existing `sub` group alongside v1 cancel/defer\n\n sub\n .command(\"cancel-v2 <token>\")\n .description(\"Cancel a subscription (v2 -- supports cancellation types)\")\n .option(\n \"--type <cancellationType>\",\n \"USER_REQUESTED_STOP_RENEWALS (default) or DEVELOPER_REQUESTED_STOP_PAYMENTS\",\n )\n .action(async (token: string, options: { type?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription cancel-v2\",\n action: \"cancel\",\n target: token.slice(0, 16) + \"...\",\n details: { cancellationType: options.type },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n await requireConfirm(\n `Cancel subscription (token: ${token.slice(0, 16)}...)? This cannot be undone.`,\n program,\n );\n\n const client = await getClient(config);\n\n await cancelSubscriptionV2(client, packageName, token, options.type);\n console.log(\"Subscription cancelled.\");\n });\n\n sub\n .command(\"defer-v2 <token>\")\n .description(\"Defer a subscription renewal (v2 -- supports add-on subscriptions)\")\n .requiredOption(\"--duration <seconds>\", \"Duration to defer by (e.g. '2592000s' for 30 days)\")\n .option(\"--etag <etag>\", \"Subscription etag (fetched automatically if omitted)\")\n .action(async (token: string, options: { duration: string; etag?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Defer subscription renewal by ${options.duration}?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"purchases subscription defer-v2\",\n action: \"defer\",\n target: token.slice(0, 16) + \"...\",\n details: { deferDuration: options.duration },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await deferSubscriptionV2(\n client,\n packageName,\n token,\n options.duration,\n options.etag,\n );\n for (const item of result.itemExpiryTimeDetails) {\n console.log(`${item.productId}: new expiry ${item.expiryTime}`);\n }\n });\n}\n"],"mappings":"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","names":["purchases"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/setup.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nconst ANDROID_PACKAGE_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)+$/;\n\nfunction step(n: number, total: number, label: string, status: string): void {\n const padded = `Step ${n}/${total} ${label}`.padEnd(50);\n console.log(`${padded}${status}`);\n}\n\nexport function registerSetupCommand(program: Command): void {\n program\n .command(\"setup\")\n .description(\"Guided first-time setup: auth, config, verification, and shell completion\")\n .option(\"--auto\", \"Non-interactive setup from env vars and auto-detected credentials\")\n .action(async (options: { auto?: boolean }) => {\n const { isInteractive, promptInput, promptSelect, promptConfirm } =\n await import(\"../prompt.js\");\n const { loadConfig, initConfig, setConfigValue, getUserConfigPath } =\n await import(\"@gpc-cli/config\");\n const { resolveAuth, loadServiceAccountKey } = await import(\"@gpc-cli/auth\");\n\n const interactive = !options.auto && isInteractive(program);\n const total = 5;\n\n console.log(\"\\nGPC — Setup\");\n console.log(\"═\".repeat(50));\n\n if (options.auto) {\n console.log(\"Running in auto mode (non-interactive)\\n\");\n }\n\n // ---------------------------------------------------------------\n // Step 1: Credentials\n // ---------------------------------------------------------------\n let saPath: string | undefined;\n let authOk = false;\n let email: string;\n\n if (options.auto) {\n // Auto mode: try env vars, existing config, then ADC\n try {\n const auth = await resolveAuth();\n email = auth.getClientEmail();\n await auth.getAccessToken();\n authOk = true;\n const method =\n process.env[\"GPC_SERVICE_ACCOUNT\"] || process.env[\"GOOGLE_APPLICATION_CREDENTIALS\"]\n ? \"env\"\n : \"adc\";\n step(1, total, \"Authenticate\", `✓ ${email} (${method})`);\n } catch {\n step(1, total, \"Authenticate\", \"✗ No credentials found\");\n console.log(\"\\n Set GPC_SERVICE_ACCOUNT or GOOGLE_APPLICATION_CREDENTIALS,\");\n console.log(\" or run `gpc setup` interactively.\\n\");\n process.exitCode = 1;\n return;\n }\n } else if (interactive) {\n // Check for existing credentials first\n try {\n const existing = await loadConfig();\n if (existing.auth?.serviceAccount) {\n const auth = await resolveAuth({\n serviceAccountPath: existing.auth.serviceAccount,\n });\n email = auth.getClientEmail();\n await auth.getAccessToken();\n authOk = true;\n step(1, total, \"Authenticate\", `✓ ${email} (existing config)`);\n }\n } catch {\n // No existing config or invalid credentials\n }\n\n if (!authOk) {\n const method = await promptSelect(\n \"\\nAuthentication method:\",\n [\"service-account\", \"adc\"],\n \"service-account\",\n );\n\n if (method === \"adc\") {\n try {\n const auth = await resolveAuth();\n email = auth.getClientEmail();\n await auth.getAccessToken();\n authOk = true;\n step(1, total, \"Authenticate\", `✓ ${email} (ADC)`);\n } catch (err) {\n step(\n 1,\n total,\n \"Authenticate\",\n `✗ ADC failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n console.log(\" Run: gcloud auth application-default login\");\n }\n } else {\n // Service account with retry loop\n const commonPaths = [\n \"~/gpc-service-account.json\",\n \"./service-account.json\",\n \"./gpc-service-account.json\",\n \"~/.config/gpc/service-account.json\",\n ].map((p) => resolve(p.replace(\"~\", process.env[\"HOME\"] || \"\")));\n\n const autoDetected = commonPaths.find((p) => existsSync(p));\n const defaultHint = autoDetected ? ` (found: ${autoDetected})` : \"\";\n\n let attempts = 0;\n while (!authOk && attempts < 3) {\n const input = await promptInput(\n `Path to service account JSON key${defaultHint}`,\n autoDetected,\n );\n if (!input) {\n step(1, total, \"Authenticate\", \"— skipped\");\n break;\n }\n\n const absPath = resolve(input.replace(\"~\", process.env[\"HOME\"] || \"\"));\n if (!existsSync(absPath)) {\n console.log(` File not found: ${absPath}`);\n attempts++;\n continue;\n }\n\n try {\n const key = await loadServiceAccountKey(absPath);\n const auth = await resolveAuth({ serviceAccountPath: absPath });\n await auth.getAccessToken();\n saPath = absPath;\n email = key.client_email;\n authOk = true;\n step(1, total, \"Authenticate\", `✓ ${email}`);\n } catch (err) {\n console.log(` Auth failed: ${err instanceof Error ? err.message : String(err)}`);\n attempts++;\n }\n }\n\n if (!authOk && attempts >= 3) {\n step(1, total, \"Authenticate\", \"✗ Failed after 3 attempts\");\n }\n }\n }\n } else {\n step(1, total, \"Authenticate\", \"— non-interactive, skipped\");\n }\n\n // ---------------------------------------------------------------\n // Step 2: Package name\n // ---------------------------------------------------------------\n let packageName: string | undefined;\n\n if (options.auto) {\n packageName = process.env[\"GPC_APP\"];\n if (packageName) {\n step(2, total, \"Default app\", `✓ ${packageName}`);\n } else {\n step(2, total, \"Default app\", \"— GPC_APP not set (optional)\");\n }\n } else if (interactive) {\n // Check existing config\n try {\n const existing = await loadConfig();\n if (existing.app) {\n const keep = await promptConfirm(`Keep existing app: ${existing.app}?`, true);\n if (keep) {\n packageName = existing.app;\n }\n }\n } catch {\n // No existing config\n }\n\n if (!packageName) {\n const input = await promptInput(\n \"Default package name (e.g. com.example.app, blank to skip)\",\n );\n if (input) {\n if (!ANDROID_PACKAGE_RE.test(input)) {\n console.log(` Warning: \"${input}\" doesn't look like a valid Android package name`);\n }\n packageName = input;\n }\n }\n\n if (packageName) {\n step(2, total, \"Default app\", `✓ ${packageName}`);\n } else {\n step(2, total, \"Default app\", \"— skipped (set later with: gpc config set app <pkg>)\");\n }\n } else {\n step(2, total, \"Default app\", \"— non-interactive, skipped\");\n }\n\n // ---------------------------------------------------------------\n // Step 3: Write config\n // ---------------------------------------------------------------\n const configPayload: Record<string, unknown> = {};\n if (saPath) configPayload[\"auth\"] = { serviceAccount: saPath };\n if (packageName) configPayload[\"app\"] = packageName;\n\n const configPath = getUserConfigPath();\n const configExists = existsSync(configPath);\n\n if (Object.keys(configPayload).length > 0) {\n try {\n if (configExists) {\n if (saPath) await setConfigValue(\"auth.serviceAccount\", saPath);\n if (packageName) await setConfigValue(\"app\", packageName);\n step(3, total, \"Save config\", `✓ Updated ${configPath}`);\n } else {\n await initConfig(configPayload);\n step(3, total, \"Save config\", `✓ Created ${configPath}`);\n }\n } catch (err) {\n step(\n 3,\n total,\n \"Save config\",\n `✗ Failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else if (configExists) {\n step(3, total, \"Save config\", `✓ Existing config at ${configPath}`);\n } else if (options.auto) {\n step(3, total, \"Save config\", \"— using env vars only\");\n } else {\n step(3, total, \"Save config\", \"— nothing to save\");\n }\n\n // ---------------------------------------------------------------\n // Step 4: Shell completion\n // ---------------------------------------------------------------\n if (interactive) {\n const installCompletion = await promptConfirm(\"Install shell completions?\", true);\n if (installCompletion) {\n const shell = process.env[\"SHELL\"] || \"\";\n let completionHint = \"\";\n if (shell.includes(\"zsh\")) {\n completionHint = \"gpc completion zsh > ~/.zsh/completions/_gpc && compinit\";\n } else if (shell.includes(\"bash\")) {\n completionHint = \"gpc completion bash >> ~/.bashrc && source ~/.bashrc\";\n } else if (shell.includes(\"fish\")) {\n completionHint = \"gpc completion fish > ~/.config/fish/completions/gpc.fish\";\n }\n\n if (completionHint) {\n console.log(`\\n Run: ${completionHint}\\n`);\n } else {\n console.log(\"\\n Run: gpc completion --help\\n\");\n }\n step(4, total, \"Shell completion\", \"✓ Instructions printed\");\n } else {\n step(4, total, \"Shell completion\", \"— skipped\");\n }\n } else {\n step(4, total, \"Shell completion\", \"— skipped (non-interactive)\");\n }\n\n // ---------------------------------------------------------------\n // Step 5: Doctor verification\n // ---------------------------------------------------------------\n console.log(\"\");\n try {\n const { spawnSync } = await import(\"node:child_process\");\n const result = spawnSync(\"gpc\", [\"doctor\"], {\n stdio: \"pipe\",\n encoding: \"utf-8\",\n });\n\n if (result.error) {\n step(5, total, \"Verify (doctor)\", \"— gpc not in PATH, run: gpc doctor\");\n } else if (result.status === 0) {\n step(5, total, \"Verify (doctor)\", \"✓ All checks passed\");\n } else {\n step(5, total, \"Verify (doctor)\", \"⚠ Some checks need attention\");\n if (result.stdout) {\n const lines = result.stdout.split(\"\\n\").filter((l: string) => l.includes(\"✗\"));\n for (const line of lines.slice(0, 5)) {\n console.log(` ${line.trim()}`);\n }\n }\n console.log(\" Run: gpc doctor --fix\");\n }\n } catch {\n step(5, total, \"Verify (doctor)\", \"— run: gpc doctor\");\n }\n\n // ---------------------------------------------------------------\n // Summary\n // ---------------------------------------------------------------\n console.log(\"\\n\" + \"═\".repeat(50));\n\n if (authOk) {\n console.log(\"\\nReady! Here's what you can do next:\\n\");\n console.log(\" gpc status → app health snapshot\");\n console.log(\" gpc releases list → current tracks and versions\");\n console.log(\" gpc reviews list → recent user reviews\");\n console.log(\" gpc vitals overview → crash and ANR rates\");\n console.log(\" gpc publish app.aab → end-to-end upload and release\");\n console.log(\"\\nDocs: https://yasserstudio.github.io/gpc/\");\n } else {\n console.log(\"\\nSetup incomplete. Fix the issues above, then run `gpc setup` again.\");\n console.log(\"Need help? Run `gpc doctor` for detailed diagnostics.\");\n console.log(\"Full guide: https://yasserstudio.github.io/gpc/guide/authentication\");\n process.exitCode = 1;\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/users.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 type { DeveloperPermission } from \"@gpc-cli/api\";\nimport {\n listUsers,\n getUser,\n inviteUser,\n updateUser,\n removeUser,\n parseGrantArg,\n PERMISSION_PROPAGATION_WARNING,\n formatOutput,\n sortResults,\n GpcError,\n} 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 throw new GpcError(\n \"No developer ID. Use --developer-id <id> or gpc config set developerId <id>\",\n \"MISSING_DEVELOPER_ID\",\n 2,\n \"gpc config set developerId <id>\",\n );\n }\n return id;\n}\n\nasync function getUsersClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createUsersClient({ auth });\n}\n\nexport function registerUsersCommands(program: Command): void {\n const users = program\n .command(\"users\")\n .description(\"Manage developer account users and permissions\")\n .option(\"--developer-id <id>\", \"Developer account ID\");\n\n users\n .command(\"list\")\n .description(\"List all users in the developer account\")\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 developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const client = await getUsersClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listUsers(client, developerId, {\n limit: options.limit,\n nextPage: options.nextPage,\n });\n if (options.sort) {\n result.users = sortResults(result.users, options.sort);\n }\n if (format !== \"json\") {\n const users = (result.users || []) as unknown as Record<string, unknown>[];\n if (users.length === 0) {\n console.log(\"No users found.\");\n } else {\n const rows = users.map((u) => ({\n email: u[\"email\"] || \"-\",\n name: u[\"name\"] || \"-\",\n accessState: u[\"accessState\"] || \"-\",\n grants: Array.isArray(u[\"grants\"]) ? (u[\"grants\"] as unknown[]).length : 0,\n permissions: Array.isArray(u[\"developerAccountPermission\"])\n ? (u[\"developerAccountPermission\"] as unknown[]).length\n : 0,\n }));\n console.log(formatOutput(rows, format));\n }\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n users\n .command(\"get <email>\")\n .description(\"Get user details\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const client = await getUsersClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await getUser(client, developerId, email);\n console.log(formatOutput(result, format));\n });\n\n users\n .command(\"invite <email>\")\n .description(\"Invite a user to the developer account\")\n .option(\"--role <permissions...>\", \"Developer-level permissions\")\n .option(\n \"--grant <grants...>\",\n \"Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"users invite\",\n action: \"invite\",\n target: email,\n details: { role: options.role, grant: options.grant },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n const permissions = options.role as DeveloperPermission[] | undefined;\n const grants = options.grant?.map((g: string) => parseGrantArg(g));\n const result = await inviteUser(client, developerId, email, permissions, grants);\n console.log(formatOutput(result, format));\n console.error(PERMISSION_PROPAGATION_WARNING);\n });\n\n users\n .command(\"update <email>\")\n .description(\"Update user permissions\")\n .option(\"--role <permissions...>\", \"Developer-level permissions\")\n .option(\n \"--grant <grants...>\",\n \"Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"users update\",\n action: \"update\",\n target: email,\n details: { role: options.role, grant: options.grant },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n const permissions = options.role as DeveloperPermission[] | undefined;\n const grants = options.grant?.map((g: string) => parseGrantArg(g));\n const result = await updateUser(client, developerId, email, permissions, grants);\n console.log(formatOutput(result, format));\n console.error(PERMISSION_PROPAGATION_WARNING);\n });\n\n users\n .command(\"remove <email>\")\n .description(\"Remove a user from the developer account\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n\n await requireConfirm(`Remove user \"${email}\" from developer account?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"users remove\",\n action: \"remove\",\n target: email,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n await removeUser(client, developerId, email);\n console.log(`User ${email} removed.`);\n console.error(PERMISSION_PROPAGATION_WARNING);\n });\n}\n"],"mappings":"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","names":["users"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|