@gpc-cli/cli 0.9.7 → 0.9.9
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/{apps-TZG5GEDW.js → apps-5YQPQ3KB.js} +20 -3
- package/dist/apps-5YQPQ3KB.js.map +1 -0
- package/dist/bin.js +18 -1
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-LQ7FJ4QA.js → chunk-ZXEA4KAA.js} +31 -12
- package/dist/chunk-ZXEA4KAA.js.map +1 -0
- package/dist/{completion-3UYUJD6S.js → completion-C3PPWNS7.js} +68 -1
- package/dist/completion-C3PPWNS7.js.map +1 -0
- package/dist/device-tiers-FUZC6IHD.js +74 -0
- package/dist/device-tiers-FUZC6IHD.js.map +1 -0
- package/dist/generated-apks-SUPM3NS3.js +73 -0
- package/dist/generated-apks-SUPM3NS3.js.map +1 -0
- package/dist/{iap-ZZS5NVFN.js → iap-2CV6SJUF.js} +7 -2
- package/dist/iap-2CV6SJUF.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/internal-sharing-TWMHLQLN.js +49 -0
- package/dist/internal-sharing-TWMHLQLN.js.map +1 -0
- package/dist/{listings-FYNMWTIE.js → listings-4QCTOEWL.js} +35 -3
- package/dist/listings-4QCTOEWL.js.map +1 -0
- package/dist/migrate-5IA6WGMO.js +76 -0
- package/dist/migrate-5IA6WGMO.js.map +1 -0
- package/dist/one-time-products-BHE6WPZI.js +266 -0
- package/dist/one-time-products-BHE6WPZI.js.map +1 -0
- package/dist/purchase-options-2NUBLODI.js +145 -0
- package/dist/purchase-options-2NUBLODI.js.map +1 -0
- package/dist/{recovery-ZANX3WIQ.js → recovery-DC66ZTGD.js} +77 -18
- package/dist/recovery-DC66ZTGD.js.map +1 -0
- package/dist/{releases-GUMQZRFC.js → releases-HDCDARH5.js} +30 -3
- package/dist/releases-HDCDARH5.js.map +1 -0
- package/dist/{reports-OJSCABN6.js → reports-T6GBAYUK.js} +2 -2
- package/dist/reports-T6GBAYUK.js.map +1 -0
- package/dist/{testers-SB77565D.js → testers-NXWT2PFS.js} +2 -2
- package/dist/testers-NXWT2PFS.js.map +1 -0
- package/dist/tracks-D6FUNJ75.js +84 -0
- package/dist/tracks-D6FUNJ75.js.map +1 -0
- package/package.json +4 -4
- package/dist/apps-TZG5GEDW.js.map +0 -1
- package/dist/chunk-LQ7FJ4QA.js.map +0 -1
- package/dist/completion-3UYUJD6S.js.map +0 -1
- package/dist/iap-ZZS5NVFN.js.map +0 -1
- package/dist/listings-FYNMWTIE.js.map +0 -1
- package/dist/recovery-ZANX3WIQ.js.map +0 -1
- package/dist/releases-GUMQZRFC.js.map +0 -1
- package/dist/reports-OJSCABN6.js.map +0 -1
- package/dist/testers-SB77565D.js.map +0 -1
- package/dist/tracks-HMJ3F55N.js +0 -41
- package/dist/tracks-HMJ3F55N.js.map +0 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/generated-apks.ts
|
|
4
|
+
import { loadConfig } from "@gpc-cli/config";
|
|
5
|
+
import { resolveAuth } from "@gpc-cli/auth";
|
|
6
|
+
import { createApiClient } from "@gpc-cli/api";
|
|
7
|
+
import {
|
|
8
|
+
listGeneratedApks,
|
|
9
|
+
downloadGeneratedApk,
|
|
10
|
+
detectOutputFormat,
|
|
11
|
+
formatOutput
|
|
12
|
+
} from "@gpc-cli/core";
|
|
13
|
+
function resolvePackageName(packageArg, config) {
|
|
14
|
+
const name = packageArg || config.app;
|
|
15
|
+
if (!name) {
|
|
16
|
+
console.error("Error: No package name. Use --app <package> or gpc config set app <package>");
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
return name;
|
|
20
|
+
}
|
|
21
|
+
async function getClient(config) {
|
|
22
|
+
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
23
|
+
return createApiClient({ auth });
|
|
24
|
+
}
|
|
25
|
+
function registerGeneratedApksCommands(program) {
|
|
26
|
+
const cmd = program.command("generated-apks").description("Manage generated (device-specific) APKs");
|
|
27
|
+
cmd.command("list <version-code>").description("List generated APKs for a version code").action(async (versionCodeStr) => {
|
|
28
|
+
const config = await loadConfig();
|
|
29
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
30
|
+
const client = await getClient(config);
|
|
31
|
+
const format = detectOutputFormat();
|
|
32
|
+
const versionCode = parseInt(versionCodeStr, 10);
|
|
33
|
+
if (isNaN(versionCode)) {
|
|
34
|
+
console.error("Error: version-code must be a number");
|
|
35
|
+
process.exit(2);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const result = await listGeneratedApks(client, packageName, versionCode);
|
|
39
|
+
console.log(formatOutput(result, format));
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
process.exit(4);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
cmd.command("download <version-code> <apk-id>").description("Download a generated APK").requiredOption("--output <path>", "Output file path").action(async (versionCodeStr, apkId, opts) => {
|
|
46
|
+
const config = await loadConfig();
|
|
47
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
48
|
+
const client = await getClient(config);
|
|
49
|
+
const format = detectOutputFormat();
|
|
50
|
+
const versionCode = parseInt(versionCodeStr, 10);
|
|
51
|
+
if (isNaN(versionCode)) {
|
|
52
|
+
console.error("Error: version-code must be a number");
|
|
53
|
+
process.exit(2);
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const result = await downloadGeneratedApk(
|
|
57
|
+
client,
|
|
58
|
+
packageName,
|
|
59
|
+
versionCode,
|
|
60
|
+
apkId,
|
|
61
|
+
opts.output
|
|
62
|
+
);
|
|
63
|
+
console.log(formatOutput(result, format));
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
66
|
+
process.exit(4);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
registerGeneratedApksCommands
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=generated-apks-SUPM3NS3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/generated-apks.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport {\n listGeneratedApks,\n downloadGeneratedApk,\n detectOutputFormat,\n formatOutput,\n} from \"@gpc-cli/core\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerGeneratedApksCommands(program: Command): void {\n const cmd = program\n .command(\"generated-apks\")\n .description(\"Manage generated (device-specific) APKs\");\n\n cmd\n .command(\"list <version-code>\")\n .description(\"List generated APKs for a version code\")\n .action(async (versionCodeStr: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = detectOutputFormat();\n\n const versionCode = parseInt(versionCodeStr, 10);\n if (isNaN(versionCode)) {\n console.error(\"Error: version-code must be a number\");\n process.exit(2);\n }\n\n try {\n const result = await listGeneratedApks(client, packageName, versionCode);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n cmd\n .command(\"download <version-code> <apk-id>\")\n .description(\"Download a generated APK\")\n .requiredOption(\"--output <path>\", \"Output file path\")\n .action(async (versionCodeStr: string, apkId: string, opts: { output: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = detectOutputFormat();\n\n const versionCode = parseInt(versionCodeStr, 10);\n if (isNaN(versionCode)) {\n console.error(\"Error: version-code must be a number\");\n process.exit(2);\n }\n\n try {\n const result = await downloadGeneratedApk(\n client,\n packageName,\n versionCode,\n apkId,\n opts.output,\n );\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":";;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,mBAAmB,YAAgC,QAA2B;AACrF,QAAM,OAAO,cAAc,OAAO;AAClC,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,UAAU,QAAmB;AAC1C,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,gBAAgB,EAAE,KAAK,CAAC;AACjC;AAEO,SAAS,8BAA8B,SAAwB;AACpE,QAAM,MAAM,QACT,QAAQ,gBAAgB,EACxB,YAAY,yCAAyC;AAExD,MACG,QAAQ,qBAAqB,EAC7B,YAAY,wCAAwC,EACpD,OAAO,OAAO,mBAA2B;AACxC,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,UAAM,cAAc,SAAS,gBAAgB,EAAE;AAC/C,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,MAAM,sCAAsC;AACpD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,kBAAkB,QAAQ,aAAa,WAAW;AACvE,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,kCAAkC,EAC1C,YAAY,0BAA0B,EACtC,eAAe,mBAAmB,kBAAkB,EACpD,OAAO,OAAO,gBAAwB,OAAe,SAA6B;AACjF,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,UAAM,cAAc,SAAS,gBAAgB,EAAE;AAC/C,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,MAAM,sCAAsC;AACpD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI;AACF,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK;AAAA,MACP;AACA,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
|
|
@@ -21,7 +21,8 @@ import {
|
|
|
21
21
|
syncInAppProducts,
|
|
22
22
|
detectOutputFormat,
|
|
23
23
|
formatOutput,
|
|
24
|
-
sortResults
|
|
24
|
+
sortResults,
|
|
25
|
+
createSpinner
|
|
25
26
|
} from "@gpc-cli/core";
|
|
26
27
|
function resolvePackageName(packageArg, config) {
|
|
27
28
|
const name = packageArg || config.app;
|
|
@@ -155,15 +156,19 @@ function registerIapCommands(program) {
|
|
|
155
156
|
const client = await getClient(config);
|
|
156
157
|
const format = detectOutputFormat();
|
|
157
158
|
const dryRun = isDryRun(program);
|
|
159
|
+
const spinner = createSpinner("Syncing in-app products...");
|
|
160
|
+
if (!program.opts()["quiet"] && process.stderr.isTTY) spinner.start();
|
|
158
161
|
try {
|
|
159
162
|
const result = await syncInAppProducts(client, packageName, options.dir, {
|
|
160
163
|
dryRun
|
|
161
164
|
});
|
|
165
|
+
spinner.stop("Sync complete");
|
|
162
166
|
if (dryRun) {
|
|
163
167
|
console.log(`[dry-run] Would create: ${result.created}, update: ${result.updated}`);
|
|
164
168
|
}
|
|
165
169
|
console.log(formatOutput(result, format));
|
|
166
170
|
} catch (error) {
|
|
171
|
+
spinner.fail("Sync failed");
|
|
167
172
|
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
168
173
|
process.exit(4);
|
|
169
174
|
}
|
|
@@ -172,4 +177,4 @@ function registerIapCommands(program) {
|
|
|
172
177
|
export {
|
|
173
178
|
registerIapCommands
|
|
174
179
|
};
|
|
175
|
-
//# sourceMappingURL=iap-
|
|
180
|
+
//# sourceMappingURL=iap-2CV6SJUF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/iap.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport {\n listInAppProducts,\n getInAppProduct,\n createInAppProduct,\n updateInAppProduct,\n deleteInAppProduct,\n syncInAppProducts,\n detectOutputFormat,\n formatOutput,\n sortResults,\n createSpinner,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerIapCommands(program: Command): void {\n const iap = program.command(\"iap\").description(\"Manage in-app products\");\n\n iap\n .command(\"list\")\n .description(\"List in-app products\")\n .option(\"--max <n>\", \"Maximum results per page\", parseInt)\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await listInAppProducts(client, packageName, {\n maxResults: options.max,\n limit: options.limit,\n nextPage: options.nextPage,\n });\n if (options.sort) {\n result.inappproduct = sortResults(result.inappproduct, options.sort);\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"get <sku>\")\n .description(\"Get an in-app product\")\n .action(async (sku: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await getInAppProduct(client, packageName, sku);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"create\")\n .description(\"Create an in-app product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = detectOutputFormat();\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"iap create\",\n action: \"create\",\n target: `in-app product from ${options.file}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = JSON.parse(await readFile(options.file, \"utf-8\"));\n const result = await createInAppProduct(client, packageName, data);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"update <sku>\")\n .description(\"Update an in-app product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .action(async (sku: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = detectOutputFormat();\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"iap update\",\n action: \"update\",\n target: sku,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = JSON.parse(await readFile(options.file, \"utf-8\"));\n const result = await updateInAppProduct(client, packageName, sku, data);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"delete <sku>\")\n .description(\"Delete an in-app product\")\n .action(async (sku: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete in-app product \"${sku}\"?`, program);\n\n if (isDryRun(program)) {\n const format = detectOutputFormat();\n printDryRun(\n {\n command: \"iap delete\",\n action: \"delete\",\n target: sku,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteInAppProduct(client, packageName, sku);\n console.log(`In-app product ${sku} deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"sync\")\n .description(\"Sync in-app products from a directory of JSON files\")\n .requiredOption(\"--dir <path>\", \"Directory containing product JSON files\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = detectOutputFormat();\n const dryRun = isDryRun(program);\n\n const spinner = createSpinner(\"Syncing in-app products...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const result = await syncInAppProducts(client, packageName, options.dir, {\n dryRun,\n });\n spinner.stop(\"Sync complete\");\n if (dryRun) {\n console.log(`[dry-run] Would create: ${result.created}, update: ${result.updated}`);\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Sync failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,gBAAgB;AAGzB,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP,SAAS,mBAAmB,YAAgC,QAA2B;AACrF,QAAM,OAAO,cAAc,OAAO;AAClC,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,UAAU,QAAmB;AAC1C,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,gBAAgB,EAAE,KAAK,CAAC;AACjC;AAEO,SAAS,oBAAoB,SAAwB;AAC1D,QAAM,MAAM,QAAQ,QAAQ,KAAK,EAAE,YAAY,wBAAwB;AAEvE,MACG,QAAQ,MAAM,EACd,YAAY,sBAAsB,EAClC,OAAO,aAAa,4BAA4B,QAAQ,EACxD,OAAO,eAAe,yBAAyB,QAAQ,EACvD,OAAO,uBAAuB,wBAAwB,EACtD,OAAO,kBAAkB,8CAA8C,EACvE,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,SAAS,MAAM,kBAAkB,QAAQ,aAAa;AAAA,QAC1D,YAAY,QAAQ;AAAA,QACpB,OAAO,QAAQ;AAAA,QACf,UAAU,QAAQ;AAAA,MACpB,CAAC;AACD,UAAI,QAAQ,MAAM;AAChB,eAAO,eAAe,YAAY,OAAO,cAAc,QAAQ,IAAI;AAAA,MACrE;AACA,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,WAAW,EACnB,YAAY,uBAAuB,EACnC,OAAO,OAAO,QAAgB;AAC7B,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,SAAS,MAAM,gBAAgB,QAAQ,aAAa,GAAG;AAC7D,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,QAAQ,EAChB,YAAY,yCAAyC,EACrD,eAAe,iBAAiB,6BAA6B,EAC7D,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,mBAAmB;AAElC,QAAI,SAAS,OAAO,GAAG;AACrB;AAAA,QACE;AAAA,UACE,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ,uBAAuB,QAAQ,IAAI;AAAA,QAC7C;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,MAAM,SAAS,QAAQ,MAAM,OAAO,CAAC;AAC7D,YAAM,SAAS,MAAM,mBAAmB,QAAQ,aAAa,IAAI;AACjE,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,cAAc,EACtB,YAAY,yCAAyC,EACrD,eAAe,iBAAiB,6BAA6B,EAC7D,OAAO,OAAO,KAAa,YAAY;AACtC,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,mBAAmB;AAElC,QAAI,SAAS,OAAO,GAAG;AACrB;AAAA,QACE;AAAA,UACE,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,SAAS,EAAE,MAAM,QAAQ,KAAK;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,MAAM,SAAS,QAAQ,MAAM,OAAO,CAAC;AAC7D,YAAM,SAAS,MAAM,mBAAmB,QAAQ,aAAa,KAAK,IAAI;AACtE,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,cAAc,EACtB,YAAY,0BAA0B,EACtC,OAAO,OAAO,QAAgB;AAC7B,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AAEpE,UAAM,eAAe,0BAA0B,GAAG,MAAM,OAAO;AAE/D,QAAI,SAAS,OAAO,GAAG;AACrB,YAAM,SAAS,mBAAmB;AAClC;AAAA,QACE;AAAA,UACE,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,QAAI;AACF,YAAM,mBAAmB,QAAQ,aAAa,GAAG;AACjD,cAAQ,IAAI,kBAAkB,GAAG,WAAW;AAAA,IAC9C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,MAAM,EACd,YAAY,qDAAqD,EACjE,eAAe,gBAAgB,yCAAyC,EACxE,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAClC,UAAM,SAAS,SAAS,OAAO;AAE/B,UAAM,UAAU,cAAc,4BAA4B;AAC1D,QAAI,CAAC,QAAQ,KAAK,EAAE,OAAO,KAAK,QAAQ,OAAO,MAAO,SAAQ,MAAM;AAEpE,QAAI;AACF,YAAM,SAAS,MAAM,kBAAkB,QAAQ,aAAa,QAAQ,KAAK;AAAA,QACvE;AAAA,MACF,CAAC;AACD,cAAQ,KAAK,eAAe;AAC5B,UAAI,QAAQ;AACV,gBAAQ,IAAI,2BAA2B,OAAO,OAAO,aAAa,OAAO,OAAO,EAAE;AAAA,MACpF;AACA,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,KAAK,aAAa;AAC1B,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/internal-sharing.ts
|
|
4
|
+
import { loadConfig } from "@gpc-cli/config";
|
|
5
|
+
import { resolveAuth } from "@gpc-cli/auth";
|
|
6
|
+
import { createApiClient } from "@gpc-cli/api";
|
|
7
|
+
import {
|
|
8
|
+
uploadInternalSharing,
|
|
9
|
+
detectOutputFormat,
|
|
10
|
+
formatOutput,
|
|
11
|
+
createSpinner
|
|
12
|
+
} from "@gpc-cli/core";
|
|
13
|
+
function resolvePackageName(packageArg, config) {
|
|
14
|
+
const name = packageArg || config.app;
|
|
15
|
+
if (!name) {
|
|
16
|
+
console.error("Error: No package name. Use --app <package> or gpc config set app <package>");
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
return name;
|
|
20
|
+
}
|
|
21
|
+
async function getClient(config) {
|
|
22
|
+
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
23
|
+
return createApiClient({ auth });
|
|
24
|
+
}
|
|
25
|
+
function registerInternalSharingCommands(program) {
|
|
26
|
+
const cmd = program.command("internal-sharing").description("Internal app sharing (upload bundles/APKs for instant sharing)");
|
|
27
|
+
cmd.command("upload <file>").description("Upload a bundle or APK for internal app sharing").option("--type <type>", "File type: bundle or apk (auto-detected from extension)").action(async (file, opts) => {
|
|
28
|
+
const config = await loadConfig();
|
|
29
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
30
|
+
const client = await getClient(config);
|
|
31
|
+
const format = detectOutputFormat();
|
|
32
|
+
const fileType = opts.type;
|
|
33
|
+
const spinner = createSpinner("Uploading for internal sharing...");
|
|
34
|
+
if (!program.opts()["quiet"] && process.stderr.isTTY) spinner.start();
|
|
35
|
+
try {
|
|
36
|
+
const result = await uploadInternalSharing(client, packageName, file, fileType);
|
|
37
|
+
spinner.stop("Upload complete");
|
|
38
|
+
console.log(formatOutput(result, format));
|
|
39
|
+
} catch (error) {
|
|
40
|
+
spinner.fail("Upload failed");
|
|
41
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
process.exit(4);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
registerInternalSharingCommands
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=internal-sharing-TWMHLQLN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/internal-sharing.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport {\n uploadInternalSharing,\n detectOutputFormat,\n formatOutput,\n createSpinner,\n} from \"@gpc-cli/core\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerInternalSharingCommands(program: Command): void {\n const cmd = program\n .command(\"internal-sharing\")\n .description(\"Internal app sharing (upload bundles/APKs for instant sharing)\");\n\n cmd\n .command(\"upload <file>\")\n .description(\"Upload a bundle or APK for internal app sharing\")\n .option(\"--type <type>\", \"File type: bundle or apk (auto-detected from extension)\")\n .action(async (file: string, opts: { type?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = detectOutputFormat();\n\n const fileType = opts.type as \"bundle\" | \"apk\" | undefined;\n\n const spinner = createSpinner(\"Uploading for internal sharing...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const result = await uploadInternalSharing(client, packageName, file, fileType);\n spinner.stop(\"Upload complete\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Upload failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":";;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,mBAAmB,YAAgC,QAA2B;AACrF,QAAM,OAAO,cAAc,OAAO;AAClC,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,UAAU,QAAmB;AAC1C,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,gBAAgB,EAAE,KAAK,CAAC;AACjC;AAEO,SAAS,gCAAgC,SAAwB;AACtE,QAAM,MAAM,QACT,QAAQ,kBAAkB,EAC1B,YAAY,gEAAgE;AAE/E,MACG,QAAQ,eAAe,EACvB,YAAY,iDAAiD,EAC7D,OAAO,iBAAiB,yDAAyD,EACjF,OAAO,OAAO,MAAc,SAA4B;AACvD,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,UAAM,WAAW,KAAK;AAEtB,UAAM,UAAU,cAAc,mCAAmC;AACjE,QAAI,CAAC,QAAQ,KAAK,EAAE,OAAO,KAAK,QAAQ,OAAO,MAAO,SAAQ,MAAM;AAEpE,QAAI;AACF,YAAM,SAAS,MAAM,sBAAsB,QAAQ,aAAa,MAAM,QAAQ;AAC9E,cAAQ,KAAK,iBAAiB;AAC9B,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,KAAK,eAAe;AAC5B,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
|
|
@@ -23,9 +23,11 @@ import {
|
|
|
23
23
|
listImages,
|
|
24
24
|
uploadImage,
|
|
25
25
|
deleteImage,
|
|
26
|
+
exportImages,
|
|
26
27
|
getCountryAvailability,
|
|
27
28
|
detectOutputFormat,
|
|
28
|
-
formatOutput
|
|
29
|
+
formatOutput,
|
|
30
|
+
createSpinner
|
|
29
31
|
} from "@gpc-cli/core";
|
|
30
32
|
function resolvePackageName(packageArg, config) {
|
|
31
33
|
const name = packageArg || config.app;
|
|
@@ -185,12 +187,16 @@ function registerListingsCommands(program) {
|
|
|
185
187
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
186
188
|
const client = await getClient(config);
|
|
187
189
|
const format = detectOutputFormat();
|
|
190
|
+
const spinner = createSpinner("Pushing listings...");
|
|
191
|
+
if (!program.opts()["quiet"] && process.stderr.isTTY) spinner.start();
|
|
188
192
|
try {
|
|
189
193
|
const result = await pushListings(client, packageName, options.dir, {
|
|
190
194
|
dryRun: isDryRun(program)
|
|
191
195
|
});
|
|
196
|
+
spinner.stop("Listings pushed");
|
|
192
197
|
console.log(formatOutput(result, format));
|
|
193
198
|
} catch (error) {
|
|
199
|
+
spinner.fail("Push failed");
|
|
194
200
|
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
195
201
|
process.exit(4);
|
|
196
202
|
}
|
|
@@ -225,7 +231,7 @@ function registerListingsCommands(program) {
|
|
|
225
231
|
}
|
|
226
232
|
});
|
|
227
233
|
const images = listings.command("images").description("Manage listing images");
|
|
228
|
-
images.command("list").description("List images for a language and type").option("--lang <language>", "Language code (BCP 47)").option("--type <type>", "Image type").action(async (options) => {
|
|
234
|
+
images.command("list").description("List images for a language and type").option("--lang <language>", "Language code (BCP 47)").option("--type <type>", "Image type").option("--limit <n>", "Maximum results to return").option("--next-page <token>", "Pagination token for next page").action(async (options) => {
|
|
229
235
|
const config = await loadConfig();
|
|
230
236
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
231
237
|
const interactive = isInteractive(program);
|
|
@@ -283,10 +289,14 @@ function registerListingsCommands(program) {
|
|
|
283
289
|
const client = await getClient(config);
|
|
284
290
|
const format = detectOutputFormat();
|
|
285
291
|
const imageType = validateImageType(options.type);
|
|
292
|
+
const spinner = createSpinner("Uploading image...");
|
|
293
|
+
if (!program.opts()["quiet"] && process.stderr.isTTY) spinner.start();
|
|
286
294
|
try {
|
|
287
295
|
const result = await uploadImage(client, packageName, options.lang, imageType, file);
|
|
296
|
+
spinner.stop("Image uploaded");
|
|
288
297
|
console.log(formatOutput(result, format));
|
|
289
298
|
} catch (error) {
|
|
299
|
+
spinner.fail("Image upload failed");
|
|
290
300
|
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
291
301
|
process.exit(4);
|
|
292
302
|
}
|
|
@@ -331,6 +341,28 @@ function registerListingsCommands(program) {
|
|
|
331
341
|
process.exit(4);
|
|
332
342
|
}
|
|
333
343
|
});
|
|
344
|
+
images.command("export").description("Export all images to a local directory").option("--dir <path>", "Output directory", "images").option("--lang <language>", "Language code (BCP 47) \u2014 export only this language").option("--type <type>", "Image type \u2014 export only this type").action(async (options) => {
|
|
345
|
+
const config = await loadConfig();
|
|
346
|
+
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
347
|
+
const client = await getClient(config);
|
|
348
|
+
const format = detectOutputFormat();
|
|
349
|
+
const exportOpts = {};
|
|
350
|
+
if (options.lang) exportOpts.lang = options.lang;
|
|
351
|
+
if (options.type) {
|
|
352
|
+
exportOpts.type = validateImageType(options.type);
|
|
353
|
+
}
|
|
354
|
+
const spinner = createSpinner("Exporting images...");
|
|
355
|
+
if (!program.opts()["quiet"] && process.stderr.isTTY) spinner.start();
|
|
356
|
+
try {
|
|
357
|
+
const result = await exportImages(client, packageName, options.dir, exportOpts);
|
|
358
|
+
spinner.stop("Images exported");
|
|
359
|
+
console.log(formatOutput(result, format));
|
|
360
|
+
} catch (error) {
|
|
361
|
+
spinner.fail("Image export failed");
|
|
362
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
363
|
+
process.exit(4);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
334
366
|
listings.command("availability").description("Get country availability for a track").option("--track <track>", "Track name", "production").action(async (options) => {
|
|
335
367
|
const config = await loadConfig();
|
|
336
368
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
@@ -348,4 +380,4 @@ function registerListingsCommands(program) {
|
|
|
348
380
|
export {
|
|
349
381
|
registerListingsCommands
|
|
350
382
|
};
|
|
351
|
-
//# sourceMappingURL=listings-
|
|
383
|
+
//# sourceMappingURL=listings-4QCTOEWL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/listings.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport type { ImageType } from \"@gpc-cli/api\";\nimport {\n getListings,\n updateListing,\n deleteListing,\n pullListings,\n pushListings,\n diffListingsCommand,\n listImages,\n uploadImage,\n deleteImage,\n exportImages,\n getCountryAvailability,\n detectOutputFormat,\n formatOutput,\n createSpinner,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nconst VALID_IMAGE_TYPES: ImageType[] = [\n \"phoneScreenshots\",\n \"sevenInchScreenshots\",\n \"tenInchScreenshots\",\n \"tvScreenshots\",\n \"wearScreenshots\",\n \"icon\",\n \"featureGraphic\",\n \"tvBanner\",\n];\n\nfunction validateImageType(type: string): ImageType {\n if (!VALID_IMAGE_TYPES.includes(type as ImageType)) {\n console.error(`Error: Invalid image type \"${type}\".`);\n console.error(`Valid types: ${VALID_IMAGE_TYPES.join(\", \")}`);\n process.exit(2);\n }\n return type as ImageType;\n}\n\nexport function registerListingsCommands(program: Command): void {\n const listings = program.command(\"listings\").description(\"Manage store listings and metadata\");\n\n // Get\n listings\n .command(\"get\")\n .description(\"Get store listing(s)\")\n .option(\"--lang <language>\", \"Language code (BCP 47)\")\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 = detectOutputFormat();\n\n try {\n const result = await getListings(client, packageName, options.lang);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Update\n listings\n .command(\"update\")\n .description(\"Update a store listing\")\n .option(\"--lang <language>\", \"Language code (BCP 47)\")\n .option(\"--title <text>\", \"App title\")\n .option(\"--short <text>\", \"Short description\")\n .option(\"--full <text>\", \"Full description\")\n .option(\"--full-file <path>\", \"Read full description from file\")\n .option(\"--video <url>\", \"Video URL\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const interactive = isInteractive(program);\n\n options.lang = await requireOption(\n \"lang\",\n options.lang,\n {\n message: \"Language code (BCP 47):\",\n default: \"en-US\",\n },\n interactive,\n );\n const format = detectOutputFormat();\n\n try {\n const data: Record<string, string> = {};\n if (options[\"title\"]) data[\"title\"] = options[\"title\"];\n if (options[\"short\"]) data[\"shortDescription\"] = options[\"short\"];\n if (options[\"full\"]) data[\"fullDescription\"] = options[\"full\"];\n if (options[\"fullFile\"]) {\n const { readFile } = await import(\"node:fs/promises\");\n data[\"fullDescription\"] = (await readFile(options[\"fullFile\"], \"utf-8\")).trimEnd();\n }\n if (options[\"video\"]) data[\"video\"] = options[\"video\"];\n\n if (Object.keys(data).length === 0) {\n console.error(\n \"Error: Provide at least one field to update (--title, --short, --full, --full-file, --video).\",\n );\n process.exit(2);\n }\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"listings update\",\n action: \"update listing for\",\n target: options.lang,\n details: data,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n const result = await updateListing(client, packageName, options.lang, data);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Delete\n listings\n .command(\"delete\")\n .description(\"Delete a store listing for a language\")\n .option(\"--lang <language>\", \"Language code (BCP 47)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const interactive = isInteractive(program);\n\n options.lang = await requireOption(\n \"lang\",\n options.lang,\n {\n message: \"Language code (BCP 47):\",\n },\n interactive,\n );\n\n await requireConfirm(`Delete listing for \"${options.lang}\"?`, program);\n\n if (isDryRun(program)) {\n const format = detectOutputFormat();\n printDryRun(\n {\n command: \"listings delete\",\n action: \"delete listing for\",\n target: options.lang,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteListing(client, packageName, options.lang);\n console.log(`Listing for \"${options.lang}\" deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Pull\n listings\n .command(\"pull\")\n .description(\"Download listings to Fastlane-format directory\")\n .option(\"--dir <path>\", \"Output directory\", \"metadata\")\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 = detectOutputFormat();\n\n try {\n const result = await pullListings(client, packageName, options.dir);\n console.log(\n formatOutput(\n {\n directory: options.dir,\n languages: result.listings.map((l) => l.language),\n count: result.listings.length,\n },\n format,\n ),\n );\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Push\n listings\n .command(\"push\")\n .description(\"Upload listings from Fastlane-format directory\")\n .option(\"--dir <path>\", \"Source directory\", \"metadata\")\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 = detectOutputFormat();\n\n const spinner = createSpinner(\"Pushing listings...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const result = await pushListings(client, packageName, options.dir, {\n dryRun: isDryRun(program),\n });\n spinner.stop(\"Listings pushed\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Push failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Diff\n listings\n .command(\"diff\")\n .description(\"Compare local Fastlane-format metadata against remote listings\")\n .option(\"--dir <path>\", \"Local metadata directory\", \"metadata\")\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 = detectOutputFormat();\n\n try {\n const diffs = await diffListingsCommand(client, packageName, options.dir);\n\n if (diffs.length === 0) {\n if (format === \"json\") {\n console.log(formatOutput([], format));\n } else {\n console.log(\"No differences found.\");\n }\n return;\n }\n\n if (format === \"json\") {\n console.log(formatOutput(diffs, format));\n } else {\n for (const diff of diffs) {\n console.log(`[${diff.language}] ${diff.field}:`);\n console.log(` local: ${diff.local || \"(empty)\"}`);\n console.log(` remote: ${diff.remote || \"(empty)\"}`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Images subcommand\n const images = listings.command(\"images\").description(\"Manage listing images\");\n\n // Images list\n images\n .command(\"list\")\n .description(\"List images for a language and type\")\n .option(\"--lang <language>\", \"Language code (BCP 47)\")\n .option(\"--type <type>\", \"Image type\")\n .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const interactive = isInteractive(program);\n\n options.lang = await requireOption(\n \"lang\",\n options.lang,\n {\n message: \"Language code (BCP 47):\",\n default: \"en-US\",\n },\n interactive,\n );\n\n options.type = await requireOption(\n \"type\",\n options.type,\n {\n message: \"Image type:\",\n choices: VALID_IMAGE_TYPES as unknown as string[],\n },\n interactive,\n );\n\n const client = await getClient(config);\n const format = detectOutputFormat();\n const imageType = validateImageType(options.type);\n\n try {\n const result = await listImages(client, packageName, options.lang, imageType);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Images upload\n images\n .command(\"upload <file>\")\n .description(\"Upload an image\")\n .option(\"--lang <language>\", \"Language code (BCP 47)\")\n .option(\"--type <type>\", \"Image type\")\n .action(async (file: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const interactive = isInteractive(program);\n\n options.lang = await requireOption(\n \"lang\",\n options.lang,\n {\n message: \"Language code (BCP 47):\",\n default: \"en-US\",\n },\n interactive,\n );\n\n options.type = await requireOption(\n \"type\",\n options.type,\n {\n message: \"Image type:\",\n choices: VALID_IMAGE_TYPES as unknown as string[],\n },\n interactive,\n );\n\n const client = await getClient(config);\n const format = detectOutputFormat();\n const imageType = validateImageType(options.type);\n\n const spinner = createSpinner(\"Uploading image...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const result = await uploadImage(client, packageName, options.lang, imageType, file);\n spinner.stop(\"Image uploaded\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Image upload failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Images delete\n images\n .command(\"delete\")\n .description(\"Delete an image\")\n .option(\"--lang <language>\", \"Language code (BCP 47)\")\n .option(\"--type <type>\", \"Image type\")\n .option(\"--id <imageId>\", \"Image ID to delete\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const interactive = isInteractive(program);\n\n options.lang = await requireOption(\n \"lang\",\n options.lang,\n {\n message: \"Language code (BCP 47):\",\n },\n interactive,\n );\n\n options.type = await requireOption(\n \"type\",\n options.type,\n {\n message: \"Image type:\",\n choices: VALID_IMAGE_TYPES as unknown as string[],\n },\n interactive,\n );\n\n options.id = await requireOption(\n \"id\",\n options.id,\n {\n message: \"Image ID to delete:\",\n },\n interactive,\n );\n\n await requireConfirm(`Delete image \"${options.id}\"?`, program);\n\n const client = await getClient(config);\n const imageType = validateImageType(options.type);\n\n try {\n await deleteImage(client, packageName, options.lang, imageType, options.id);\n console.log(`Image \"${options.id}\" deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Images export\n images\n .command(\"export\")\n .description(\"Export all images to a local directory\")\n .option(\"--dir <path>\", \"Output directory\", \"images\")\n .option(\"--lang <language>\", \"Language code (BCP 47) — export only this language\")\n .option(\"--type <type>\", \"Image type — export only this type\")\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 = detectOutputFormat();\n\n const exportOpts: { lang?: string; type?: ImageType } = {};\n if (options.lang) exportOpts.lang = options.lang;\n if (options.type) {\n exportOpts.type = validateImageType(options.type);\n }\n\n const spinner = createSpinner(\"Exporting images...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const result = await exportImages(client, packageName, options.dir, exportOpts);\n spinner.stop(\"Images exported\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Image export failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Availability\n listings\n .command(\"availability\")\n .description(\"Get country availability for a track\")\n .option(\"--track <track>\", \"Track name\", \"production\")\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 = detectOutputFormat();\n\n try {\n const result = await getCountryAvailability(client, packageName, options.track);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":";;;;;;;;;;;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAEhC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP,SAAS,mBAAmB,YAAgC,QAA2B;AACrF,QAAM,OAAO,cAAc,OAAO;AAClC,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,UAAU,QAAmB;AAC1C,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,gBAAgB,EAAE,KAAK,CAAC;AACjC;AAEA,IAAM,oBAAiC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,kBAAkB,MAAyB;AAClD,MAAI,CAAC,kBAAkB,SAAS,IAAiB,GAAG;AAClD,YAAQ,MAAM,8BAA8B,IAAI,IAAI;AACpD,YAAQ,MAAM,gBAAgB,kBAAkB,KAAK,IAAI,CAAC,EAAE;AAC5D,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,SAAwB;AAC/D,QAAM,WAAW,QAAQ,QAAQ,UAAU,EAAE,YAAY,oCAAoC;AAG7F,WACG,QAAQ,KAAK,EACb,YAAY,sBAAsB,EAClC,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,SAAS,MAAM,YAAY,QAAQ,aAAa,QAAQ,IAAI;AAClE,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,WACG,QAAQ,QAAQ,EAChB,YAAY,wBAAwB,EACpC,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,kBAAkB,WAAW,EACpC,OAAO,kBAAkB,mBAAmB,EAC5C,OAAO,iBAAiB,kBAAkB,EAC1C,OAAO,sBAAsB,iCAAiC,EAC9D,OAAO,iBAAiB,WAAW,EACnC,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,cAAc,cAAc,OAAO;AAEzC,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,OAA+B,CAAC;AACtC,UAAI,QAAQ,OAAO,EAAG,MAAK,OAAO,IAAI,QAAQ,OAAO;AACrD,UAAI,QAAQ,OAAO,EAAG,MAAK,kBAAkB,IAAI,QAAQ,OAAO;AAChE,UAAI,QAAQ,MAAM,EAAG,MAAK,iBAAiB,IAAI,QAAQ,MAAM;AAC7D,UAAI,QAAQ,UAAU,GAAG;AACvB,cAAM,EAAE,SAAS,IAAI,MAAM,OAAO,aAAkB;AACpD,aAAK,iBAAiB,KAAK,MAAM,SAAS,QAAQ,UAAU,GAAG,OAAO,GAAG,QAAQ;AAAA,MACnF;AACA,UAAI,QAAQ,OAAO,EAAG,MAAK,OAAO,IAAI,QAAQ,OAAO;AAErD,UAAI,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG;AAClC,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI,SAAS,OAAO,GAAG;AACrB;AAAA,UACE;AAAA,YACE,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,QAAQ,QAAQ;AAAA,YAChB,SAAS;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,UAAU,MAAM;AACrC,YAAM,SAAS,MAAM,cAAc,QAAQ,aAAa,QAAQ,MAAM,IAAI;AAC1E,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,WACG,QAAQ,QAAQ,EAChB,YAAY,uCAAuC,EACnD,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,cAAc,cAAc,OAAO;AAEzC,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,UAAM,eAAe,uBAAuB,QAAQ,IAAI,MAAM,OAAO;AAErE,QAAI,SAAS,OAAO,GAAG;AACrB,YAAM,SAAS,mBAAmB;AAClC;AAAA,QACE;AAAA,UACE,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ,QAAQ;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,MAAM;AAErC,QAAI;AACF,YAAM,cAAc,QAAQ,aAAa,QAAQ,IAAI;AACrD,cAAQ,IAAI,gBAAgB,QAAQ,IAAI,YAAY;AAAA,IACtD,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,WACG,QAAQ,MAAM,EACd,YAAY,gDAAgD,EAC5D,OAAO,gBAAgB,oBAAoB,UAAU,EACrD,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,SAAS,MAAM,aAAa,QAAQ,aAAa,QAAQ,GAAG;AAClE,cAAQ;AAAA,QACN;AAAA,UACE;AAAA,YACE,WAAW,QAAQ;AAAA,YACnB,WAAW,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,QAAQ;AAAA,YAChD,OAAO,OAAO,SAAS;AAAA,UACzB;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,WACG,QAAQ,MAAM,EACd,YAAY,gDAAgD,EAC5D,OAAO,gBAAgB,oBAAoB,UAAU,EACrD,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,UAAM,UAAU,cAAc,qBAAqB;AACnD,QAAI,CAAC,QAAQ,KAAK,EAAE,OAAO,KAAK,QAAQ,OAAO,MAAO,SAAQ,MAAM;AAEpE,QAAI;AACF,YAAM,SAAS,MAAM,aAAa,QAAQ,aAAa,QAAQ,KAAK;AAAA,QAClE,QAAQ,SAAS,OAAO;AAAA,MAC1B,CAAC;AACD,cAAQ,KAAK,iBAAiB;AAC9B,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,KAAK,aAAa;AAC1B,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,WACG,QAAQ,MAAM,EACd,YAAY,gEAAgE,EAC5E,OAAO,gBAAgB,4BAA4B,UAAU,EAC7D,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,QAAQ,MAAM,oBAAoB,QAAQ,aAAa,QAAQ,GAAG;AAExE,UAAI,MAAM,WAAW,GAAG;AACtB,YAAI,WAAW,QAAQ;AACrB,kBAAQ,IAAI,aAAa,CAAC,GAAG,MAAM,CAAC;AAAA,QACtC,OAAO;AACL,kBAAQ,IAAI,uBAAuB;AAAA,QACrC;AACA;AAAA,MACF;AAEA,UAAI,WAAW,QAAQ;AACrB,gBAAQ,IAAI,aAAa,OAAO,MAAM,CAAC;AAAA,MACzC,OAAO;AACL,mBAAW,QAAQ,OAAO;AACxB,kBAAQ,IAAI,IAAI,KAAK,QAAQ,KAAK,KAAK,KAAK,GAAG;AAC/C,kBAAQ,IAAI,aAAa,KAAK,SAAS,SAAS,EAAE;AAClD,kBAAQ,IAAI,aAAa,KAAK,UAAU,SAAS,EAAE;AAAA,QACrD;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,QAAM,SAAS,SAAS,QAAQ,QAAQ,EAAE,YAAY,uBAAuB;AAG7E,SACG,QAAQ,MAAM,EACd,YAAY,qCAAqC,EACjD,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,iBAAiB,YAAY,EACpC,OAAO,eAAe,2BAA2B,EACjD,OAAO,uBAAuB,gCAAgC,EAC9D,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,cAAc,cAAc,OAAO;AAEzC,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAClC,UAAM,YAAY,kBAAkB,QAAQ,IAAI;AAEhD,QAAI;AACF,YAAM,SAAS,MAAM,WAAW,QAAQ,aAAa,QAAQ,MAAM,SAAS;AAC5E,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,eAAe,EACvB,YAAY,iBAAiB,EAC7B,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,iBAAiB,YAAY,EACpC,OAAO,OAAO,MAAc,YAAY;AACvC,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,cAAc,cAAc,OAAO;AAEzC,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAClC,UAAM,YAAY,kBAAkB,QAAQ,IAAI;AAEhD,UAAM,UAAU,cAAc,oBAAoB;AAClD,QAAI,CAAC,QAAQ,KAAK,EAAE,OAAO,KAAK,QAAQ,OAAO,MAAO,SAAQ,MAAM;AAEpE,QAAI;AACF,YAAM,SAAS,MAAM,YAAY,QAAQ,aAAa,QAAQ,MAAM,WAAW,IAAI;AACnF,cAAQ,KAAK,gBAAgB;AAC7B,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,KAAK,qBAAqB;AAClC,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,QAAQ,EAChB,YAAY,iBAAiB,EAC7B,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,iBAAiB,YAAY,EACpC,OAAO,kBAAkB,oBAAoB,EAC7C,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,cAAc,cAAc,OAAO;AAEzC,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,YAAQ,KAAK,MAAM;AAAA,MACjB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,UAAM,eAAe,iBAAiB,QAAQ,EAAE,MAAM,OAAO;AAE7D,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,YAAY,kBAAkB,QAAQ,IAAI;AAEhD,QAAI;AACF,YAAM,YAAY,QAAQ,aAAa,QAAQ,MAAM,WAAW,QAAQ,EAAE;AAC1E,cAAQ,IAAI,UAAU,QAAQ,EAAE,YAAY;AAAA,IAC9C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,QAAQ,EAChB,YAAY,wCAAwC,EACpD,OAAO,gBAAgB,oBAAoB,QAAQ,EACnD,OAAO,qBAAqB,yDAAoD,EAChF,OAAO,iBAAiB,yCAAoC,EAC5D,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,UAAM,aAAkD,CAAC;AACzD,QAAI,QAAQ,KAAM,YAAW,OAAO,QAAQ;AAC5C,QAAI,QAAQ,MAAM;AAChB,iBAAW,OAAO,kBAAkB,QAAQ,IAAI;AAAA,IAClD;AAEA,UAAM,UAAU,cAAc,qBAAqB;AACnD,QAAI,CAAC,QAAQ,KAAK,EAAE,OAAO,KAAK,QAAQ,OAAO,MAAO,SAAQ,MAAM;AAEpE,QAAI;AACF,YAAM,SAAS,MAAM,aAAa,QAAQ,aAAa,QAAQ,KAAK,UAAU;AAC9E,cAAQ,KAAK,iBAAiB;AAC9B,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,KAAK,qBAAqB;AAClC,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,WACG,QAAQ,cAAc,EACtB,YAAY,sCAAsC,EAClD,OAAO,mBAAmB,cAAc,YAAY,EACpD,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,SAAS,MAAM,uBAAuB,QAAQ,aAAa,QAAQ,KAAK;AAC9E,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/migrate.ts
|
|
4
|
+
import {
|
|
5
|
+
detectFastlane,
|
|
6
|
+
generateMigrationPlan,
|
|
7
|
+
writeMigrationOutput,
|
|
8
|
+
detectOutputFormat,
|
|
9
|
+
formatOutput
|
|
10
|
+
} from "@gpc-cli/core";
|
|
11
|
+
function registerMigrateCommands(program) {
|
|
12
|
+
const migrate = program.command("migrate").description("Migrate from other tools to GPC");
|
|
13
|
+
migrate.command("fastlane").description("Migrate from Fastlane to GPC").option("--dir <path>", "Directory containing Fastlane files", ".").option("--output <path>", "Output directory for migration files", ".").action(async (options) => {
|
|
14
|
+
const format = detectOutputFormat();
|
|
15
|
+
try {
|
|
16
|
+
const detection = await detectFastlane(options.dir);
|
|
17
|
+
if (format === "json") {
|
|
18
|
+
console.log(formatOutput(detection, format));
|
|
19
|
+
} else {
|
|
20
|
+
console.log("Fastlane Detection Results:");
|
|
21
|
+
console.log(` Fastfile: ${detection.hasFastfile ? "found" : "not found"}`);
|
|
22
|
+
console.log(` Appfile: ${detection.hasAppfile ? "found" : "not found"}`);
|
|
23
|
+
console.log(` Metadata: ${detection.hasMetadata ? "found" : "not found"}`);
|
|
24
|
+
console.log(` Gemfile: ${detection.hasGemfile ? "found" : "not found"}`);
|
|
25
|
+
if (detection.packageName) {
|
|
26
|
+
console.log(` Package: ${detection.packageName}`);
|
|
27
|
+
}
|
|
28
|
+
if (detection.lanes.length > 0) {
|
|
29
|
+
console.log(`
|
|
30
|
+
Lanes found: ${detection.lanes.length}`);
|
|
31
|
+
for (const lane of detection.lanes) {
|
|
32
|
+
const equiv = lane.gpcEquivalent ? ` -> ${lane.gpcEquivalent}` : " (no equivalent)";
|
|
33
|
+
console.log(` - ${lane.name}${equiv}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (detection.metadataLanguages.length > 0) {
|
|
37
|
+
console.log(`
|
|
38
|
+
Metadata languages: ${detection.metadataLanguages.join(", ")}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!detection.hasFastfile && !detection.hasAppfile && !detection.hasMetadata) {
|
|
42
|
+
if (format !== "json") {
|
|
43
|
+
console.log("\nNo Fastlane files detected. Nothing to migrate.");
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const plan = generateMigrationPlan(detection);
|
|
48
|
+
const files = await writeMigrationOutput(plan, options.output);
|
|
49
|
+
if (format === "json") {
|
|
50
|
+
console.log(formatOutput({ detection, plan, files }, format));
|
|
51
|
+
} else {
|
|
52
|
+
console.log("\nMigration files written:");
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
console.log(` ${file}`);
|
|
55
|
+
}
|
|
56
|
+
if (plan.warnings.length > 0) {
|
|
57
|
+
console.log("\nWarnings:");
|
|
58
|
+
for (const warning of plan.warnings) {
|
|
59
|
+
console.log(` - ${warning}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
console.log("\nMigration Checklist:");
|
|
63
|
+
for (const item of plan.checklist) {
|
|
64
|
+
console.log(` [ ] ${item}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
registerMigrateCommands
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=migrate-5IA6WGMO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/migrate.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport {\n detectFastlane,\n generateMigrationPlan,\n writeMigrationOutput,\n detectOutputFormat,\n formatOutput,\n} from \"@gpc-cli/core\";\n\nexport function registerMigrateCommands(program: Command): void {\n const migrate = program.command(\"migrate\").description(\"Migrate from other tools to GPC\");\n\n migrate\n .command(\"fastlane\")\n .description(\"Migrate from Fastlane to GPC\")\n .option(\"--dir <path>\", \"Directory containing Fastlane files\", \".\")\n .option(\"--output <path>\", \"Output directory for migration files\", \".\")\n .action(async (options) => {\n const format = detectOutputFormat();\n\n try {\n const detection = await detectFastlane(options.dir);\n\n // Show detection results\n if (format === \"json\") {\n console.log(formatOutput(detection, format));\n } else {\n console.log(\"Fastlane Detection Results:\");\n console.log(` Fastfile: ${detection.hasFastfile ? \"found\" : \"not found\"}`);\n console.log(` Appfile: ${detection.hasAppfile ? \"found\" : \"not found\"}`);\n console.log(` Metadata: ${detection.hasMetadata ? \"found\" : \"not found\"}`);\n console.log(` Gemfile: ${detection.hasGemfile ? \"found\" : \"not found\"}`);\n\n if (detection.packageName) {\n console.log(` Package: ${detection.packageName}`);\n }\n\n if (detection.lanes.length > 0) {\n console.log(`\\n Lanes found: ${detection.lanes.length}`);\n for (const lane of detection.lanes) {\n const equiv = lane.gpcEquivalent ? ` -> ${lane.gpcEquivalent}` : \" (no equivalent)\";\n console.log(` - ${lane.name}${equiv}`);\n }\n }\n\n if (detection.metadataLanguages.length > 0) {\n console.log(`\\n Metadata languages: ${detection.metadataLanguages.join(\", \")}`);\n }\n }\n\n if (\n !detection.hasFastfile &&\n !detection.hasAppfile &&\n !detection.hasMetadata\n ) {\n if (format !== \"json\") {\n console.log(\"\\nNo Fastlane files detected. Nothing to migrate.\");\n }\n return;\n }\n\n // Generate migration plan\n const plan = generateMigrationPlan(detection);\n\n // Write output files\n const files = await writeMigrationOutput(plan, options.output);\n\n if (format === \"json\") {\n console.log(formatOutput({ detection, plan, files }, format));\n } else {\n console.log(\"\\nMigration files written:\");\n for (const file of files) {\n console.log(` ${file}`);\n }\n\n if (plan.warnings.length > 0) {\n console.log(\"\\nWarnings:\");\n for (const warning of plan.warnings) {\n console.log(` - ${warning}`);\n }\n }\n\n console.log(\"\\nMigration Checklist:\");\n for (const item of plan.checklist) {\n console.log(` [ ] ${item}`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n}\n"],"mappings":";;;AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,SAAS,wBAAwB,SAAwB;AAC9D,QAAM,UAAU,QAAQ,QAAQ,SAAS,EAAE,YAAY,iCAAiC;AAExF,UACG,QAAQ,UAAU,EAClB,YAAY,8BAA8B,EAC1C,OAAO,gBAAgB,uCAAuC,GAAG,EACjE,OAAO,mBAAmB,wCAAwC,GAAG,EACrE,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,mBAAmB;AAElC,QAAI;AACF,YAAM,YAAY,MAAM,eAAe,QAAQ,GAAG;AAGlD,UAAI,WAAW,QAAQ;AACrB,gBAAQ,IAAI,aAAa,WAAW,MAAM,CAAC;AAAA,MAC7C,OAAO;AACL,gBAAQ,IAAI,6BAA6B;AACzC,gBAAQ,IAAI,gBAAgB,UAAU,cAAc,UAAU,WAAW,EAAE;AAC3E,gBAAQ,IAAI,gBAAgB,UAAU,aAAa,UAAU,WAAW,EAAE;AAC1E,gBAAQ,IAAI,gBAAgB,UAAU,cAAc,UAAU,WAAW,EAAE;AAC3E,gBAAQ,IAAI,gBAAgB,UAAU,aAAa,UAAU,WAAW,EAAE;AAE1E,YAAI,UAAU,aAAa;AACzB,kBAAQ,IAAI,gBAAgB,UAAU,WAAW,EAAE;AAAA,QACrD;AAEA,YAAI,UAAU,MAAM,SAAS,GAAG;AAC9B,kBAAQ,IAAI;AAAA,iBAAoB,UAAU,MAAM,MAAM,EAAE;AACxD,qBAAW,QAAQ,UAAU,OAAO;AAClC,kBAAM,QAAQ,KAAK,gBAAgB,OAAO,KAAK,aAAa,KAAK;AACjE,oBAAQ,IAAI,SAAS,KAAK,IAAI,GAAG,KAAK,EAAE;AAAA,UAC1C;AAAA,QACF;AAEA,YAAI,UAAU,kBAAkB,SAAS,GAAG;AAC1C,kBAAQ,IAAI;AAAA,wBAA2B,UAAU,kBAAkB,KAAK,IAAI,CAAC,EAAE;AAAA,QACjF;AAAA,MACF;AAEA,UACE,CAAC,UAAU,eACX,CAAC,UAAU,cACX,CAAC,UAAU,aACX;AACA,YAAI,WAAW,QAAQ;AACrB,kBAAQ,IAAI,mDAAmD;AAAA,QACjE;AACA;AAAA,MACF;AAGA,YAAM,OAAO,sBAAsB,SAAS;AAG5C,YAAM,QAAQ,MAAM,qBAAqB,MAAM,QAAQ,MAAM;AAE7D,UAAI,WAAW,QAAQ;AACrB,gBAAQ,IAAI,aAAa,EAAE,WAAW,MAAM,MAAM,GAAG,MAAM,CAAC;AAAA,MAC9D,OAAO;AACL,gBAAQ,IAAI,4BAA4B;AACxC,mBAAW,QAAQ,OAAO;AACxB,kBAAQ,IAAI,KAAK,IAAI,EAAE;AAAA,QACzB;AAEA,YAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,kBAAQ,IAAI,aAAa;AACzB,qBAAW,WAAW,KAAK,UAAU;AACnC,oBAAQ,IAAI,OAAO,OAAO,EAAE;AAAA,UAC9B;AAAA,QACF;AAEA,gBAAQ,IAAI,wBAAwB;AACpC,mBAAW,QAAQ,KAAK,WAAW;AACjC,kBAAQ,IAAI,SAAS,IAAI,EAAE;AAAA,QAC7B;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
|