@wp-playground/cli 1.0.29 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/download.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EmscriptenDownloadMonitor } from '@php-wasm/progress';
1
+ import type { EmscriptenDownloadMonitor } from '@php-wasm/progress';
2
2
  export declare const CACHE_FOLDER: string;
3
3
  export declare function fetchSqliteIntegration(monitor: EmscriptenDownloadMonitor): Promise<File>;
4
4
  export declare function cachedDownload(remoteUrl: string, cacheKey: string, monitor: EmscriptenDownloadMonitor): Promise<File>;
package/index.cjs CHANGED
@@ -1,22 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("fs"),m=require("path"),D=require("express"),x=require("@php-wasm/universal"),l=require("@php-wasm/logger"),B=require("@wp-playground/blueprints"),W=require("@php-wasm/progress"),H=require("@php-wasm/node"),I=require("@wp-playground/common"),E=require("@wp-playground/wordpress"),A=require("tls"),P=require("fs-extra"),M=require("os");async function U(e){const s=D(),n=await new Promise((c,i)=>{const o=s.listen(e.port,()=>{const d=o.address();d===null||typeof d=="string"?i(new Error("Server address is not available")):c(o)})});s.use("/",async(c,i)=>{const o=await e.handleRequest({url:c.url,headers:T(c),method:c.method,body:await _(c)});i.statusCode=o.httpStatusCode;for(const d in o.headers)i.setHeader(d,o.headers[d]);i.end(o.bytes)});const g=n.address().port;return await e.onBind(n,g)}const _=async e=>await new Promise(s=>{const n=[];e.on("data",f=>{n.push(f)}),e.on("end",()=>{s(new Uint8Array(Buffer.concat(n)))})}),T=e=>{const s={};if(e.rawHeaders&&e.rawHeaders.length)for(let n=0;n<e.rawHeaders.length;n+=2)s[e.rawHeaders[n].toLowerCase()]=e.rawHeaders[n+1];return s},$=m.join(M.homedir(),".wordpress-playground");async function Z(e){return await S("https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/main.zip","sqlite.zip",e)}async function S(e,s,n){const f=m.join($,s);return P.existsSync(f)||(P.ensureDirSync($),await k(e,f,n)),F(f)}async function k(e,s,n){const g=(await n.monitorFetch(fetch(e))).body.getReader(),c=`${s}.partial`,i=P.createWriteStream(c);for(;;){const{done:o,value:d}=await g.read();if(d&&i.write(d),o)break}i.close(),i.closed||await new Promise((o,d)=>{i.on("finish",t=>{t?(P.removeSync(c),d(t)):(P.renameSync(c,s),o(null))})})}function F(e,s){return new File([P.readFileSync(e)],s??m.basename(e))}async function j(e){e.quiet&&(l.logger.handlers=[]);async function s(t){const{php:a,reap:p}=await o.processManager.acquirePHPInstance();try{await a.run({code:`<?php
2
- $zip = new ZipArchive();
3
- if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
4
- throw new Exception('Failed to create ZIP');
5
- }
6
- $files = new RecursiveIteratorIterator(
7
- new RecursiveDirectoryIterator('/wordpress')
8
- );
9
- foreach ($files as $file) {
10
- echo $file . PHP_EOL;
11
- if (!$file->isFile()) {
12
- continue;
13
- }
14
- $zip->addFile($file->getPathname(), $file->getPathname());
15
- }
16
- $zip->close();
17
-
18
- `});const r=a.readFileAsBuffer("/tmp/build.zip");b.writeFileSync(t,r)}finally{p()}}function n(t,a){const p=a.map(r=>{const[h,w]=r.split(":");return{hostPath:m.resolve(process.cwd(),h),vfsPath:w}});for(const r of p)t.mkdir(r.vfsPath),t.mount(r.vfsPath,H.createNodeFsMountHandler(r.hostPath))}function f(){let t;e.blueprint?t=e.blueprint:t={preferredVersions:{php:e.php??I.RecommendedPHPVersion,wp:e.wp??"latest"},login:e.login};const a=new W.ProgressTracker;let p="",r=!1;return a.addEventListener("progress",h=>{if(r)return;r=h.detail.progress===100;const w=Math.floor(h.detail.progress);p=h.detail.caption||p||"Running the Blueprint";const v=`${p.trim()} – ${w}%`;e.quiet||c(process.stdout,v,r)}),B.compileBlueprint(t,{progress:a})}let g="";function c(t,a,p){a!==g&&(g=a,t.isTTY?(t.cursorTo(0),t.write(a),t.clearLine(1),p&&t.write(`
19
- `)):t.write(`${a}
20
- `))}const i=f();let o,d=!1;return l.logger.log("Starting a PHP server..."),U({port:e.port,onBind:async(t,a)=>{const p=`http://127.0.0.1:${a}`;l.logger.log(`Setting up WordPress ${e.wp}`);let r;const h=new W.EmscriptenDownloadMonitor;if(!e.skipWordPressSetup){let u=!1;h.addEventListener("progress",y=>{if(u)return;const{loaded:z,total:L}=y.detail,q=Math.floor(Math.min(100,100*z/L));u=q===100,e.quiet||c(process.stdout,`Downloading WordPress ${q}%...`,u)}),r=await E.resolveWordPressRelease(e.wp)}l.logger.log(`Resolved WordPress release URL: ${r?.releaseUrl}`);const w=r&&m.join($,`prebuilt-wp-content-for-wp-${r.version}.zip`),v=r?b.existsSync(w)?F(w):await S(r.releaseUrl,`${r.version}.zip`,h):void 0,C={WP_DEBUG:!0,WP_DEBUG_LOG:!0,WP_DEBUG_DISPLAY:!1};l.logger.log("Booting WordPress..."),o=await E.bootWordPress({siteUrl:p,createPhpRuntime:async()=>await H.loadNodeRuntime(i.versions.php),wordPressZip:v,sqliteIntegrationPluginZip:Z(h),sapiName:"cli",createFiles:{"/internal/shared/ca-bundle.crt":A.rootCertificates.join(`
21
- `)},constants:C,phpIniEntries:{"openssl.cafile":"/internal/shared/ca-bundle.crt",allow_url_fopen:"1",disable_functions:""},hooks:{async beforeWordPressFiles(u){e.mountBeforeInstall&&n(u,e.mountBeforeInstall)}}}),l.logger.log("Booted!");const R=await o.getPrimaryPhp();try{if(r&&!e.mountBeforeInstall&&!b.existsSync(w)&&(l.logger.log("Caching preinstalled WordPress for the next boot..."),b.writeFileSync(w,await I.zipDirectory(R,"/wordpress")),l.logger.log("Cached!")),e.mount&&n(R,e.mount),d=!0,i){const{php:u,reap:y}=await o.processManager.acquirePHPInstance();try{l.logger.log("Running the Blueprint..."),await B.runBlueprintSteps(i,u),l.logger.log("Finished running the blueprint")}finally{y()}}return e.command==="build-snapshot"?(await s(e.outfile),l.logger.log(`WordPress exported to ${e.outfile}`),process.exit(0)):e.command==="run-blueprint"?(l.logger.log("Blueprint executed"),process.exit(0)):l.logger.log(`WordPress is running on ${p}`),{requestHandler:o,server:t}}catch(u){if(!e.debug)throw u;const y=R.readFileAsText(l.errorLogPath);throw new Error(y,{cause:u})}},async handleRequest(t){return d?await o.request(t):x.PHPResponse.forHttpCode(502,"WordPress is not ready yet")}})}exports.runCLI=j;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./run-cli-BSw9FKSW.cjs");exports.runCLI=e.runCLI;
22
2
  //# sourceMappingURL=index.cjs.map
package/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../packages/playground/cli/src/server.ts","../../../../packages/playground/cli/src/download.ts","../../../../packages/playground/cli/src/run-cli.ts"],"sourcesContent":["import type { PHPRequest, PHPResponse } from '@php-wasm/universal';\nimport type { Request } from 'express';\nimport express from 'express';\nimport type { IncomingMessage, Server, ServerResponse } from 'http';\nimport type { AddressInfo } from 'net';\nimport type { RunCLIServer } from './run-cli';\n\nexport interface ServerOptions {\n\tport: number;\n\tonBind: (server: Server, port: number) => Promise<RunCLIServer>;\n\thandleRequest: (request: PHPRequest) => Promise<PHPResponse>;\n}\n\nexport async function startServer(\n\toptions: ServerOptions\n): Promise<RunCLIServer> {\n\tconst app = express();\n\n\tconst server = await new Promise<\n\t\tServer<typeof IncomingMessage, typeof ServerResponse>\n\t>((resolve, reject) => {\n\t\tconst server = app.listen(options.port, () => {\n\t\t\tconst address = server.address();\n\t\t\tif (address === null || typeof address === 'string') {\n\t\t\t\treject(new Error('Server address is not available'));\n\t\t\t} else {\n\t\t\t\tresolve(server);\n\t\t\t}\n\t\t});\n\t});\n\n\tapp.use('/', async (req, res) => {\n\t\tconst phpResponse = await options.handleRequest({\n\t\t\turl: req.url,\n\t\t\theaders: parseHeaders(req),\n\t\t\tmethod: req.method as any,\n\t\t\tbody: await bufferRequestBody(req),\n\t\t});\n\n\t\tres.statusCode = phpResponse.httpStatusCode;\n\t\tfor (const key in phpResponse.headers) {\n\t\t\tres.setHeader(key, phpResponse.headers[key]);\n\t\t}\n\t\tres.end(phpResponse.bytes);\n\t});\n\n\tconst address = server.address();\n\tconst port = (address! as AddressInfo).port;\n\treturn await options.onBind(server, port);\n}\n\nconst bufferRequestBody = async (req: Request): Promise<Uint8Array> =>\n\tawait new Promise((resolve) => {\n\t\tconst body: Uint8Array[] = [];\n\t\treq.on('data', (chunk) => {\n\t\t\tbody.push(chunk);\n\t\t});\n\t\treq.on('end', () => {\n\t\t\tresolve(new Uint8Array(Buffer.concat(body)));\n\t\t});\n\t});\n\nconst parseHeaders = (req: Request): Record<string, string> => {\n\tconst requestHeaders: Record<string, string> = {};\n\tif (req.rawHeaders && req.rawHeaders.length) {\n\t\tfor (let i = 0; i < req.rawHeaders.length; i += 2) {\n\t\t\trequestHeaders[req.rawHeaders[i].toLowerCase()] =\n\t\t\t\treq.rawHeaders[i + 1];\n\t\t}\n\t}\n\treturn requestHeaders;\n};\n","import { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport fs from 'fs-extra';\nimport os from 'os';\nimport path, { basename } from 'path';\n\nexport const CACHE_FOLDER = path.join(os.homedir(), '.wordpress-playground');\n\nexport async function fetchSqliteIntegration(\n\tmonitor: EmscriptenDownloadMonitor\n) {\n\tconst sqliteZip = await cachedDownload(\n\t\t'https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/main.zip',\n\t\t'sqlite.zip',\n\t\tmonitor\n\t);\n\treturn sqliteZip;\n}\n\n// @TODO: Support HTTP cache, invalidate the local file if the remote file has\n// changed\nexport async function cachedDownload(\n\tremoteUrl: string,\n\tcacheKey: string,\n\tmonitor: EmscriptenDownloadMonitor\n) {\n\tconst artifactPath = path.join(CACHE_FOLDER, cacheKey);\n\tif (!fs.existsSync(artifactPath)) {\n\t\tfs.ensureDirSync(CACHE_FOLDER);\n\t\tawait downloadTo(remoteUrl, artifactPath, monitor);\n\t}\n\treturn readAsFile(artifactPath);\n}\n\nasync function downloadTo(\n\tremoteUrl: string,\n\tlocalPath: string,\n\tmonitor: EmscriptenDownloadMonitor\n) {\n\tconst response = await monitor.monitorFetch(fetch(remoteUrl));\n\tconst reader = response.body!.getReader();\n\tconst tmpPath = `${localPath}.partial`;\n\tconst writer = fs.createWriteStream(tmpPath);\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (value) {\n\t\t\twriter.write(value);\n\t\t}\n\t\tif (done) {\n\t\t\tbreak;\n\t\t}\n\t}\n\twriter.close();\n\tif (!writer.closed) {\n\t\tawait new Promise((resolve, reject) => {\n\t\t\twriter.on('finish', (err: any) => {\n\t\t\t\tif (err) {\n\t\t\t\t\tfs.removeSync(tmpPath);\n\t\t\t\t\treject(err);\n\t\t\t\t} else {\n\t\t\t\t\tfs.renameSync(tmpPath, localPath);\n\t\t\t\t\tresolve(null);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n}\n\nexport function readAsFile(path: string, fileName?: string): File {\n\treturn new File([fs.readFileSync(path)], fileName ?? basename(path));\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { startServer } from './server';\nimport {\n\tPHP,\n\tPHPRequest,\n\tPHPRequestHandler,\n\tPHPResponse,\n\tSupportedPHPVersion,\n} from '@php-wasm/universal';\nimport { logger, errorLogPath } from '@php-wasm/logger';\nimport {\n\tBlueprint,\n\tcompileBlueprint,\n\trunBlueprintSteps,\n} from '@wp-playground/blueprints';\nimport type { Server } from 'http';\nimport { EmscriptenDownloadMonitor, ProgressTracker } from '@php-wasm/progress';\nimport { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node';\nimport { RecommendedPHPVersion, zipDirectory } from '@wp-playground/common';\nimport { bootWordPress } from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport {\n\tCACHE_FOLDER,\n\tcachedDownload,\n\tfetchSqliteIntegration,\n\treadAsFile,\n} from './download';\nimport { resolveWordPressRelease } from '@wp-playground/wordpress';\n\nexport interface RunCLIArgs {\n\tblueprint?: Blueprint;\n\tcommand: 'server' | 'run-blueprint' | 'build-snapshot';\n\tdebug?: boolean;\n\tlogin?: boolean;\n\tmount?: string[];\n\tmountBeforeInstall?: string[];\n\toutfile?: string;\n\tphp?: SupportedPHPVersion;\n\tport?: number;\n\tquiet?: boolean;\n\tskipWordPressSetup?: boolean;\n\twp?: string;\n}\n\nexport interface RunCLIServer {\n\trequestHandler: PHPRequestHandler;\n\tserver: Server;\n}\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\nexport async function runCLI(args: RunCLIArgs): Promise<RunCLIServer> {\n\tif (args.quiet) {\n\t\t// @ts-ignore\n\t\tlogger.handlers = [];\n\t}\n\n\t/**\n\t * TODO: This exact feature will be provided in the PHP Blueprints library.\n\t * Let's use it when it ships. Let's also use it in the web Playground\n\t * app.\n\t */\n\tasync function zipSite(outfile: string) {\n\t\t// Fake URL for the build\n\t\tconst { php, reap } =\n\t\t\tawait requestHandler.processManager.acquirePHPInstance();\n\t\ttry {\n\t\t\tawait php.run({\n\t\t\t\tcode: `<?php\n\t\t\t\t$zip = new ZipArchive();\n\t\t\t\tif(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {\n\t\t\t\t\tthrow new Exception('Failed to create ZIP');\n\t\t\t\t}\n\t\t\t\t$files = new RecursiveIteratorIterator(\n\t\t\t\t\tnew RecursiveDirectoryIterator('/wordpress')\n\t\t\t\t);\n\t\t\t\tforeach ($files as $file) {\n\t\t\t\t\techo $file . PHP_EOL;\n\t\t\t\t\tif (!$file->isFile()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t$zip->addFile($file->getPathname(), $file->getPathname());\n\t\t\t\t}\n\t\t\t\t$zip->close();\n\n\t\t\t`,\n\t\t\t});\n\t\t\tconst zip = php.readFileAsBuffer('/tmp/build.zip');\n\t\t\tfs.writeFileSync(outfile, zip);\n\t\t} finally {\n\t\t\treap();\n\t\t}\n\t}\n\n\tfunction mountResources(php: PHP, rawMounts: string[]) {\n\t\tconst parsedMounts = rawMounts.map((mount) => {\n\t\t\tconst [source, vfsPath] = mount.split(':');\n\t\t\treturn {\n\t\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\t\tvfsPath,\n\t\t\t};\n\t\t});\n\t\tfor (const mount of parsedMounts) {\n\t\t\tphp.mkdir(mount.vfsPath);\n\t\t\tphp.mount(mount.vfsPath, createNodeFsMountHandler(mount.hostPath));\n\t\t}\n\t}\n\n\tfunction compileInputBlueprint() {\n\t\t/**\n\t\t * @TODO This looks similar to the resolveBlueprint() call in the website package:\n\t\t * \t https://github.com/WordPress/wordpress-playground/blob/ce586059e5885d185376184fdd2f52335cca32b0/packages/playground/website/src/main.tsx#L41\n\t\t *\n\t\t * \t\t Also the Blueprint Builder tool does something similar.\n\t\t * Perhaps all these cases could be handled by the same function?\n\t\t */\n\t\tlet blueprint: Blueprint | undefined;\n\t\tif (args.blueprint) {\n\t\t\tblueprint = args.blueprint as Blueprint;\n\t\t} else {\n\t\t\tblueprint = {\n\t\t\t\tpreferredVersions: {\n\t\t\t\t\tphp: args.php ?? RecommendedPHPVersion,\n\t\t\t\t\twp: args.wp ?? 'latest',\n\t\t\t\t},\n\t\t\t\tlogin: args.login,\n\t\t\t};\n\t\t}\n\n\t\tconst tracker = new ProgressTracker();\n\t\tlet lastCaption = '';\n\t\tlet progressReached100 = false;\n\t\ttracker.addEventListener('progress', (e: any) => {\n\t\t\tif (progressReached100) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprogressReached100 = e.detail.progress === 100;\n\n\t\t\t// Use floor() so we don't report 100% until truly there.\n\t\t\tconst progressInteger = Math.floor(e.detail.progress);\n\t\t\tlastCaption =\n\t\t\t\te.detail.caption || lastCaption || 'Running the Blueprint';\n\t\t\tconst message = `${lastCaption.trim()} – ${progressInteger}%`;\n\t\t\tif (!args.quiet) {\n\t\t\t\twriteProgressUpdate(\n\t\t\t\t\tprocess.stdout,\n\t\t\t\t\tmessage,\n\t\t\t\t\tprogressReached100\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\treturn compileBlueprint(blueprint as Blueprint, {\n\t\t\tprogress: tracker,\n\t\t});\n\t}\n\n\tlet lastProgressMessage = '';\n\tfunction writeProgressUpdate(\n\t\twriteStream: NodeJS.WriteStream,\n\t\tmessage: string,\n\t\tfinalUpdate: boolean\n\t) {\n\t\tif (message === lastProgressMessage) {\n\t\t\t// Avoid repeating the same message\n\t\t\treturn;\n\t\t}\n\t\tlastProgressMessage = message;\n\n\t\tif (writeStream.isTTY) {\n\t\t\t// Overwrite previous progress updates in-place for a quieter UX.\n\t\t\twriteStream.cursorTo(0);\n\t\t\twriteStream.write(message);\n\t\t\twriteStream.clearLine(1);\n\n\t\t\tif (finalUpdate) {\n\t\t\t\twriteStream.write('\\n');\n\t\t\t}\n\t\t} else {\n\t\t\t// Fall back to writing one line per progress update\n\t\t\twriteStream.write(`${message}\\n`);\n\t\t}\n\t}\n\n\tconst compiledBlueprint = compileInputBlueprint();\n\n\tlet requestHandler: PHPRequestHandler;\n\tlet wordPressReady = false;\n\n\tlogger.log('Starting a PHP server...');\n\n\treturn startServer({\n\t\tport: args['port'] as number,\n\t\tonBind: async (server: Server, port: number): Promise<RunCLIServer> => {\n\t\t\tconst absoluteUrl = `http://127.0.0.1:${port}`;\n\n\t\t\tlogger.log(`Setting up WordPress ${args.wp}`);\n\t\t\tlet wpDetails: any = undefined;\n\t\t\t// @TODO: Rename to FetchProgressMonitor. There's nothing Emscripten\n\t\t\t// about that class anymore.\n\t\t\tconst monitor = new EmscriptenDownloadMonitor();\n\t\t\tif (!args.skipWordPressSetup) {\n\t\t\t\tlet progressReached100 = false;\n\t\t\t\tmonitor.addEventListener('progress', ((\n\t\t\t\t\te: CustomEvent<ProgressEvent & { finished: boolean }>\n\t\t\t\t) => {\n\t\t\t\t\tif (progressReached100) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// @TODO Every progress bar will want percentages. The\n\t\t\t\t\t// download monitor should just provide that.\n\t\t\t\t\tconst { loaded, total } = e.detail;\n\t\t\t\t\t// Use floor() so we don't report 100% until truly there.\n\t\t\t\t\tconst percentProgress = Math.floor(\n\t\t\t\t\t\tMath.min(100, (100 * loaded) / total)\n\t\t\t\t\t);\n\t\t\t\t\tprogressReached100 = percentProgress === 100;\n\n\t\t\t\t\tif (!args.quiet) {\n\t\t\t\t\t\twriteProgressUpdate(\n\t\t\t\t\t\t\tprocess.stdout,\n\t\t\t\t\t\t\t`Downloading WordPress ${percentProgress}%...`,\n\t\t\t\t\t\t\tprogressReached100\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}) as any);\n\n\t\t\t\twpDetails = await resolveWordPressRelease(args.wp);\n\t\t\t}\n\t\t\tlogger.log(\n\t\t\t\t`Resolved WordPress release URL: ${wpDetails?.releaseUrl}`\n\t\t\t);\n\n\t\t\tconst preinstalledWpContentPath =\n\t\t\t\twpDetails &&\n\t\t\t\tpath.join(\n\t\t\t\t\tCACHE_FOLDER,\n\t\t\t\t\t`prebuilt-wp-content-for-wp-${wpDetails.version}.zip`\n\t\t\t\t);\n\t\t\tconst wordPressZip = !wpDetails\n\t\t\t\t? undefined\n\t\t\t\t: fs.existsSync(preinstalledWpContentPath)\n\t\t\t\t? readAsFile(preinstalledWpContentPath)\n\t\t\t\t: await cachedDownload(\n\t\t\t\t\t\twpDetails.releaseUrl,\n\t\t\t\t\t\t`${wpDetails.version}.zip`,\n\t\t\t\t\t\tmonitor\n\t\t\t\t );\n\n\t\t\tconst constants: Record<string, string | number | boolean | null> =\n\t\t\t\t{\n\t\t\t\t\tWP_DEBUG: true,\n\t\t\t\t\tWP_DEBUG_LOG: true,\n\t\t\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t\t\t};\n\n\t\t\tlogger.log(`Booting WordPress...`);\n\t\t\trequestHandler = await bootWordPress({\n\t\t\t\tsiteUrl: absoluteUrl,\n\t\t\t\tcreatePhpRuntime: async () =>\n\t\t\t\t\tawait loadNodeRuntime(compiledBlueprint.versions.php),\n\t\t\t\twordPressZip,\n\t\t\t\tsqliteIntegrationPluginZip: fetchSqliteIntegration(monitor),\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles: {\n\t\t\t\t\t'/internal/shared/ca-bundle.crt':\n\t\t\t\t\t\trootCertificates.join('\\n'),\n\t\t\t\t},\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries: {\n\t\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t\t\tallow_url_fopen: '1',\n\t\t\t\t\tdisable_functions: '',\n\t\t\t\t},\n\t\t\t\thooks: {\n\t\t\t\t\tasync beforeWordPressFiles(php) {\n\t\t\t\t\t\tif (args.mountBeforeInstall) {\n\t\t\t\t\t\t\tmountResources(php, args.mountBeforeInstall);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t\tlogger.log(`Booted!`);\n\n\t\t\tconst php = await requestHandler.getPrimaryPhp();\n\t\t\ttry {\n\t\t\t\tif (\n\t\t\t\t\twpDetails &&\n\t\t\t\t\t!args.mountBeforeInstall &&\n\t\t\t\t\t!fs.existsSync(preinstalledWpContentPath)\n\t\t\t\t) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t`Caching preinstalled WordPress for the next boot...`\n\t\t\t\t\t);\n\t\t\t\t\tfs.writeFileSync(\n\t\t\t\t\t\tpreinstalledWpContentPath,\n\t\t\t\t\t\tawait zipDirectory(php, '/wordpress')\n\t\t\t\t\t);\n\t\t\t\t\tlogger.log(`Cached!`);\n\t\t\t\t}\n\n\t\t\t\tif (args.mount) {\n\t\t\t\t\tmountResources(php, args.mount);\n\t\t\t\t}\n\n\t\t\t\twordPressReady = true;\n\n\t\t\t\tif (compiledBlueprint) {\n\t\t\t\t\tconst { php, reap } =\n\t\t\t\t\t\tawait requestHandler.processManager.acquirePHPInstance();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlogger.log(`Running the Blueprint...`);\n\t\t\t\t\t\tawait runBlueprintSteps(compiledBlueprint, php);\n\t\t\t\t\t\tlogger.log(`Finished running the blueprint`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\treap();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (args.command === 'build-snapshot') {\n\t\t\t\t\tawait zipSite(args.outfile as string);\n\t\t\t\t\tlogger.log(`WordPress exported to ${args.outfile}`);\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t} else if (args.command === 'run-blueprint') {\n\t\t\t\t\tlogger.log(`Blueprint executed`);\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(`WordPress is running on ${absoluteUrl}`);\n\t\t\t\t}\n\n\t\t\t\treturn { requestHandler, server };\n\t\t\t} catch (error) {\n\t\t\t\tif (!args.debug) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst phpLogs = php.readFileAsText(errorLogPath);\n\t\t\t\tthrow new Error(phpLogs, { cause: error });\n\t\t\t}\n\t\t},\n\t\tasync handleRequest(request: PHPRequest) {\n\t\t\tif (!wordPressReady) {\n\t\t\t\treturn PHPResponse.forHttpCode(\n\t\t\t\t\t502,\n\t\t\t\t\t'WordPress is not ready yet'\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn await requestHandler.request(request);\n\t\t},\n\t});\n}\n"],"names":["startServer","options","app","express","server","resolve","reject","address","req","res","phpResponse","parseHeaders","bufferRequestBody","key","port","body","chunk","requestHeaders","i","CACHE_FOLDER","path","os","fetchSqliteIntegration","monitor","cachedDownload","remoteUrl","cacheKey","artifactPath","fs","downloadTo","readAsFile","localPath","reader","tmpPath","writer","done","value","err","fileName","basename","runCLI","args","logger","zipSite","outfile","php","reap","requestHandler","zip","mountResources","rawMounts","parsedMounts","mount","source","vfsPath","createNodeFsMountHandler","compileInputBlueprint","blueprint","RecommendedPHPVersion","tracker","ProgressTracker","lastCaption","progressReached100","e","progressInteger","message","writeProgressUpdate","compileBlueprint","lastProgressMessage","writeStream","finalUpdate","compiledBlueprint","wordPressReady","absoluteUrl","wpDetails","EmscriptenDownloadMonitor","loaded","total","percentProgress","resolveWordPressRelease","preinstalledWpContentPath","wordPressZip","constants","bootWordPress","loadNodeRuntime","rootCertificates","zipDirectory","runBlueprintSteps","error","phpLogs","errorLogPath","request","PHPResponse"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/index.js CHANGED
@@ -1,247 +1,5 @@
1
- import g from "fs";
2
- import b, { basename as S } from "path";
3
- import z from "express";
4
- import { PHPResponse as C } from "@php-wasm/universal";
5
- import { logger as c, errorLogPath as x } from "@php-wasm/logger";
6
- import { runBlueprintSteps as D, compileBlueprint as L } from "@wp-playground/blueprints";
7
- import { EmscriptenDownloadMonitor as A, ProgressTracker as U } from "@php-wasm/progress";
8
- import { loadNodeRuntime as _, createNodeFsMountHandler as q } from "@php-wasm/node";
9
- import { zipDirectory as M, RecommendedPHPVersion as T } from "@wp-playground/common";
10
- import { resolveWordPressRelease as Z, bootWordPress as k } from "@wp-playground/wordpress";
11
- import { rootCertificates as j } from "tls";
12
- import P from "fs-extra";
13
- import G from "os";
14
- async function O(e) {
15
- const n = z(), s = await new Promise((l, i) => {
16
- const o = n.listen(e.port, () => {
17
- const p = o.address();
18
- p === null || typeof p == "string" ? i(new Error("Server address is not available")) : l(o);
19
- });
20
- });
21
- n.use("/", async (l, i) => {
22
- const o = await e.handleRequest({
23
- url: l.url,
24
- headers: V(l),
25
- method: l.method,
26
- body: await N(l)
27
- });
28
- i.statusCode = o.httpStatusCode;
29
- for (const p in o.headers)
30
- i.setHeader(p, o.headers[p]);
31
- i.end(o.bytes);
32
- });
33
- const m = s.address().port;
34
- return await e.onBind(s, m);
35
- }
36
- const N = async (e) => await new Promise((n) => {
37
- const s = [];
38
- e.on("data", (f) => {
39
- s.push(f);
40
- }), e.on("end", () => {
41
- n(new Uint8Array(Buffer.concat(s)));
42
- });
43
- }), V = (e) => {
44
- const n = {};
45
- if (e.rawHeaders && e.rawHeaders.length)
46
- for (let s = 0; s < e.rawHeaders.length; s += 2)
47
- n[e.rawHeaders[s].toLowerCase()] = e.rawHeaders[s + 1];
48
- return n;
49
- }, $ = b.join(G.homedir(), ".wordpress-playground");
50
- async function Y(e) {
51
- return await W(
52
- "https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/main.zip",
53
- "sqlite.zip",
54
- e
55
- );
56
- }
57
- async function W(e, n, s) {
58
- const f = b.join($, n);
59
- return P.existsSync(f) || (P.ensureDirSync($), await J(e, f, s)), H(f);
60
- }
61
- async function J(e, n, s) {
62
- const m = (await s.monitorFetch(fetch(e))).body.getReader(), l = `${n}.partial`, i = P.createWriteStream(l);
63
- for (; ; ) {
64
- const { done: o, value: p } = await m.read();
65
- if (p && i.write(p), o)
66
- break;
67
- }
68
- i.close(), i.closed || await new Promise((o, p) => {
69
- i.on("finish", (t) => {
70
- t ? (P.removeSync(l), p(t)) : (P.renameSync(l, n), o(null));
71
- });
72
- });
73
- }
74
- function H(e, n) {
75
- return new File([P.readFileSync(e)], n ?? S(e));
76
- }
77
- async function ce(e) {
78
- e.quiet && (c.handlers = []);
79
- async function n(t) {
80
- const { php: a, reap: d } = await o.processManager.acquirePHPInstance();
81
- try {
82
- await a.run({
83
- code: `<?php
84
- $zip = new ZipArchive();
85
- if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
86
- throw new Exception('Failed to create ZIP');
87
- }
88
- $files = new RecursiveIteratorIterator(
89
- new RecursiveDirectoryIterator('/wordpress')
90
- );
91
- foreach ($files as $file) {
92
- echo $file . PHP_EOL;
93
- if (!$file->isFile()) {
94
- continue;
95
- }
96
- $zip->addFile($file->getPathname(), $file->getPathname());
97
- }
98
- $zip->close();
99
-
100
- `
101
- });
102
- const r = a.readFileAsBuffer("/tmp/build.zip");
103
- g.writeFileSync(t, r);
104
- } finally {
105
- d();
106
- }
107
- }
108
- function s(t, a) {
109
- const d = a.map((r) => {
110
- const [h, w] = r.split(":");
111
- return {
112
- hostPath: b.resolve(process.cwd(), h),
113
- vfsPath: w
114
- };
115
- });
116
- for (const r of d)
117
- t.mkdir(r.vfsPath), t.mount(r.vfsPath, q(r.hostPath));
118
- }
119
- function f() {
120
- let t;
121
- e.blueprint ? t = e.blueprint : t = {
122
- preferredVersions: {
123
- php: e.php ?? T,
124
- wp: e.wp ?? "latest"
125
- },
126
- login: e.login
127
- };
128
- const a = new U();
129
- let d = "", r = !1;
130
- return a.addEventListener("progress", (h) => {
131
- if (r)
132
- return;
133
- r = h.detail.progress === 100;
134
- const w = Math.floor(h.detail.progress);
135
- d = h.detail.caption || d || "Running the Blueprint";
136
- const v = `${d.trim()} – ${w}%`;
137
- e.quiet || l(
138
- process.stdout,
139
- v,
140
- r
141
- );
142
- }), L(t, {
143
- progress: a
144
- });
145
- }
146
- let m = "";
147
- function l(t, a, d) {
148
- a !== m && (m = a, t.isTTY ? (t.cursorTo(0), t.write(a), t.clearLine(1), d && t.write(`
149
- `)) : t.write(`${a}
150
- `));
151
- }
152
- const i = f();
153
- let o, p = !1;
154
- return c.log("Starting a PHP server..."), O({
155
- port: e.port,
156
- onBind: async (t, a) => {
157
- const d = `http://127.0.0.1:${a}`;
158
- c.log(`Setting up WordPress ${e.wp}`);
159
- let r;
160
- const h = new A();
161
- if (!e.skipWordPressSetup) {
162
- let u = !1;
163
- h.addEventListener("progress", (y) => {
164
- if (u)
165
- return;
166
- const { loaded: I, total: F } = y.detail, B = Math.floor(
167
- Math.min(100, 100 * I / F)
168
- );
169
- u = B === 100, e.quiet || l(
170
- process.stdout,
171
- `Downloading WordPress ${B}%...`,
172
- u
173
- );
174
- }), r = await Z(e.wp);
175
- }
176
- c.log(
177
- `Resolved WordPress release URL: ${r?.releaseUrl}`
178
- );
179
- const w = r && b.join(
180
- $,
181
- `prebuilt-wp-content-for-wp-${r.version}.zip`
182
- ), v = r ? g.existsSync(w) ? H(w) : await W(
183
- r.releaseUrl,
184
- `${r.version}.zip`,
185
- h
186
- ) : void 0, E = {
187
- WP_DEBUG: !0,
188
- WP_DEBUG_LOG: !0,
189
- WP_DEBUG_DISPLAY: !1
190
- };
191
- c.log("Booting WordPress..."), o = await k({
192
- siteUrl: d,
193
- createPhpRuntime: async () => await _(i.versions.php),
194
- wordPressZip: v,
195
- sqliteIntegrationPluginZip: Y(h),
196
- sapiName: "cli",
197
- createFiles: {
198
- "/internal/shared/ca-bundle.crt": j.join(`
199
- `)
200
- },
201
- constants: E,
202
- phpIniEntries: {
203
- "openssl.cafile": "/internal/shared/ca-bundle.crt",
204
- allow_url_fopen: "1",
205
- disable_functions: ""
206
- },
207
- hooks: {
208
- async beforeWordPressFiles(u) {
209
- e.mountBeforeInstall && s(u, e.mountBeforeInstall);
210
- }
211
- }
212
- }), c.log("Booted!");
213
- const R = await o.getPrimaryPhp();
214
- try {
215
- if (r && !e.mountBeforeInstall && !g.existsSync(w) && (c.log(
216
- "Caching preinstalled WordPress for the next boot..."
217
- ), g.writeFileSync(
218
- w,
219
- await M(R, "/wordpress")
220
- ), c.log("Cached!")), e.mount && s(R, e.mount), p = !0, i) {
221
- const { php: u, reap: y } = await o.processManager.acquirePHPInstance();
222
- try {
223
- c.log("Running the Blueprint..."), await D(i, u), c.log("Finished running the blueprint");
224
- } finally {
225
- y();
226
- }
227
- }
228
- return e.command === "build-snapshot" ? (await n(e.outfile), c.log(`WordPress exported to ${e.outfile}`), process.exit(0)) : e.command === "run-blueprint" ? (c.log("Blueprint executed"), process.exit(0)) : c.log(`WordPress is running on ${d}`), { requestHandler: o, server: t };
229
- } catch (u) {
230
- if (!e.debug)
231
- throw u;
232
- const y = R.readFileAsText(x);
233
- throw new Error(y, { cause: u });
234
- }
235
- },
236
- async handleRequest(t) {
237
- return p ? await o.request(t) : C.forHttpCode(
238
- 502,
239
- "WordPress is not ready yet"
240
- );
241
- }
242
- });
243
- }
1
+ import { r as a } from "./run-cli-_8y4VW5F.js";
244
2
  export {
245
- ce as runCLI
3
+ a as runCLI
246
4
  };
247
5
  //# sourceMappingURL=index.js.map
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../packages/playground/cli/src/server.ts","../../../../packages/playground/cli/src/download.ts","../../../../packages/playground/cli/src/run-cli.ts"],"sourcesContent":["import type { PHPRequest, PHPResponse } from '@php-wasm/universal';\nimport type { Request } from 'express';\nimport express from 'express';\nimport type { IncomingMessage, Server, ServerResponse } from 'http';\nimport type { AddressInfo } from 'net';\nimport type { RunCLIServer } from './run-cli';\n\nexport interface ServerOptions {\n\tport: number;\n\tonBind: (server: Server, port: number) => Promise<RunCLIServer>;\n\thandleRequest: (request: PHPRequest) => Promise<PHPResponse>;\n}\n\nexport async function startServer(\n\toptions: ServerOptions\n): Promise<RunCLIServer> {\n\tconst app = express();\n\n\tconst server = await new Promise<\n\t\tServer<typeof IncomingMessage, typeof ServerResponse>\n\t>((resolve, reject) => {\n\t\tconst server = app.listen(options.port, () => {\n\t\t\tconst address = server.address();\n\t\t\tif (address === null || typeof address === 'string') {\n\t\t\t\treject(new Error('Server address is not available'));\n\t\t\t} else {\n\t\t\t\tresolve(server);\n\t\t\t}\n\t\t});\n\t});\n\n\tapp.use('/', async (req, res) => {\n\t\tconst phpResponse = await options.handleRequest({\n\t\t\turl: req.url,\n\t\t\theaders: parseHeaders(req),\n\t\t\tmethod: req.method as any,\n\t\t\tbody: await bufferRequestBody(req),\n\t\t});\n\n\t\tres.statusCode = phpResponse.httpStatusCode;\n\t\tfor (const key in phpResponse.headers) {\n\t\t\tres.setHeader(key, phpResponse.headers[key]);\n\t\t}\n\t\tres.end(phpResponse.bytes);\n\t});\n\n\tconst address = server.address();\n\tconst port = (address! as AddressInfo).port;\n\treturn await options.onBind(server, port);\n}\n\nconst bufferRequestBody = async (req: Request): Promise<Uint8Array> =>\n\tawait new Promise((resolve) => {\n\t\tconst body: Uint8Array[] = [];\n\t\treq.on('data', (chunk) => {\n\t\t\tbody.push(chunk);\n\t\t});\n\t\treq.on('end', () => {\n\t\t\tresolve(new Uint8Array(Buffer.concat(body)));\n\t\t});\n\t});\n\nconst parseHeaders = (req: Request): Record<string, string> => {\n\tconst requestHeaders: Record<string, string> = {};\n\tif (req.rawHeaders && req.rawHeaders.length) {\n\t\tfor (let i = 0; i < req.rawHeaders.length; i += 2) {\n\t\t\trequestHeaders[req.rawHeaders[i].toLowerCase()] =\n\t\t\t\treq.rawHeaders[i + 1];\n\t\t}\n\t}\n\treturn requestHeaders;\n};\n","import { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport fs from 'fs-extra';\nimport os from 'os';\nimport path, { basename } from 'path';\n\nexport const CACHE_FOLDER = path.join(os.homedir(), '.wordpress-playground');\n\nexport async function fetchSqliteIntegration(\n\tmonitor: EmscriptenDownloadMonitor\n) {\n\tconst sqliteZip = await cachedDownload(\n\t\t'https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/main.zip',\n\t\t'sqlite.zip',\n\t\tmonitor\n\t);\n\treturn sqliteZip;\n}\n\n// @TODO: Support HTTP cache, invalidate the local file if the remote file has\n// changed\nexport async function cachedDownload(\n\tremoteUrl: string,\n\tcacheKey: string,\n\tmonitor: EmscriptenDownloadMonitor\n) {\n\tconst artifactPath = path.join(CACHE_FOLDER, cacheKey);\n\tif (!fs.existsSync(artifactPath)) {\n\t\tfs.ensureDirSync(CACHE_FOLDER);\n\t\tawait downloadTo(remoteUrl, artifactPath, monitor);\n\t}\n\treturn readAsFile(artifactPath);\n}\n\nasync function downloadTo(\n\tremoteUrl: string,\n\tlocalPath: string,\n\tmonitor: EmscriptenDownloadMonitor\n) {\n\tconst response = await monitor.monitorFetch(fetch(remoteUrl));\n\tconst reader = response.body!.getReader();\n\tconst tmpPath = `${localPath}.partial`;\n\tconst writer = fs.createWriteStream(tmpPath);\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (value) {\n\t\t\twriter.write(value);\n\t\t}\n\t\tif (done) {\n\t\t\tbreak;\n\t\t}\n\t}\n\twriter.close();\n\tif (!writer.closed) {\n\t\tawait new Promise((resolve, reject) => {\n\t\t\twriter.on('finish', (err: any) => {\n\t\t\t\tif (err) {\n\t\t\t\t\tfs.removeSync(tmpPath);\n\t\t\t\t\treject(err);\n\t\t\t\t} else {\n\t\t\t\t\tfs.renameSync(tmpPath, localPath);\n\t\t\t\t\tresolve(null);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n}\n\nexport function readAsFile(path: string, fileName?: string): File {\n\treturn new File([fs.readFileSync(path)], fileName ?? basename(path));\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { startServer } from './server';\nimport {\n\tPHP,\n\tPHPRequest,\n\tPHPRequestHandler,\n\tPHPResponse,\n\tSupportedPHPVersion,\n} from '@php-wasm/universal';\nimport { logger, errorLogPath } from '@php-wasm/logger';\nimport {\n\tBlueprint,\n\tcompileBlueprint,\n\trunBlueprintSteps,\n} from '@wp-playground/blueprints';\nimport type { Server } from 'http';\nimport { EmscriptenDownloadMonitor, ProgressTracker } from '@php-wasm/progress';\nimport { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node';\nimport { RecommendedPHPVersion, zipDirectory } from '@wp-playground/common';\nimport { bootWordPress } from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport {\n\tCACHE_FOLDER,\n\tcachedDownload,\n\tfetchSqliteIntegration,\n\treadAsFile,\n} from './download';\nimport { resolveWordPressRelease } from '@wp-playground/wordpress';\n\nexport interface RunCLIArgs {\n\tblueprint?: Blueprint;\n\tcommand: 'server' | 'run-blueprint' | 'build-snapshot';\n\tdebug?: boolean;\n\tlogin?: boolean;\n\tmount?: string[];\n\tmountBeforeInstall?: string[];\n\toutfile?: string;\n\tphp?: SupportedPHPVersion;\n\tport?: number;\n\tquiet?: boolean;\n\tskipWordPressSetup?: boolean;\n\twp?: string;\n}\n\nexport interface RunCLIServer {\n\trequestHandler: PHPRequestHandler;\n\tserver: Server;\n}\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\nexport async function runCLI(args: RunCLIArgs): Promise<RunCLIServer> {\n\tif (args.quiet) {\n\t\t// @ts-ignore\n\t\tlogger.handlers = [];\n\t}\n\n\t/**\n\t * TODO: This exact feature will be provided in the PHP Blueprints library.\n\t * Let's use it when it ships. Let's also use it in the web Playground\n\t * app.\n\t */\n\tasync function zipSite(outfile: string) {\n\t\t// Fake URL for the build\n\t\tconst { php, reap } =\n\t\t\tawait requestHandler.processManager.acquirePHPInstance();\n\t\ttry {\n\t\t\tawait php.run({\n\t\t\t\tcode: `<?php\n\t\t\t\t$zip = new ZipArchive();\n\t\t\t\tif(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {\n\t\t\t\t\tthrow new Exception('Failed to create ZIP');\n\t\t\t\t}\n\t\t\t\t$files = new RecursiveIteratorIterator(\n\t\t\t\t\tnew RecursiveDirectoryIterator('/wordpress')\n\t\t\t\t);\n\t\t\t\tforeach ($files as $file) {\n\t\t\t\t\techo $file . PHP_EOL;\n\t\t\t\t\tif (!$file->isFile()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t$zip->addFile($file->getPathname(), $file->getPathname());\n\t\t\t\t}\n\t\t\t\t$zip->close();\n\n\t\t\t`,\n\t\t\t});\n\t\t\tconst zip = php.readFileAsBuffer('/tmp/build.zip');\n\t\t\tfs.writeFileSync(outfile, zip);\n\t\t} finally {\n\t\t\treap();\n\t\t}\n\t}\n\n\tfunction mountResources(php: PHP, rawMounts: string[]) {\n\t\tconst parsedMounts = rawMounts.map((mount) => {\n\t\t\tconst [source, vfsPath] = mount.split(':');\n\t\t\treturn {\n\t\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\t\tvfsPath,\n\t\t\t};\n\t\t});\n\t\tfor (const mount of parsedMounts) {\n\t\t\tphp.mkdir(mount.vfsPath);\n\t\t\tphp.mount(mount.vfsPath, createNodeFsMountHandler(mount.hostPath));\n\t\t}\n\t}\n\n\tfunction compileInputBlueprint() {\n\t\t/**\n\t\t * @TODO This looks similar to the resolveBlueprint() call in the website package:\n\t\t * \t https://github.com/WordPress/wordpress-playground/blob/ce586059e5885d185376184fdd2f52335cca32b0/packages/playground/website/src/main.tsx#L41\n\t\t *\n\t\t * \t\t Also the Blueprint Builder tool does something similar.\n\t\t * Perhaps all these cases could be handled by the same function?\n\t\t */\n\t\tlet blueprint: Blueprint | undefined;\n\t\tif (args.blueprint) {\n\t\t\tblueprint = args.blueprint as Blueprint;\n\t\t} else {\n\t\t\tblueprint = {\n\t\t\t\tpreferredVersions: {\n\t\t\t\t\tphp: args.php ?? RecommendedPHPVersion,\n\t\t\t\t\twp: args.wp ?? 'latest',\n\t\t\t\t},\n\t\t\t\tlogin: args.login,\n\t\t\t};\n\t\t}\n\n\t\tconst tracker = new ProgressTracker();\n\t\tlet lastCaption = '';\n\t\tlet progressReached100 = false;\n\t\ttracker.addEventListener('progress', (e: any) => {\n\t\t\tif (progressReached100) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprogressReached100 = e.detail.progress === 100;\n\n\t\t\t// Use floor() so we don't report 100% until truly there.\n\t\t\tconst progressInteger = Math.floor(e.detail.progress);\n\t\t\tlastCaption =\n\t\t\t\te.detail.caption || lastCaption || 'Running the Blueprint';\n\t\t\tconst message = `${lastCaption.trim()} – ${progressInteger}%`;\n\t\t\tif (!args.quiet) {\n\t\t\t\twriteProgressUpdate(\n\t\t\t\t\tprocess.stdout,\n\t\t\t\t\tmessage,\n\t\t\t\t\tprogressReached100\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\treturn compileBlueprint(blueprint as Blueprint, {\n\t\t\tprogress: tracker,\n\t\t});\n\t}\n\n\tlet lastProgressMessage = '';\n\tfunction writeProgressUpdate(\n\t\twriteStream: NodeJS.WriteStream,\n\t\tmessage: string,\n\t\tfinalUpdate: boolean\n\t) {\n\t\tif (message === lastProgressMessage) {\n\t\t\t// Avoid repeating the same message\n\t\t\treturn;\n\t\t}\n\t\tlastProgressMessage = message;\n\n\t\tif (writeStream.isTTY) {\n\t\t\t// Overwrite previous progress updates in-place for a quieter UX.\n\t\t\twriteStream.cursorTo(0);\n\t\t\twriteStream.write(message);\n\t\t\twriteStream.clearLine(1);\n\n\t\t\tif (finalUpdate) {\n\t\t\t\twriteStream.write('\\n');\n\t\t\t}\n\t\t} else {\n\t\t\t// Fall back to writing one line per progress update\n\t\t\twriteStream.write(`${message}\\n`);\n\t\t}\n\t}\n\n\tconst compiledBlueprint = compileInputBlueprint();\n\n\tlet requestHandler: PHPRequestHandler;\n\tlet wordPressReady = false;\n\n\tlogger.log('Starting a PHP server...');\n\n\treturn startServer({\n\t\tport: args['port'] as number,\n\t\tonBind: async (server: Server, port: number): Promise<RunCLIServer> => {\n\t\t\tconst absoluteUrl = `http://127.0.0.1:${port}`;\n\n\t\t\tlogger.log(`Setting up WordPress ${args.wp}`);\n\t\t\tlet wpDetails: any = undefined;\n\t\t\t// @TODO: Rename to FetchProgressMonitor. There's nothing Emscripten\n\t\t\t// about that class anymore.\n\t\t\tconst monitor = new EmscriptenDownloadMonitor();\n\t\t\tif (!args.skipWordPressSetup) {\n\t\t\t\tlet progressReached100 = false;\n\t\t\t\tmonitor.addEventListener('progress', ((\n\t\t\t\t\te: CustomEvent<ProgressEvent & { finished: boolean }>\n\t\t\t\t) => {\n\t\t\t\t\tif (progressReached100) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// @TODO Every progress bar will want percentages. The\n\t\t\t\t\t// download monitor should just provide that.\n\t\t\t\t\tconst { loaded, total } = e.detail;\n\t\t\t\t\t// Use floor() so we don't report 100% until truly there.\n\t\t\t\t\tconst percentProgress = Math.floor(\n\t\t\t\t\t\tMath.min(100, (100 * loaded) / total)\n\t\t\t\t\t);\n\t\t\t\t\tprogressReached100 = percentProgress === 100;\n\n\t\t\t\t\tif (!args.quiet) {\n\t\t\t\t\t\twriteProgressUpdate(\n\t\t\t\t\t\t\tprocess.stdout,\n\t\t\t\t\t\t\t`Downloading WordPress ${percentProgress}%...`,\n\t\t\t\t\t\t\tprogressReached100\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}) as any);\n\n\t\t\t\twpDetails = await resolveWordPressRelease(args.wp);\n\t\t\t}\n\t\t\tlogger.log(\n\t\t\t\t`Resolved WordPress release URL: ${wpDetails?.releaseUrl}`\n\t\t\t);\n\n\t\t\tconst preinstalledWpContentPath =\n\t\t\t\twpDetails &&\n\t\t\t\tpath.join(\n\t\t\t\t\tCACHE_FOLDER,\n\t\t\t\t\t`prebuilt-wp-content-for-wp-${wpDetails.version}.zip`\n\t\t\t\t);\n\t\t\tconst wordPressZip = !wpDetails\n\t\t\t\t? undefined\n\t\t\t\t: fs.existsSync(preinstalledWpContentPath)\n\t\t\t\t? readAsFile(preinstalledWpContentPath)\n\t\t\t\t: await cachedDownload(\n\t\t\t\t\t\twpDetails.releaseUrl,\n\t\t\t\t\t\t`${wpDetails.version}.zip`,\n\t\t\t\t\t\tmonitor\n\t\t\t\t );\n\n\t\t\tconst constants: Record<string, string | number | boolean | null> =\n\t\t\t\t{\n\t\t\t\t\tWP_DEBUG: true,\n\t\t\t\t\tWP_DEBUG_LOG: true,\n\t\t\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t\t\t};\n\n\t\t\tlogger.log(`Booting WordPress...`);\n\t\t\trequestHandler = await bootWordPress({\n\t\t\t\tsiteUrl: absoluteUrl,\n\t\t\t\tcreatePhpRuntime: async () =>\n\t\t\t\t\tawait loadNodeRuntime(compiledBlueprint.versions.php),\n\t\t\t\twordPressZip,\n\t\t\t\tsqliteIntegrationPluginZip: fetchSqliteIntegration(monitor),\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles: {\n\t\t\t\t\t'/internal/shared/ca-bundle.crt':\n\t\t\t\t\t\trootCertificates.join('\\n'),\n\t\t\t\t},\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries: {\n\t\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t\t\tallow_url_fopen: '1',\n\t\t\t\t\tdisable_functions: '',\n\t\t\t\t},\n\t\t\t\thooks: {\n\t\t\t\t\tasync beforeWordPressFiles(php) {\n\t\t\t\t\t\tif (args.mountBeforeInstall) {\n\t\t\t\t\t\t\tmountResources(php, args.mountBeforeInstall);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t\tlogger.log(`Booted!`);\n\n\t\t\tconst php = await requestHandler.getPrimaryPhp();\n\t\t\ttry {\n\t\t\t\tif (\n\t\t\t\t\twpDetails &&\n\t\t\t\t\t!args.mountBeforeInstall &&\n\t\t\t\t\t!fs.existsSync(preinstalledWpContentPath)\n\t\t\t\t) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t`Caching preinstalled WordPress for the next boot...`\n\t\t\t\t\t);\n\t\t\t\t\tfs.writeFileSync(\n\t\t\t\t\t\tpreinstalledWpContentPath,\n\t\t\t\t\t\tawait zipDirectory(php, '/wordpress')\n\t\t\t\t\t);\n\t\t\t\t\tlogger.log(`Cached!`);\n\t\t\t\t}\n\n\t\t\t\tif (args.mount) {\n\t\t\t\t\tmountResources(php, args.mount);\n\t\t\t\t}\n\n\t\t\t\twordPressReady = true;\n\n\t\t\t\tif (compiledBlueprint) {\n\t\t\t\t\tconst { php, reap } =\n\t\t\t\t\t\tawait requestHandler.processManager.acquirePHPInstance();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlogger.log(`Running the Blueprint...`);\n\t\t\t\t\t\tawait runBlueprintSteps(compiledBlueprint, php);\n\t\t\t\t\t\tlogger.log(`Finished running the blueprint`);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\treap();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (args.command === 'build-snapshot') {\n\t\t\t\t\tawait zipSite(args.outfile as string);\n\t\t\t\t\tlogger.log(`WordPress exported to ${args.outfile}`);\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t} else if (args.command === 'run-blueprint') {\n\t\t\t\t\tlogger.log(`Blueprint executed`);\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(`WordPress is running on ${absoluteUrl}`);\n\t\t\t\t}\n\n\t\t\t\treturn { requestHandler, server };\n\t\t\t} catch (error) {\n\t\t\t\tif (!args.debug) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst phpLogs = php.readFileAsText(errorLogPath);\n\t\t\t\tthrow new Error(phpLogs, { cause: error });\n\t\t\t}\n\t\t},\n\t\tasync handleRequest(request: PHPRequest) {\n\t\t\tif (!wordPressReady) {\n\t\t\t\treturn PHPResponse.forHttpCode(\n\t\t\t\t\t502,\n\t\t\t\t\t'WordPress is not ready yet'\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn await requestHandler.request(request);\n\t\t},\n\t});\n}\n"],"names":["startServer","options","app","express","server","resolve","reject","address","req","res","phpResponse","parseHeaders","bufferRequestBody","key","port","body","chunk","requestHeaders","i","CACHE_FOLDER","path","os","fetchSqliteIntegration","monitor","cachedDownload","remoteUrl","cacheKey","artifactPath","fs","downloadTo","readAsFile","localPath","reader","tmpPath","writer","done","value","err","fileName","basename","runCLI","args","logger","zipSite","outfile","php","reap","requestHandler","zip","mountResources","rawMounts","parsedMounts","mount","source","vfsPath","createNodeFsMountHandler","compileInputBlueprint","blueprint","RecommendedPHPVersion","tracker","ProgressTracker","lastCaption","progressReached100","e","progressInteger","message","writeProgressUpdate","compileBlueprint","lastProgressMessage","writeStream","finalUpdate","compiledBlueprint","wordPressReady","absoluteUrl","wpDetails","EmscriptenDownloadMonitor","loaded","total","percentProgress","resolveWordPressRelease","preinstalledWpContentPath","wordPressZip","constants","bootWordPress","loadNodeRuntime","rootCertificates","zipDirectory","runBlueprintSteps","error","phpLogs","errorLogPath","request","PHPResponse"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
package/mount.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import type { PHP } from '@php-wasm/universal';
2
+ export interface Mount {
3
+ hostPath: string;
4
+ vfsPath: string;
5
+ }
6
+ /**
7
+ * Parse an array of mount argument strings where the host path and VFS path
8
+ * are separated by a colon.
9
+ *
10
+ * Example:
11
+ * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )
12
+ * // returns:
13
+ * [
14
+ * { hostPath: '/host/path', vfsPath: '/vfs/path' },
15
+ * { hostPath: '/host/path', vfsPath: '/vfs/path' }
16
+ * ]
17
+ *
18
+ * @param mounts - An array of mount argument strings separated by a colon.
19
+ * @returns An array of Mount objects.
20
+ */
21
+ export declare function parseMountWithDelimiterArguments(mounts: string[]): Mount[];
22
+ /**
23
+ * Parse an array of mount argument strings where each odd array element is a host path
24
+ * and each even element is the VFS path.
25
+ * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]
26
+ *
27
+ * The result will be an array of Mount objects for each host path the
28
+ * following element is it's VFS path.
29
+ * e.g. [
30
+ * { hostPath: '/host/path', vfsPath: '/vfs/path' },
31
+ * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }
32
+ * ]
33
+ *
34
+ * @param mounts - An array of paths
35
+ * @returns An array of Mount objects.
36
+ */
37
+ export declare function parseMountDirArguments(mounts: string[]): Mount[];
38
+ export declare function mountResources(php: PHP, mounts: Mount[]): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-playground/cli",
3
- "version": "1.0.29",
3
+ "version": "1.1.1",
4
4
  "description": "WordPress Playground CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,44 +15,60 @@
15
15
  "url": "https://github.com/adamziel"
16
16
  }
17
17
  ],
18
+ "exports": {
19
+ ".": {
20
+ "import": "./index.js",
21
+ "require": "./index.cjs"
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
18
25
  "publishConfig": {
19
26
  "access": "public",
20
27
  "directory": "../../../dist/packages/playground/cli"
21
28
  },
22
29
  "license": "GPL-2.0-or-later",
23
30
  "type": "module",
24
- "main": "index.js",
31
+ "main": "./index.cjs",
32
+ "module": "./index.js",
33
+ "types": "index.d.ts",
25
34
  "bin": "wp-playground.js",
26
- "gitHead": "173e69f62e1b43bd7353b875054bb1ef5e394de8",
35
+ "gitHead": "8bff9428d68d3c4a5e84c6cd633e82bf8512a4e3",
27
36
  "dependencies": {
37
+ "@zip.js/zip.js": "2.7.57",
28
38
  "ajv": "8.12.0",
29
39
  "async-lock": "1.4.1",
30
- "buffer": "6.0.3",
31
40
  "clean-git-ref": "2.0.1",
32
41
  "comlink": "^4.4.1",
33
42
  "crc-32": "1.2.2",
34
43
  "diff3": "0.0.4",
35
- "events": "3.3.0",
36
- "express": "4.19.2",
44
+ "express": "4.21.2",
37
45
  "fs-extra": "11.1.1",
38
- "ignore": "5.2.4",
46
+ "ignore": "5.3.2",
39
47
  "ini": "4.1.2",
40
48
  "minimisted": "2.0.1",
41
- "octokit": "3.1.1",
49
+ "octokit": "3.1.2",
42
50
  "pako": "1.0.10",
43
- "pify": "5.0.0",
51
+ "pify": "2.3.0",
44
52
  "readable-stream": "3.6.2",
45
53
  "sha.js": "2.4.11",
46
54
  "simple-get": "4.0.1",
47
55
  "wasm-feature-detect": "1.8.0",
48
- "ws": "8.18.0",
56
+ "ws": "8.18.1",
49
57
  "yargs": "17.7.2",
50
- "@php-wasm/universal": "1.0.29",
51
- "@wp-playground/common": "1.0.29",
52
- "@php-wasm/progress": "1.0.29",
53
- "@php-wasm/logger": "1.0.29",
54
- "@wp-playground/blueprints": "1.0.29",
55
- "@php-wasm/node": "1.0.29",
56
- "@wp-playground/wordpress": "1.0.29"
58
+ "@wp-playground/blueprints": "1.1.1",
59
+ "@php-wasm/universal": "1.1.1",
60
+ "@wp-playground/common": "1.1.1",
61
+ "@php-wasm/progress": "1.1.1",
62
+ "@php-wasm/node": "1.1.1",
63
+ "@php-wasm/logger": "1.1.1",
64
+ "@wp-playground/storage": "1.1.1",
65
+ "@wp-playground/wordpress": "1.1.1"
66
+ },
67
+ "overrides": {
68
+ "rollup": "^4.34.6",
69
+ "react": "18.3.1",
70
+ "react-dom": "18.3.1",
71
+ "typescript": "5.4.5",
72
+ "ws": "^8.18.0"
57
73
  }
58
- }
74
+ }
@@ -0,0 +1,5 @@
1
+ export declare class ReportableError extends Error {
2
+ isReportableInCLI: boolean;
3
+ constructor(message: string, options?: ErrorOptions);
4
+ static getReportableCause(error: unknown): Error | null;
5
+ }
@@ -0,0 +1,17 @@
1
+ type ResolveBlueprintOptions = {
2
+ sourceString: string | undefined;
3
+ blueprintMayReadAdjacentFiles: boolean;
4
+ };
5
+ /**
6
+ * Resolves a blueprint from a URL or a local path.
7
+ *
8
+ * @TODO: Extract the common Blueprint resolution logic between CLI and
9
+ * the website into a single, isomorphic resolveBlueprint() function.
10
+ * Still retain the CLI-specific bits in the CLI package.
11
+ *
12
+ * @param sourceString - The source string to resolve the blueprint from.
13
+ * @param blueprintMayReadAdjacentFiles - Whether the blueprint may read adjacent files.
14
+ * @returns The resolved blueprint.
15
+ */
16
+ export declare function resolveBlueprint({ sourceString, blueprintMayReadAdjacentFiles, }: ResolveBlueprintOptions): Promise<import("@wp-playground/storage").Filesystem | undefined>;
17
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";const p=require("@php-wasm/logger"),H=require("@php-wasm/node"),x=require("@php-wasm/progress"),z=require("@php-wasm/universal"),b=require("@wp-playground/blueprints"),q=require("@wp-playground/common"),B=require("@wp-playground/wordpress"),d=require("fs"),f=require("path"),L=require("tls"),P=require("fs-extra"),T=require("os"),U=require("express");function Z(e){const t=process.cwd(),n=[...e.mount||[]],o=[...e.mountBeforeInstall||[]];if(M(t)){const r=f.basename(t);n.push({hostPath:t,vfsPath:`/wordpress/wp-content/plugins/${r}`})}else if(F(t)){const r=f.basename(t);n.push({hostPath:t,vfsPath:`/wordpress/wp-content/themes/${r}`})}else if(C(t))n.push(...E(t));else if(S(t)){const r=d.readdirSync(t),l=[];for(const s of r)s.startsWith("wp-content")||l.push({hostPath:`${t}/${s}`,vfsPath:`/wordpress/${s}`});o.push(...l,...E(f.join(t,"wp-content")))}else n.push({hostPath:t,vfsPath:"/wordpress"});const i=e.blueprint||{};i.steps=[...i.steps||[],...j(t)];const a=e.skipWordPressSetup||S(t);return{...e,blueprint:i,mount:n,mountBeforeInstall:o,skipWordPressSetup:a}}function S(e){const t=d.readdirSync(e);return t.includes("wp-admin")&&t.includes("wp-includes")&&t.includes("wp-content")}function C(e){const t=d.readdirSync(e);return t.includes("themes")||t.includes("plugins")||t.includes("mu-plugins")||t.includes("uploads")}function F(e){if(!d.readdirSync(e).includes("style.css"))return!1;const n=d.readFileSync(f.join(e,"style.css"),"utf8");return!!/^(?:[ \t]*<\?php)?[ \t/*#@]*Theme Name:(.*)$/im.exec(n)}function M(e){const t=d.readdirSync(e),n=/^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;return!!t.filter(i=>i.endsWith(".php")).find(i=>{const a=d.readFileSync(f.join(e,i),"utf8");return!!n.exec(a)})}function E(e){return d.readdirSync(e).filter(n=>!n.startsWith("index.php")).map(n=>({hostPath:`${e}/${n}`,vfsPath:`/wordpress/wp-content/${n}`}))}function j(e){return M(e)?[{step:"activatePlugin",pluginPath:`/wordpress/wp-content/plugins/${f.basename(e)}`}]:F(e)?[{step:"activateTheme",themeFolderName:f.basename(e)}]:C(e)||S(e)?[{step:"runPHP",code:`<?php
2
+ require_once '/wordpress/wp-load.php';
3
+ $theme = wp_get_theme();
4
+ if (!$theme->exists()) {
5
+ $themes = wp_get_themes();
6
+ if (count($themes) > 0) {
7
+ $themeName = array_keys($themes)[0];
8
+ switch_theme($themeName);
9
+ }
10
+ }
11
+ `}]:[]}const W=f.join(T.homedir(),".wordpress-playground");async function V(e){return await D("https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip","sqlite.zip",e)}async function D(e,t,n){const o=f.join(W,t);return P.existsSync(o)||(P.ensureDirSync(W),await G(e,o,n)),_(o)}async function G(e,t,n){const i=(await n.monitorFetch(fetch(e))).body.getReader(),a=`${t}.partial`,r=P.createWriteStream(a);for(;;){const{done:l,value:s}=await i.read();if(s&&r.write(s),l)break}r.close(),r.closed||await new Promise((l,s)=>{r.on("finish",()=>{P.renameSync(a,t),l(null)}),r.on("error",c=>{P.removeSync(a),s(c)})})}function _(e,t){return new File([P.readFileSync(e)],f.basename(e))}async function O(e){const t=U(),n=await new Promise((a,r)=>{const l=t.listen(e.port,()=>{const s=l.address();s===null||typeof s=="string"?r(new Error("Server address is not available")):a(l)})});t.use("/",async(a,r)=>{const l=await e.handleRequest({url:a.url,headers:J(a),method:a.method,body:await Y(a)});r.statusCode=l.httpStatusCode;for(const s in l.headers)r.setHeader(s,l.headers[s]);r.end(l.bytes)});const i=n.address().port;return await e.onBind(n,i)}const Y=async e=>await new Promise(t=>{const n=[];e.on("data",o=>{n.push(o)}),e.on("end",()=>{t(new Uint8Array(Buffer.concat(n)))})}),J=e=>{const t={};if(e.rawHeaders&&e.rawHeaders.length)for(let n=0;n<e.rawHeaders.length;n+=2)t[e.rawHeaders[n].toLowerCase()]=e.rawHeaders[n+1];return t};function K(e){const t=[];for(const n of e){const o=n.split(":");if(o.length!==2)throw new Error(`Invalid mount format: ${n}.
12
+ Expected format: /host/path:/vfs/path.
13
+ If your path contains a colon, e.g. C:\\myplugin, use the --mount-dir option instead.
14
+ Example: --mount-dir C:\\my-plugin /wordpress/wp-content/plugins/my-plugin`);const[i,a]=o;if(!d.existsSync(i))throw new Error(`Host path does not exist: ${i}`);t.push({hostPath:i,vfsPath:a})}return t}function Q(e){if(e.length%2!==0)throw new Error("Invalid mount format. Expected: /host/path /vfs/path");const t=[];for(let n=0;n<e.length;n+=2){const o=e[n],i=e[n+1];if(!d.existsSync(o))throw new Error(`Host path does not exist: ${o}`);t.push({hostPath:f.resolve(process.cwd(),o),vfsPath:i})}return t}function I(e,t){for(const n of t)e.mkdir(n.vfsPath),e.mount(n.vfsPath,H.createNodeFsMountHandler(n.hostPath))}async function X(e){e.autoMount&&(e=Z(e));async function t(s){const{php:c,reap:h}=await r.processManager.acquirePHPInstance();try{await c.run({code:`<?php
15
+ $zip = new ZipArchive();
16
+ if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
17
+ throw new Exception('Failed to create ZIP');
18
+ }
19
+ $files = new RecursiveIteratorIterator(
20
+ new RecursiveDirectoryIterator('/wordpress')
21
+ );
22
+ foreach ($files as $file) {
23
+ echo $file . PHP_EOL;
24
+ if (!$file->isFile()) {
25
+ continue;
26
+ }
27
+ $zip->addFile($file->getPathname(), $file->getPathname());
28
+ }
29
+ $zip->close();
30
+
31
+ `});const u=c.readFileAsBuffer("/tmp/build.zip");d.writeFileSync(s,u)}finally{h()}}async function n(){const s=b.isBlueprintBundle(e.blueprint)?e.blueprint:{login:e.login,...e.blueprint,preferredVersions:{php:e.php??e?.blueprint?.preferredVersions?.php??q.RecommendedPHPVersion,wp:e.wp??e?.blueprint?.preferredVersions?.wp??"latest",...e.blueprint?.preferredVersions||{}}},c=new x.ProgressTracker;let h="",u=!1;return c.addEventListener("progress",m=>{if(u)return;u=m.detail.progress===100;const g=Math.floor(m.detail.progress);h=m.detail.caption||h||"Running the Blueprint";const v=`${h.trim()} – ${g}%`;e.quiet||i(process.stdout,v,u)}),await b.compileBlueprint(s,{progress:c})}let o="";function i(s,c,h){c!==o&&(o=c,s.isTTY?(s.cursorTo(0),s.write(c),s.clearLine(1),h&&s.write(`
32
+ `)):s.write(`${c}
33
+ `))}e.quiet&&(p.logger.handlers=[]);const a=await n();let r,l=!1;return p.logger.log("Starting a PHP server..."),O({port:e.port,onBind:async(s,c)=>{const h=`http://127.0.0.1:${c}`;p.logger.log(`Setting up WordPress ${e.wp}`);let u;const m=new x.EmscriptenDownloadMonitor;if(!e.skipWordPressSetup){let w=!1;m.addEventListener("progress",y=>{if(w)return;const{loaded:A,total:k}=y.detail,R=Math.floor(Math.min(100,100*A/k));w=R===100,e.quiet||i(process.stdout,`Downloading WordPress ${R}%...`,w)}),u=await B.resolveWordPressRelease(e.wp)}p.logger.log(`Resolved WordPress release URL: ${u?.releaseUrl}`);const g=u&&f.join(W,`prebuilt-wp-content-for-wp-${u.version}.zip`),v=u?d.existsSync(g)?_(g):await D(u.releaseUrl,`${u.version}.zip`,m):void 0,N={WP_DEBUG:!0,WP_DEBUG_LOG:!0,WP_DEBUG_DISPLAY:!1};p.logger.log("Booting WordPress..."),r=await B.bootWordPress({siteUrl:h,createPhpRuntime:async()=>await H.loadNodeRuntime(a.versions.php,{followSymlinks:e.followSymlinks===!0}),wordPressZip:v,sqliteIntegrationPluginZip:e.skipSqliteSetup?void 0:V(m),sapiName:"cli",createFiles:{"/internal/shared/ca-bundle.crt":L.rootCertificates.join(`
34
+ `)},constants:N,phpIniEntries:{"openssl.cafile":"/internal/shared/ca-bundle.crt",allow_url_fopen:"1",disable_functions:""},hooks:{async beforeWordPressFiles(w){e.mountBeforeInstall&&I(w,e.mountBeforeInstall)}},cookieStore:!1}),p.logger.log("Booted!");const $=await r.getPrimaryPhp();try{if(u&&!e.mountBeforeInstall&&!d.existsSync(g)&&(p.logger.log("Caching preinstalled WordPress for the next boot..."),d.writeFileSync(g,await q.zipDirectory($,"/wordpress")),p.logger.log("Cached!")),e.mount&&I($,e.mount),l=!0,a){const{php:w,reap:y}=await r.processManager.acquirePHPInstance();try{p.logger.log("Running the Blueprint..."),await b.runBlueprintSteps(a,w),p.logger.log("Finished running the blueprint")}finally{y()}}return e.command==="build-snapshot"?(await t(e.outfile),p.logger.log(`WordPress exported to ${e.outfile}`),process.exit(0)):e.command==="run-blueprint"?(p.logger.log("Blueprint executed"),process.exit(0)):p.logger.log(`WordPress is running on ${h}`),{requestHandler:r,server:s}}catch(w){if(!e.debug)throw w;const y=$.readFileAsText(p.errorLogPath);throw new Error(y,{cause:w})}},async handleRequest(s){return l?await r.request(s):z.PHPResponse.forHttpCode(502,"WordPress is not ready yet")}})}exports.parseMountDirArguments=Q;exports.parseMountWithDelimiterArguments=K;exports.runCLI=X;
35
+ //# sourceMappingURL=run-cli-BSw9FKSW.cjs.map