UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

760 lines (738 loc) 33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadAuthAndServiceConfig = loadAuthAndServiceConfig; exports.validateEnabledValue = validateEnabledValue; exports.validateOutputFormat = validateOutputFormat; exports.validateUrlFormat = validateUrlFormat; exports.registerPlatformCommands = registerPlatformCommands; const platform_handler_1 = require("../handlers/platform.handler"); const manager_1 = require("../config/manager"); const auth_adapter_1 = require("../config/auth-adapter"); const errors_1 = require("../utils/errors"); const confirmation_1 = require("../utils/confirmation"); const api_command_1 = require("../utils/api-command"); const platform_1 = require("../types/platform"); const DEFAULT_TIMEOUT_MS = 30000; async function loadAuthAndServiceConfig(parentOptions) { const authResult = auth_adapter_1.authAdapter.tryGetAuthConfig(parentOptions); if (!authResult) { throw new Error(auth_adapter_1.authAdapter.getStatusMessage(parentOptions)); } let configResult; try { configResult = await manager_1.configManager.load({ cliOptions: parentOptions, }); } catch (error) { if (error instanceof Error && error.message.includes('Auth configuration is incomplete')) { configResult = { config: { baseUrl: 'https://api.polyv.net', timeout: DEFAULT_TIMEOUT_MS, debug: false, }, }; } else { throw error; } } const serviceConfig = { baseUrl: configResult.config.baseUrl, timeout: configResult.config.timeout, debug: configResult.config.debug, }; const isVerbose = !!parentOptions['verbose']; if (isVerbose) { console.log(`🔐 Authentication Source: ${authResult.source}`); if (authResult.accountName) { console.log(`👤 Account: ${authResult.accountName}`); } console.log(''); } return { authConfig: authResult.config, serviceConfig, isVerbose, }; } function validateEnabledValue(value) { if (value !== 'Y' && value !== 'N') { throw new Error('enabled 必须是 Y 或 N'); } return value; } function validateOutputFormat(value) { if (!['table', 'json'].includes(value)) { throw new Error('Invalid output format. Must be "table" or "json"'); } return value; } function validateUrlFormat(value) { if (!value.startsWith('http://') && !value.startsWith('https://')) { throw new Error('url 必须以 http:// 或 https:// 开头'); } return value; } function parsePositiveInteger(value) { const parsed = Number(value); if (!Number.isInteger(parsed) || parsed <= 0) { throw new Error('value must be a positive integer'); } return parsed; } function parseNonNegativeInteger(value) { const parsed = Number(value); if (parsed !== 0 && parsed !== 1) { throw new Error('value must be 0 or 1'); } return parsed; } function parseTimestamp(value) { const parsed = Number(value); if (!Number.isFinite(parsed) || parsed <= 0) { throw new Error('timestamp must be a positive number'); } return parsed; } function parseIdList(value) { const ids = value.split(',').map(item => Number(item.trim())).filter(Number.isFinite); if (ids.length === 0 || ids.some(id => !Number.isInteger(id) || id <= 0)) { throw new Error('ids must be positive integers separated by comma'); } return ids; } function parseStringList(value) { const ids = value.split(',').map(item => item.trim()).filter(Boolean); if (ids.length === 0) { throw new Error('ids must not be empty'); } return ids; } function parseJsonObject(value) { const parsed = JSON.parse(value); if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { throw new Error('config must be a JSON object'); } return parsed; } function validateSex(value) { if (value !== 'M' && value !== 'W') { throw new Error('sex must be M or W'); } return value; } function validateContentGroupType(value) { if (value !== 'script' && value !== 'robot') { throw new Error('type must be script or robot'); } return value; } function validateReceiveSource(value) { if (value !== 'CHANNEL' && value !== 'AGGREGATE_PAGE') { throw new Error('receive-source must be CHANNEL or AGGREGATE_PAGE'); } return value; } async function confirmPlatformWrite(force, message) { if (force) return; const confirmed = await (0, confirmation_1.confirmDeletion)(message); if (!confirmed) { throw new Error('Operation cancelled.'); } } function registerPlatformCommands(program) { const platformCmd = program.command('platform'); platformCmd.description('Platform account info management commands (平台账号信息管理)'); const getCmd = platformCmd .command('get') .description('Get account info (获取账号信息)') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const getOptions = { output: options.output, }; await platformHandler.getAccountInfo(getOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); getCmd.addHelpText('after', ` Examples: $ polyv-live-cli platform get $ polyv-live-cli platform get -o json Output Formats: table - Formatted table output (default) json - JSON format for programmatic use `); const switchCmd = platformCmd.command('switch'); switchCmd.description('Switch configuration management (开关配置管理)'); const switchGetCmd = switchCmd .command('get') .description('Get switch configuration (获取开关配置)') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const getOptions = { output: options.output, }; await platformHandler.getSwitchConfig(getOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); switchGetCmd.addHelpText('after', ` Examples: $ polyv-live-cli platform switch get $ polyv-live-cli platform switch get -o json Output Formats: table - Formatted table output (default) json - JSON format for programmatic use `); const switchUpdateCmd = switchCmd .command('update') .description('Update switch configuration (更新开关配置)') .requiredOption('--param <name>', `switch parameter name (${platform_1.VALID_SWITCH_PARAMS.join('|')})`) .requiredOption('--enabled <value>', 'enable status (Y|N)', validateEnabledValue) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const updateOptions = { param: options.param, enabled: options.enabled, output: options.output, }; await confirmPlatformWrite(options.force, `Update platform switch ${options.param}?`); await platformHandler.updateSwitchConfig(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); switchUpdateCmd.addHelpText('after', ` Examples: # Enable chat $ polyv-live-cli platform switch update --param chat --enabled Y # Disable barrage (danmu) $ polyv-live-cli platform switch update --param closeDanmu --enabled Y # JSON output $ polyv-live-cli platform switch update --param autoPlay --enabled N -o json Tip: run \`platform switch get\` to see the available switch \`type\` values and their current status; pass any of those \`type\` values to \`--param\`. Available Parameters (same as the \`type\` values returned by \`switch get\`): ${platform_1.VALID_SWITCH_PARAMS.join(', ')} Enable Values: Y - Enable the switch N - Disable the switch `); const callbackCmd = platformCmd.command('callback'); callbackCmd.description('Callback settings management (回调设置管理)'); const callbackGetCmd = callbackCmd .command('get') .description('Get callback settings (获取回调设置)') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const getOptions = { output: options.output, }; await platformHandler.getCallbackSettings(getOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); callbackGetCmd.addHelpText('after', ` Examples: $ polyv-live-cli platform callback get $ polyv-live-cli platform callback get -o json Output Formats: table - Formatted table output (default) json - JSON format for programmatic use `); const callbackUpdateCmd = callbackCmd .command('update') .description('Update callback settings (更新回调设置)') .option('--url <url>', 'live status callback URL / streamCallbackUrl (must start with http:// or https://)', validateUrlFormat) .option('--clear-url', 'clear the live status callback URL / streamCallbackUrl (sets it to empty)') .option('--enabled <value>', 'enable status (Y|N)', validateEnabledValue) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const updateOptions = { url: options.url, clearUrl: options.clearUrl, enabled: options.enabled, output: options.output, }; await confirmPlatformWrite(options.force, 'Update platform callback settings?'); await platformHandler.updateCallbackSettings(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); callbackUpdateCmd.addHelpText('after', ` Examples: # Update live status callback URL (streamCallbackUrl) $ polyv-live-cli platform callback update --url https://example.com/callback # Enable/disable callback $ polyv-live-cli platform callback update --enabled Y $ polyv-live-cli platform callback update --enabled N # Combined update $ polyv-live-cli platform callback update --url https://example.com/new-callback --enabled Y # Clear live status callback URL (streamCallbackUrl) $ polyv-live-cli platform callback update --clear-url # JSON output $ polyv-live-cli platform callback update --url https://example.com/callback -o json URL Format: URL must start with http:// or https:// Enable Values: Y - Enable callback N - Disable callback Note: At least one parameter (--url, --enabled, or --clear-url) must be provided. --url/--clear-url only target streamCallbackUrl (直播状态改变回调URL). --enabled N only disables rebirthVodCallbackEnabled; use --clear-url to remove streamCallbackUrl itself. `); const settingCmd = platformCmd.command('setting'); settingCmd.description('Global channel settings management (全局频道设置管理)'); const settingGetCmd = settingCmd .command('get') .description('Get global channel settings (获取全局频道设置)') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const getOptions = { output: options.output, }; await platformHandler.getGlobalSettings(getOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); settingGetCmd.addHelpText('after', ` Examples: $ polyv-live-cli platform setting get $ polyv-live-cli platform setting get -o json Output Formats: table - Formatted table output (default) json - JSON format for programmatic use Note: The backend GET endpoint returns: channelConcurrencesEnabled, timelyConvertEnabled, donateEnabled, rebirthAutoUploadEnabled, rebirthAutoConvertEnabled, pptCoveredEnabled, coverImgType. The \`testModeButtonEnabled\` switch is WRITE-ONLY (set via \`platform setting update --test-mode-button-enabled\`) and is NOT returned here, so it cannot be read back through this command. `); const settingUpdateCmd = settingCmd .command('update') .description('Update global channel settings (更新全局频道设置)') .option('--channel-concurrences-enabled <value>', 'enable max concurrent viewers (Y|N)', validateGlobalSettingEnabledValue) .option('--timely-convert-enabled <value>', 'enable auto convert (Y|N)', validateGlobalSettingEnabledValue) .option('--donate-enabled <value>', 'enable donation (Y|N)', validateGlobalSettingEnabledValue) .option('--rebirth-auto-upload-enabled <value>', 'enable rebirth auto upload (Y|N)', validateGlobalSettingEnabledValue) .option('--rebirth-auto-convert-enabled <value>', 'enable rebirth auto convert (Y|N)', validateGlobalSettingEnabledValue) .option('--ppt-covered-enabled <value>', 'enable PPT full screen (Y|N)', validateGlobalSettingEnabledValue) .option('--cover-img-type <value>', 'cover image type (contain|cover)', validateCoverImgType) .option('--test-mode-button-enabled <value>', 'enable test mode button (Y|N) — write-only, NOT returned by `setting get`', validateGlobalSettingEnabledValue) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const updateOptions = { channelConcurrencesEnabled: options.channelConcurrencesEnabled, timelyConvertEnabled: options.timelyConvertEnabled, donateEnabled: options.donateEnabled, rebirthAutoUploadEnabled: options.rebirthAutoUploadEnabled, rebirthAutoConvertEnabled: options.rebirthAutoConvertEnabled, pptCoveredEnabled: options.pptCoveredEnabled, coverImgType: options.coverImgType, testModeButtonEnabled: options.testModeButtonEnabled, output: options.output, }; await confirmPlatformWrite(options.force, 'Update global channel settings?'); await platformHandler.updateGlobalSettings(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); settingUpdateCmd.addHelpText('after', ` Examples: # Update single setting $ polyv-live-cli platform setting update --channel-concurrences-enabled Y $ polyv-live-cli platform setting update --donate-enabled N $ polyv-live-cli platform setting update --cover-img-type contain # Update multiple settings $ polyv-live-cli platform setting update \\ --channel-concurrences-enabled Y \\ --timely-convert-enabled Y \\ --donate-enabled N \\ --cover-img-type contain # JSON output $ polyv-live-cli platform setting update --donate-enabled Y -o json Boolean Parameters: Y - Enable the setting N - Disable the setting Cover Image Types: contain - Contain mode cover - Cover mode Note: At least one parameter must be provided `); const anchorCmd = platformCmd .command('anchor') .description('Anchor management (主播管理)'); anchorCmd .command('list') .description('List anchors') .option('--page <page>', 'page number', parsePositiveInteger) .option('--page-size <size>', 'page size', parsePositiveInteger) .option('--status <status>', 'status (0|1)', parseNonNegativeInteger) .option('--sex <sex>', 'sex (M|W)', validateSex) .option('--nickname <nickname>', 'nickname keyword') .option('--start-time <timestamp>', 'start timestamp', parseTimestamp) .option('--end-time <timestamp>', 'end timestamp', parseTimestamp) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const listOptions = { pageNumber: options.page, pageSize: options.pageSize, status: options.status, sex: options.sex, nickname: options.nickname, startTime: options.startTime, endTime: options.endTime, output: options.output, }; await platformHandler.listAnchors(listOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); anchorCmd .command('get') .description('Get anchor detail') .requiredOption('--anchor-id <id>', 'anchor ID', parsePositiveInteger) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const getOptions = { anchorId: options.anchorId, output: options.output, }; await platformHandler.getAnchor(getOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); anchorCmd .command('create') .description('Create anchor') .requiredOption('--nickname <nickname>', 'anchor nickname') .requiredOption('--sex <sex>', 'sex (M|W)', validateSex) .requiredOption('--avatar <url>', 'avatar URL') .option('--description <text>', 'description') .option('--add-channel-ids <ids>', 'channel IDs to associate, comma-separated', parseIdList) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const createOptions = { nickname: options.nickname, sex: options.sex, avatar: options.avatar, description: options.description, addChannelIds: options.addChannelIds, force: options.force, output: options.output, }; await platformHandler.createAnchor(createOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); anchorCmd .command('update') .description('Update anchor') .requiredOption('--anchor-id <id>', 'anchor ID', parsePositiveInteger) .option('--nickname <nickname>', 'anchor nickname') .option('--sex <sex>', 'sex (M|W)', validateSex) .option('--avatar <url>', 'avatar URL') .option('--description <text>', 'description') .option('--add-channel-ids <ids>', 'channel IDs to add, comma-separated', parseIdList) .option('--del-channel-ids <ids>', 'channel IDs to remove, comma-separated', parseIdList) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const updateOptions = { anchorId: options.anchorId, nickname: options.nickname, sex: options.sex, avatar: options.avatar, description: options.description, addChannelIds: options.addChannelIds, delChannelIds: options.delChannelIds, force: options.force, output: options.output, }; await platformHandler.updateAnchor(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); anchorCmd .command('update-status') .description('Update anchor status') .requiredOption('--anchor-id <id>', 'anchor ID', parsePositiveInteger) .requiredOption('--status <status>', 'status (0|1)', parseNonNegativeInteger) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const updateOptions = { anchorId: options.anchorId, status: options.status, force: options.force, output: options.output, }; await platformHandler.updateAnchorStatus(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); anchorCmd .command('relation-list') .description('List channels related to an anchor') .requiredOption('--anchor-id <id>', 'anchor ID', parsePositiveInteger) .option('--page <page>', 'page number', parsePositiveInteger) .option('--page-size <size>', 'page size', parsePositiveInteger) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const relationOptions = { anchorId: options.anchorId, pageNumber: options.page, pageSize: options.pageSize, output: options.output, }; await platformHandler.listAnchorRelations(relationOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); anchorCmd .command('unrelation-list') .description('List channels not related to an anchor') .requiredOption('--anchor-id <id>', 'anchor ID', parsePositiveInteger) .option('--page <page>', 'page number', parsePositiveInteger) .option('--page-size <size>', 'page size', parsePositiveInteger) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const relationOptions = { anchorId: options.anchorId, pageNumber: options.page, pageSize: options.pageSize, output: options.output, }; await platformHandler.listAnchorUnrelations(relationOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); const contentGroupCmd = platformCmd .command('content-group') .description('Content group management'); contentGroupCmd .command('list') .description('List content groups') .requiredOption('--type <type>', 'content type (script|robot)', validateContentGroupType) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const listOptions = { type: options.type, output: options.output, }; await platformHandler.listContentGroups(listOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); const couponCmd = platformCmd .command('coupon') .description('Platform coupon operations'); couponCmd .command('viewer-list') .description('List viewers that received a coupon') .requiredOption('--coupon-id <id>', 'coupon ID') .option('--page <page>', 'page number', parsePositiveInteger) .option('--page-size <size>', 'page size', parsePositiveInteger) .option('--keyword <keyword>', 'viewer keyword') .option('--receive-source <source>', 'receive source (CHANNEL|AGGREGATE_PAGE)', validateReceiveSource) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const listOptions = { couponId: options.couponId, pageNumber: options.page, pageSize: options.pageSize, keyword: options.keyword, receiveSource: options.receiveSource, output: options.output, }; await platformHandler.listCouponViewers(listOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); couponCmd .command('update') .description('Update coupon fields from a JSON object') .requiredOption('--coupon-id <id>', 'coupon ID') .option('--config-json <json>', 'coupon update JSON object', parseJsonObject) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const config = (0, api_command_1.resolveJsonObjectOption)(options.configJson, parentOptions['config']); const updateOptions = { couponId: options.couponId, force: options.force, output: options.output, }; if (config) { updateOptions.config = config; } await platformHandler.updateCoupon(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); couponCmd .command('status-batch') .description('Batch update coupon status') .requiredOption('--coupon-ids <ids>', 'coupon IDs, comma-separated', parseStringList) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const platformHandler = new platform_handler_1.PlatformHandler(authConfig, serviceConfig); const updateOptions = { couponIds: options.couponIds, force: options.force, output: options.output, }; await platformHandler.updateCouponsStatusBatch(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); } function validateGlobalSettingEnabledValue(value) { if (value !== 'Y' && value !== 'N') { throw new Error('参数值必须是 Y 或 N'); } return value; } function validateCoverImgType(value) { if (value !== 'contain' && value !== 'cover') { throw new Error('cover-img-type 必须是 contain 或 cover'); } return value; } //# sourceMappingURL=platform.commands.js.map