e744ad1f96
事故鏈(07-31 深夜,leo 刷新撞到):t159 重打包 staging bundle 時,build-ui-bundle 吃了 feat/step3 分支的 console-ui/public/——該分支基底早於 maind7fab7c「拿掉登記新庫」,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 同步到 maine28e190世代+註解字樣改寫達成「登記新庫」全檔 0 命中);deploy.mjs 改為直接託管 public(無 build 步)+世代閘(缺「不需要人工新增」或含「登記新庫」拒部署)。 驗:tsc 全綠;deploy.mjs node --check 過;重打 ui bundle 242KB 過世代閘, 指紋「登記新庫」=0/「不需要人工新增」=1。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
47 lines
2.4 KiB
JavaScript
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);
|