import ts from 'typescript';import {readFileSync} from 'node:fs'; import {withXiaoshuRuntime} from './lib/xiaoshu-runtime-compat.mjs'; function tree(source){return ts.createSourceFile('gateway.js',source,ts.ScriptTarget.Latest,true,ts.ScriptKind.JS);} function lastFunction(source,name){return tree(source).statements.filter(n=>ts.isFunctionDeclaration(n)&&n.name?.text===name).at(-1);} 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';} export function patchReadPressureGateway(baseline,kind){ const marker='// XIAOSHU_ISOLATED_RUNTIME_COMPAT_V1';let source=baseline; if(kind==='ops'){ const history=readFileSync(new URL('./cloud/lesson-records.js',import.meta.url),'utf8'),parsed=tree(history); const owned=new Set(['lessonHistoryBase','lessonHistoryTypeRows','lessonHistoryRead','lessonHistoryPage','lessonHistoryPageData','lessonHistoryPlan']); for(const node of parsed.statements)if(ts.isFunctionDeclaration(node)&&owned.has(node.name.text))source=patchFunction(source,node.getText(parsed),node.name.text); if(!source.includes('const LESSON_RECORDS_VERSION='))source="const LESSON_RECORDS_VERSION='2026-10-13-lesson-records-v10';\n"+source; const exports=readFileSync(new URL('./cloud/lesson-export.js',import.meta.url),'utf8'),exportsTree=tree(exports); for(const node of exportsTree.statements)if(ts.isFunctionDeclaration(node))source=patchFunction(source,node.getText(exportsTree),node.name.text); const operations=['create','status','cancel','download','maintenance','claim','snapshot','chunk','finish','fail','release']; const handler=lastFunction(source,'xiaoshuBusinessHandler')||lastFunction(source,'handler');if(!handler)throw Error('Missing operations handler'); let text=handler.getText();const anchor="if(operation==='ops/lessons/list')";if(!text.includes(anchor))throw Error('Missing lesson route anchor'); 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(''); text=text.replace(anchor,routes+anchor);source=source.slice(0,handler.getStart())+text+source.slice(handler.end); const version=lastFunction(source,'operationsScopeVersion');if(version&&!version.getText().includes("to_regprocedure('xs_read_version(text,text)')")){ 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); } const parsedSource=tree(source),store=parsedSource.statements.find(n=>ts.isVariableStatement(n)&&n.declarationList.declarations.some(d=>d.name.getText()==='STORE_OPERATIONS')); 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);} } if(lastFunction(source,'xiaoshuBusinessHandler')){ const oldWrapper=lastFunction(source,'handler');if(!oldWrapper?.getText().includes('resolveXiaoshuRuntime')||!oldWrapper.getText().includes('xiaoshuBusinessHandler'))throw Error('Unknown production runtime wrapper'); const wrapper=withXiaoshuRuntime('async function handler(request,response){return null;}',{readPressure:kind}),parsed=tree(wrapper); const replace=new Set(['readPressurePolicy','readPressureStable','readPressureDb','dispatchReadPressure','handler']); for(const node of parsed.statements)if(ts.isFunctionDeclaration(node)&&replace.has(node.name.text))source=patchFunction(source,node.getText(parsed),node.name.text); }else source=withXiaoshuRuntime(source,{readPressure:kind}); new Function(source);return source; }