_patch-errorhandling.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!/usr/bin/env node
  2. /**
  3. * 批量修补所有 api-config.json 的 errorHandling.balanceInsufficient:
  4. * 1) 添加 `mess` responseField 检查 (voc-social-api 返回 `mess` 而非 `message`)
  5. * 2) 在 msg/mess/message 的 contains 列表中追加 "没有开通"、"权限或余额"
  6. *
  7. * 目标是让后端 403 `{"code":403,"mess":"没有开通社交平台API权限或余额不足"}`
  8. * 正确触发 onBalanceInsufficient 流程(而非被错误路由到 onMissing)
  9. *
  10. * 运行: node scripts/tools/_patch-errorhandling.js
  11. * node scripts/tools/_patch-errorhandling.js --dry-run
  12. */
  13. const fs = require('fs');
  14. const path = require('path');
  15. const ROOT = path.resolve(__dirname, '..', '..');
  16. const DRY = process.argv.includes('--dry-run');
  17. const SOURCE_DIRS = [
  18. 'voc', 'social-media', 'competitor-analysis', 'review-analysis',
  19. 'synthesis', 'social-voc', 'douyin', 'video-creation',
  20. 'jimeng', 'payment', 'workshop'
  21. ];
  22. // 增量关键词(避免重复添加)
  23. const EXTRA_KEYWORDS = ['没有开通', '权限或余额'];
  24. function uniqMerge(existing, extras) {
  25. const set = new Set(existing);
  26. extras.forEach(x => set.add(x));
  27. return Array.from(set);
  28. }
  29. function patch(config, filePath) {
  30. let changed = false;
  31. const bi = config?.errorHandling?.balanceInsufficient;
  32. if (!bi || !Array.isArray(bi.conditions)) return false;
  33. const hasMess = bi.conditions.some(c => c.responseField === 'mess');
  34. // 收集一个参考的 contains value 列表(优先从 msg 获取;没有则用 message;再没有兜底默认)
  35. const msgCond = bi.conditions.find(c => c.responseField === 'msg');
  36. const messageCond = bi.conditions.find(c => c.responseField === 'message');
  37. const baseValues = (msgCond?.value || messageCond?.value || ['余额不足', 'insufficient', 'balance', 'quota']).slice();
  38. // 1. 给 msg / message 的 value 追加关键词
  39. for (const cond of bi.conditions) {
  40. if (cond.operator !== 'contains') continue;
  41. if (cond.responseField === 'msg' || cond.responseField === 'message') {
  42. const merged = uniqMerge(cond.value || [], EXTRA_KEYWORDS);
  43. if (JSON.stringify(merged) !== JSON.stringify(cond.value)) {
  44. cond.value = merged;
  45. changed = true;
  46. }
  47. }
  48. }
  49. // 2. 追加 mess responseField 条件(若不存在)
  50. if (!hasMess) {
  51. const messCond = {
  52. responseField: 'mess',
  53. operator: 'contains',
  54. value: uniqMerge(baseValues, EXTRA_KEYWORDS)
  55. };
  56. // 插在 msg 条件之后,保持排序直观
  57. const insertIdx = bi.conditions.findIndex(c => c.responseField === 'msg');
  58. if (insertIdx >= 0) {
  59. bi.conditions.splice(insertIdx + 1, 0, messCond);
  60. } else {
  61. bi.conditions.push(messCond);
  62. }
  63. changed = true;
  64. }
  65. return changed;
  66. }
  67. const processed = [];
  68. for (const dir of SOURCE_DIRS) {
  69. const catPath = path.join(ROOT, dir);
  70. if (!fs.existsSync(catPath)) continue;
  71. for (const skill of fs.readdirSync(catPath)) {
  72. const p = path.join(catPath, skill, 'api-config.json');
  73. if (!fs.existsSync(p)) continue;
  74. try {
  75. const raw = fs.readFileSync(p, 'utf-8');
  76. const config = JSON.parse(raw);
  77. if (patch(config, p)) {
  78. if (!DRY) {
  79. fs.writeFileSync(p, JSON.stringify(config, null, 2) + '\n', 'utf-8');
  80. }
  81. processed.push({ file: path.relative(ROOT, p), status: DRY ? 'would-change' : 'updated' });
  82. } else {
  83. processed.push({ file: path.relative(ROOT, p), status: 'no-change' });
  84. }
  85. } catch (e) {
  86. console.error(`[ERROR] ${p}: ${e.message}`);
  87. }
  88. }
  89. }
  90. const updated = processed.filter(p => p.status === 'updated' || p.status === 'would-change');
  91. const skipped = processed.filter(p => p.status === 'no-change');
  92. console.log(`\n${DRY ? '[DRY]' : '[WRITE]'} 已扫描 ${processed.length} 个 api-config.json`);
  93. console.log(` 变更: ${updated.length}`);
  94. console.log(` 无需变更: ${skipped.length}`);
  95. console.log('');
  96. updated.forEach(p => console.log(` ✓ ${p.file}`));
  97. if (skipped.length && updated.length < 20) {
  98. skipped.forEach(p => console.log(` - ${p.file} (已包含 mess 或无 balanceInsufficient)`));
  99. }