upload-policy-library.mjs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * 把本地政策库上传到 DMS,并把返回的相对路径写进 `public/config.js`
  3. * 的 `dms.policyRemotePath`(DMS uploadFile **会改名**,不能假定固定文件名)。
  4. *
  5. * node harness/tools/upload-policy-library.mjs
  6. * node harness/tools/upload-policy-library.mjs https://host/dms
  7. *
  8. * 需要 dev server 起着(默认 https://localhost:8083/dms)。
  9. * 若 config 里已有路径且可读、条数一致 → 跳过上传。
  10. */
  11. process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
  12. const base = String(process.argv[2] || 'https://localhost:8083/dms').replace(/\/+$/, '');
  13. globalThis.VITE_DMS_API = base;
  14. const { uploadDmsAttachment, buildDmsFileDisplayUrl } = await import('./_dms.mjs');
  15. const { readFileSync, writeFileSync } = await import('node:fs');
  16. const LOCAL_FILE = 'public/merchant-agent/policies_public.v2.json';
  17. const CONFIG_FILE = 'public/config.js';
  18. const FILE_NAME = 'policies_public.v2.json';
  19. const bytes = readFileSync(LOCAL_FILE);
  20. const list = JSON.parse(bytes.toString('utf8'));
  21. const localCount = Array.isArray(list) ? list.length : null;
  22. const readConfiguredRel = () => {
  23. const src = readFileSync(CONFIG_FILE, 'utf8');
  24. const m = src.match(/policyRemotePath\s*:\s*["']([^"']*)["']/);
  25. return m ? m[1].trim() : '';
  26. };
  27. const writeConfiguredRel = (rel) => {
  28. let src = readFileSync(CONFIG_FILE, 'utf8');
  29. if (/policyRemotePath\s*:/.test(src)) {
  30. src = src.replace(
  31. /policyRemotePath\s*:\s*["'][^"']*["']/,
  32. `policyRemotePath:\n ${JSON.stringify(rel)}`
  33. );
  34. } else {
  35. throw new Error(`${CONFIG_FILE} 里找不到 policyRemotePath 字段`);
  36. }
  37. writeFileSync(CONFIG_FILE, src, 'utf8');
  38. };
  39. const probe = async (url) => {
  40. const response = await fetch(url);
  41. const text = await response.text();
  42. let parsed = null;
  43. try {
  44. parsed = JSON.parse(text);
  45. } catch {
  46. /* ignore */
  47. }
  48. const count = Array.isArray(parsed) ? parsed.length : null;
  49. return { response, count };
  50. };
  51. console.log(`本地 ${LOCAL_FILE}(${(bytes.length / 1024).toFixed(0)} KB / ${localCount ?? '?'} 条)`);
  52. const configuredRel = readConfiguredRel();
  53. if (configuredRel) {
  54. const url = configuredRel.startsWith('http')
  55. ? configuredRel
  56. : `${base}${configuredRel.startsWith('/') ? '' : '/'}${configuredRel}`;
  57. console.log(`config 已配置 ${configuredRel}`);
  58. const existing = await probe(url);
  59. if (existing.response.ok && existing.count != null) {
  60. console.log(`\n已可读:HTTP ${existing.response.status} · ${existing.count} 条`);
  61. if (localCount != null && existing.count === localCount) {
  62. console.log(' ✓ 与本地条数一致,无需上传');
  63. process.exit(0);
  64. }
  65. console.warn(` ⚠️ 条数不一致(远端 ${existing.count} / 本地 ${localCount}),将重新上传并更新 config`);
  66. } else {
  67. console.log(` 不可读(HTTP ${existing.response.status}),将重新上传`);
  68. }
  69. } else {
  70. console.log('config 未配置 policyRemotePath,将上传并写入');
  71. }
  72. console.log(`\n上传 ${FILE_NAME}(DMS 会改名,属正常)…`);
  73. const file = new File([bytes], FILE_NAME, { type: 'application/json' });
  74. const relativePath = await uploadDmsAttachment(file, { isImage: false });
  75. const displayUrl = buildDmsFileDisplayUrl(relativePath);
  76. console.log('\n上传结果:');
  77. console.log(' 相对路径:' + relativePath);
  78. console.log(' 可访问地址:' + displayUrl);
  79. const after = await probe(displayUrl);
  80. console.log('\n自检:');
  81. console.log(` HTTP ${after.response.status} · 条数=${after.count ?? '(解析失败)'}`);
  82. if (after.count !== localCount) {
  83. console.error(' ⚠️ 远端内容与本地不一致,未写入 config');
  84. process.exit(1);
  85. }
  86. console.log(' ✓ 与本地一致');
  87. writeConfiguredRel(relativePath);
  88. console.log(`\n已写入 ${CONFIG_FILE} → dms.policyRemotePath = ${JSON.stringify(relativePath)}`);