@gpc-cli/cli 0.9.34 → 0.9.36

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.
Files changed (133) hide show
  1. package/README.md +20 -15
  2. package/dist/{anomalies-QZJGQXTZ.js → anomalies-KRRA75MJ.js} +1 -1
  3. package/dist/anomalies-KRRA75MJ.js.map +1 -0
  4. package/dist/{apps-CVBURB5V.js → apps-J2446UDA.js} +2 -2
  5. package/dist/{apps-CVBURB5V.js.map → apps-J2446UDA.js.map} +1 -1
  6. package/dist/{audit-A4BP27DN.js → audit-N2CRHWUN.js} +21 -6
  7. package/dist/audit-N2CRHWUN.js.map +1 -0
  8. package/dist/{auth-QSDK7NUO.js → auth-XGSTT5G5.js} +107 -9
  9. package/dist/auth-XGSTT5G5.js.map +1 -0
  10. package/dist/bin.js +2 -2
  11. package/dist/bin.js.map +1 -1
  12. package/dist/{bundle-7IF5FIB4.js → bundle-F43TD2BQ.js} +48 -14
  13. package/dist/bundle-F43TD2BQ.js.map +1 -0
  14. package/dist/{cache-SHWAVON6.js → cache-SLNFRTI2.js} +7 -3
  15. package/dist/cache-SLNFRTI2.js.map +1 -0
  16. package/dist/{chunk-7BXCQKJG.js → chunk-P5GF73XK.js} +1 -1
  17. package/dist/chunk-P5GF73XK.js.map +1 -0
  18. package/dist/{chunk-UH3TMIAL.js → chunk-U6ZTQ34I.js} +15 -17
  19. package/dist/chunk-U6ZTQ34I.js.map +1 -0
  20. package/dist/{chunk-5CSWPQO6.js → chunk-XHI7VKWZ.js} +113 -43
  21. package/dist/chunk-XHI7VKWZ.js.map +1 -0
  22. package/dist/{completion-C3PPWNS7.js → completion-BCHRJSAT.js} +23 -10
  23. package/dist/completion-BCHRJSAT.js.map +1 -0
  24. package/dist/{config-7EOY5HGL.js → config-F2U3KUHX.js} +4 -4
  25. package/dist/config-F2U3KUHX.js.map +1 -0
  26. package/dist/{data-safety-GDPKV5PN.js → data-safety-JR6PZ2BD.js} +11 -8
  27. package/dist/data-safety-JR6PZ2BD.js.map +1 -0
  28. package/dist/{device-tiers-GHIYJPMB.js → device-tiers-5SGJPSYG.js} +7 -8
  29. package/dist/device-tiers-5SGJPSYG.js.map +1 -0
  30. package/dist/{docs-HIGQU4UL.js → docs-7DUXIKA3.js} +3 -3
  31. package/dist/docs-7DUXIKA3.js.map +1 -0
  32. package/dist/{doctor-UKKOK55S.js → doctor-4BUPAVFT.js} +51 -7
  33. package/dist/doctor-4BUPAVFT.js.map +1 -0
  34. package/dist/enterprise-7THXNBTC.js +69 -0
  35. package/dist/enterprise-7THXNBTC.js.map +1 -0
  36. package/dist/{external-transactions-HCL7ROMN.js → external-transactions-O5P4QBIT.js} +5 -8
  37. package/dist/external-transactions-O5P4QBIT.js.map +1 -0
  38. package/dist/{feedback-W5MZMRF2.js → feedback-BZWHEADD.js} +3 -3
  39. package/dist/feedback-BZWHEADD.js.map +1 -0
  40. package/dist/games-X57AGM3E.js +80 -0
  41. package/dist/games-X57AGM3E.js.map +1 -0
  42. package/dist/{generated-apks-VX7HYZDU.js → generated-apks-KB2PLWDI.js} +2 -6
  43. package/dist/generated-apks-KB2PLWDI.js.map +1 -0
  44. package/dist/grants-TKQJ3IER.js +142 -0
  45. package/dist/grants-TKQJ3IER.js.map +1 -0
  46. package/dist/{iap-6XHJV5HX.js → iap-BNIAHBDN.js} +7 -3
  47. package/dist/iap-BNIAHBDN.js.map +1 -0
  48. package/dist/index.js +1 -1
  49. package/dist/{internal-sharing-E7SJYDW3.js → internal-sharing-M74VNIQ2.js} +7 -7
  50. package/dist/internal-sharing-M74VNIQ2.js.map +1 -0
  51. package/dist/{listings-TOYS6XBU.js → listings-IVHZJNES.js} +91 -10
  52. package/dist/listings-IVHZJNES.js.map +1 -0
  53. package/dist/{migrate-OHN2FDY6.js → migrate-SQT6RD6T.js} +2 -4
  54. package/dist/migrate-SQT6RD6T.js.map +1 -0
  55. package/dist/{one-time-products-2PK4QKWE.js → one-time-products-3WNXDKE3.js} +43 -28
  56. package/dist/one-time-products-3WNXDKE3.js.map +1 -0
  57. package/dist/{pricing-BYZSLN74.js → pricing-HMHZD44S.js} +1 -1
  58. package/dist/pricing-HMHZD44S.js.map +1 -0
  59. package/dist/{publish-I6WJGR4S.js → publish-EPZXLGKZ.js} +4 -9
  60. package/dist/publish-EPZXLGKZ.js.map +1 -0
  61. package/dist/{purchases-YRO6B7M6.js → purchases-7ZPVCN6D.js} +31 -2
  62. package/dist/purchases-7ZPVCN6D.js.map +1 -0
  63. package/dist/quickstart-EYNNOTVD.js +87 -0
  64. package/dist/quickstart-EYNNOTVD.js.map +1 -0
  65. package/dist/quota-UHIQQYOY.js +58 -0
  66. package/dist/quota-UHIQQYOY.js.map +1 -0
  67. package/dist/{recovery-S5UNJDBO.js → recovery-YGPOVUFD.js} +7 -3
  68. package/dist/recovery-YGPOVUFD.js.map +1 -0
  69. package/dist/{releases-ANC54YWF.js → releases-I7QQVKPJ.js} +62 -22
  70. package/dist/releases-I7QQVKPJ.js.map +1 -0
  71. package/dist/{reports-N5X66IUN.js → reports-2YX3RDOS.js} +1 -1
  72. package/dist/reports-2YX3RDOS.js.map +1 -0
  73. package/dist/{reviews-UHK4FGK6.js → reviews-MOVGATUI.js} +68 -7
  74. package/dist/reviews-MOVGATUI.js.map +1 -0
  75. package/dist/{status-DQYZ7A6Y.js → status-G3AMJ34G.js} +17 -5
  76. package/dist/status-G3AMJ34G.js.map +1 -0
  77. package/dist/{subscriptions-Z5ZPVUFM.js → subscriptions-LSOJID6H.js} +39 -2
  78. package/dist/subscriptions-LSOJID6H.js.map +1 -0
  79. package/dist/{testers-UWSUGGVT.js → testers-SDLVWQ2Z.js} +1 -1
  80. package/dist/testers-SDLVWQ2Z.js.map +1 -0
  81. package/dist/{tracks-XFUN7JJX.js → tracks-NERFFEDT.js} +2 -2
  82. package/dist/tracks-NERFFEDT.js.map +1 -0
  83. package/dist/train-PX5Z26PQ.js +150 -0
  84. package/dist/train-PX5Z26PQ.js.map +1 -0
  85. package/dist/{update-NIVJLUNH.js → update-ARIQO53C.js} +6 -12
  86. package/dist/update-ARIQO53C.js.map +1 -0
  87. package/dist/{users-JASXONRY.js → users-2YTC4Q36.js} +1 -1
  88. package/dist/users-2YTC4Q36.js.map +1 -0
  89. package/dist/{validate-MHLPENCM.js → validate-VNIS6OEB.js} +9 -4
  90. package/dist/validate-VNIS6OEB.js.map +1 -0
  91. package/dist/{version-7AI5IHVK.js → version-MXIJ4BUH.js} +11 -9
  92. package/dist/version-MXIJ4BUH.js.map +1 -0
  93. package/dist/{vitals-QGWOFH7E.js → vitals-H7DCI6JJ.js} +125 -7
  94. package/dist/vitals-H7DCI6JJ.js.map +1 -0
  95. package/package.json +7 -3
  96. package/dist/anomalies-QZJGQXTZ.js.map +0 -1
  97. package/dist/audit-A4BP27DN.js.map +0 -1
  98. package/dist/auth-QSDK7NUO.js.map +0 -1
  99. package/dist/bundle-7IF5FIB4.js.map +0 -1
  100. package/dist/cache-SHWAVON6.js.map +0 -1
  101. package/dist/chunk-5CSWPQO6.js.map +0 -1
  102. package/dist/chunk-7BXCQKJG.js.map +0 -1
  103. package/dist/chunk-UH3TMIAL.js.map +0 -1
  104. package/dist/completion-C3PPWNS7.js.map +0 -1
  105. package/dist/config-7EOY5HGL.js.map +0 -1
  106. package/dist/data-safety-GDPKV5PN.js.map +0 -1
  107. package/dist/device-tiers-GHIYJPMB.js.map +0 -1
  108. package/dist/docs-HIGQU4UL.js.map +0 -1
  109. package/dist/doctor-UKKOK55S.js.map +0 -1
  110. package/dist/external-transactions-HCL7ROMN.js.map +0 -1
  111. package/dist/feedback-W5MZMRF2.js.map +0 -1
  112. package/dist/generated-apks-VX7HYZDU.js.map +0 -1
  113. package/dist/iap-6XHJV5HX.js.map +0 -1
  114. package/dist/internal-sharing-E7SJYDW3.js.map +0 -1
  115. package/dist/listings-TOYS6XBU.js.map +0 -1
  116. package/dist/migrate-OHN2FDY6.js.map +0 -1
  117. package/dist/one-time-products-2PK4QKWE.js.map +0 -1
  118. package/dist/pricing-BYZSLN74.js.map +0 -1
  119. package/dist/publish-I6WJGR4S.js.map +0 -1
  120. package/dist/purchases-YRO6B7M6.js.map +0 -1
  121. package/dist/recovery-S5UNJDBO.js.map +0 -1
  122. package/dist/releases-ANC54YWF.js.map +0 -1
  123. package/dist/reports-N5X66IUN.js.map +0 -1
  124. package/dist/reviews-UHK4FGK6.js.map +0 -1
  125. package/dist/status-DQYZ7A6Y.js.map +0 -1
  126. package/dist/subscriptions-Z5ZPVUFM.js.map +0 -1
  127. package/dist/testers-UWSUGGVT.js.map +0 -1
  128. package/dist/tracks-XFUN7JJX.js.map +0 -1
  129. package/dist/update-NIVJLUNH.js.map +0 -1
  130. package/dist/users-JASXONRY.js.map +0 -1
  131. package/dist/validate-MHLPENCM.js.map +0 -1
  132. package/dist/version-7AI5IHVK.js.map +0 -1
  133. package/dist/vitals-QGWOFH7E.js.map +0 -1
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getOutputFormat
4
+ } from "./chunk-ELXAK7GI.js";
5
+
6
+ // src/commands/games.ts
7
+ import { loadConfig } from "@gpc-cli/config";
8
+ import { resolveAuth } from "@gpc-cli/auth";
9
+ import { createGamesClient } from "@gpc-cli/api";
10
+ import { listLeaderboards, listAchievements, listEvents, formatOutput } from "@gpc-cli/core";
11
+ function resolvePackageName(packageArg, config) {
12
+ const name = packageArg || config.app;
13
+ if (!name) {
14
+ console.error("Error: No package name. Use --app <package> or gpc config set app <package>");
15
+ process.exit(2);
16
+ }
17
+ return name;
18
+ }
19
+ async function getClient(config) {
20
+ const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
21
+ return createGamesClient({ auth });
22
+ }
23
+ function registerGamesCommands(program) {
24
+ const games = program.command("games").description("Manage Play Games Services \u2014 leaderboards, achievements, events");
25
+ games.command("leaderboards").description("List leaderboards for the app").action(async () => {
26
+ const config = await loadConfig();
27
+ const packageName = resolvePackageName(program.opts()["app"], config);
28
+ const client = await getClient(config);
29
+ const format = getOutputFormat(program, config);
30
+ try {
31
+ const result = await listLeaderboards(client, packageName);
32
+ if (result.length === 0 && format !== "json") {
33
+ console.log("No leaderboards found.");
34
+ return;
35
+ }
36
+ console.log(formatOutput(result, format));
37
+ } catch (error) {
38
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
39
+ process.exit(4);
40
+ }
41
+ });
42
+ games.command("achievements").description("List achievements for the app").action(async () => {
43
+ const config = await loadConfig();
44
+ const packageName = resolvePackageName(program.opts()["app"], config);
45
+ const client = await getClient(config);
46
+ const format = getOutputFormat(program, config);
47
+ try {
48
+ const result = await listAchievements(client, packageName);
49
+ if (result.length === 0 && format !== "json") {
50
+ console.log("No achievements found.");
51
+ return;
52
+ }
53
+ console.log(formatOutput(result, format));
54
+ } catch (error) {
55
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
56
+ process.exit(4);
57
+ }
58
+ });
59
+ games.command("events").description("List events for the app").action(async () => {
60
+ const config = await loadConfig();
61
+ const packageName = resolvePackageName(program.opts()["app"], config);
62
+ const client = await getClient(config);
63
+ const format = getOutputFormat(program, config);
64
+ try {
65
+ const result = await listEvents(client, packageName);
66
+ if (result.length === 0 && format !== "json") {
67
+ console.log("No events found.");
68
+ return;
69
+ }
70
+ console.log(formatOutput(result, format));
71
+ } catch (error) {
72
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
73
+ process.exit(4);
74
+ }
75
+ });
76
+ }
77
+ export {
78
+ registerGamesCommands
79
+ };
80
+ //# sourceMappingURL=games-X57AGM3E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/games.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createGamesClient } from \"@gpc-cli/api\";\nimport { listLeaderboards, listAchievements, listEvents, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createGamesClient({ auth });\n}\n\nexport function registerGamesCommands(program: Command): void {\n const games = program\n .command(\"games\")\n .description(\"Manage Play Games Services — leaderboards, achievements, events\");\n\n games\n .command(\"leaderboards\")\n .description(\"List leaderboards for the app\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await listLeaderboards(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No leaderboards found.\");\n return;\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n games\n .command(\"achievements\")\n .description(\"List achievements for the app\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await listAchievements(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No achievements found.\");\n return;\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n games\n .command(\"events\")\n .description(\"List events for the app\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await listEvents(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No events found.\");\n return;\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":";;;;;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,kBAAkB,kBAAkB,YAAY,oBAAoB;AAG7E,SAAS,mBAAmB,YAAgC,QAA2B;AACrF,QAAM,OAAO,cAAc,OAAO;AAClC,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,UAAU,QAAmB;AAC1C,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,kBAAkB,EAAE,KAAK,CAAC;AACnC;AAEO,SAAS,sBAAsB,SAAwB;AAC5D,QAAM,QAAQ,QACX,QAAQ,OAAO,EACf,YAAY,sEAAiE;AAEhF,QACG,QAAQ,cAAc,EACtB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,iBAAiB,QAAQ,WAAW;AACzD,UAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,gBAAQ,IAAI,wBAAwB;AACpC;AAAA,MACF;AACA,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,QACG,QAAQ,cAAc,EACtB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,iBAAiB,QAAQ,WAAW;AACzD,UAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,gBAAQ,IAAI,wBAAwB;AACpC;AAAA,MACF;AACA,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,yBAAyB,EACrC,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,WAAW,QAAQ,WAAW;AACnD,UAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,gBAAQ,IAAI,kBAAkB;AAC9B;AAAA,MACF;AACA,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
@@ -7,11 +7,7 @@ import {
7
7
  import { loadConfig } from "@gpc-cli/config";
8
8
  import { resolveAuth } from "@gpc-cli/auth";
9
9
  import { createApiClient } from "@gpc-cli/api";
10
- import {
11
- listGeneratedApks,
12
- downloadGeneratedApk,
13
- formatOutput
14
- } from "@gpc-cli/core";
10
+ import { listGeneratedApks, downloadGeneratedApk, formatOutput } from "@gpc-cli/core";
15
11
  function resolvePackageName(packageArg, config) {
16
12
  const name = packageArg || config.app;
17
13
  if (!name) {
@@ -87,4 +83,4 @@ function registerGeneratedApksCommands(program) {
87
83
  export {
88
84
  registerGeneratedApksCommands
89
85
  };
90
- //# sourceMappingURL=generated-apks-VX7HYZDU.js.map
86
+ //# sourceMappingURL=generated-apks-KB2PLWDI.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 { listGeneratedApks, downloadGeneratedApk, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerGeneratedApksCommands(program: Command): void {\n const cmd = program\n .command(\"generated-apks\")\n .description(\"Manage device-specific APKs generated by Google Play\");\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 = getOutputFormat(program, config);\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 if (format !== \"json\") {\n const apks = (result as unknown as Record<string, unknown>)[\"generatedApks\"] as\n | Array<Record<string, unknown>>\n | undefined;\n if (apks && apks.length > 0) {\n const rows = apks.map((apk) => ({\n id: apk[\"generatedApkId\"] || \"-\",\n variantId: apk[\"variantId\"] || \"-\",\n moduleName: apk[\"moduleName\"] || \"-\",\n sha256: String(apk[\"certificateSha256Fingerprint\"] || \"-\").slice(0, 16) + \"...\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(\"No generated APKs found.\");\n }\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n 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 = getOutputFormat(program, config);\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,SAAS,mBAAmB,sBAAsB,oBAAoB;AAGtE,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,sDAAsD;AAErE,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,gBAAgB,SAAS,MAAM;AAE9C,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,UAAI,WAAW,QAAQ;AACrB,cAAM,OAAQ,OAA8C,eAAe;AAG3E,YAAI,QAAQ,KAAK,SAAS,GAAG;AAC3B,gBAAM,OAAO,KAAK,IAAI,CAAC,SAAS;AAAA,YAC9B,IAAI,IAAI,gBAAgB,KAAK;AAAA,YAC7B,WAAW,IAAI,WAAW,KAAK;AAAA,YAC/B,YAAY,IAAI,YAAY,KAAK;AAAA,YACjC,QAAQ,OAAO,IAAI,8BAA8B,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,IAAI;AAAA,UAC5E,EAAE;AACF,kBAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AAAA,QACxC,OAAO;AACL,kBAAQ,IAAI,0BAA0B;AAAA,QACxC;AAAA,MACF,OAAO;AACL,gBAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,MAC1C;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;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,gBAAgB,SAAS,MAAM;AAE9C,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":[]}
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ isDryRun,
4
+ printDryRun
5
+ } from "./chunk-Y3QZDAKS.js";
6
+ import {
7
+ getOutputFormat
8
+ } from "./chunk-ELXAK7GI.js";
9
+ import {
10
+ requireConfirm
11
+ } from "./chunk-NV75I5VP.js";
12
+
13
+ // src/commands/grants.ts
14
+ import { loadConfig } from "@gpc-cli/config";
15
+ import { resolveAuth } from "@gpc-cli/auth";
16
+ import { createUsersClient } from "@gpc-cli/api";
17
+ import { listGrants, createGrant, updateGrant, deleteGrant, formatOutput } from "@gpc-cli/core";
18
+ function resolveDeveloperId(devIdArg, config) {
19
+ const id = devIdArg || config.developerId;
20
+ if (!id) {
21
+ console.error(
22
+ "Error: No developer ID. Use --developer-id <id> or gpc config set developerId <id>"
23
+ );
24
+ process.exit(2);
25
+ }
26
+ return id;
27
+ }
28
+ async function getClient(config) {
29
+ const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
30
+ return createUsersClient({ auth });
31
+ }
32
+ function registerGrantsCommands(program) {
33
+ const grants = program.command("grants").description("Manage per-app permission grants for developer account users").option("--developer-id <id>", "Developer account ID");
34
+ grants.command("list <email>").description("List all per-app grants for a user").action(async (email) => {
35
+ const config = await loadConfig();
36
+ const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
37
+ const client = await getClient(config);
38
+ const format = getOutputFormat(program, config);
39
+ try {
40
+ const result = await listGrants(client, developerId, email);
41
+ if (result.length === 0) {
42
+ if (format === "json") {
43
+ console.log(formatOutput([], format));
44
+ } else {
45
+ console.log(`No grants found for ${email}.`);
46
+ }
47
+ return;
48
+ }
49
+ console.log(formatOutput(result, format));
50
+ } catch (error) {
51
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
52
+ process.exit(4);
53
+ }
54
+ });
55
+ grants.command("create <email>").description("Grant app-level permissions to a user").requiredOption("--package <packageName>", "App package name").requiredOption(
56
+ "--permissions <list>",
57
+ "Comma-separated permissions (e.g. CAN_MANAGE_RELEASES,VIEW_APP_INFORMATION)"
58
+ ).action(async (email, options) => {
59
+ const config = await loadConfig();
60
+ const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
61
+ const format = getOutputFormat(program, config);
62
+ const perms = options.permissions.split(",").map((p) => p.trim());
63
+ if (isDryRun(program)) {
64
+ printDryRun(
65
+ {
66
+ command: "grants create",
67
+ action: "grant permissions",
68
+ target: `${email}/${options.package}`,
69
+ details: { permissions: perms }
70
+ },
71
+ format,
72
+ formatOutput
73
+ );
74
+ return;
75
+ }
76
+ const client = await getClient(config);
77
+ try {
78
+ const result = await createGrant(client, developerId, email, options.package, perms);
79
+ console.log(formatOutput(result, format));
80
+ } catch (error) {
81
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
82
+ process.exit(4);
83
+ }
84
+ });
85
+ grants.command("update <email>").description("Update app-level permissions for a user").requiredOption("--package <packageName>", "App package name").requiredOption("--permissions <list>", "New comma-separated permissions").action(async (email, options) => {
86
+ const config = await loadConfig();
87
+ const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
88
+ const format = getOutputFormat(program, config);
89
+ const perms = options.permissions.split(",").map((p) => p.trim());
90
+ if (isDryRun(program)) {
91
+ printDryRun(
92
+ {
93
+ command: "grants update",
94
+ action: "update permissions",
95
+ target: `${email}/${options.package}`,
96
+ details: { permissions: perms }
97
+ },
98
+ format,
99
+ formatOutput
100
+ );
101
+ return;
102
+ }
103
+ const client = await getClient(config);
104
+ try {
105
+ const result = await updateGrant(client, developerId, email, options.package, perms);
106
+ console.log(formatOutput(result, format));
107
+ } catch (error) {
108
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
109
+ process.exit(4);
110
+ }
111
+ });
112
+ grants.command("delete <email>").description("Remove a per-app grant from a user").requiredOption("--package <packageName>", "App package name").action(async (email, options) => {
113
+ const config = await loadConfig();
114
+ const developerId = resolveDeveloperId(grants.opts()["developerId"], config);
115
+ const format = getOutputFormat(program, config);
116
+ await requireConfirm(`Remove grant for "${email}" on ${options.package}?`, program);
117
+ if (isDryRun(program)) {
118
+ printDryRun(
119
+ {
120
+ command: "grants delete",
121
+ action: "remove grant",
122
+ target: `${email}/${options.package}`
123
+ },
124
+ format,
125
+ formatOutput
126
+ );
127
+ return;
128
+ }
129
+ const client = await getClient(config);
130
+ try {
131
+ await deleteGrant(client, developerId, email, options.package);
132
+ console.log(`Grant removed for ${email} on ${options.package}.`);
133
+ } catch (error) {
134
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
135
+ process.exit(4);
136
+ }
137
+ });
138
+ }
139
+ export {
140
+ registerGrantsCommands
141
+ };
142
+ //# sourceMappingURL=grants-TKQJ3IER.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/grants.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createUsersClient } from \"@gpc-cli/api\";\nimport { listGrants, createGrant, updateGrant, deleteGrant, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\n\nfunction resolveDeveloperId(devIdArg: string | undefined, config: GpcConfig): string {\n const id = devIdArg || config.developerId;\n if (!id) {\n console.error(\n \"Error: No developer ID. Use --developer-id <id> or gpc config set developerId <id>\",\n );\n process.exit(2);\n }\n return id;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createUsersClient({ auth });\n}\n\nexport function registerGrantsCommands(program: Command): void {\n const grants = program\n .command(\"grants\")\n .description(\"Manage per-app permission grants for developer account users\")\n .option(\"--developer-id <id>\", \"Developer account ID\");\n\n grants\n .command(\"list <email>\")\n .description(\"List all per-app grants for a user\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await listGrants(client, developerId, email);\n if (result.length === 0) {\n if (format === \"json\") {\n console.log(formatOutput([], format));\n } else {\n console.log(`No grants found for ${email}.`);\n }\n return;\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n grants\n .command(\"create <email>\")\n .description(\"Grant app-level permissions to a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\n \"--permissions <list>\",\n \"Comma-separated permissions (e.g. CAN_MANAGE_RELEASES,VIEW_APP_INFORMATION)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants create\",\n action: \"grant permissions\",\n target: `${email}/${options.package}`,\n details: { permissions: perms },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await createGrant(client, developerId, email, options.package, perms);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n grants\n .command(\"update <email>\")\n .description(\"Update app-level permissions for a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\"--permissions <list>\", \"New comma-separated permissions\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants update\",\n action: \"update permissions\",\n target: `${email}/${options.package}`,\n details: { permissions: perms },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await updateGrant(client, developerId, email, options.package, perms);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n grants\n .command(\"delete <email>\")\n .description(\"Remove a per-app grant from a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n await requireConfirm(`Remove grant for \"${email}\" on ${options.package}?`, program);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants delete\",\n action: \"remove grant\",\n target: `${email}/${options.package}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteGrant(client, developerId, email, options.package);\n console.log(`Grant removed for ${email} on ${options.package}.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -47,7 +47,9 @@ function registerIapCommands(program) {
47
47
  const packageName = resolvePackageName(program.opts()["app"], config);
48
48
  const client = await getClient(config);
49
49
  const format = getOutputFormat(program, config);
50
- console.error("Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)");
50
+ console.error(
51
+ "Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)"
52
+ );
51
53
  try {
52
54
  const result = await listOneTimeProducts(client, packageName);
53
55
  let products = result.oneTimeProducts || [];
@@ -65,7 +67,9 @@ function registerIapCommands(program) {
65
67
  const packageName = resolvePackageName(program.opts()["app"], config);
66
68
  const client = await getClient(config);
67
69
  const format = getOutputFormat(program, config);
68
- console.error("Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)");
70
+ console.error(
71
+ "Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)"
72
+ );
69
73
  try {
70
74
  const result = await getOneTimeProduct(client, packageName, sku);
71
75
  console.log(formatOutput(result, format));
@@ -228,4 +232,4 @@ function registerIapCommands(program) {
228
232
  export {
229
233
  registerIapCommands
230
234
  };
231
- //# sourceMappingURL=iap-6XHJV5HX.js.map
235
+ //# sourceMappingURL=iap-BNIAHBDN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/iap.ts"],"sourcesContent":["import type { GpcConfig } from \"@gpc-cli/config\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport {\n listOneTimeProducts,\n getOneTimeProduct,\n createInAppProduct,\n updateInAppProduct,\n deleteInAppProduct,\n syncInAppProducts,\n formatOutput,\n sortResults,\n createSpinner,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { getOutputFormat } from \"../format.js\";\nimport { requireConfirm } from \"../prompt.js\";\nimport { readJsonFile } from \"../json.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerIapCommands(program: Command): void {\n const iap = program\n .command(\"iap\")\n .description(\"Manage in-app products (uses one-time products API)\");\n\n iap\n .command(\"list\")\n .description(\"List in-app products\")\n .option(\"--max <n>\", \"Maximum results per page\", parseInt)\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n console.error(\n \"Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)\",\n );\n\n try {\n const result = await listOneTimeProducts(client, packageName);\n let products = result.oneTimeProducts || [];\n if (options.sort) {\n products = sortResults(products, options.sort);\n }\n console.log(formatOutput(products, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"get <sku>\")\n .description(\"Get an in-app product\")\n .action(async (sku: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n console.error(\n \"Note: Using oneTimeProducts API (inappproducts endpoint is deprecated, shutdown Aug 2027)\",\n );\n\n try {\n const result = await getOneTimeProduct(client, packageName, sku);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"create\")\n .description(\"Create an in-app product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"iap create\",\n action: \"create\",\n target: `in-app product from ${options.file}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await createInAppProduct(client, packageName, data as any);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"update <sku>\")\n .description(\"Update an in-app product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .action(async (sku: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"iap update\",\n action: \"update\",\n target: sku,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await updateInAppProduct(client, packageName, sku, data as any);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"delete <sku>\")\n .description(\"Delete an in-app product\")\n .action(async (sku: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete in-app product \"${sku}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"iap delete\",\n action: \"delete\",\n target: sku,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteInAppProduct(client, packageName, sku);\n console.log(`In-app product ${sku} deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"sync\")\n .description(\"Sync in-app products from a directory of JSON files\")\n .requiredOption(\"--dir <path>\", \"Directory containing product JSON files\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n const dryRun = isDryRun(program);\n\n const spinner = createSpinner(\"Syncing in-app products...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const result = await syncInAppProducts(client, packageName, options.dir, {\n dryRun,\n });\n spinner.stop(\"Sync complete\");\n if (dryRun) {\n console.log(`[dry-run] Would create: ${result.created}, update: ${result.updated}`);\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Sync failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n iap\n .command(\"batch-get\")\n .description(\"Batch get multiple in-app products\")\n .option(\"--skus <skus>\", \"Comma-separated list of SKUs\")\n .option(\"--file <path>\", \"JSON file with array of SKUs\")\n .action(async (_options) => {\n console.error(\n \"Note: The inappproducts batchGet endpoint is permanently blocked by Google Play (returns 403 PERMISSION_DENIED).\\n\" +\n \"Use `gpc iap get <sku>` for a single product, or `gpc iap list` for all products.\",\n );\n process.exit(1);\n });\n\n iap\n .command(\"batch-update\")\n .description(\"Batch update multiple in-app products from a JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with array of product objects\")\n .option(\"--dry-run\", \"Preview changes without executing\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (options.dryRun || isDryRun(program)) {\n const data = await readJsonFile(options.file);\n const products = Array.isArray(data) ? data : [];\n console.log(`[dry-run] Would batch update ${products.length} product(s)`);\n if (format !== \"json\") {\n const rows = products.map((p: Record<string, unknown>) => ({\n sku: p[\"sku\"] || \"-\",\n action: \"update\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(products, format));\n }\n return;\n }\n\n const client = await getClient(config);\n console.error(\"Note: Using inappproducts batch API\");\n\n const spinner = createSpinner(\"Batch updating products...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const data = await readJsonFile(options.file);\n const products = Array.isArray(data) ? data : [];\n const request = {\n requests: products.map((p: Record<string, unknown>) => ({\n inappproduct: p,\n packageName,\n sku: p[\"sku\"] as string,\n })),\n };\n const result = await client.inappproducts.batchUpdate(packageName, request as any);\n spinner.stop(\"Batch update complete\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Batch update failed\");\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createProgram,
4
4
  handleCliError
5
- } from "./chunk-5CSWPQO6.js";
5
+ } from "./chunk-XHI7VKWZ.js";
6
6
  export {
7
7
  createProgram,
8
8
  handleCliError
@@ -11,11 +11,7 @@ import {
11
11
  import { loadConfig } from "@gpc-cli/config";
12
12
  import { resolveAuth } from "@gpc-cli/auth";
13
13
  import { createApiClient } from "@gpc-cli/api";
14
- import {
15
- uploadInternalSharing,
16
- formatOutput,
17
- createSpinner
18
- } from "@gpc-cli/core";
14
+ import { uploadInternalSharing, formatOutput, createSpinner } from "@gpc-cli/core";
19
15
  function resolvePackageName(packageArg, config) {
20
16
  const name = packageArg || config.app;
21
17
  if (!name) {
@@ -37,7 +33,11 @@ function registerInternalSharingCommands(program) {
37
33
  const fileType = opts.type;
38
34
  if (isDryRun(program)) {
39
35
  printDryRun(
40
- { command: "internal-sharing upload", action: "upload for internal sharing", target: file },
36
+ {
37
+ command: "internal-sharing upload",
38
+ action: "upload for internal sharing",
39
+ target: file
40
+ },
41
41
  format,
42
42
  formatOutput
43
43
  );
@@ -60,4 +60,4 @@ function registerInternalSharingCommands(program) {
60
60
  export {
61
61
  registerInternalSharingCommands
62
62
  };
63
- //# sourceMappingURL=internal-sharing-E7SJYDW3.js.map
63
+ //# sourceMappingURL=internal-sharing-M74VNIQ2.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 { uploadInternalSharing, formatOutput, createSpinner } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.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 registerInternalSharingCommands(program: Command): void {\n const cmd = program\n .command(\"internal-sharing\")\n .description(\"Upload bundles or APKs for instant internal 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 format = getOutputFormat(program, config);\n\n const fileType = opts.type as \"bundle\" | \"apk\" | undefined;\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"internal-sharing upload\",\n action: \"upload for internal sharing\",\n target: file,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\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,SAAS,uBAAuB,cAAc,qBAAqB;AAInE,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,qDAAqD;AAEpE,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,gBAAgB,SAAS,MAAM;AAE9C,UAAM,WAAW,KAAK;AAEtB,QAAI,SAAS,OAAO,GAAG;AACrB;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;AACrC,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":[]}
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  green,
8
8
  red
9
- } from "./chunk-7BXCQKJG.js";
9
+ } from "./chunk-P5GF73XK.js";
10
10
  import {
11
11
  getOutputFormat
12
12
  } from "./chunk-ELXAK7GI.js";
@@ -26,7 +26,9 @@ import {
26
26
  deleteListing,
27
27
  pullListings,
28
28
  pushListings,
29
- diffListingsCommand,
29
+ diffListingsEnhanced,
30
+ lintLocalListings,
31
+ analyzeRemoteListings,
30
32
  listImages,
31
33
  uploadImage,
32
34
  deleteImage,
@@ -188,7 +190,7 @@ function registerListingsCommands(program) {
188
190
  process.exit(4);
189
191
  }
190
192
  });
191
- listings.command("push").description("Upload listings from Fastlane-format directory").option("--dir <path>", "Source directory (default: metadata)", "metadata").action(async (options) => {
193
+ listings.command("push").description("Upload listings from Fastlane-format directory").option("--dir <path>", "Source directory (default: metadata)", "metadata").option("--force", "Push even if fields exceed character limits").action(async (options) => {
192
194
  const config = await loadConfig();
193
195
  const packageName = resolvePackageName(program.opts()["app"], config);
194
196
  const client = await getClient(config);
@@ -198,7 +200,8 @@ function registerListingsCommands(program) {
198
200
  try {
199
201
  const dryRun = isDryRun(program);
200
202
  const result = await pushListings(client, packageName, options.dir, {
201
- dryRun
203
+ dryRun,
204
+ force: options.force
202
205
  });
203
206
  spinner.stop(dryRun ? "Dry-run complete (no changes made)" : "Listings pushed");
204
207
  console.log(formatOutput(result, format));
@@ -208,13 +211,16 @@ function registerListingsCommands(program) {
208
211
  process.exit(4);
209
212
  }
210
213
  });
211
- listings.command("diff").description("Compare local Fastlane-format metadata against remote listings").option("--dir <path>", "Local metadata directory", "metadata").action(async (options) => {
214
+ listings.command("diff").description("Compare local Fastlane-format metadata against remote listings").option("--dir <path>", "Local metadata directory", "metadata").option("--lang <language>", "Filter diff to a specific language").option("--word-diff", "Show word-level inline diff for fullDescription").action(async (options) => {
212
215
  const config = await loadConfig();
213
216
  const packageName = resolvePackageName(program.opts()["app"], config);
214
217
  const client = await getClient(config);
215
218
  const format = getOutputFormat(program, config);
216
219
  try {
217
- const diffs = await diffListingsCommand(client, packageName, options.dir);
220
+ const diffs = await diffListingsEnhanced(client, packageName, options.dir, {
221
+ lang: options.lang,
222
+ wordLevel: options.wordDiff
223
+ });
218
224
  if (diffs.length === 0) {
219
225
  if (format === "json") {
220
226
  console.log(formatOutput([], format));
@@ -227,9 +233,14 @@ function registerListingsCommands(program) {
227
233
  console.log(formatOutput(diffs, format));
228
234
  } else {
229
235
  for (const diff of diffs) {
230
- console.log(`[${diff.language}] ${diff.field}:`);
231
- console.log(green(`+ local: ${diff.local || "(empty)"}`));
232
- console.log(red(`- remote: ${diff.remote || "(empty)"}`));
236
+ const charInfo = diff["chars"] ? ` (${diff["chars"]} chars)` : "";
237
+ console.log(`[${diff.language}] ${diff.field}:${charInfo}`);
238
+ if (diff["diffSummary"]) {
239
+ console.log(` ${diff["diffSummary"]}`);
240
+ } else {
241
+ console.log(green(` + local: ${diff.local || "(empty)"}`));
242
+ console.log(red(` - remote: ${diff.remote || "(empty)"}`));
243
+ }
233
244
  }
234
245
  }
235
246
  } catch (error) {
@@ -237,6 +248,76 @@ function registerListingsCommands(program) {
237
248
  process.exit(4);
238
249
  }
239
250
  });
251
+ listings.command("lint").description("Lint local listing metadata for Play Store character limits (no API)").option("--dir <path>", "Metadata directory", "metadata").action(async (options) => {
252
+ const format = getOutputFormat(program, await loadConfig());
253
+ try {
254
+ const results = await lintLocalListings(options.dir);
255
+ if (format === "json") {
256
+ console.log(formatOutput(results, format));
257
+ return;
258
+ }
259
+ let exitCode = 0;
260
+ for (const r of results) {
261
+ console.log(`
262
+ [${r.language}] ${r.valid ? green("\u2713 valid") : red("\u2717 over limit")}`);
263
+ const rows = r.fields.map((f) => ({
264
+ field: f.field,
265
+ chars: f.chars,
266
+ limit: f.limit,
267
+ pct: `${f.pct}%`,
268
+ status: f.status === "ok" ? green("\u2713") : f.status === "warn" ? "\u26A0" : red("\u2717")
269
+ }));
270
+ console.log(formatOutput(rows, "table"));
271
+ if (!r.valid) exitCode = 1;
272
+ }
273
+ if (exitCode) process.exit(exitCode);
274
+ } catch (error) {
275
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
276
+ process.exit(1);
277
+ }
278
+ });
279
+ listings.command("analyze").description("Analyze live Play Store listings for character limit compliance").option("--expected <locales>", "Comma-separated list of expected locale codes").action(async (options) => {
280
+ const config = await loadConfig();
281
+ const packageName = resolvePackageName(program.opts()["app"], config);
282
+ const client = await getClient(config);
283
+ const format = getOutputFormat(program, config);
284
+ const spinner = createSpinner("Fetching remote listings...");
285
+ if (!program.opts()["quiet"] && process.stderr.isTTY) spinner.start();
286
+ try {
287
+ const expectedLocales = options.expected ? options.expected.split(",").map((s) => s.trim()) : void 0;
288
+ const { results, missingLocales } = await analyzeRemoteListings(client, packageName, {
289
+ expectedLocales
290
+ });
291
+ spinner.stop("Done");
292
+ if (format === "json") {
293
+ console.log(formatOutput({ results, missingLocales }, format));
294
+ return;
295
+ }
296
+ let exitCode = 0;
297
+ for (const r of results) {
298
+ console.log(`
299
+ [${r.language}] ${r.valid ? green("\u2713 valid") : red("\u2717 over limit")}`);
300
+ const rows = r.fields.map((f) => ({
301
+ field: f.field,
302
+ chars: f.chars,
303
+ limit: f.limit,
304
+ pct: `${f.pct}%`,
305
+ status: f.status === "ok" ? green("\u2713") : f.status === "warn" ? "\u26A0" : red("\u2717")
306
+ }));
307
+ console.log(formatOutput(rows, "table"));
308
+ if (!r.valid) exitCode = 1;
309
+ }
310
+ if (missingLocales && missingLocales.length > 0) {
311
+ console.log(`
312
+ Missing locales: ${missingLocales.join(", ")}`);
313
+ }
314
+ if (exitCode) process.exit(exitCode);
315
+ } catch (error) {
316
+ spinner.fail("Analysis failed");
317
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
318
+ process.exit(4);
319
+ }
320
+ });
240
321
  const images = listings.command("images").description("Manage listing images");
241
322
  images.command("list").description("List images for a language and type").option("--lang <language>", "Language code (BCP 47)").option("--type <type>", "Image type").option("--limit <n>", "Maximum results to return").option("--next-page <token>", "Pagination token for next page").action(async (options) => {
242
323
  const config = await loadConfig();
@@ -392,4 +473,4 @@ function registerListingsCommands(program) {
392
473
  export {
393
474
  registerListingsCommands
394
475
  };
395
- //# sourceMappingURL=listings-TOYS6XBU.js.map
476
+ //# sourceMappingURL=listings-IVHZJNES.js.map