@gpc-cli/cli 0.9.53 → 0.9.54

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 (148) hide show
  1. package/README.md +19 -19
  2. package/dist/{anomalies-V3AFS4LD.js → anomalies-I5P6QQAZ.js} +14 -5
  3. package/dist/anomalies-I5P6QQAZ.js.map +1 -0
  4. package/dist/{apps-4GP3FD7O.js → apps-WPUQOQLL.js} +2 -2
  5. package/dist/{audit-VTWXTXC6.js → audit-M7GYID74.js} +2 -2
  6. package/dist/{auth-BA4FE2PO.js → auth-4DRT7ZH2.js} +10 -4
  7. package/dist/auth-4DRT7ZH2.js.map +1 -0
  8. package/dist/bin.js +2 -2
  9. package/dist/{bundle-F7MUVC5J.js → bundle-PFTE7XMU.js} +4 -2
  10. package/dist/bundle-PFTE7XMU.js.map +1 -0
  11. package/dist/{cache-XKPLZYEB.js → cache-FGNP7Y37.js} +6 -2
  12. package/dist/cache-FGNP7Y37.js.map +1 -0
  13. package/dist/{chunk-SLNJEAMK.js → chunk-22XCOLZX.js} +4 -2
  14. package/dist/chunk-22XCOLZX.js.map +1 -0
  15. package/dist/{chunk-GQVZ2VCT.js → chunk-6HIY4IGM.js} +48 -45
  16. package/dist/chunk-6HIY4IGM.js.map +1 -0
  17. package/dist/{chunk-BCBXQC7J.js → chunk-E7SVZ7RF.js} +1 -1
  18. package/dist/chunk-E7SVZ7RF.js.map +1 -0
  19. package/dist/{chunk-NQH4G7BI.js → chunk-JDRY7HK5.js} +6 -9
  20. package/dist/chunk-JDRY7HK5.js.map +1 -0
  21. package/dist/{chunk-YFUBD2XB.js → chunk-RZQSEDKI.js} +6 -9
  22. package/dist/chunk-RZQSEDKI.js.map +1 -0
  23. package/dist/{chunk-A7VRCCNS.js → chunk-WSLFHX5X.js} +3 -3
  24. package/dist/chunk-WSLFHX5X.js.map +1 -0
  25. package/dist/{config-KT3PIL52.js → config-PUINDZON.js} +3 -3
  26. package/dist/{data-safety-AFMD6MYI.js → data-safety-46VY64OO.js} +12 -4
  27. package/dist/data-safety-46VY64OO.js.map +1 -0
  28. package/dist/{device-tiers-AQAMUQXI.js → device-tiers-MNZYMG3Y.js} +2 -2
  29. package/dist/device-tiers-MNZYMG3Y.js.map +1 -0
  30. package/dist/{diff-6EO4ID6W.js → diff-OBSHUSTL.js} +2 -2
  31. package/dist/diff-OBSHUSTL.js.map +1 -0
  32. package/dist/{docs-GMFN6V4K.js → docs-GP6AEX4N.js} +8 -4
  33. package/dist/docs-GP6AEX4N.js.map +1 -0
  34. package/dist/{doctor-GNI44SIP.js → doctor-T3QFYBRV.js} +5 -5
  35. package/dist/doctor-T3QFYBRV.js.map +1 -0
  36. package/dist/{external-transactions-LCZALS3V.js → external-transactions-JL3G4IG5.js} +11 -5
  37. package/dist/external-transactions-JL3G4IG5.js.map +1 -0
  38. package/dist/{feedback-XVTGMIBB.js → feedback-AULXQLJ7.js} +3 -3
  39. package/dist/feedback-AULXQLJ7.js.map +1 -0
  40. package/dist/{games-ZSNGEI7A.js → games-SVFN2YIS.js} +2 -2
  41. package/dist/games-SVFN2YIS.js.map +1 -0
  42. package/dist/{generated-apks-RX2IUWSF.js → generated-apks-TC33S2YN.js} +2 -2
  43. package/dist/generated-apks-TC33S2YN.js.map +1 -0
  44. package/dist/{grants-EBPECI26.js → grants-UHNBPIFD.js} +10 -3
  45. package/dist/grants-UHNBPIFD.js.map +1 -0
  46. package/dist/{iap-OUI5YYN4.js → iap-ETOL7OAC.js} +4 -4
  47. package/dist/iap-ETOL7OAC.js.map +1 -0
  48. package/dist/index.js +1 -1
  49. package/dist/{init-WSTQTJOD.js → init-6CCSVJC2.js} +7 -3
  50. package/dist/init-6CCSVJC2.js.map +1 -0
  51. package/dist/{install-skills-JKPYZHYS.js → install-skills-S342NJ7T.js} +7 -3
  52. package/dist/{install-skills-JKPYZHYS.js.map → install-skills-S342NJ7T.js.map} +1 -1
  53. package/dist/{internal-sharing-ONNIWIAT.js → internal-sharing-KW6YENDG.js} +2 -2
  54. package/dist/internal-sharing-KW6YENDG.js.map +1 -0
  55. package/dist/{listings-LNX6MQYN.js → listings-MOHHHNE6.js} +27 -7
  56. package/dist/listings-MOHHHNE6.js.map +1 -0
  57. package/dist/one-time-products-Y5RNIPV2.js +472 -0
  58. package/dist/one-time-products-Y5RNIPV2.js.map +1 -0
  59. package/dist/{preflight-W3JAJ4GO.js → preflight-KIWZPFTX.js} +4 -13
  60. package/dist/preflight-KIWZPFTX.js.map +1 -0
  61. package/dist/{pricing-JJZFICFL.js → pricing-HYQRXKNO.js} +3 -3
  62. package/dist/pricing-HYQRXKNO.js.map +1 -0
  63. package/dist/{prompt-GXC2JSLA.js → prompt-HJXNXXAR.js} +2 -2
  64. package/dist/{publish-P5KIGSLI.js → publish-26SSZ2W3.js} +11 -5
  65. package/dist/publish-26SSZ2W3.js.map +1 -0
  66. package/dist/{purchases-UBFLNYZC.js → purchases-AHWGLW6V.js} +35 -32
  67. package/dist/purchases-AHWGLW6V.js.map +1 -0
  68. package/dist/{quickstart-Z5Y3FYJU.js → quickstart-FOWM3OKT.js} +7 -2
  69. package/dist/quickstart-FOWM3OKT.js.map +1 -0
  70. package/dist/{recovery-YE3Z7NIN.js → recovery-B7DZQ6XG.js} +28 -12
  71. package/dist/recovery-B7DZQ6XG.js.map +1 -0
  72. package/dist/{releases-LUAHKIMY.js → releases-XY57V22L.js} +33 -8
  73. package/dist/releases-XY57V22L.js.map +1 -0
  74. package/dist/{reviews-YCBBM656.js → reviews-P4M6BEJI.js} +4 -6
  75. package/dist/reviews-P4M6BEJI.js.map +1 -0
  76. package/dist/{rtdn-LID2B7XZ.js → rtdn-YII4H6SD.js} +29 -21
  77. package/dist/rtdn-YII4H6SD.js.map +1 -0
  78. package/dist/{status-3HXBBXG6.js → status-32AJ7A6O.js} +13 -32
  79. package/dist/status-32AJ7A6O.js.map +1 -0
  80. package/dist/{subscriptions-LURZFPGJ.js → subscriptions-GTVJB4HX.js} +49 -12
  81. package/dist/subscriptions-GTVJB4HX.js.map +1 -0
  82. package/dist/system-apks-L6M7QYB3.js +111 -0
  83. package/dist/system-apks-L6M7QYB3.js.map +1 -0
  84. package/dist/{testers-6CQL4KQV.js → testers-QUWZHO6M.js} +25 -7
  85. package/dist/testers-QUWZHO6M.js.map +1 -0
  86. package/dist/{tracks-I4QZNZ3M.js → tracks-RH3RKVFB.js} +9 -3
  87. package/dist/{tracks-I4QZNZ3M.js.map → tracks-RH3RKVFB.js.map} +1 -1
  88. package/dist/{train-MDD2EBHS.js → train-D2NKUW3M.js} +3 -3
  89. package/dist/train-D2NKUW3M.js.map +1 -0
  90. package/dist/{update-QPPKXWI5.js → update-73YOR4GP.js} +8 -11
  91. package/dist/{update-QPPKXWI5.js.map → update-73YOR4GP.js.map} +1 -1
  92. package/dist/{users-UKG7VIQH.js → users-FOMAT7DY.js} +2 -2
  93. package/dist/{validate-QIYSA3N7.js → validate-RHWEZYD2.js} +6 -2
  94. package/dist/validate-RHWEZYD2.js.map +1 -0
  95. package/dist/{verify-UUQNQMPG.js → verify-H4ZUVHMZ.js} +5 -13
  96. package/dist/verify-H4ZUVHMZ.js.map +1 -0
  97. package/dist/{version-KUWLAZGT.js → version-RXLEX62V.js} +3 -3
  98. package/dist/{vitals-PJEQUUAK.js → vitals-PRBPNMVC.js} +26 -8
  99. package/dist/vitals-PRBPNMVC.js.map +1 -0
  100. package/package.json +5 -5
  101. package/dist/anomalies-V3AFS4LD.js.map +0 -1
  102. package/dist/auth-BA4FE2PO.js.map +0 -1
  103. package/dist/bundle-F7MUVC5J.js.map +0 -1
  104. package/dist/cache-XKPLZYEB.js.map +0 -1
  105. package/dist/chunk-A7VRCCNS.js.map +0 -1
  106. package/dist/chunk-BCBXQC7J.js.map +0 -1
  107. package/dist/chunk-GQVZ2VCT.js.map +0 -1
  108. package/dist/chunk-NQH4G7BI.js.map +0 -1
  109. package/dist/chunk-SLNJEAMK.js.map +0 -1
  110. package/dist/chunk-YFUBD2XB.js.map +0 -1
  111. package/dist/data-safety-AFMD6MYI.js.map +0 -1
  112. package/dist/device-tiers-AQAMUQXI.js.map +0 -1
  113. package/dist/diff-6EO4ID6W.js.map +0 -1
  114. package/dist/docs-GMFN6V4K.js.map +0 -1
  115. package/dist/doctor-GNI44SIP.js.map +0 -1
  116. package/dist/external-transactions-LCZALS3V.js.map +0 -1
  117. package/dist/feedback-XVTGMIBB.js.map +0 -1
  118. package/dist/games-ZSNGEI7A.js.map +0 -1
  119. package/dist/generated-apks-RX2IUWSF.js.map +0 -1
  120. package/dist/grants-EBPECI26.js.map +0 -1
  121. package/dist/iap-OUI5YYN4.js.map +0 -1
  122. package/dist/init-WSTQTJOD.js.map +0 -1
  123. package/dist/internal-sharing-ONNIWIAT.js.map +0 -1
  124. package/dist/listings-LNX6MQYN.js.map +0 -1
  125. package/dist/one-time-products-MGZTU7OM.js +0 -254
  126. package/dist/one-time-products-MGZTU7OM.js.map +0 -1
  127. package/dist/preflight-W3JAJ4GO.js.map +0 -1
  128. package/dist/pricing-JJZFICFL.js.map +0 -1
  129. package/dist/publish-P5KIGSLI.js.map +0 -1
  130. package/dist/purchases-UBFLNYZC.js.map +0 -1
  131. package/dist/quickstart-Z5Y3FYJU.js.map +0 -1
  132. package/dist/recovery-YE3Z7NIN.js.map +0 -1
  133. package/dist/releases-LUAHKIMY.js.map +0 -1
  134. package/dist/reviews-YCBBM656.js.map +0 -1
  135. package/dist/rtdn-LID2B7XZ.js.map +0 -1
  136. package/dist/status-3HXBBXG6.js.map +0 -1
  137. package/dist/subscriptions-LURZFPGJ.js.map +0 -1
  138. package/dist/testers-6CQL4KQV.js.map +0 -1
  139. package/dist/train-MDD2EBHS.js.map +0 -1
  140. package/dist/validate-QIYSA3N7.js.map +0 -1
  141. package/dist/verify-UUQNQMPG.js.map +0 -1
  142. package/dist/vitals-PJEQUUAK.js.map +0 -1
  143. /package/dist/{apps-4GP3FD7O.js.map → apps-WPUQOQLL.js.map} +0 -0
  144. /package/dist/{audit-VTWXTXC6.js.map → audit-M7GYID74.js.map} +0 -0
  145. /package/dist/{config-KT3PIL52.js.map → config-PUINDZON.js.map} +0 -0
  146. /package/dist/{prompt-GXC2JSLA.js.map → prompt-HJXNXXAR.js.map} +0 -0
  147. /package/dist/{users-UKG7VIQH.js.map → users-FOMAT7DY.js.map} +0 -0
  148. /package/dist/{version-KUWLAZGT.js.map → version-RXLEX62V.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/listings.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport type { ImageType } from \"@gpc-cli/api\";\nimport {\n getListings,\n updateListing,\n deleteListing,\n pullListings,\n pushListings,\n diffListingsEnhanced,\n lintLocalListings,\n analyzeRemoteListings,\n listImages,\n uploadImage,\n deleteImage,\n exportImages,\n getCountryAvailability,\n formatOutput,\n createSpinner,\n GpcError,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\nimport { green, red } from \"../colors.js\";\nimport { buildCommitOptions } from \"../commit-options.js\";\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 throw new GpcError(\n `Invalid image type \"${type}\". Valid types: ${VALID_IMAGE_TYPES.join(\", \")}`,\n \"LISTINGS_USAGE_ERROR\",\n 2,\n `Use one of: ${VALID_IMAGE_TYPES.join(\", \")}`,\n );\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 = getOutputFormat(program, config);\n\n const result = await getListings(client, packageName, options.lang);\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\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 = getOutputFormat(program, config);\n\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 throw new GpcError(\n \"Provide at least one field to update (--title, --short, --full, --full-file, --video).\",\n \"LISTINGS_USAGE_ERROR\",\n 2,\n \"Pass at least one of: --title, --short, --full, --full-file, --video\",\n );\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(\n client,\n packageName,\n options.lang,\n data,\n buildCommitOptions(options),\n );\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\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 = getOutputFormat(program, config);\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 await deleteListing(client, packageName, options.lang, buildCommitOptions(options));\n console.log(`Listing for \"${options.lang}\" deleted.`);\n });\n\n // Pull\n listings\n .command(\"pull\")\n .description(\"Download listings to Fastlane-format directory\")\n .option(\"--dir <path>\", \"Target directory (default: metadata)\", \"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 = getOutputFormat(program, config);\n\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 });\n\n // Push\n listings\n .command(\"push\")\n .description(\"Upload listings from Fastlane-format directory\")\n .option(\"--dir <path>\", \"Source directory (default: metadata)\", \"metadata\")\n .option(\"--force\", \"Push even if fields exceed character limits\")\n .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const spinner = createSpinner(\"Pushing listings...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const dryRun = isDryRun(program);\n const result = await pushListings(client, packageName, options.dir, {\n dryRun,\n force: options.force,\n commitOptions: buildCommitOptions(options),\n });\n spinner.stop(dryRun ? \"Dry-run complete (no changes made)\" : \"Listings pushed\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Push failed\");\n throw error;\n }\n });\n\n // Diff (enhanced: --lang filter, word-level inline 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 .option(\"--lang <language>\", \"Filter diff to a specific language\")\n .option(\"--word-diff\", \"Show word-level inline diff for fullDescription\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const diffs = await diffListingsEnhanced(client, packageName, options.dir, {\n lang: options.lang,\n wordLevel: options.wordDiff,\n });\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 const charInfo = (diff as unknown as Record<string, unknown>)[\"chars\"]\n ? ` (${(diff as unknown as Record<string, unknown>)[\"chars\"]} chars)`\n : \"\";\n console.log(`[${diff.language}] ${diff.field}:${charInfo}`);\n if ((diff as unknown as Record<string, unknown>)[\"diffSummary\"]) {\n console.log(` ${(diff as unknown as Record<string, unknown>)[\"diffSummary\"]}`);\n } else {\n console.log(green(` + local: ${diff.local || \"(empty)\"}`));\n console.log(red(` - remote: ${diff.remote || \"(empty)\"}`));\n }\n }\n }\n });\n\n // Lint (local, no API)\n listings\n .command(\"lint\")\n .description(\"Lint local listing metadata for Play Store character limits (no API)\")\n .option(\"--dir <path>\", \"Metadata directory\", \"metadata\")\n .action(async (options) => {\n const format = getOutputFormat(program, await loadConfig());\n const results = await lintLocalListings(options.dir);\n if (format === \"json\") {\n console.log(formatOutput(results, format));\n return;\n }\n let hasErrors = false;\n for (const r of results) {\n console.log(`\\n[${r.language}] ${r.valid ? green(\"✓ valid\") : red(\"✗ over limit\")}`);\n const rows = r.fields.map((f) => ({\n field: f.field,\n chars: f.chars,\n limit: f.limit,\n pct: `${f.pct}%`,\n status: f.status === \"ok\" ? green(\"✓\") : f.status === \"warn\" ? \"⚠\" : red(\"✗\"),\n }));\n console.log(formatOutput(rows, \"table\"));\n if (!r.valid) hasErrors = true;\n }\n if (hasErrors) {\n process.exitCode = 1;\n }\n });\n\n // Analyze (live, fetches remote)\n listings\n .command(\"analyze\")\n .description(\"Analyze live Play Store listings for character limit compliance\")\n .option(\"--expected <locales>\", \"Comma-separated list of expected locale codes\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const spinner = createSpinner(\"Fetching remote listings...\");\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n const expectedLocales = options.expected\n ? (options.expected as string).split(\",\").map((s: string) => s.trim())\n : undefined;\n const { results, missingLocales } = await analyzeRemoteListings(client, packageName, {\n expectedLocales,\n });\n spinner.stop(\"Done\");\n\n if (format === \"json\") {\n console.log(formatOutput({ results, missingLocales }, format));\n return;\n }\n\n let hasErrors = false;\n for (const r of results) {\n console.log(`\\n[${r.language}] ${r.valid ? green(\"✓ valid\") : red(\"✗ over limit\")}`);\n const rows = r.fields.map((f) => ({\n field: f.field,\n chars: f.chars,\n limit: f.limit,\n pct: `${f.pct}%`,\n status: f.status === \"ok\" ? green(\"✓\") : f.status === \"warn\" ? \"⚠\" : red(\"✗\"),\n }));\n console.log(formatOutput(rows, \"table\"));\n if (!r.valid) hasErrors = true;\n }\n\n if (missingLocales && missingLocales.length > 0) {\n console.log(`\\nMissing locales: ${missingLocales.join(\", \")}`);\n }\n\n if (hasErrors) {\n process.exitCode = 1;\n }\n } catch (error) {\n spinner.fail(\"Analysis failed\");\n throw error;\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 = getOutputFormat(program, config);\n const imageType = validateImageType(options.type);\n\n const result = await listImages(client, packageName, options.lang, imageType);\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\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 = getOutputFormat(program, config);\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(\n client,\n packageName,\n options.lang,\n imageType,\n file,\n buildCommitOptions(options),\n );\n spinner.stop(\"Image uploaded\");\n console.log(formatOutput(result, format));\n } catch (error) {\n spinner.fail(\"Image upload failed\");\n throw error;\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\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 await deleteImage(\n client,\n packageName,\n options.lang,\n imageType,\n options.id,\n buildCommitOptions(options),\n );\n console.log(`Image \"${options.id}\" deleted.`);\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 = getOutputFormat(program, config);\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 throw error;\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 = getOutputFormat(program, config);\n\n const result = await getCountryAvailability(client, packageName, options.track);\n const countries = (result as unknown as Record<string, unknown>)[\"countryTargeting\"] as\n | unknown[]\n | undefined;\n if (\n format !== \"json\" &&\n (!countries || (Array.isArray(countries) && countries.length === 0)) &&\n Object.keys(result as object).length === 0\n ) {\n console.log(\"No availability data.\");\n return;\n }\n console.log(formatOutput(result, format));\n });\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,472 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readJsonFile
4
+ } from "./chunk-22XCOLZX.js";
5
+ import {
6
+ getClient,
7
+ resolvePackageName
8
+ } from "./chunk-JDRY7HK5.js";
9
+ import {
10
+ isDryRun,
11
+ printDryRun
12
+ } from "./chunk-Y3QZDAKS.js";
13
+ import {
14
+ getOutputFormat
15
+ } from "./chunk-ELXAK7GI.js";
16
+ import {
17
+ requireConfirm
18
+ } from "./chunk-RZQSEDKI.js";
19
+
20
+ // src/commands/one-time-products.ts
21
+ import { loadConfig } from "@gpc-cli/config";
22
+ import {
23
+ listOneTimeProducts,
24
+ getOneTimeProduct,
25
+ createOneTimeProduct,
26
+ updateOneTimeProduct,
27
+ deleteOneTimeProduct,
28
+ listOneTimeOffers,
29
+ getOneTimeOffer,
30
+ createOneTimeOffer,
31
+ updateOneTimeOffer,
32
+ deleteOneTimeOffer,
33
+ diffOneTimeProduct,
34
+ formatOutput,
35
+ sortResults
36
+ } from "@gpc-cli/core";
37
+ async function readJsonArray(filePath) {
38
+ const data = await readJsonFile(filePath);
39
+ if (!Array.isArray(data)) {
40
+ const err = new Error(`Expected a JSON array in ${filePath}, got ${typeof data}`);
41
+ Object.assign(err, { code: "USAGE_ERROR", exitCode: 2 });
42
+ throw err;
43
+ }
44
+ return data;
45
+ }
46
+ function registerOneTimeProductsCommands(program) {
47
+ const otp = program.command("one-time-products").alias("otp").description("Manage one-time products and offers (modern OTP API)");
48
+ otp.command("list").description("List one-time products").option("--sort <field>", "Sort by field (prefix with - for descending)").action(async (options) => {
49
+ const config = await loadConfig();
50
+ const packageName = resolvePackageName(program.opts()["app"], config);
51
+ const client = await getClient(config);
52
+ const format = getOutputFormat(program, config);
53
+ const result = await listOneTimeProducts(client, packageName);
54
+ if (options.sort) {
55
+ result.oneTimeProducts = sortResults(result.oneTimeProducts, options.sort);
56
+ }
57
+ const products = result.oneTimeProducts || [];
58
+ if (format !== "json") {
59
+ if (products.length === 0) {
60
+ console.log("No one-time products found.");
61
+ return;
62
+ }
63
+ const summary = products.map((p) => ({
64
+ productId: p.productId,
65
+ purchaseType: p["purchaseType"] || "-",
66
+ listings: p.listings ? Object.keys(p.listings).length : 0,
67
+ firstTitle: p.listings ? Object.values(p.listings)[0]?.title || "-" : "-"
68
+ }));
69
+ console.log(formatOutput(summary, format));
70
+ } else {
71
+ console.log(formatOutput(result, format));
72
+ }
73
+ });
74
+ otp.command("get <product-id>").description("Get a one-time product").action(async (productId) => {
75
+ const config = await loadConfig();
76
+ const packageName = resolvePackageName(program.opts()["app"], config);
77
+ const client = await getClient(config);
78
+ const format = getOutputFormat(program, config);
79
+ const result = await getOneTimeProduct(client, packageName, productId);
80
+ console.log(formatOutput(result, format));
81
+ });
82
+ otp.command("create").description("Create a one-time product from JSON file").requiredOption("--file <path>", "JSON file with product data").action(async (options) => {
83
+ const config = await loadConfig();
84
+ const packageName = resolvePackageName(program.opts()["app"], config);
85
+ const format = getOutputFormat(program, config);
86
+ if (isDryRun(program)) {
87
+ printDryRun(
88
+ {
89
+ command: "one-time-products create",
90
+ action: "create",
91
+ target: `one-time product from ${options.file}`
92
+ },
93
+ format,
94
+ formatOutput
95
+ );
96
+ return;
97
+ }
98
+ const client = await getClient(config);
99
+ const data = await readJsonFile(options.file);
100
+ const result = await createOneTimeProduct(client, packageName, data);
101
+ console.log(formatOutput(result, format));
102
+ });
103
+ otp.command("update <product-id>").description("Update a one-time product from JSON file").requiredOption("--file <path>", "JSON file with product data").option("--update-mask <fields>", "Comma-separated field mask").action(async (productId, options) => {
104
+ const config = await loadConfig();
105
+ const packageName = resolvePackageName(program.opts()["app"], config);
106
+ const format = getOutputFormat(program, config);
107
+ if (isDryRun(program)) {
108
+ printDryRun(
109
+ {
110
+ command: "one-time-products update",
111
+ action: "update",
112
+ target: productId,
113
+ details: { file: options.file }
114
+ },
115
+ format,
116
+ formatOutput
117
+ );
118
+ return;
119
+ }
120
+ const client = await getClient(config);
121
+ const data = await readJsonFile(options.file);
122
+ const result = await updateOneTimeProduct(
123
+ client,
124
+ packageName,
125
+ productId,
126
+ data,
127
+ options.updateMask
128
+ );
129
+ console.log(formatOutput(result, format));
130
+ });
131
+ otp.command("delete <product-id>").description("Delete a one-time product").action(async (productId) => {
132
+ const config = await loadConfig();
133
+ const packageName = resolvePackageName(program.opts()["app"], config);
134
+ await requireConfirm(`Delete one-time product "${productId}"?`, program);
135
+ if (isDryRun(program)) {
136
+ const format = getOutputFormat(program, config);
137
+ printDryRun(
138
+ {
139
+ command: "one-time-products delete",
140
+ action: "delete",
141
+ target: productId
142
+ },
143
+ format,
144
+ formatOutput
145
+ );
146
+ return;
147
+ }
148
+ const client = await getClient(config);
149
+ await deleteOneTimeProduct(client, packageName, productId);
150
+ console.log(`One-time product ${productId} deleted.`);
151
+ });
152
+ const offers = otp.command("offers").description("Manage one-time product offers");
153
+ offers.command("list <product-id>").description("List offers for a one-time product").option("--purchase-option <id>", 'Purchase option ID (default: "-" for all)', "-").option("--sort <field>", "Sort by field (prefix with - for descending)").action(async (productId, options) => {
154
+ const config = await loadConfig();
155
+ const packageName = resolvePackageName(program.opts()["app"], config);
156
+ const client = await getClient(config);
157
+ const format = getOutputFormat(program, config);
158
+ const result = await listOneTimeOffers(
159
+ client,
160
+ packageName,
161
+ productId,
162
+ options.purchaseOption
163
+ );
164
+ const items = result.oneTimeProductOffers ?? result.oneTimeOffers ?? [];
165
+ if (options.sort) {
166
+ console.log(formatOutput(sortResults(items, options.sort), format));
167
+ } else {
168
+ console.log(
169
+ formatOutput(items.length > 0 ? result : { oneTimeProductOffers: items }, format)
170
+ );
171
+ }
172
+ });
173
+ offers.command("get <product-id> <offer-id>").description("Get an offer for a one-time product").option("--purchase-option <id>", 'Purchase option ID (default: "-" for all)', "-").action(async (productId, offerId, options) => {
174
+ const config = await loadConfig();
175
+ const packageName = resolvePackageName(program.opts()["app"], config);
176
+ const client = await getClient(config);
177
+ const format = getOutputFormat(program, config);
178
+ const result = await getOneTimeOffer(
179
+ client,
180
+ packageName,
181
+ productId,
182
+ offerId,
183
+ options.purchaseOption
184
+ );
185
+ console.log(formatOutput(result, format));
186
+ });
187
+ offers.command("create <product-id>").description("Create an offer from JSON file").requiredOption("--file <path>", "JSON file with offer data").option("--purchase-option <id>", 'Purchase option ID (default: "-" for all)', "-").action(async (productId, options) => {
188
+ const config = await loadConfig();
189
+ const packageName = resolvePackageName(program.opts()["app"], config);
190
+ const format = getOutputFormat(program, config);
191
+ if (isDryRun(program)) {
192
+ printDryRun(
193
+ {
194
+ command: "one-time-products offers create",
195
+ action: "create offer for",
196
+ target: productId,
197
+ details: { file: options.file, purchaseOption: options.purchaseOption }
198
+ },
199
+ format,
200
+ formatOutput
201
+ );
202
+ return;
203
+ }
204
+ const client = await getClient(config);
205
+ const data = await readJsonFile(options.file);
206
+ const result = await createOneTimeOffer(
207
+ client,
208
+ packageName,
209
+ productId,
210
+ data,
211
+ options.purchaseOption
212
+ );
213
+ console.log(formatOutput(result, format));
214
+ });
215
+ offers.command("update <product-id> <offer-id>").description("Update an offer from JSON file").requiredOption("--file <path>", "JSON file with offer data").option("--update-mask <fields>", "Comma-separated field mask").option("--purchase-option <id>", 'Purchase option ID (default: "-" for all)', "-").action(
216
+ async (productId, offerId, options) => {
217
+ const config = await loadConfig();
218
+ const packageName = resolvePackageName(program.opts()["app"], config);
219
+ const format = getOutputFormat(program, config);
220
+ if (isDryRun(program)) {
221
+ printDryRun(
222
+ {
223
+ command: "one-time-products offers update",
224
+ action: "update offer",
225
+ target: `${productId}/${offerId}`,
226
+ details: { file: options.file, purchaseOption: options.purchaseOption }
227
+ },
228
+ format,
229
+ formatOutput
230
+ );
231
+ return;
232
+ }
233
+ const client = await getClient(config);
234
+ const data = await readJsonFile(options.file);
235
+ const result = await updateOneTimeOffer(
236
+ client,
237
+ packageName,
238
+ productId,
239
+ offerId,
240
+ data,
241
+ options.updateMask,
242
+ options.purchaseOption
243
+ );
244
+ console.log(formatOutput(result, format));
245
+ }
246
+ );
247
+ offers.command("delete <product-id> <offer-id>").description("Delete an offer").option("--purchase-option <id>", 'Purchase option ID (default: "-" for all)', "-").action(async (productId, offerId, options) => {
248
+ const config = await loadConfig();
249
+ const packageName = resolvePackageName(program.opts()["app"], config);
250
+ await requireConfirm(`Delete offer "${offerId}" for product "${productId}"?`, program);
251
+ if (isDryRun(program)) {
252
+ const format = getOutputFormat(program, config);
253
+ printDryRun(
254
+ {
255
+ command: "one-time-products offers delete",
256
+ action: "delete offer",
257
+ target: `${productId}/${offerId}`
258
+ },
259
+ format,
260
+ formatOutput
261
+ );
262
+ return;
263
+ }
264
+ const client = await getClient(config);
265
+ await deleteOneTimeOffer(client, packageName, productId, offerId, options.purchaseOption);
266
+ console.log(`Offer ${offerId} deleted.`);
267
+ });
268
+ offers.command("cancel <product-id> <offer-id>").description("Cancel an offer (permanent, cannot be re-activated)").option("--purchase-option <id>", 'Purchase option ID (default: "-" for all)', "-").action(async (productId, offerId, options) => {
269
+ const config = await loadConfig();
270
+ const packageName = resolvePackageName(program.opts()["app"], config);
271
+ await requireConfirm(
272
+ `Cancel offer "${offerId}"? This is permanent and cannot be undone.`,
273
+ program
274
+ );
275
+ if (isDryRun(program)) {
276
+ const format2 = getOutputFormat(program, config);
277
+ printDryRun(
278
+ {
279
+ command: "otp offers cancel",
280
+ action: "cancel offer",
281
+ target: `${productId}/${offerId}`
282
+ },
283
+ format2,
284
+ formatOutput
285
+ );
286
+ return;
287
+ }
288
+ const client = await getClient(config);
289
+ const format = getOutputFormat(program, config);
290
+ const result = await client.oneTimeProducts.cancelOffer(
291
+ packageName,
292
+ productId,
293
+ options.purchaseOption,
294
+ offerId
295
+ );
296
+ console.log(formatOutput(result, format));
297
+ });
298
+ offers.command("batch-get <product-id>").description("Batch get multiple offers").requiredOption(
299
+ "--file <path>",
300
+ "JSON file with array of {productId, purchaseOptionId, offerId}"
301
+ ).option("--purchase-option <id>", 'Purchase option ID in URL path (default: "-")', "-").action(async (productId, options) => {
302
+ const config = await loadConfig();
303
+ const packageName = resolvePackageName(program.opts()["app"], config);
304
+ const client = await getClient(config);
305
+ const format = getOutputFormat(program, config);
306
+ const requests = await readJsonArray(options.file);
307
+ const result = await client.oneTimeProducts.batchGetOffers(
308
+ packageName,
309
+ productId,
310
+ options.purchaseOption,
311
+ requests.map((r) => ({
312
+ packageName,
313
+ productId: r.productId || productId,
314
+ purchaseOptionId: r.purchaseOptionId || "-",
315
+ offerId: r.offerId
316
+ }))
317
+ );
318
+ console.log(formatOutput(result, format));
319
+ });
320
+ offers.command("batch-update <product-id>").description("Batch create or update multiple offers (max 100)").requiredOption("--file <path>", "JSON file with update requests").option("--purchase-option <id>", 'Purchase option ID in URL path (default: "-")', "-").action(async (productId, options) => {
321
+ const config = await loadConfig();
322
+ const packageName = resolvePackageName(program.opts()["app"], config);
323
+ const format = getOutputFormat(program, config);
324
+ if (isDryRun(program)) {
325
+ printDryRun(
326
+ {
327
+ command: "otp offers batch-update",
328
+ action: "batch update offers for",
329
+ target: productId,
330
+ details: { file: options.file }
331
+ },
332
+ format,
333
+ formatOutput
334
+ );
335
+ return;
336
+ }
337
+ const client = await getClient(config);
338
+ const requests = await readJsonArray(options.file);
339
+ const result = await client.oneTimeProducts.batchUpdateOffers(
340
+ packageName,
341
+ productId,
342
+ options.purchaseOption,
343
+ requests
344
+ );
345
+ console.log(formatOutput(result, format));
346
+ });
347
+ offers.command("batch-update-states <product-id>").description("Batch activate, deactivate, or cancel multiple offers (max 100)").requiredOption("--file <path>", "JSON file with state transition requests").option("--purchase-option <id>", 'Purchase option ID in URL path (default: "-")', "-").action(async (productId, options) => {
348
+ const config = await loadConfig();
349
+ const packageName = resolvePackageName(program.opts()["app"], config);
350
+ const format = getOutputFormat(program, config);
351
+ if (isDryRun(program)) {
352
+ printDryRun(
353
+ {
354
+ command: "otp offers batch-update-states",
355
+ action: "batch update offer states for",
356
+ target: productId,
357
+ details: { file: options.file }
358
+ },
359
+ format,
360
+ formatOutput
361
+ );
362
+ return;
363
+ }
364
+ const client = await getClient(config);
365
+ const requests = await readJsonArray(options.file);
366
+ const result = await client.oneTimeProducts.batchUpdateOfferStates(
367
+ packageName,
368
+ productId,
369
+ options.purchaseOption,
370
+ requests
371
+ );
372
+ console.log(formatOutput(result, format));
373
+ });
374
+ offers.command("batch-delete <product-id>").description("Batch delete multiple offers (max 100)").requiredOption(
375
+ "--file <path>",
376
+ "JSON file with array of {productId, purchaseOptionId, offerId}"
377
+ ).option("--purchase-option <id>", 'Purchase option ID in URL path (default: "-")', "-").action(async (productId, options) => {
378
+ const config = await loadConfig();
379
+ const packageName = resolvePackageName(program.opts()["app"], config);
380
+ await requireConfirm(`Batch delete offers for product "${productId}"?`, program);
381
+ if (isDryRun(program)) {
382
+ const format = getOutputFormat(program, config);
383
+ printDryRun(
384
+ {
385
+ command: "otp offers batch-delete",
386
+ action: "batch delete offers for",
387
+ target: productId,
388
+ details: { file: options.file }
389
+ },
390
+ format,
391
+ formatOutput
392
+ );
393
+ return;
394
+ }
395
+ const client = await getClient(config);
396
+ const requests = await readJsonArray(options.file);
397
+ await client.oneTimeProducts.batchDeleteOffers(
398
+ packageName,
399
+ productId,
400
+ options.purchaseOption,
401
+ requests
402
+ );
403
+ console.log(`Batch delete completed.`);
404
+ });
405
+ const po = otp.command("purchase-options").description("Manage purchase option batch operations");
406
+ po.command("batch-delete <product-id>").description("Batch delete purchase options (max 100)").requiredOption("--file <path>", "JSON file with delete requests").action(async (productId, options) => {
407
+ const config = await loadConfig();
408
+ const packageName = resolvePackageName(program.opts()["app"], config);
409
+ await requireConfirm(`Batch delete purchase options for product "${productId}"?`, program);
410
+ if (isDryRun(program)) {
411
+ const format = getOutputFormat(program, config);
412
+ printDryRun(
413
+ {
414
+ command: "otp purchase-options batch-delete",
415
+ action: "batch delete purchase options for",
416
+ target: productId,
417
+ details: { file: options.file }
418
+ },
419
+ format,
420
+ formatOutput
421
+ );
422
+ return;
423
+ }
424
+ const client = await getClient(config);
425
+ const requests = await readJsonArray(options.file);
426
+ await client.oneTimeProducts.batchDeletePurchaseOptions(packageName, productId, requests);
427
+ console.log(`Batch delete completed.`);
428
+ });
429
+ po.command("batch-update-states <product-id>").description("Batch activate or deactivate purchase options (max 100)").requiredOption("--file <path>", "JSON file with state transition requests").action(async (productId, options) => {
430
+ const config = await loadConfig();
431
+ const packageName = resolvePackageName(program.opts()["app"], config);
432
+ const format = getOutputFormat(program, config);
433
+ if (isDryRun(program)) {
434
+ printDryRun(
435
+ {
436
+ command: "otp purchase-options batch-update-states",
437
+ action: "batch update purchase option states for",
438
+ target: productId,
439
+ details: { file: options.file }
440
+ },
441
+ format,
442
+ formatOutput
443
+ );
444
+ return;
445
+ }
446
+ const client = await getClient(config);
447
+ const requests = await readJsonArray(options.file);
448
+ const result = await client.oneTimeProducts.batchUpdatePurchaseOptionStates(
449
+ packageName,
450
+ productId,
451
+ requests
452
+ );
453
+ console.log(formatOutput(result, format));
454
+ });
455
+ otp.command("diff <product-id>").description("Compare local JSON file against remote one-time product").requiredOption("--file <path>", "Local JSON file to compare against remote").action(async (productId, options) => {
456
+ const config = await loadConfig();
457
+ const packageName = resolvePackageName(program.opts()["app"], config);
458
+ const client = await getClient(config);
459
+ const format = getOutputFormat(program, config);
460
+ const localData = await readJsonFile(options.file);
461
+ const diffs = await diffOneTimeProduct(client, packageName, productId, localData);
462
+ if (diffs.length === 0) {
463
+ console.log("No differences found.");
464
+ } else {
465
+ console.log(formatOutput(diffs, format));
466
+ }
467
+ });
468
+ }
469
+ export {
470
+ registerOneTimeProductsCommands
471
+ };
472
+ //# sourceMappingURL=one-time-products-Y5RNIPV2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/one-time-products.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport type { OneTimeProduct } from \"@gpc-cli/api\";\nimport {\n listOneTimeProducts,\n getOneTimeProduct,\n createOneTimeProduct,\n updateOneTimeProduct,\n deleteOneTimeProduct,\n listOneTimeOffers,\n getOneTimeOffer,\n createOneTimeOffer,\n updateOneTimeOffer,\n deleteOneTimeOffer,\n diffOneTimeProduct,\n formatOutput,\n sortResults,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\nimport { readJsonFile } from \"../json.js\";\n\nasync function readJsonArray<T = any>(filePath: string): Promise<T[]> {\n const data = await readJsonFile(filePath);\n if (!Array.isArray(data)) {\n const err = new Error(`Expected a JSON array in ${filePath}, got ${typeof data}`);\n Object.assign(err, { code: \"USAGE_ERROR\", exitCode: 2 });\n throw err;\n }\n return data as T[];\n}\n\nexport function registerOneTimeProductsCommands(program: Command): void {\n const otp = program\n .command(\"one-time-products\")\n .alias(\"otp\")\n .description(\"Manage one-time products and offers (modern OTP API)\");\n\n otp\n .command(\"list\")\n .description(\"List one-time products\")\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 const result = await listOneTimeProducts(client, packageName);\n if (options.sort) {\n result.oneTimeProducts = sortResults(result.oneTimeProducts, options.sort);\n }\n const products = result.oneTimeProducts || [];\n if (format !== \"json\") {\n if (products.length === 0) {\n console.log(\"No one-time products found.\");\n return;\n }\n const summary = products.map((p: OneTimeProduct) => ({\n productId: p.productId,\n purchaseType: (p as unknown as Record<string, unknown>)[\"purchaseType\"] || \"-\",\n listings: p.listings ? Object.keys(p.listings).length : 0,\n firstTitle: p.listings ? Object.values(p.listings)[0]?.title || \"-\" : \"-\",\n }));\n console.log(formatOutput(summary, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n otp\n .command(\"get <product-id>\")\n .description(\"Get a one-time product\")\n .action(async (productId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await getOneTimeProduct(client, packageName, productId);\n console.log(formatOutput(result, format));\n });\n\n otp\n .command(\"create\")\n .description(\"Create a one-time 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: \"one-time-products create\",\n action: \"create\",\n target: `one-time product from ${options.file}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await createOneTimeProduct(client, packageName, data as any);\n console.log(formatOutput(result, format));\n });\n\n otp\n .command(\"update <product-id>\")\n .description(\"Update a one-time product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .option(\"--update-mask <fields>\", \"Comma-separated field mask\")\n .action(async (productId: 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: \"one-time-products update\",\n action: \"update\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await updateOneTimeProduct(\n client,\n packageName,\n productId,\n data as any,\n options.updateMask,\n );\n console.log(formatOutput(result, format));\n });\n\n otp\n .command(\"delete <product-id>\")\n .description(\"Delete a one-time product\")\n .action(async (productId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete one-time product \"${productId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"one-time-products delete\",\n action: \"delete\",\n target: productId,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await deleteOneTimeProduct(client, packageName, productId);\n console.log(`One-time product ${productId} deleted.`);\n });\n\n // --- Offers ---\n const offers = otp.command(\"offers\").description(\"Manage one-time product offers\");\n\n offers\n .command(\"list <product-id>\")\n .description(\"List offers for a one-time product\")\n .option(\"--purchase-option <id>\", 'Purchase option ID (default: \"-\" for all)', \"-\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (productId: string, options: { purchaseOption: string; sort?: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listOneTimeOffers(\n client,\n packageName,\n productId,\n options.purchaseOption,\n );\n const items = result.oneTimeProductOffers ?? result.oneTimeOffers ?? [];\n if (options.sort) {\n console.log(formatOutput(sortResults(items, options.sort), format));\n } else {\n console.log(\n formatOutput(items.length > 0 ? result : { oneTimeProductOffers: items }, format),\n );\n }\n });\n\n offers\n .command(\"get <product-id> <offer-id>\")\n .description(\"Get an offer for a one-time product\")\n .option(\"--purchase-option <id>\", 'Purchase option ID (default: \"-\" for all)', \"-\")\n .action(async (productId: string, offerId: string, options: { purchaseOption: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await getOneTimeOffer(\n client,\n packageName,\n productId,\n offerId,\n options.purchaseOption,\n );\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"create <product-id>\")\n .description(\"Create an offer from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with offer data\")\n .option(\"--purchase-option <id>\", 'Purchase option ID (default: \"-\" for all)', \"-\")\n .action(async (productId: string, options: { file: string; purchaseOption: string }) => {\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: \"one-time-products offers create\",\n action: \"create offer for\",\n target: productId,\n details: { file: options.file, purchaseOption: options.purchaseOption },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await createOneTimeOffer(\n client,\n packageName,\n productId,\n data as any,\n options.purchaseOption,\n );\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"update <product-id> <offer-id>\")\n .description(\"Update an offer from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with offer data\")\n .option(\"--update-mask <fields>\", \"Comma-separated field mask\")\n .option(\"--purchase-option <id>\", 'Purchase option ID (default: \"-\" for all)', \"-\")\n .action(\n async (\n productId: string,\n offerId: string,\n options: { file: string; updateMask?: string; purchaseOption: string },\n ) => {\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: \"one-time-products offers update\",\n action: \"update offer\",\n target: `${productId}/${offerId}`,\n details: { file: options.file, purchaseOption: options.purchaseOption },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await updateOneTimeOffer(\n client,\n packageName,\n productId,\n offerId,\n data as any,\n options.updateMask,\n options.purchaseOption,\n );\n console.log(formatOutput(result, format));\n },\n );\n\n offers\n .command(\"delete <product-id> <offer-id>\")\n .description(\"Delete an offer\")\n .option(\"--purchase-option <id>\", 'Purchase option ID (default: \"-\" for all)', \"-\")\n .action(async (productId: string, offerId: string, options: { purchaseOption: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete offer \"${offerId}\" for product \"${productId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"one-time-products offers delete\",\n action: \"delete offer\",\n target: `${productId}/${offerId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await deleteOneTimeOffer(client, packageName, productId, offerId, options.purchaseOption);\n console.log(`Offer ${offerId} deleted.`);\n });\n\n offers\n .command(\"cancel <product-id> <offer-id>\")\n .description(\"Cancel an offer (permanent, cannot be re-activated)\")\n .option(\"--purchase-option <id>\", 'Purchase option ID (default: \"-\" for all)', \"-\")\n .action(async (productId: string, offerId: string, options: { purchaseOption: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(\n `Cancel offer \"${offerId}\"? This is permanent and cannot be undone.`,\n program,\n );\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"otp offers cancel\",\n action: \"cancel offer\",\n target: `${productId}/${offerId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n const result = await client.oneTimeProducts.cancelOffer(\n packageName,\n productId,\n options.purchaseOption,\n offerId,\n );\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"batch-get <product-id>\")\n .description(\"Batch get multiple offers\")\n .requiredOption(\n \"--file <path>\",\n \"JSON file with array of {productId, purchaseOptionId, offerId}\",\n )\n .option(\"--purchase-option <id>\", 'Purchase option ID in URL path (default: \"-\")', \"-\")\n .action(async (productId: string, options: { file: string; purchaseOption: 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 requests = await readJsonArray(options.file);\n const result = await client.oneTimeProducts.batchGetOffers(\n packageName,\n productId,\n options.purchaseOption,\n requests.map((r: any) => ({\n packageName,\n productId: r.productId || productId,\n purchaseOptionId: r.purchaseOptionId || \"-\",\n offerId: r.offerId,\n })),\n );\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"batch-update <product-id>\")\n .description(\"Batch create or update multiple offers (max 100)\")\n .requiredOption(\"--file <path>\", \"JSON file with update requests\")\n .option(\"--purchase-option <id>\", 'Purchase option ID in URL path (default: \"-\")', \"-\")\n .action(async (productId: string, options: { file: string; purchaseOption: string }) => {\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: \"otp offers batch-update\",\n action: \"batch update offers for\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n const requests = await readJsonArray(options.file);\n const result = await client.oneTimeProducts.batchUpdateOffers(\n packageName,\n productId,\n options.purchaseOption,\n requests,\n );\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"batch-update-states <product-id>\")\n .description(\"Batch activate, deactivate, or cancel multiple offers (max 100)\")\n .requiredOption(\"--file <path>\", \"JSON file with state transition requests\")\n .option(\"--purchase-option <id>\", 'Purchase option ID in URL path (default: \"-\")', \"-\")\n .action(async (productId: string, options: { file: string; purchaseOption: string }) => {\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: \"otp offers batch-update-states\",\n action: \"batch update offer states for\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n const requests = await readJsonArray(options.file);\n const result = await client.oneTimeProducts.batchUpdateOfferStates(\n packageName,\n productId,\n options.purchaseOption,\n requests,\n );\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"batch-delete <product-id>\")\n .description(\"Batch delete multiple offers (max 100)\")\n .requiredOption(\n \"--file <path>\",\n \"JSON file with array of {productId, purchaseOptionId, offerId}\",\n )\n .option(\"--purchase-option <id>\", 'Purchase option ID in URL path (default: \"-\")', \"-\")\n .action(async (productId: string, options: { file: string; purchaseOption: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Batch delete offers for product \"${productId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"otp offers batch-delete\",\n action: \"batch delete offers for\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n const requests = await readJsonArray(options.file);\n await client.oneTimeProducts.batchDeleteOffers(\n packageName,\n productId,\n options.purchaseOption,\n requests,\n );\n console.log(`Batch delete completed.`);\n });\n\n // --- Purchase Options batch ---\n const po = otp.command(\"purchase-options\").description(\"Manage purchase option batch operations\");\n\n po.command(\"batch-delete <product-id>\")\n .description(\"Batch delete purchase options (max 100)\")\n .requiredOption(\"--file <path>\", \"JSON file with delete requests\")\n .action(async (productId: string, options: { file: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Batch delete purchase options for product \"${productId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"otp purchase-options batch-delete\",\n action: \"batch delete purchase options for\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n const requests = await readJsonArray(options.file);\n await client.oneTimeProducts.batchDeletePurchaseOptions(packageName, productId, requests);\n console.log(`Batch delete completed.`);\n });\n\n po.command(\"batch-update-states <product-id>\")\n .description(\"Batch activate or deactivate purchase options (max 100)\")\n .requiredOption(\"--file <path>\", \"JSON file with state transition requests\")\n .action(async (productId: string, options: { file: string }) => {\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: \"otp purchase-options batch-update-states\",\n action: \"batch update purchase option states for\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n const requests = await readJsonArray(options.file);\n const result = await client.oneTimeProducts.batchUpdatePurchaseOptionStates(\n packageName,\n productId,\n requests,\n );\n console.log(formatOutput(result, format));\n });\n\n // --- Diff ---\n otp\n .command(\"diff <product-id>\")\n .description(\"Compare local JSON file against remote one-time product\")\n .requiredOption(\"--file <path>\", \"Local JSON file to compare against remote\")\n .action(async (productId: string, options: { file: 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 localData = (await readJsonFile(options.file)) as OneTimeProduct;\n const diffs = await diffOneTimeProduct(client, packageName, productId, localData);\n if (diffs.length === 0) {\n console.log(\"No differences found.\");\n } else {\n console.log(formatOutput(diffs, format));\n }\n });\n}\n"],"mappings":"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","names":["format"]}