UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

323 lines (316 loc) 13.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateOutputFormat = validateOutputFormat; exports.parsePositiveInteger = parsePositiveInteger; exports.parseNonNegativeInteger = parseNonNegativeInteger; exports.registerQaCommands = registerQaCommands; const qa_questionnaire_handler_1 = require("../handlers/qa-questionnaire.handler"); const manager_1 = require("../config/manager"); const auth_adapter_1 = require("../config/auth-adapter"); const errors_1 = require("../utils/errors"); function validateOutputFormat(value) { if (!['table', 'json'].includes(value)) { throw new Error('Output format must be either "table" or "json"'); } return value; } function parsePositiveInteger(value) { const parsed = parseInt(value, 10); if (!Number.isInteger(parsed) || parsed < 1) { throw new Error('Value must be a positive integer'); } return parsed; } function parseNonNegativeInteger(value) { const parsed = parseInt(value, 10); if (!Number.isInteger(parsed) || parsed < 0) { throw new Error('Value must be a non-negative integer'); } return parsed; } function registerQaCommands(program) { const qaCmd = program.command('qa'); qaCmd.description('Manage live streaming QA question cards'); const sendCmd = qaCmd .command('send') .description('Send a QA question card to the channel') .requiredOption('-c, --channel-id <id>', 'channel ID') .requiredOption('--question-id <id>', 'question ID') .option('--duration <seconds>', 'answer duration in seconds (1-99)', parseInt) .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 handler = new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig); await handler.sendQa({ channelId: options.channelId, questionId: options.questionId, duration: options.duration, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); sendCmd.addHelpText('after', ` Examples: # Send a QA question card $ polyv-live-cli qa send -c "3151318" --question-id "gv0uf9s5v7" # Send with time limit (30 seconds) $ polyv-live-cli qa send -c "3151318" --question-id "gv0uf9s5v7" --duration 30 # JSON output $ polyv-live-cli qa send -c "3151318" --question-id "gv0uf9s5v7" -o json Output Formats: table - Formatted table output (default) json - JSON format for programmatic use `); const listCmd = qaCmd .command('list') .description('List QA question cards for the channel') .requiredOption('-c, --channel-id <id>', 'channel ID') .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 handler = new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig); await handler.listQa({ channelId: options.channelId, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); listCmd.addHelpText('after', ` Examples: # List all QA question cards $ polyv-live-cli qa list -c "3151318" # JSON output $ polyv-live-cli qa list -c "3151318" -o json Output Formats: table - Formatted table output (default) json - JSON format for programmatic use `); const stopCmd = qaCmd .command('stop') .description('Stop a QA question card and get answer statistics') .requiredOption('-c, --channel-id <id>', 'channel ID') .requiredOption('--question-id <id>', 'question ID') .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 handler = new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig); await handler.stopQa({ channelId: options.channelId, questionId: options.questionId, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); stopCmd.addHelpText('after', ` Examples: # Stop a QA question card $ polyv-live-cli qa stop -c "3151318" --question-id "gv0uf9s5v7" # JSON output $ polyv-live-cli qa stop -c "3151318" --question-id "gv0uf9s5v7" -o json Output Formats: table - Formatted table output (default) json - JSON format for programmatic use `); qaCmd .command('send-times') .description('List QA question card send times') .requiredOption('-c, --channel-id <id>', 'channel ID') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).listQuestionSendTime({ channelId: options.channelId, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); qaCmd .command('answers') .description('List QA answer records') .requiredOption('-c, --channel-id <id>', 'channel ID') .option('--session-id <id>', 'filter by live session ID') .option('--start-date <date>', 'start date filter (yyyy-MM-dd)') .option('--end-date <date>', 'end date filter (yyyy-MM-dd)') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).getAnswerList({ channelId: options.channelId, sessionId: options.sessionId, startDate: options.startDate, endDate: options.endDate, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); qaCmd .command('question-list') .description('List student question records') .requiredOption('-c, --channel-id <id>', 'channel ID') .option('--begin <timestamp>', 'begin timestamp', parsePositiveInteger) .option('--end <timestamp>', 'end timestamp', 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); await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).getQuestionList({ channelId: options.channelId, begin: options.begin, end: options.end, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); qaCmd .command('add-edit') .description('Create or update a QA question card') .requiredOption('-c, --channel-id <id>', 'channel ID') .option('--question-id <id>', 'question ID; omit to create a new question card') .requiredOption('--type <type>', 'question type (R|C|S|V)') .requiredOption('--answer <answer>', 'correct answer') .requiredOption('--name <name>', 'question title') .requiredOption('--item-type <number>', 'item type', parseNonNegativeInteger) .option('--option <value...>', 'question option values, repeat by providing multiple values') .option('--tip <value...>', 'answer explanation values, repeat by providing multiple values') .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); await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).addEditQuestion({ channelId: options.channelId, questionId: options.questionId, type: options.type, answer: options.answer, name: options.name, itemType: options.itemType, options: options.option, tips: options.tip, force: options.force, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); qaCmd .command('delete-question') .description('Delete a QA question card') .requiredOption('-c, --channel-id <id>', 'channel ID') .requiredOption('--question-id <id>', 'question ID') .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); await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).deleteQuestion({ channelId: options.channelId, questionId: options.questionId, force: options.force, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); qaCmd .command('send-result') .description('Publish QA question result statistics') .requiredOption('-c, --channel-id <id>', 'channel ID') .requiredOption('--question-id <id>', 'question ID') .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); await new qa_questionnaire_handler_1.QaQuestionnaireHandler(authConfig, serviceConfig).sendQuestionResult({ channelId: options.channelId, questionId: options.questionId, force: options.force, output: options.output, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); } 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: 30000, debug: false } }; } else { throw error; } } const serviceConfig = { baseUrl: configResult.config.baseUrl, timeout: configResult.config.timeout, debug: configResult.config.debug, }; return { authConfig: authResult.config, serviceConfig, }; } //# sourceMappingURL=qa.commands.js.map