@wp-playground/cli 0.7.10 → 0.7.14

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.
Files changed (2) hide show
  1. package/cli.js +7 -7
  2. package/package.json +9 -9
package/cli.js CHANGED
@@ -1,7 +1,7 @@
1
- import m from"fs";import h,{basename as x}from"path";import z from"yargs";import E from"express";import{rotatePHPRuntime as I,__private__dont__use as b,SupportedPHPVersions as H,PHPRequestHandler as W,PHPResponse as k}from"@php-wasm/universal";import{logger as w}from"@php-wasm/logger";import{NodePHP as F}from"@php-wasm/node";import{rootCertificates as B}from"tls";import{dirname as q}from"@php-wasm/util";import{unzip as v,defineSiteUrl as $,zipWpContent as C,runWpInstallationWizard as D,runBlueprintSteps as T,compileBlueprint as A}from"@wp-playground/blueprints";import P from"fs-extra";import L from"os";import{EmscriptenDownloadMonitor as j,ProgressTracker as M}from"@php-wasm/progress";import{RecommendedPHPVersion as O}from"@wp-playground/wordpress";async function N(e){const t=E(),r=await new Promise((o,p)=>{const n=t.listen(e.port,()=>{const f=n.address();f===null||typeof f=="string"?p(new Error("Server address is not available")):o(n)})});t.use("/",async(o,p)=>{const n=await e.handleRequest({url:o.url,headers:V(o),method:o.method,body:await U(o)});p.statusCode=n.httpStatusCode;for(const f in n.headers)p.setHeader(f,n.headers[f]);p.end(n.bytes)});const s=r.address().port;await e.onBind(s)}const U=async e=>await new Promise(t=>{const r=[];e.on("data",i=>{r.push(i)}),e.on("end",()=>{t(Buffer.concat(r))})}),V=e=>{const t={};if(e.rawHeaders&&e.rawHeaders.length)for(let r=0;r<e.rawHeaders.length;r+=2)t[e.rawHeaders[r].toLowerCase()]=e.rawHeaders[r+1];return t};async function Z(e,t,r){const i=async()=>await F.loadRuntime(t),s=new F;return s.requestHandler=e,s.initializeRuntime(await i()),s.setSapiName("cli"),s.setPhpIniPath("/tmp/php.ini"),s.writeFile("/tmp/php.ini",""),s.setPhpIniEntry("memory_limit","256M"),s.setPhpIniEntry("allow_url_fopen","1"),s.setPhpIniEntry("disable_functions",""),s.setPhpIniEntry("openssl.cafile","/tmp/ca-bundle.crt"),s.writeFile("/tmp/ca-bundle.crt",B.join(`
2
- `)),r||J(await e.getPrimaryPhp(),s,"/wordpress"),I({php:s,cwd:"/wordpress",recreateRuntime:i,maxRequests:400}),s}function J(e,t,r){for(const i of[r,"/tmp"])t.fileExists(i)||t.mkdir(i),e.fileExists(i)||e.mkdir(i),t[b].FS.mount(t[b].PROXYFS,{root:i,fs:e[b].FS},i)}async function Q(e,t,r){const i=(await e.run({code:"<?php echo php_ini_loaded_file();"})).text,s=q(i);e.fileExists(s)||e.mkdir(s),e.fileExists(i)||e.writeFile(i,"");const o=e.readFileAsText(i),p=Object.entries(t).map(([n,f])=>`${n} = ${f}`).join(`
3
- `);e.writeFile(i,[o,p].join(`
4
- `));try{await r()}finally{e.writeFile(i,o)}}const _=h.join(L.homedir(),".wordpress-playground");async function S(e,t,r){const i=h.join(_,t);return P.existsSync(i)||(P.ensureDirSync(_),await Y(e,i,r)),R(i)}async function Y(e,t,r){const s=(await r.monitorFetch(fetch(e))).body.getReader(),o=P.createWriteStream(t);for(;;){const{done:p,value:n}=await s.read();if(p)break;o.write(Buffer.from(n))}}function R(e,t){return new File([P.readFileSync(e)],t??x(e))}async function G(e="latest"){if(e==="trunk"||e==="nightly")return{url:"https://wordpress.org/nightly-builds/wordpress-latest.zip",version:"nightly-"+new Date().toISOString().split("T")[0]};let t=await fetch("https://api.wordpress.org/core/version-check/1.7/?channel=beta").then(r=>r.json());t=t.offers.filter(r=>r.response==="autoupdate");for(const r of t){if(e==="beta"&&r.version.includes("beta"))return{url:r.download,version:r.version};if(e==="latest")return{url:r.download,version:r.version};if(r.version.substring(0,e.length)===e)return{url:r.download,version:r.version}}return{url:`https://wordpress.org/wordpress-${e}.zip`,version:e}}async function K(e,t="latest",r){const i=await G(t),[s,o]=await Promise.all([S(i.url,`${i.version}.zip`,r),S("https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/main.zip","sqlite.zip",r)]);await X(e,s,o);const p=h.join(_,`prebuilt-wp-content-for-wp-${i.version}.zip`);if(m.existsSync(p))await v(e,{zipFile:R(p),extractToPath:"/wordpress"});else{await $(e,{siteUrl:"http://playground.internal"}),await Q(e,{disable_functions:"fsockopen",allow_url_fopen:"0"},async()=>await D(e,{options:{}}));const n=await C(e);m.writeFileSync(p,n)}}async function X(e,t,r){e.mkdir("/tmp/unzipped-wordpress"),await v(e,{zipFile:t,extractToPath:"/tmp/unzipped-wordpress"});const i=e.fileExists("/tmp/unzipped-wordpress/wordpress")?"/tmp/unzipped-wordpress/wordpress":"/tmp/unzipped-wordpress";e.mv(i,"/wordpress"),e.mkdir("/tmp/sqlite-database-integration"),await v(e,{zipFile:r,extractToPath:"/tmp/sqlite-database-integration"}),e.mv("/tmp/sqlite-database-integration/sqlite-database-integration-main","/wordpress/sqlite-database-integration");const o=e.readFileAsText("/wordpress/sqlite-database-integration/db.copy").replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'","__DIR__.'/../sqlite-database-integration/'").replace("'{SQLITE_PLUGIN}'","__DIR__.'/../sqlite-database-integration/load.php'");e.writeFile("/wordpress/wp-content/db.php",o),e.writeFile("/wordpress/wp-includes/default-filters.php",e.readFileAsText("/wordpress/wp-includes/default-filters.php")+`
1
+ import m from"fs";import h,{basename as x}from"path";import z from"yargs";import E from"express";import{rotatePHPRuntime as I,__private__dont__use as b,SupportedPHPVersions as H,PHPRequestHandler as W,PHPResponse as k}from"@php-wasm/universal";import{logger as f}from"@php-wasm/logger";import{NodePHP as F}from"@php-wasm/node";import{rootCertificates as q}from"tls";import{dirname as B}from"@php-wasm/util";import{unzip as v,defineSiteUrl as $,zipWpContent as C,runWpInstallationWizard as D,runBlueprintSteps as T,compileBlueprint as A}from"@wp-playground/blueprints";import P from"fs-extra";import L from"os";import{EmscriptenDownloadMonitor as j,ProgressTracker as M}from"@php-wasm/progress";import{RecommendedPHPVersion as O}from"@wp-playground/wordpress";async function N(e){const t=E(),r=await new Promise((o,a)=>{const n=t.listen(e.port,()=>{const d=n.address();d===null||typeof d=="string"?a(new Error("Server address is not available")):o(n)})});t.use("/",async(o,a)=>{const n=await e.handleRequest({url:o.url,headers:V(o),method:o.method,body:await U(o)});a.statusCode=n.httpStatusCode;for(const d in n.headers)a.setHeader(d,n.headers[d]);a.end(n.bytes)});const s=r.address().port;await e.onBind(s)}const U=async e=>await new Promise(t=>{const r=[];e.on("data",i=>{r.push(i)}),e.on("end",()=>{t(Buffer.concat(r))})}),V=e=>{const t={};if(e.rawHeaders&&e.rawHeaders.length)for(let r=0;r<e.rawHeaders.length;r+=2)t[e.rawHeaders[r].toLowerCase()]=e.rawHeaders[r+1];return t};async function Z(e,t,r){const i=async()=>await F.loadRuntime(t),s=new F;return s.requestHandler=e,s.initializeRuntime(await i()),s.setSapiName("cli"),s.setPhpIniPath("/tmp/php.ini"),s.writeFile("/tmp/php.ini",""),s.setPhpIniEntry("memory_limit","256M"),s.setPhpIniEntry("allow_url_fopen","1"),s.setPhpIniEntry("disable_functions",""),s.setPhpIniEntry("openssl.cafile","/tmp/ca-bundle.crt"),s.writeFile("/tmp/ca-bundle.crt",q.join(`
2
+ `)),r||J(await e.getPrimaryPhp(),s,"/wordpress"),I({php:s,cwd:"/wordpress",recreateRuntime:i,maxRequests:400}),s}function J(e,t,r){for(const i of[r,"/tmp"])t.fileExists(i)||t.mkdir(i),e.fileExists(i)||e.mkdir(i),t[b].FS.mount(t[b].PROXYFS,{root:i,fs:e[b].FS},i)}async function Q(e,t,r){const i=(await e.run({code:"<?php echo php_ini_loaded_file();"})).text,s=B(i);e.fileExists(s)||e.mkdir(s),e.fileExists(i)||e.writeFile(i,"");const o=e.readFileAsText(i),a=Object.entries(t).map(([n,d])=>`${n} = ${d}`).join(`
3
+ `);e.writeFile(i,[o,a].join(`
4
+ `));try{await r()}finally{e.writeFile(i,o)}}const _=h.join(L.homedir(),".wordpress-playground");async function S(e,t,r){const i=h.join(_,t);return P.existsSync(i)||(P.ensureDirSync(_),await Y(e,i,r)),R(i)}async function Y(e,t,r){const s=(await r.monitorFetch(fetch(e))).body.getReader(),o=P.createWriteStream(t);for(;;){const{done:a,value:n}=await s.read();if(n&&o.write(n),a)break}o.close(),o.closed||await new Promise((a,n)=>{o.on("finish",d=>{d?n(d):a(null)})})}function R(e,t){return new File([P.readFileSync(e)],t??x(e))}async function G(e="latest"){if(e==="trunk"||e==="nightly")return{url:"https://wordpress.org/nightly-builds/wordpress-latest.zip",version:"nightly-"+new Date().toISOString().split("T")[0]};let t=await fetch("https://api.wordpress.org/core/version-check/1.7/?channel=beta").then(r=>r.json());t=t.offers.filter(r=>r.response==="autoupdate");for(const r of t){if(e==="beta"&&r.version.includes("beta"))return{url:r.download,version:r.version};if(e==="latest")return{url:r.download,version:r.version};if(r.version.substring(0,e.length)===e)return{url:r.download,version:r.version}}return{url:`https://wordpress.org/wordpress-${e}.zip`,version:e}}async function K(e,t="latest",r){const i=await G(t),[s,o]=await Promise.all([S(i.url,`${i.version}.zip`,r),S("https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/main.zip","sqlite.zip",r)]);await X(e,s,o);const a=h.join(_,`prebuilt-wp-content-for-wp-${i.version}.zip`);if(m.existsSync(a))await v(e,{zipFile:R(a),extractToPath:"/wordpress"});else{await $(e,{siteUrl:"http://playground.internal"}),await Q(e,{disable_functions:"fsockopen",allow_url_fopen:"0"},async()=>await D(e,{options:{}}));const n=await C(e);m.writeFileSync(a,n)}}async function X(e,t,r){e.mkdir("/tmp/unzipped-wordpress"),await v(e,{zipFile:t,extractToPath:"/tmp/unzipped-wordpress"});const i=e.fileExists("/tmp/unzipped-wordpress/wordpress")?"/tmp/unzipped-wordpress/wordpress":"/tmp/unzipped-wordpress";e.mv(i,"/wordpress"),e.mkdir("/tmp/sqlite-database-integration"),await v(e,{zipFile:r,extractToPath:"/tmp/sqlite-database-integration"}),e.mv("/tmp/sqlite-database-integration/sqlite-database-integration-main","/wordpress/sqlite-database-integration");const o=e.readFileAsText("/wordpress/sqlite-database-integration/db.copy").replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'","__DIR__.'/../sqlite-database-integration/'").replace("'{SQLITE_PLUGIN}'","__DIR__.'/../sqlite-database-integration/load.php'");e.writeFile("/wordpress/wp-content/db.php",o),e.writeFile("/wordpress/wp-includes/default-filters.php",e.readFileAsText("/wordpress/wp-includes/default-filters.php")+`
5
5
  // Redirect /wp-admin to /wp-admin/
6
6
  add_filter( 'redirect_canonical', function( $redirect_url ) {
7
7
  if ( '/wp-admin' === $redirect_url ) {
@@ -22,7 +22,7 @@ import m from"fs";import h,{basename as x}from"path";import z from"yargs";import
22
22
 
23
23
  // Support permalinks without "index.php"
24
24
  add_filter( 'got_url_rewrite', '__return_true' );
25
- `),e.writeFile("/wordpress/wp-config.php",e.readFileAsText("/wordpress/wp-config-sample.php"))}function ee(e){return/^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e)}async function te(){const e=await z(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command",{describe:"Command to run",type:"string",choices:["server","run-blueprint","build-snapshot"]}).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:O,choices:H}).option("wp",{describe:"WordPress version to use.",type:"string",default:"latest"}).option("mount",{describe:"Mount a directory to the PHP runtime. You can provide --mount multiple times. Format: /host/path:/vfs/path",type:"array",string:!0}).option("login",{describe:"Should log the user in",type:"boolean",default:!1}).option("blueprint",{describe:"Blueprint to execute.",type:"string"}).option("skipWordPressSetup",{describe:"Do not download, unzip, and install WordPress. Useful for mounting a pre-configured WordPress directory at /wordpress.",type:"boolean",default:!1}).option("quiet",{describe:"Do not output logs and progress messages.",type:"boolean",default:!1}).check(a=>{if(a.wp!==void 0&&!ee(a.wp))throw new Error('Unrecognized WordPress version. Please use "latest" or numeric versions such as "6.2", "6.0.1", "6.2-beta1", or "6.2-RC1"');if(a.blueprint!==void 0){const d=h.resolve(process.cwd(),a.blueprint);if(!m.existsSync(d))throw new Error("Blueprint file does not exist");const u=m.readFileSync(d,"utf-8");try{a.blueprint=JSON.parse(u)}catch{throw new Error("Blueprint file is not a valid JSON file")}}return!0});e.wrap(e.terminalWidth());const t=await e.argv;t.quiet&&(w.handlers=[]);async function r(a){const{php:d,reap:u}=await n.processManager.acquirePHPInstance();try{await d.run({code:`<?php
25
+ `),e.writeFile("/wordpress/wp-config.php",e.readFileAsText("/wordpress/wp-config-sample.php"))}function ee(e){return/^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e)}async function te(){const e=await z(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command",{describe:"Command to run",type:"string",choices:["server","run-blueprint","build-snapshot"]}).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:O,choices:H}).option("wp",{describe:"WordPress version to use.",type:"string",default:"latest"}).option("mount",{describe:"Mount a directory to the PHP runtime. You can provide --mount multiple times. Format: /host/path:/vfs/path",type:"array",string:!0}).option("login",{describe:"Should log the user in",type:"boolean",default:!1}).option("blueprint",{describe:"Blueprint to execute.",type:"string"}).option("skipWordPressSetup",{describe:"Do not download, unzip, and install WordPress. Useful for mounting a pre-configured WordPress directory at /wordpress.",type:"boolean",default:!1}).option("quiet",{describe:"Do not output logs and progress messages.",type:"boolean",default:!1}).check(p=>{if(p.wp!==void 0&&!ee(p.wp))throw new Error('Unrecognized WordPress version. Please use "latest" or numeric versions such as "6.2", "6.0.1", "6.2-beta1", or "6.2-RC1"');if(p.blueprint!==void 0){const l=h.resolve(process.cwd(),p.blueprint);if(!m.existsSync(l))throw new Error("Blueprint file does not exist");const w=m.readFileSync(l,"utf-8");try{p.blueprint=JSON.parse(w)}catch{throw new Error("Blueprint file is not a valid JSON file")}}return!0});e.wrap(e.terminalWidth());const t=await e.argv;t.quiet&&(f.handlers=[]);async function r(p){const{php:l,reap:w}=await n.processManager.acquirePHPInstance();try{await l.run({code:`<?php
26
26
  $zip = new ZipArchive();
27
27
  if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
28
28
  throw new Exception('Failed to create ZIP');
@@ -39,5 +39,5 @@ import m from"fs";import h,{basename as x}from"path";import z from"yargs";import
39
39
  }
40
40
  $zip->close();
41
41
 
42
- `});const c=d.readFileAsBuffer("/tmp/build.zip");m.writeFileSync(a,c)}finally{u()}}async function i(a,d,u){if(!t.skipWordPressSetup){w.log(`Setting up WordPress ${d}`);const l=new j;l.addEventListener("progress",g=>{const y=Math.round(Math.min(100,100*g.detail.loaded/g.detail.total));t.quiet||process.stdout.write(`\rDownloading WordPress ${y}%... `)}),await K(a,d,l)}const c=(t.mount||[]).map(l=>{const[g,y]=l.split(":");return{hostPath:h.resolve(process.cwd(),g),vfsPath:y}});for(const l of c)a.mount(l.hostPath,l.vfsPath);await $(a,{siteUrl:u})}function s(){let a;t.blueprint?a=t.blueprint:a={preferredVersions:{php:t.php,wp:t.wp},login:t.login};const d=new M;let u="",c=!1;return d.addEventListener("progress",l=>{c||(l.detail.progress===100&&(c=!0),u=l.detail.caption||u||"Running the Blueprint",process.stdout.write(`\r\x1B[K${u.trim()} – ${l.detail.progress}%`),c&&process.stdout.write(`
43
- `))}),A(a,{progress:d})}const o=t._[0];["run-blueprint","server","build-snapshot"].includes(o)||(e.showHelp(),process.exit(1));const p=s();let n,f=!1;w.log("Starting a PHP server..."),N({port:t.port,onBind:async a=>{const d=`http://127.0.0.1:${a}`;n=new W({phpFactory:async({isPrimary:c})=>Z(n,p.versions.php,c),documentRoot:"/wordpress",absoluteUrl:d});const u=await n.getPrimaryPhp();if(await i(u,p.versions.wp,d),f=!0,p){const{php:c,reap:l}=await n.processManager.acquirePHPInstance();try{w.log("Running the Blueprint..."),await T(p,c),w.log("Finished running the blueprint")}finally{l()}}o==="build-snapshot"?(r(t.outfile),w.log(`WordPress exported to ${t.outfile}`),process.exit(0)):o==="run-blueprint"?(w.log("Blueprint executed"),process.exit(0)):w.log(`WordPress is running on ${d}`)},async handleRequest(a){return f?await n.request(a):k.forHttpCode(502,"WordPress is not ready yet")}})}te();
42
+ `});const u=l.readFileAsBuffer("/tmp/build.zip");m.writeFileSync(p,u)}finally{w()}}async function i(p,l,w){if(!t.skipWordPressSetup){f.log(`Setting up WordPress ${l}`);const c=new j;c.addEventListener("progress",g=>{const y=Math.round(Math.min(100,100*g.detail.loaded/g.detail.total));t.quiet||process.stdout.write(`\rDownloading WordPress ${y}%... `)}),await K(p,l,c)}const u=(t.mount||[]).map(c=>{const[g,y]=c.split(":");return{hostPath:h.resolve(process.cwd(),g),vfsPath:y}});for(const c of u)p.mount(c.hostPath,c.vfsPath);await $(p,{siteUrl:w})}function s(){let p;t.blueprint?p=t.blueprint:p={preferredVersions:{php:t.php,wp:t.wp},login:t.login};const l=new M;let w="",u=!1;return l.addEventListener("progress",c=>{u||(c.detail.progress===100&&(u=!0),w=c.detail.caption||w||"Running the Blueprint",process.stdout.write(`\r\x1B[K${w.trim()} – ${c.detail.progress}%`),u&&process.stdout.write(`
43
+ `))}),A(p,{progress:l})}const o=t._[0];["run-blueprint","server","build-snapshot"].includes(o)||(e.showHelp(),process.exit(1));const a=s();let n,d=!1;f.log("Starting a PHP server..."),N({port:t.port,onBind:async p=>{const l=`http://127.0.0.1:${p}`;n=new W({phpFactory:async({isPrimary:u})=>Z(n,a.versions.php,u),documentRoot:"/wordpress",absoluteUrl:l});const w=await n.getPrimaryPhp();if(await i(w,a.versions.wp,l),d=!0,a){const{php:u,reap:c}=await n.processManager.acquirePHPInstance();try{f.log("Running the Blueprint..."),await T(a,u),f.log("Finished running the blueprint")}finally{c()}}o==="build-snapshot"?(r(t.outfile),f.log(`WordPress exported to ${t.outfile}`),process.exit(0)):o==="run-blueprint"?(f.log("Blueprint executed"),process.exit(0)):f.log(`WordPress is running on ${l}`)},async handleRequest(p){return d?await n.request(p):k.forHttpCode(502,"WordPress is not ready yet")}})}te();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-playground/cli",
3
- "version": "0.7.10",
3
+ "version": "0.7.14",
4
4
  "description": "WordPress Playground CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,19 +23,19 @@
23
23
  "type": "module",
24
24
  "main": "main.js",
25
25
  "bin": "wp-playground.js",
26
- "gitHead": "b936cbd8d63893b5668e26faac29c6a3450b0eb9",
26
+ "gitHead": "37d63b91cc725a797c7c988742403ae50c3c179d",
27
27
  "dependencies": {
28
28
  "comlink": "^4.4.1",
29
29
  "express": "4.19.2",
30
30
  "fs-extra": "11.1.1",
31
31
  "ws": "8.13.0",
32
32
  "yargs": "17.7.2",
33
- "@php-wasm/universal": "0.7.10",
34
- "@php-wasm/logger": "0.7.10",
35
- "@wp-playground/blueprints": "0.7.10",
36
- "@php-wasm/node": "0.7.10",
37
- "@php-wasm/progress": "0.7.10",
38
- "@wp-playground/wordpress": "0.7.10",
39
- "@php-wasm/util": "0.7.10"
33
+ "@php-wasm/universal": "0.7.14",
34
+ "@php-wasm/logger": "0.7.14",
35
+ "@wp-playground/blueprints": "0.7.14",
36
+ "@php-wasm/node": "0.7.14",
37
+ "@php-wasm/progress": "0.7.14",
38
+ "@wp-playground/wordpress": "0.7.14",
39
+ "@php-wasm/util": "0.7.14"
40
40
  }
41
41
  }