/** Offline modern-ESM reconstruction. Only trusted virtual-file plugin executes. */ import {createHash} from 'node:crypto'; import {createRequire} from 'node:module'; import {pathToFileURL} from 'node:url'; import path from 'node:path'; import {buildArtifactPlan} from './build_artifact_plan.mjs'; import {moduleReferences} from './module_references.mjs'; const require=createRequire(import.meta.url); const viteRequire=createRequire(require.resolve('vite/package.json')); const {rolldown,VERSION}=await import(pathToFileURL(viteRequire.resolve('rolldown')).href); const sha=b=>createHash('sha256').update(b).digest('hex'); const fail=s=>{throw Error(s);}; const safe=s=>typeof s==='string'&&s.length<=512&&!s.startsWith('/')&&!/[\\%?#:\s]/.test(s)&&s.split('/').every(x=>x&&x!=='.'&&x!=='..'); export async function buildDeclaredModule(pkg,importer,policy){ if(policy!=='modern-esm-bundle-v1')fail('EXPLICIT_BUILD_POLICY_REQUIRED'); const records=pkg?.repository?.files; if(!records||Object.keys(records).length>64||!safe(importer))fail('BUILD_PACKAGE_BUDGET'); const files=new Map();let total=0; for(const [name,r] of Object.entries(records)){ const body=Buffer.from(r.base64,'base64');total+=body.length; if(!safe(name)||body.length!==r.bytes||sha(body)!==r.sha256||total>2097152)fail('BUILD_SOURCE_BINDING'); files.set(name,body); } const text=name=>{if(!files.has(name))fail('BUILD_INPUT_MISSING');return new TextDecoder('utf-8',{fatal:true}).decode(files.get(name));}; const plan=buildArtifactPlan(text('rollup.config.js'),text('package.json')); const aliases=new Map(); for(const m of plan.mappings.filter(m=>m.format==='es')){ if(aliases.has(m.destination)||files.has(m.destination))fail('BUILD_MAPPING_AMBIGUOUS'); aliases.set(m.destination,m.input); } if(!aliases.size)fail('BUILD_ES_MAPPING_REQUIRED'); const used=new Map(); const resolve=name=>{ if(!safe(name))fail('BUILD_PATH_DENIED'); const candidates=path.posix.extname(name)?[name]:[name,name+'.js',name+'.mjs',name+'/index.js',name+'/index.mjs']; const found=candidates.filter(n=>files.has(n)||aliases.has(n)); if(found.length!==1)fail('BUILD_MODULE_MISSING_OR_AMBIGUOUS'); const chosen=found[0];if(!/\.(m?js)$/.test(chosen))fail('BUILD_MODULE_TYPE'); return chosen; }; const prefix='\0chameleon:'; const bundle=await rolldown({input:importer,treeshake:false,plugins:[{ name:'captured-files-only', resolveId(specifier,from){ if(!from)return prefix+resolve(specifier); if(!from.startsWith(prefix)||!specifier.startsWith('./')&&!specifier.startsWith('../'))fail('BUILD_EXTERNAL_IMPORT_DENIED'); const logical=from.slice(prefix.length),source=aliases.get(logical)??logical; return prefix+resolve(path.posix.normalize(path.posix.join(path.posix.dirname(source),specifier))); }, load(id){ if(!id.startsWith(prefix))fail('BUILD_HOST_READ_DENIED'); const logical=id.slice(prefix.length),source=aliases.get(logical)??logical; const body=text(source);if(moduleReferences(body).dynamic_imports)fail('BUILD_DYNAMIC_IMPORT_DENIED'); used.set(logical,{source,sha256:sha(files.get(source))});return body; } }]}); let generated; try{generated=await bundle.generate({format:'es',minify:true,sourcemap:false});}finally{await bundle.close();} if(generated.output.length!==1||generated.output[0].type!=='chunk')fail('BUILD_OUTPUT_SHAPE'); const body=Buffer.from(generated.output[0].code); if(body.length>65536)fail('BUILD_OUTPUT_BUDGET'); return {version:'modern-esm-build-candidate-v1',status:'UNVERIFIED_CANDIDATE',source_digest:pkg.digest, importer,policy,tool:{name:'rolldown',version:VERSION},plan,used:Object.fromEntries(used), after_base64:body.toString('base64'),after_sha256:sha(body),bytes:body.length, scope:'Trusted modern ESM bundling over captured virtual files; original plugins not executed; original build equivalence and application behavior unverified'}; } if(process.argv[1]&&import.meta.url===pathToFileURL(path.resolve(process.argv[1])).href){ const chunks=[];let size=0; for await(const chunk of process.stdin){size+=chunk.length;if(size>8388608)fail('BUILD_INPUT_BUDGET');chunks.push(chunk);} const r=JSON.parse(Buffer.concat(chunks).toString('utf8')); process.stdout.write(JSON.stringify(await buildDeclaredModule(r.package,r.importer,r.policy))); }