32 lines
3.6 KiB
JavaScript
32 lines
3.6 KiB
JavaScript
/** Execute via production auth-cli run; token stays in memory. Uses only the designated origin. */
|
|
import {readFile,writeFile,mkdir} from 'node:fs/promises';
|
|
const base=process.env.AUTH_CHECK_BASE_URL||'http://8.211.154.134:18131';
|
|
if(base!=='http://8.211.154.134:18131')throw Error('Use the designated acceptance origin');
|
|
const dir=process.env.STUDIO_LIBRARY_DIR||'/tmp/studio-library';
|
|
await mkdir(dir,{recursive:true});
|
|
async function api(path,body,method=body?'POST':'GET'){
|
|
const response=await fetch(base+path,{method,...(body?{headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}:{})});
|
|
if(!response.ok)throw Error(path+' status '+response.status);
|
|
return response.json();
|
|
}
|
|
const canonical='8eb8c76500580f7a4b56ba3c',legacy='9ebd8f78d54b4b9db741b4e8';
|
|
const {entry:current,tags}=await api('/api/notes/'+canonical),{entry:old}=await api('/api/notes/'+legacy);
|
|
// Snapshot only non-secret editorial state. Retain the first backup across repeat publication.
|
|
for(const [id,entry] of [[canonical,current],[legacy,old]]){try{await readFile(dir+'/'+id+'-before.json')}catch{await writeFile(dir+'/'+id+'-before.json',JSON.stringify(entry),{mode:0o600})}}
|
|
const catalogue=await api('/studio/api/layouts');
|
|
let markdown=(await readFile(dir+'/layouts-api.md','utf8')).replace('{{LAYOUTS}}',catalogue.layouts.filter(l=>l.family==='fixed').map(l=>`- [${l.id} · ${l.name}](${l.url}) · [参数](${l.api})`).join('\n'));
|
|
const legacyOriginal=JSON.parse(await readFile(dir+'/'+legacy+'-before.json','utf8')).editableMarkdown;
|
|
markdown+='\n\n## 兼容工具原说明与代码示例\n\n以下保留原工具的说明与 HTML/React/Next.js 调用示例;它们是无状态兼容接口,持久化页面请使用上文 CRUD。\n\n'+legacyOriginal;
|
|
const tagIds=entry=>[...new Set([...(entry.systemTags||[]).map(t=>t.id),...entry.categories.map(name=>tags.find(t=>t.name===name)?.id).filter(Boolean)])];
|
|
const body=(entry,text,title=entry.title)=>({title,description:entry.description,markdown:text,tags:tagIds(entry),assets:entry.assets,coverAssetId:entry.coverAssetId,revision:entry.revision});
|
|
await api('/api/notes/'+canonical,{...body(current,markdown,'Studio 排版 API · 标准图文与27套固定构图'),description:'coding agent 经 HTTP 选择标准图文或27套固定构图,上传压缩展示素材,创建、读取、更新、归档与恢复稳定 ID 原生页面;含兼容工具箱。'},'PUT');
|
|
const redirectText=`# Studio 文档已合并\n\n[前往 Studio 排版 API 统一入口](/explore/${canonical})\n\n[可视化 API 库](/studio) · [原 ref-17 工具](/studio/ideas/learning-skills-template) · [原三种构图工具](/studio/ideas/layout-selection)\n\n完整原说明与代码示例已保留在统一入口的兼容工具章节。此记录仅可恢复归档,未删除工具、素材或设计。`;
|
|
await api('/api/notes/'+legacy,body(old,redirectText),'PUT');
|
|
await api('/api/posts/'+legacy+'/archive',{archived:true});
|
|
const entries=await api('/api/explore-feed?category='+encodeURIComponent('文档入口'));
|
|
const expected=['3c98946754c33309d73d5284','4ce3283fd98bb03a8fb39a19',canonical].sort();
|
|
if(entries.total!==3||entries.nextCursor||JSON.stringify(entries.entries.map(e=>e.id).sort())!==JSON.stringify(expected))throw Error('Document-entry category does not contain exactly the intended three posts');
|
|
const after=(await api('/api/notes/'+legacy)).entry;
|
|
if(!after.archived||!after.editableMarkdown.includes(canonical))throw Error('Legacy compatibility link missing');
|
|
console.log(JSON.stringify({canonical:base+'/explore/'+canonical,legacyArchived:true,documentEntryCount:entries.total}));
|