Files
Arcrun/console-ui/public/portal/safejson.test.mjs
T
uncle6me-web e744ad1f96 t160 世代債清除(leo:「如果你會搞不清楚,就把錯的東西刪掉」)——repo 只留一個 UI 世代
事故鏈(07-31 深夜,leo 刷新撞到):t159 重打包 staging bundle 時,build-ui-bundle
吃了 feat/step3 分支的 console-ui/public/——該分支基底早於 main d7fab7c
「拿掉登記新庫」,public 停在舊世代 ⇒ youlin 實例 UI 被打回被淘汰的
「登記新庫」人工表單典範(07-27 mistakes 已記帳的 src/public 雙世代債,
這次由「分支副本停舊代」路徑引爆——債沒還,任何一個部署路徑都會引爆它)。

刪掉的(舊世代,git rm 實體刪除):
- console-ui/src/(console.ts/console-dashboard.ts/portal-ui.ts)=07-22 從
  cypher-executor 搬出的 renderer 快照,自 07-27 起與 public/ 真身脫鉤、只會
  重產舊 UI
- console-ui/scripts/build.mjs=從上述舊 renderer 重產 public 的 build 步驟
  (deploy.mjs 原自動跑它=引爆器本體)
- cypher POST /portal/admin/libraries(人工建庫端點)=死端點(e28e190 起 UI
  零呼叫;leo 規格「要直通 daemon,同步,沒有登記這回事」)。GET 列表/PATCH
  管理/t159 daemon 自動登記照舊

新唯一源:console-ui/public/=手改演進的真身(本 commit 同步到 main e28e190
世代+註解字樣改寫達成「登記新庫」全檔 0 命中);deploy.mjs 改為直接託管
public(無 build 步)+世代閘(缺「不需要人工新增」或含「登記新庫」拒部署)。

驗:tsc 全綠;deploy.mjs node --check 過;重打 ui bundle 242KB 過世代閘,
指紋「登記新庫」=0/「不需要人工新增」=1。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 14:36:48 +08:00

47 lines
2.4 KiB
JavaScript

import fs from 'node:fs';
const html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname,'utf8');
// 抽出 safeJson 與 friendlyErr 求值
const grab = (name) => {
const i = html.indexOf(`function ${name}(`);
if (i < 0) throw new Error(`找不到 ${name}`);
let d=0, j=html.indexOf('{', i);
for (let k=j;k<html.length;k++){ if(html[k]==='{')d++; if(html[k]==='}'){d--; if(!d){ return html.slice(i,k+1);} } }
throw new Error('括號不平衡');
};
const fn = new Function(grab('safeJson') + '\n' + grab('friendlyErr') + '\nreturn {safeJson, friendlyErr};')();
let pass=0, fail=0;
const t=(l,c,e='')=>{c?(console.log('PASS:',l),pass++):(console.log('FAIL:',l,e),fail++)};
// ① safeJson:非 JSON 不可拋例外(同事撞到的 404 HTML 頁)
const html404 = '<!DOCTYPE html><html><body>404 Not Found</body></html>';
await fn.safeJson({ text: () => Promise.resolve(html404) })
.then(d => t('404 HTML → 回空物件不拋錯', typeof d === 'object' && d !== null))
.catch(e => t('404 HTML → 不該拋錯', false, e.message));
await fn.safeJson({ text: () => Promise.resolve('') })
.then(d => t('空回應 → 回空物件', JSON.stringify(d)==='{}'))
.catch(() => t('空回應 → 不該拋錯', false));
await fn.safeJson({ text: () => Promise.resolve('{"error":"帳號或密碼不對"}') })
.then(d => t('正常 JSON 仍要解析得出來', d.error === '帳號或密碼不對'), )
.catch(() => t('正常 JSON 不該拋錯', false));
// ② friendlyErr:不可把技術訊息噴給使用者
const leak = fn.friendlyErr(new Error('Unexpected non-whitespace character after JSON at position 4'));
t('JSON 錯誤 → 不外洩原文', !/JSON|position/i.test(leak), `實得: ${leak}`);
t('JSON 錯誤 → 說人話', /伺服器回應異常/.test(leak), `實得: ${leak}`);
const net = fn.friendlyErr(new Error('Failed to fetch'));
t('網路錯誤 → 既有訊息保留', /連線中斷/.test(net), `實得: ${net}`);
const ours = fn.friendlyErr(new Error('帳號或密碼不對——用你在知識庫網站設定的那組'));
t('我們自己的中文訊息 → 原樣顯示', /帳號或密碼不對/.test(ours), `實得: ${ours}`);
const stack = fn.friendlyErr(new Error('TypeError: Cannot read properties of undefined'));
t('英文技術訊息 → 收斂不外洩', !/TypeError|undefined/.test(stack), `實得: ${stack}`);
console.log(`\n=== ${pass} passed, ${fail} failed ===`);
process.exit(fail?1:0);