"use strict";var ie=Object.create;var _=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var le=Object.getPrototypeOf,ce=Object.prototype.hasOwnProperty;var ue=(e,r,t,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of ae(r))!ce.call(e,o)&&o!==t&&_(e,o,{get:()=>r[o],enumerable:!(i=se(r,o))||i.enumerable});return e};var de=(e,r,t)=>(t=e!=null?ie(le(e)):{},ue(r||!e||!e.__esModule?_(t,"default",{value:e,enumerable:!0}):t,e));const a=require("@php-wasm/logger"),N=require("@php-wasm/progress"),v=require("@php-wasm/universal"),$=require("@wp-playground/blueprints"),L=require("@wp-playground/common"),g=require("fs"),b=require("path"),X=require("worker_threads"),pe=require("@wp-playground/wordpress"),E=require("./mounts-D7bhhGq3.cjs"),R=require("fs-extra"),J=require("os"),fe=require("express"),we=require("@php-wasm/node"),he=require("wasm-feature-detect"),me=require("yargs"),M=require("@wp-playground/storage");var H=typeof document<"u"?document.currentScript:null;const z=b.join(J.homedir(),".wordpress-playground");async function ye(e){return await Y("https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip","sqlite.zip",e)}async function Y(e,r,t){const i=b.join(z,r);return R.existsSync(i)||(R.ensureDirSync(z),await ge(e,i,t)),Q(i)}async function ge(e,r,t){const o=(await t.monitorFetch(fetch(e))).body.getReader(),n=`${r}.partial`,l=R.createWriteStream(n);for(;;){const{done:u,value:d}=await o.read();if(d&&l.write(d),u)break}l.close(),l.closed||await new Promise((u,d)=>{l.on("finish",()=>{R.renameSync(n,r),u(null)}),l.on("error",A=>{R.removeSync(n),d(A)})})}function Q(e,r){return new File([R.readFileSync(e)],b.basename(e))}async function be(e){const r=fe(),t=await new Promise((n,l)=>{const u=r.listen(e.port,()=>{const d=u.address();d===null||typeof d=="string"?l(new Error("Server address is not available")):n(u)})});r.use("/",async(n,l)=>{const u=await e.handleRequest({url:n.url,headers:ke(n),method:n.method,body:await Pe(n)});l.statusCode=u.httpStatusCode;for(const d in u.headers)l.setHeader(d,u.headers[d]);l.end(u.bytes)});const o=t.address().port;return await e.onBind(t,o)}const Pe=async e=>await new Promise(r=>{const t=[];e.on("data",i=>{t.push(i)}),e.on("end",()=>{r(new Uint8Array(Buffer.concat(t)))})}),ke=e=>{const r={};if(e.rawHeaders&&e.rawHeaders.length)for(let t=0;t<e.rawHeaders.length;t+=2)r[e.rawHeaders[t].toLowerCase()]=e.rawHeaders[t+1];return r},ve=""+(typeof document>"u"?require("url").pathToFileURL(__dirname+"/worker-thread-CYvRK9UX.js").href:new URL("worker-thread-CYvRK9UX.js",document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"&&document.currentScript.src||document.baseURI).href);class Re{constructor(r){this.workerLoads=[],this.addWorker(r)}addWorker(r){this.workerLoads.push({worker:r,activeRequests:new Set})}async handleRequest(r){let t=this.workerLoads[0];for(let o=1;o<this.workerLoads.length;o++){const n=this.workerLoads[o];n.activeRequests.size<t.activeRequests.size&&(t=n)}const i=t.worker.request(r);return t.activeRequests.add(i),i.url=r.url,i.finally(()=>{t.activeRequests.delete(i)})}}function We(e){return/^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e)}class K extends Error{constructor(r,t){super(r,{...t,cause:{isReportableInCLI:!0}}),this.isReportableInCLI=!0,this.isReportableInCLI=!0}static getReportableCause(r){let t=0;const i=15,o=[r];for(;o.length>0&&t<i;){const n=o.pop();if(n instanceof Error){if(n.isReportableInCLI)return n;Array.isArray(n.cause)?o.push(...n.cause):o.push(n.cause),t++,t>=i&&a.logger.warn("Recursion limit exceeded while checking if error is reportable")}}return null}}async function Se({sourceString:e,blueprintMayReadAdjacentFiles:r}){if(!e)return;if(e.startsWith("http://")||e.startsWith("https://"))return await $.resolveRemoteBlueprint(e);let t=b.resolve(process.cwd(),e);if(!g.existsSync(t))throw new Error(`Blueprint file does not exist: ${t}`);const i=g.statSync(t);if(i.isDirectory()&&(t=b.join(t,"blueprint.json")),!i.isFile()&&i.isSymbolicLink())throw new Error(`Blueprint path is neither a file nor a directory: ${t}`);const o=b.extname(t);switch(o){case".zip":return M.ZipFilesystem.fromArrayBuffer(g.readFileSync(t).buffer);case".json":{const n=g.readFileSync(t,"utf-8");try{JSON.parse(n)}catch{throw new Error(`Blueprint file at ${t} is not a valid JSON file`)}const l=b.dirname(t),u=new M.NodeJsFilesystem(l);return new M.OverlayFilesystem([new M.InMemoryFilesystem({"blueprint.json":n}),{read(d){if(!r)throw new K(`Error: Blueprint contained tried to read a local file at path "${d}" (via a resource of type "bundled"). Playground restricts access to local resources by default as a security measure. 

You can allow this Blueprint to read files from the same parent directory by explicitly adding the --blueprint-may-read-adjacent-files option to your command.`);return u.read(d)}}])}default:throw new Error(`Unsupported blueprint file extension: ${o}. Only .zip and .json files are supported.`)}}async function xe(){const e=me(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command",{describe:"Command to run",choices:["server","run-blueprint","build-snapshot"],demandOption:!0}).option("outfile",{describe:"When building, write to this output file.",type:"string",default:"wordpress.zip"}).option("port",{describe:"Port to listen on when serving.",type:"number",default:9400}).option("php",{describe:"PHP version to use.",type:"string",default:L.RecommendedPHPVersion,choices:v.SupportedPHPVersions}).option("wp",{describe:"WordPress version to use.",type:"string",default:"latest"}).option("mount",{describe:"Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path",type:"array",string:!0,coerce:E.parseMountWithDelimiterArguments}).option("mount-before-install",{describe:"Mount a directory to the PHP runtime before WordPress installation (can be used multiple times). Format: /host/path:/vfs/path",type:"array",string:!0,coerce:E.parseMountWithDelimiterArguments}).option("mount-dir",{describe:'Mount a directory to the PHP runtime (can be used multiple times). Format: "/host/path" "/vfs/path"',type:"array",nargs:2,array:!0}).option("mount-dir-before-install",{describe:'Mount a directory before WordPress installation (can be used multiple times). Format: "/host/path" "/vfs/path"',type:"string",nargs:2,array:!0,coerce:E.parseMountDirArguments}).option("login",{describe:"Should log the user in",type:"boolean",default:!1}).option("blueprint",{describe:"Blueprint to execute.",type:"string"}).option("blueprint-may-read-adjacent-files",{describe:'Consent flag: Allow "bundled" resources in a local blueprint to read files in the same directory as the blueprint file.',type:"boolean",default:!1}).option("skip-wordpress-setup",{describe:"Do not download, unzip, and install WordPress. Useful for mounting a pre-configured WordPress directory at /wordpress.",type:"boolean",default:!1}).option("skip-sqlite-setup",{describe:"Skip the SQLite integration plugin setup to allow the WordPress site to use MySQL.",type:"boolean",default:!1}).option("quiet",{describe:"Do not output logs and progress messages.",type:"boolean",default:!1}).option("debug",{describe:"Print PHP error log content if an error occurs during Playground boot.",type:"boolean",default:!1}).option("auto-mount",{describe:"Automatically mount the current working directory. You can mount a WordPress directory, a plugin directory, a theme directory, a wp-content directory, or any directory containing PHP and HTML files.",type:"boolean",default:!1}).option("follow-symlinks",{describe:`Allow Playground to follow symlinks by automatically mounting symlinked directories and files encountered in mounted directories. 
Warning: Following symlinks will expose files outside mounted directories to Playground and could be a security risk.`,type:"boolean",default:!1}).option("experimentalTrace",{describe:"Print detailed messages about system behavior to the console. Useful for troubleshooting.",type:"boolean",default:!1,hidden:!0}).option("internal-cookie-store",{describe:"Enable internal cookie handling. When enabled, Playground will manage cookies internally using an HttpCookieStore that persists cookies across requests. When disabled, cookies are handled externally (e.g., by a browser in Node.js environments).",type:"boolean",default:!1}).option("xdebug",{describe:"Enable Xdebug.",type:"boolean",default:!1}).option("experimentalMultiWorker",{describe:"Enable experimental multi-worker support which requires JSPI and a /wordpress directory backed by a real filesystem. Pass a positive number to specify the number of workers to use. Otherwise, default to the number of CPUs minus 1.",type:"number",coerce:o=>o??J.cpus().length-1}).showHelpOnFail(!1).check(async o=>{if(o.wp!==void 0&&!We(o.wp))try{new URL(o.wp)}catch{throw new Error('Unrecognized WordPress version. Please use "latest", a URL, or a numeric version such as "6.2", "6.0.1", "6.2-beta1", or "6.2-RC1"')}if(o.experimentalMultiWorker!==void 0){if(o.experimentalMultiWorker<=1)throw new Error("The --experimentalMultiWorker flag must be a positive integer greater than 1.");const n=l=>l.vfsPath==="/wordpress";if(!o.mount?.some(n)&&!o["mount-before-install"]?.some(n))throw new Error("Please mount a real filesystem directory as the /wordpress directory before using the --experimentalMultiWorker flag.")}return!0});e.wrap(e.terminalWidth());const r=await e.argv,t=r._[0];["run-blueprint","server","build-snapshot"].includes(t)||(e.showHelp(),process.exit(1));const i={...r,command:t,blueprint:await Se({sourceString:r.blueprint,blueprintMayReadAdjacentFiles:r.blueprintMayReadAdjacentFiles}),mount:[...r.mount||[],...r["mount-dir"]||[]],"mount-before-install":[...r["mount-before-install"]||[],...r["mount-dir-before-install"]||[]]};try{return G(i)}catch(o){const n=K.getReportableCause(o);if(n)console.log(""),console.log(n.message),process.exit(1);else throw o}}async function G(e){let r,t;const i=[];e.autoMount&&(e=E.expandAutoMounts(e));async function o(s){await t.run({code:`<?php
			$zip = new ZipArchive();
			if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
				throw new Exception('Failed to create ZIP');
			}
			$files = new RecursiveIteratorIterator(
				new RecursiveDirectoryIterator('/wordpress')
			);
			foreach ($files as $file) {
				echo $file . PHP_EOL;
				if (!$file->isFile()) {
					continue;
				}
				$zip->addFile($file->getPathname(), $file->getPathname());
			}
			$zip->close();

		`});const c=await t.readFileAsBuffer("/tmp/build.zip");g.writeFileSync(s,c)}async function n(s){const c=$.isBlueprintBundle(e.blueprint)?e.blueprint:{login:e.login,...e.blueprint,preferredVersions:{php:e.php??e?.blueprint?.preferredVersions?.php??L.RecommendedPHPVersion,wp:e.wp??e?.blueprint?.preferredVersions?.wp??"latest",...e.blueprint?.preferredVersions||{}}},f=new N.ProgressTracker;let h="",w=!1;return f.addEventListener("progress",p=>{if(w)return;w=p.detail.progress===100;const S=Math.floor(p.detail.progress);h=p.detail.caption||h||"Running the Blueprint";const P=`${h.trim()} – ${S}%`;e.quiet||u(process.stdout,P,w)}),await $.compileBlueprint(c,{progress:f,additionalSteps:s})}let l="";function u(s,c,f){c!==l&&(l=c,s.isTTY?(s.cursorTo(0),s.write(c),s.clearLine(1),f&&s.write(`
`)):s.write(`${c}
`))}async function d(s){const c=new X.Worker(s);return new Promise((f,h)=>{c.once("message",function(w){w.command==="worker-script-initialized"&&f({worker:c,phpPort:w.phpPort})}),c.once("error",function(w){console.error(w);const p=new Error(`Worker failed to load at ${s}. ${w.message?`Original error: ${w.message}`:""}`);p.filename=s,h(p)})})}function A(s){const c=new URL(ve,typeof document>"u"?require("url").pathToFileURL(__filename).href:H&&H.tagName.toUpperCase()==="SCRIPT"&&H.src||new URL("run-cli-B5BfXxxJ.cjs",document.baseURI).href),f=[];for(let h=0;h<s;h++)f.push(d(c));return Promise.all(f)}e.quiet&&(a.logger.handlers=[]);const W=await n(e["additional-blueprint-steps"]||[]),ee=await import("fs-ext").then(s=>s.flockSync).catch(()=>{a.logger.warn("The fs-ext package is not installed. Internal file locking will not be integrated with host OS file locking.")}),U=new we.FileLockManagerForNode(ee);async function T(){const{port1:s,port2:c}=new X.MessageChannel;return await he.jspi()?v.exposeAPI(U,null,s):await v.exposeSyncAPI(U,s),c}let j=!1;return a.logger.log("Starting a PHP server..."),be({port:e.port,onBind:async(s,c)=>{const f=`http://127.0.0.1:${c}`,h=e.experimentalMultiWorker??1,w=A(h);a.logger.log(`Setting up WordPress ${e.wp}`);let p;const S=new N.EmscriptenDownloadMonitor;if(!e.skipWordPressSetup){let m=!1;S.addEventListener("progress",k=>{if(m)return;const{loaded:C,total:B}=k.detail,F=Math.floor(Math.min(100,100*C/B));m=F===100,e.quiet||u(process.stdout,`Downloading WordPress ${F}%...`,m)}),p=await pe.resolveWordPressRelease(e.wp),a.logger.log(`Resolved WordPress release URL: ${p?.releaseUrl}`)}const P=p&&b.join(z,`prebuilt-wp-content-for-wp-${p.version}.zip`),D=p?g.existsSync(P)?Q(P):await Y(p.releaseUrl,`${p.version}.zip`,S):void 0;a.logger.log("Fetching SQLite integration plugin...");const te=e.skipSqliteSetup?void 0:await ye(S),O=e.followSymlinks===!0,Z=e.experimentalTrace===!0;try{const m=e["mount-before-install"]||[],k=e.mount||[],[C,...B]=await w;t=v.consumeAPI(C.phpPort),i.push({playground:t,worker:C.worker}),await t.isConnected();const F=await T();a.logger.log("Booting WordPress...");const I=Math.floor(Number.MAX_SAFE_INTEGER/h);if(await t.useFileLockManager(F),await t.boot({phpVersion:W.versions.php,wpVersion:W.versions.wp,absoluteUrl:f,mountsBeforeWpInstall:m,mountsAfterWpInstall:k,wordPressZip:D&&await D.arrayBuffer(),sqliteIntegrationPluginZip:await te.arrayBuffer(),firstProcessId:0,processIdSpaceLength:I,followSymlinks:O,trace:Z,internalCookieStore:e.internalCookieStore,withXdebug:e.xdebug}),p&&!e["mount-before-install"]&&!g.existsSync(P)&&(a.logger.log("Caching preinstalled WordPress for the next boot..."),g.writeFileSync(P,await L.zipDirectory(t,"/wordpress")),a.logger.log("Cached!")),r=new Re(t),await t.isReady(),j=!0,a.logger.log("Booted!"),W&&(a.logger.log("Running the Blueprint..."),await $.runBlueprintSteps(W,t),a.logger.log("Finished running the blueprint")),e.command==="build-snapshot"?(await o(e.outfile),a.logger.log(`WordPress exported to ${e.outfile}`),process.exit(0)):e.command==="run-blueprint"&&(a.logger.log("Blueprint executed"),process.exit(0)),e.experimentalMultiWorker&&e.experimentalMultiWorker>1){a.logger.log("Preparing additional workers...");const V=await L.zipDirectory(t,"/internal"),x=I;await Promise.all(B.map(async(q,re)=>{const y=v.consumeAPI(q.phpPort);i.push({playground:y,worker:q.worker}),await y.isConnected();const oe=x+re*I,ne=await T();await y.useFileLockManager(ne),await y.boot({phpVersion:W.versions.php,absoluteUrl:f,mountsBeforeWpInstall:m,mountsAfterWpInstall:k,wordPressZip:void 0,sqliteIntegrationPluginZip:void 0,dataSqlPath:"/wordpress/wp-content/database/.ht.sqlite",firstProcessId:oe,processIdSpaceLength:I,followSymlinks:O,trace:Z,internalCookieStore:e.internalCookieStore,withXdebug:e.xdebug}),await y.isReady(),await y.writeFile("/tmp/internal.zip",V),await L.unzipFile(y,"/tmp/internal.zip","/internal"),await y.unlink("/tmp/internal.zip"),r.addWorker(y)})),a.logger.log("Ready!")}return a.logger.log(`WordPress is running on ${f}`),{playground:t,server:s,[Symbol.asyncDispose]:async function(){await Promise.all(i.map(async({playground:x,worker:q})=>{await x.dispose(),await q.terminate()})),await new Promise(x=>s.close(x))}}}catch(m){if(!e.debug)throw m;const k=await t.readFileAsText(a.errorLogPath);throw new Error(k,{cause:m})}},async handleRequest(s){return j?await r.handleRequest(s):v.PHPResponse.forHttpCode(502,"WordPress is not ready yet")}})}exports.parseOptionsAndRunCLI=xe;exports.runCLI=G;
//# sourceMappingURL=run-cli-B5BfXxxJ.cjs.map
