read-pressure-release.mjs 4.2 KB

123456789101112131415161718192021222324252627282930313233
  1. import ts from 'typescript';import {readFileSync} from 'node:fs';
  2. import {withXiaoshuRuntime} from './lib/xiaoshu-runtime-compat.mjs';
  3. function tree(source){return ts.createSourceFile('gateway.js',source,ts.ScriptTarget.Latest,true,ts.ScriptKind.JS);}
  4. function lastFunction(source,name){return tree(source).statements.filter(n=>ts.isFunctionDeclaration(n)&&n.name?.text===name).at(-1);}
  5. function patchFunction(source,nodeText,name){const node=lastFunction(source,name);return node?source.slice(0,node.getStart())+nodeText+source.slice(node.end):source+'\n'+nodeText+'\n';}
  6. export function patchReadPressureGateway(baseline,kind){
  7. const marker='// XIAOSHU_ISOLATED_RUNTIME_COMPAT_V1';let source=baseline;
  8. if(kind==='ops'){
  9. const history=readFileSync(new URL('./cloud/lesson-records.js',import.meta.url),'utf8'),parsed=tree(history);
  10. const owned=new Set(['lessonHistoryBase','lessonHistoryTypeRows','lessonHistoryRead','lessonHistoryPage','lessonHistoryPageData','lessonHistoryPlan']);
  11. for(const node of parsed.statements)if(ts.isFunctionDeclaration(node)&&owned.has(node.name.text))source=patchFunction(source,node.getText(parsed),node.name.text);
  12. if(!source.includes('const LESSON_RECORDS_VERSION='))source="const LESSON_RECORDS_VERSION='2026-10-13-lesson-records-v10';\n"+source;
  13. const exports=readFileSync(new URL('./cloud/lesson-export.js',import.meta.url),'utf8'),exportsTree=tree(exports);
  14. for(const node of exportsTree.statements)if(ts.isFunctionDeclaration(node))source=patchFunction(source,node.getText(exportsTree),node.name.text);
  15. const operations=['create','status','cancel','download','maintenance','claim','snapshot','chunk','finish','fail','release'];
  16. const handler=lastFunction(source,'xiaoshuBusinessHandler')||lastFunction(source,'handler');if(!handler)throw Error('Missing operations handler');
  17. let text=handler.getText();const anchor="if(operation==='ops/lessons/list')";if(!text.includes(anchor))throw Error('Missing lesson route anchor');
  18. const routes=operations.filter(name=>!text.includes("operation==='ops/lessons/export/"+name+"'")).map(name=>"if(operation==='ops/lessons/export/"+name+"') return response.json({success:true,data:await lessonExport"+name[0].toUpperCase()+name.slice(1)+"(context,input)});\n ").join('');
  19. text=text.replace(anchor,routes+anchor);source=source.slice(0,handler.getStart())+text+source.slice(handler.end);
  20. const version=lastFunction(source,'operationsScopeVersion');if(version&&!version.getText().includes("to_regprocedure('xs_read_version(text,text)')")){
  21. const replacement=version.getText().replace('{',`{\n const installed=await Psql.one("SELECT to_regprocedure('xs_read_version(text,text)') IS NOT NULL installed");if(installed.installed)return(await Psql.one('SELECT xs_read_version($1,$2) version',[companyId,scope])).version;\n`);source=source.slice(0,version.getStart())+replacement+source.slice(version.end);
  22. }
  23. const parsedSource=tree(source),store=parsedSource.statements.find(n=>ts.isVariableStatement(n)&&n.declarationList.declarations.some(d=>d.name.getText()==='STORE_OPERATIONS'));
  24. if(store&&!store.getText().includes('ops/lessons/export/create')){const replacement=store.getText().replace("'ops/lessons/list'", "'ops/lessons/export/create','ops/lessons/export/status','ops/lessons/export/cancel','ops/lessons/export/download','ops/lessons/list'");if(replacement===store.getText())throw Error('Missing store route anchor');source=source.slice(0,store.getStart())+replacement+source.slice(store.end);}
  25. }
  26. if(lastFunction(source,'xiaoshuBusinessHandler')){
  27. const oldWrapper=lastFunction(source,'handler');if(!oldWrapper?.getText().includes('resolveXiaoshuRuntime')||!oldWrapper.getText().includes('xiaoshuBusinessHandler'))throw Error('Unknown production runtime wrapper');
  28. const wrapper=withXiaoshuRuntime('async function handler(request,response){return null;}',{readPressure:kind}),parsed=tree(wrapper);
  29. const replace=new Set(['readPressurePolicy','readPressureStable','readPressureDb','dispatchReadPressure','handler']);
  30. for(const node of parsed.statements)if(ts.isFunctionDeclaration(node)&&replace.has(node.name.text))source=patchFunction(source,node.getText(parsed),node.name.text);
  31. }else source=withXiaoshuRuntime(source,{readPressure:kind});
  32. new Function(source);return source;
  33. }