`; const pkg=JSON.stringify({name:'sitewright-export',private:true,version:'1.0.0',type:'module',scripts:{dev:'vite',build:'vite build',preview:'vite preview'},dependencies:{'@vitejs/plugin-react':'latest',react:'latest','react-dom':'latest',vite:'latest'},devDependencies:{}},null,2); const vite=`import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nexport default defineConfig({plugins:[react()]});\n`; const redirects='/* /index.html 200\n'; const env='# Add public Vite variables here when required. Never put secrets in VITE_ variables.\n'; const readme=`# ${safeName}\n\nExported by SiteWright.\n\n## Deploy to Cloudflare Pages\n1. Extract this ZIP.\n2. Upload it to a GitHub or GitLab repository.\n3. Create a Cloudflare Pages project from the repository.\n4. Framework preset: **Vite**.\n5. Build command: **npm run build**.\n6. Build output directory: **dist**.\n7. Add any required environment variables in Cloudflare.\n\nThe exported project is a standard Vite + React project. Build it before deploying; do not upload <code>node_modules</code>.\n`; return {'package.json':pkg,'package-lock.json':JSON.stringify({name:'sitewright-export',version:'1.0.0',lockfileVersion:3,requires:true,packages:{'':{name:'sitewright-export',version:'1.0.0',dependencies:{'@vitejs/plugin-react':'latest',react:'latest','react-dom':'latest',vite:'latest'}}}},null,2),'vite.config.js':vite,'index.html':index,'src/main.jsx':main,'src/App.jsx':app,'src/styles.css':appCss,'public/_redirects':redirects,'.env.example':env,'README.md':readme}; } function validateFiles(files){const errors=[];const warnings=[];for(const k of ['package.json','vite.config.js','index.html','src/main.jsx','src/App.jsx','src/styles.css','public/_redirects','README.md'])if(!(k in files))errors.push('Missing '+k);try{const pkg=JSON.parse(files['package.json']);if(!pkg.scripts?.build)errors.push('Build script missing')}catch{errors.push('Invalid package.json')}if(/localhost|127\.0\.0\.1|C:\\\\|[A-Za-z]:\\\\/i.test(Object.values(files).join('\n')))warnings.push('Local development path detected');if(/api[_-]?key|secret|password|token\s*[:=]/i.test(files['src/App.jsx']))warnings.push('Possible secret-like text detected');return {errors,warnings}} async function runExport(){ const overlay=document.createElement('div');overlay.className='status-overlay';overlay.innerHTML='

Intelligent Cloudflare Export

Validating the exact project state before packaging.

';document.body.appendChild(overlay); const stages=['Saving latest changes','Synchronizing editor and code','Checking project structure','Checking dependencies','Checking TypeScript and JSX','Validating assets and paths','Checking Cloudflare routing','Running production-readiness checks','Running final clean validation','Creating ZIP'];const list=$('#stages',overlay);stages.forEach((s,i)=>{const d=document.createElement('div');d.className='stage';d.id='stage'+i;d.innerHTML=''+s+'Waiting';list.appendChild(d)}); const setStage=(i,cls,text)=>{$('#stage'+i,overlay).className='stage '+cls;$('#stage'+i+' small',overlay).textContent=text}; for(let i=0;isetTimeout(r,180));if(i===2){const files=generatedFiles();const v=validateFiles(files);if(v.errors.length){setStage(i,'failed','Failed');$('#result',overlay).innerHTML='
Export blocked.
'+esc(v.errors.join('; '))+'
';return}state._validated=files;state._warnings=v.warnings}if(i===3){if(!state._validated){setStage(i,'failed','Failed');return}}if(i===4){if(!state._validated['src/App.jsx'].includes('export default')){setStage(i,'failed','Failed');return}}if(i===5){for(const [k,v] of Object.entries(state._validated)){if(/https?:\/\/(localhost|127\.0\.0\.1)/i.test(v)){setStage(i,'failed','Failed');$('#result',overlay).innerHTML='
Local URL found in '+esc(k)+'
';return}}}if(i===6&&!state._validated['public/_redirects'].includes('/* /index.html 200')){setStage(i,'failed','Failed');return}if(i===8){const v=validateFiles(state._validated);if(v.errors.length){setStage(i,'failed','Failed');return}}setStage(i,'done','Passed')} const blob=await createZip(state._validated);const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='sitewright-cloudflare-pages-export.zip';a.click();setTimeout(()=>URL.revokeObjectURL(a.href),1500); const warnings=state._warnings||[];$('#result',overlay).innerHTML='
Ready for Cloudflare Pages.
The ZIP was generated from the validated project state.'+(warnings.length?'

Warnings: '+esc(warnings.join('; ')):'')+'
';$('#doneExport',overlay).addEventListener('click',()=>overlay.remove()); } function crc32(buf){let c=0xffffffff;for(let i=0;i>>1)^(c&1?0xedb88320:0)}return (c^0xffffffff)>>>0} function u16(n){return new Uint8Array([n&255,(n>>>8)&255])}function u32(n){return new Uint8Array([n&255,(n>>>8)&255,(n>>>16)&255,(n>>>24)&255])} function concat(parts){let len=parts.reduce((n,p)=>n+p.length,0),out=new Uint8Array(len),o=0;for(const p of parts){out.set(p,o);o+=p.length}return out} async function createZip(files){const enc=new TextEncoder();const chunks=[];const central=[];let offset=0;for(const [name,content] of Object.entries(files)){const nb=enc.encode(name),db=enc.encode(content),crc=crc32(db);const local=concat([new Uint8Array([80,75,3,4]),u16(20),u16(0),u16(0),u16(0),u16(0),u32(crc),u32(db.length),u32(db.length),u16(nb.length),u16(0),nb,db]);chunks.push(local);const c=concat([new Uint8Array([80,75,1,2]),u16(20),u16(20),u16(0),u16(0),u16(0),u16(0),u32(crc),u32(db.length),u32(db.length),u16(nb.length),u16(0),u16(0),u16(0),u16(0),u32(0),u32(offset),nb]);central.push(c);offset+=local.length}const centralSize=central.reduce((n,p)=>n+p.length,0);const eocd=concat([new Uint8Array([80,75,5,6]),u16(0),u16(0),u16(Object.keys(files).length),u16(Object.keys(files).length),u32(centralSize),u32(offset),u16(0)]);return new Blob([concat([...chunks,...central,eocd])],{type:'application/zip'})} render(); })();