@php-wasm/fs-journal 0.6.16 → 0.7.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/index.cjs +8 -8
- package/index.js +335 -263
- package/package.json +2 -2
package/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var Y=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)};var l=(e,t,r)=>(Y(e,t,"read from private field"),r?r.call(e):t.get(e)),
|
|
1
|
+
"use strict";var Y=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)};var l=(e,t,r)=>(Y(e,t,"read from private field"),r?r.call(e):t.get(e)),d=(e,t,r)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,r)},p=(e,t,r,s)=>(Y(e,t,"write to private field"),s?s.call(e,r):t.set(e,r),r);var f=(e,t,r)=>(Y(e,t,"access private method"),r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const currentJsRuntime=function(){var e;return typeof process<"u"&&((e=process.release)==null?void 0:e.name)==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"}();if(currentJsRuntime==="NODE"){let e=function(r){return new Promise(function(s,n){r.onload=r.onerror=function(i){r.onload=r.onerror=null,i.type==="load"?s(r.result):n(new Error("Failed to read the blob/file"))}})},t=function(){const r=new Uint8Array([1,2,3,4]),n=new File([r],"test").stream();try{return n.getReader({mode:"byob"}),!0}catch{return!1}};if(typeof File>"u"){class r extends Blob{constructor(n,i,o){super(n);let a;o!=null&&o.lastModified&&(a=new Date),(!a||isNaN(a.getFullYear()))&&(a=new Date),this.lastModifiedDate=a,this.lastModified=a.getMilliseconds(),this.name=i||""}}global.File=r}typeof Blob.prototype.arrayBuffer>"u"&&(Blob.prototype.arrayBuffer=function(){const s=new FileReader;return s.readAsArrayBuffer(this),e(s)}),typeof Blob.prototype.text>"u"&&(Blob.prototype.text=function(){const s=new FileReader;return s.readAsText(this),e(s)}),(typeof Blob.prototype.stream>"u"||!t())&&(Blob.prototype.stream=function(){let r=0;const s=this;return new ReadableStream({type:"bytes",autoAllocateChunkSize:512*1024,async pull(n){const i=n.byobRequest.view,a=await s.slice(r,r+i.byteLength).arrayBuffer(),c=new Uint8Array(a);new Uint8Array(i.buffer).set(c);const u=c.byteLength;n.byobRequest.respond(u),r+=u,r>=s.size&&n.close()}})})}if(currentJsRuntime==="NODE"&&typeof CustomEvent>"u"){class e extends Event{constructor(r,s={}){super(r,s),this.detail=s.detail}initCustomEvent(){}}globalThis.CustomEvent=e}const kError=Symbol("error"),kMessage=Symbol("message");class ErrorEvent2 extends Event{constructor(t,r={}){super(t),this[kError]=r.error===void 0?null:r.error,this[kMessage]=r.message===void 0?"":r.message}get error(){return this[kError]}get message(){return this[kMessage]}}Object.defineProperty(ErrorEvent2.prototype,"error",{enumerable:!0});Object.defineProperty(ErrorEvent2.prototype,"message",{enumerable:!0});const ErrorEvent=typeof globalThis.ErrorEvent=="function"?globalThis.ErrorEvent:ErrorEvent2;function isExitCodeZero(e){return e instanceof Error?"exitCode"in e&&(e==null?void 0:e.exitCode)===0||(e==null?void 0:e.name)==="ExitStatus"&&"status"in e&&e.status===0:!1}class UnhandledRejectionsTarget extends EventTarget{constructor(){super(...arguments),this.listenersCount=0}addEventListener(t,r){++this.listenersCount,super.addEventListener(t,r)}removeEventListener(t,r){--this.listenersCount,super.removeEventListener(t,r)}hasListeners(){return this.listenersCount>0}}function improveWASMErrorReporting(e){e.asm={...e.asm};const t=new UnhandledRejectionsTarget;for(const r in e.asm)if(typeof e.asm[r]=="function"){const s=e.asm[r];e.asm[r]=function(...n){var i;try{return s(...n)}catch(o){if(!(o instanceof Error))throw o;const a=clarifyErrorMessage(o,(i=e.lastAsyncifyStackSource)==null?void 0:i.stack);if(e.lastAsyncifyStackSource&&(o.cause=e.lastAsyncifyStackSource),t.hasListeners()){t.dispatchEvent(new ErrorEvent("error",{error:o,message:a}));return}throw isExitCodeZero(o)||showCriticalErrorBox(a),o}}}return t}let functionsMaybeMissingFromAsyncify=[];function getFunctionsMaybeMissingFromAsyncify(){return functionsMaybeMissingFromAsyncify}function clarifyErrorMessage(e,t){if(e.message==="unreachable"){let r=UNREACHABLE_ERROR;t||(r+=`
|
|
2
2
|
|
|
3
3
|
This stack trace is lacking. For a better one initialize
|
|
4
4
|
the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
|
|
@@ -32,13 +32,13 @@ CLI option:
|
|
|
32
32
|
${eol}
|
|
33
33
|
${bold} WASM ERROR${reset}${redBg}`);for(const t of e.split(`
|
|
34
34
|
`))console.log(`${eol} ${t} `);console.log(`${reset}`)}}function extractPHPFunctionsFromStack(e){try{const t=e.split(`
|
|
35
|
-
`).slice(1).map(r=>{const s=r.trim().substring(3).split(" ");return{fn:s.length>=2?s[0]:"<unknown>",isWasm:r.includes("wasm://")}}).filter(({fn:r,isWasm:s})=>s&&!r.startsWith("dynCall_")&&!r.startsWith("invoke_")).map(({fn:r})=>r);return Array.from(new Set(t))}catch{return[]}}class Semaphore{constructor({concurrency:t}){this._running=0,this.concurrency=t,this.queue=[]}get running(){return this._running}async acquire(){for(;;)if(this._running>=this.concurrency)
|
|
36
|
-
`),n.push(`Content-Disposition: form-data; name="${c}"`),
|
|
37
|
-
`),
|
|
35
|
+
`).slice(1).map(r=>{const s=r.trim().substring(3).split(" ");return{fn:s.length>=2?s[0]:"<unknown>",isWasm:r.includes("wasm://")}}).filter(({fn:r,isWasm:s})=>s&&!r.startsWith("dynCall_")&&!r.startsWith("invoke_")).map(({fn:r})=>r);return Array.from(new Set(t))}catch{return[]}}const SleepFinished=Symbol("SleepFinished");function sleep(e){return new Promise(t=>{setTimeout(()=>t(SleepFinished),e)})}class AcquireTimeoutError extends Error{constructor(){super("Acquiring lock timed out")}}class Semaphore{constructor({concurrency:t,timeout:r}){this._running=0,this.concurrency=t,this.timeout=r,this.queue=[]}get remaining(){return this.concurrency-this.running}get running(){return this._running}async acquire(){for(;;)if(this._running>=this.concurrency){const t=new Promise(r=>{this.queue.push(r)});this.timeout!==void 0?await Promise.race([t,sleep(this.timeout)]).then(r=>{if(r===SleepFinished)throw new AcquireTimeoutError}):await t}else{this._running++;let t=!1;return()=>{t||(t=!0,this._running--,this.queue.length>0&&this.queue.shift()())}}}async run(t){const r=await this.acquire();try{return await t()}finally{r()}}}function joinPaths(...e){let t=e.join("/");const r=t[0]==="/",s=t.substring(t.length-1)==="/";return t=normalizePath$1(t),!t&&!r&&(t="."),t&&s&&(t+="/"),t}function basename(e){if(e==="/")return"/";e=normalizePath$1(e);const t=e.lastIndexOf("/");return t===-1?e:e.substr(t+1)}function normalizePath$1(e){const t=e[0]==="/";return e=normalizePathsArray(e.split("/").filter(r=>!!r),!t).join("/"),(t?"/":"")+e.replace(/\/$/,"")}function normalizePathsArray(e,t){let r=0;for(let s=e.length-1;s>=0;s--){const n=e[s];n==="."?e.splice(s,1):n===".."?(e.splice(s,1),r++):r&&(e.splice(s,1),r--)}if(t)for(;r;r--)e.unshift("..");return e}function splitShellCommand(e){let s=0,n="";const i=[];let o="";for(let a=0;a<e.length;a++){const c=e[a];c==="\\"?((e[a+1]==='"'||e[a+1]==="'")&&a++,o+=e[a]):s===0?c==='"'||c==="'"?(s=1,n=c):c.match(/\s/)?(o.trim().length&&i.push(o.trim()),o=c):i.length&&!o?o=i.pop()+c:o+=c:s===1&&(c===n?(s=0,n=""):o+=c)}return o&&i.push(o.trim()),i}function createSpawnHandler(e){return function(t,r=[],s={}){const n=new ChildProcess,i=new ProcessApi(n);return setTimeout(async()=>{let o=[];if(r.length)o=[t,...r];else if(typeof t=="string")o=splitShellCommand(t);else if(Array.isArray(t))o=t;else throw new Error("Invalid command ",t);await e(o,i,s),n.emit("spawn",!0)}),n}}class EventEmitter{constructor(){this.listeners={}}emit(t,r){this.listeners[t]&&this.listeners[t].forEach(function(s){s(r)})}on(t,r){this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(r)}}class ProcessApi extends EventEmitter{constructor(t){super(),this.childProcess=t,this.exited=!1,this.stdinData=[],t.on("stdin",r=>{this.stdinData?this.stdinData.push(r.slice()):this.emit("stdin",r)})}stdout(t){typeof t=="string"&&(t=new TextEncoder().encode(t)),this.childProcess.stdout.emit("data",t)}stdoutEnd(){this.childProcess.stdout.emit("end",{})}stderr(t){typeof t=="string"&&(t=new TextEncoder().encode(t)),this.childProcess.stderr.emit("data",t)}stderrEnd(){this.childProcess.stderr.emit("end",{})}exit(t){this.exited||(this.exited=!0,this.childProcess.emit("exit",t))}flushStdin(){if(this.stdinData)for(let t=0;t<this.stdinData.length;t++)this.emit("stdin",this.stdinData[t]);this.stdinData=null}}let lastPid=9743;class ChildProcess extends EventEmitter{constructor(t=lastPid++){super(),this.pid=t,this.stdout=new EventEmitter,this.stderr=new EventEmitter;const r=this;this.stdin={write:s=>{r.emit("stdin",s)}}}}ReadableStream.prototype[Symbol.asyncIterator]||(ReadableStream.prototype[Symbol.asyncIterator]=async function*(){const e=this.getReader();try{for(;;){const{done:t,value:r}=await e.read();if(t)return;yield r}}finally{e.releaseLock()}},ReadableStream.prototype.iterate=ReadableStream.prototype[Symbol.asyncIterator]);class PHPResponse{constructor(t,r,s,n="",i=0){this.httpStatusCode=t,this.headers=r,this.bytes=s,this.exitCode=i,this.errors=n}static fromRawData(t){return new PHPResponse(t.httpStatusCode,t.headers,t.bytes,t.errors,t.exitCode)}toRawData(){return{headers:this.headers,bytes:this.bytes,errors:this.errors,exitCode:this.exitCode,httpStatusCode:this.httpStatusCode}}get json(){return JSON.parse(this.text)}get text(){return new TextDecoder().decode(this.bytes)}}const DEFAULT_BASE_URL="http://example.com";function toRelativeUrl(e){return e.toString().substring(e.origin.length)}function removePathPrefix(e,t){return!t||!e.startsWith(t)?e:e.substring(t.length)}function ensurePathPrefix(e,t){return!t||e.startsWith(t)?e:t+e}async function encodeAsMultipart(e){const t=`----${Math.random().toString(36).slice(2)}`,r=`multipart/form-data; boundary=${t}`,s=new TextEncoder,n=[];for(const[c,u]of Object.entries(e))n.push(`--${t}\r
|
|
36
|
+
`),n.push(`Content-Disposition: form-data; name="${c}"`),u instanceof File&&n.push(`; filename="${u.name}"`),n.push(`\r
|
|
37
|
+
`),u instanceof File&&(n.push("Content-Type: application/octet-stream"),n.push(`\r
|
|
38
38
|
`)),n.push(`\r
|
|
39
|
-
`),
|
|
39
|
+
`),u instanceof File?n.push(await fileToUint8Array(u)):n.push(u),n.push(`\r
|
|
40
40
|
`);n.push(`--${t}--\r
|
|
41
|
-
`);const i=n.reduce((c,d)=>c+d.length,0),o=new Uint8Array(i);let a=0;for(const c of n)o.set(typeof c=="string"?s.encode(c):c,a),a+=c.length;return{bytes:o,contentType:r}}function fileToUint8Array(e){return new Promise(t=>{const r=new FileReader;r.onload=()=>{t(new Uint8Array(r.result))},r.readAsArrayBuffer(e)})}var m,F,N,R,x,_,C,b,I,K,O,Z,U,X;class PHPRequestHandler{constructor(t,r={}){u(this,I);u(this,O);u(this,U);u(this,m,void 0);u(this,F,void 0);u(this,N,void 0);u(this,R,void 0);u(this,x,void 0);u(this,_,void 0);u(this,C,void 0);u(this,b,void 0);p(this,b,new Semaphore({concurrency:1}));const{documentRoot:s="/www/",absoluteUrl:n=typeof location=="object"?location==null?void 0:location.href:"",rewriteRules:i=[]}=r;this.php=t,p(this,m,s);const o=new URL(n);p(this,N,o.hostname),p(this,R,o.port?Number(o.port):o.protocol==="https:"?443:80),p(this,F,(o.protocol||"").replace(":",""));const a=l(this,R)!==443&&l(this,R)!==80;p(this,x,[l(this,N),a?`:${l(this,R)}`:""].join("")),p(this,_,o.pathname.replace(/\/+$/,"")),p(this,C,[`${l(this,F)}://`,l(this,x),l(this,_)].join("")),this.rewriteRules=i}pathToInternalUrl(t){return`${this.absoluteUrl}${t}`}internalUrlToPath(t){const r=new URL(t);return r.pathname.startsWith(l(this,_))&&(r.pathname=r.pathname.slice(l(this,_).length)),toRelativeUrl(r)}get isRequestRunning(){return l(this,b).running>0}get absoluteUrl(){return l(this,C)}get documentRoot(){return l(this,m)}async request(t){const r=t.url.startsWith("http://")||t.url.startsWith("https://"),s=new URL(t.url.split("#")[0],r?void 0:DEFAULT_BASE_URL),n=applyRewriteRules(removePathPrefix(decodeURIComponent(s.pathname),l(this,_)),this.rewriteRules),i=joinPaths(l(this,m),n);return seemsLikeAPHPRequestHandlerPath(i)?await f(this,O,Z).call(this,t,s):f(this,I,K).call(this,i)}}m=new WeakMap,F=new WeakMap,N=new WeakMap,R=new WeakMap,x=new WeakMap,_=new WeakMap,C=new WeakMap,b=new WeakMap,I=new WeakSet,K=function(t){if(!this.php.fileExists(t))return new PHPResponse(404,{"x-file-type":["static"]},new TextEncoder().encode("404 File not found"));const r=this.php.readFileAsBuffer(t);return new PHPResponse(200,{"content-length":[`${r.byteLength}`],"content-type":[inferMimeType(t)],"accept-ranges":["bytes"],"cache-control":["public, max-age=0"]},r)},O=new WeakSet,Z=async function(t,r){var n;if(l(this,b).running>0&&((n=t.headers)==null?void 0:n["x-request-issuer"])==="php")return console.warn("Possible deadlock: Called request() before the previous request() have finished. PHP likely issued an HTTP call to itself. Normally this would lead to infinite waiting as Request 1 holds the lock that the Request 2 is waiting to acquire. That's not useful, so PHPRequestHandler will return error 502 instead."),new PHPResponse(502,{},new TextEncoder().encode("502 Bad Gateway"));const s=await l(this,b).acquire();try{this.php.addServerGlobalEntry("REMOTE_ADDR","127.0.0.1"),this.php.addServerGlobalEntry("DOCUMENT_ROOT",l(this,m)),this.php.addServerGlobalEntry("HTTPS",l(this,C).startsWith("https://")?"on":"");let i="GET";const o={host:l(this,x),...normalizeHeaders(t.headers||{})};let a=t.body;if(typeof a=="object"&&!(a instanceof Uint8Array)){i="POST";const{bytes:d,contentType:h}=await encodeAsMultipart(a);a=d,o["content-type"]=h}let c;try{c=f(this,U,X).call(this,decodeURIComponent(r.pathname))}catch{return new PHPResponse(404,{},new TextEncoder().encode("404 File not found"))}try{return await this.php.run({relativeUri:ensurePathPrefix(toRelativeUrl(r),l(this,_)),protocol:l(this,F),method:t.method||i,body:a,scriptPath:c,headers:o})}catch(d){const h=d;if(h!=null&&h.response)return h.response;throw d}}finally{s()}},U=new WeakSet,X=function(t){let r=removePathPrefix(t,l(this,_));r=applyRewriteRules(r,this.rewriteRules),r.includes(".php")?r=r.split(".php")[0]+".php":this.php.isDir(`${l(this,m)}${r}`)?(r.endsWith("/")||(r=`${r}/`),r=`${r}index.php`):r="/index.php";const s=`${l(this,m)}${r}`;if(this.php.fileExists(s))return s;throw new Error(`File not found: ${s}`)};function inferMimeType(e){switch(e.split(".").pop()){case"css":return"text/css";case"js":return"application/javascript";case"png":return"image/png";case"jpg":case"jpeg":return"image/jpeg";case"gif":return"image/gif";case"svg":return"image/svg+xml";case"woff":return"font/woff";case"woff2":return"font/woff2";case"ttf":return"font/ttf";case"otf":return"font/otf";case"eot":return"font/eot";case"ico":return"image/x-icon";case"html":return"text/html";case"json":return"application/json";case"xml":return"application/xml";case"txt":case"md":return"text/plain";default:return"application-octet-stream"}}function seemsLikeAPHPRequestHandlerPath(e){return seemsLikeAPHPFile(e)||seemsLikeADirectoryRoot(e)}function seemsLikeAPHPFile(e){return e.endsWith(".php")||e.includes(".php/")}function seemsLikeADirectoryRoot(e){return!e.split("/").pop().includes(".")}function applyRewriteRules(e,t){for(const r of t)if(new RegExp(r.match).test(e))return e.replace(r.match,r.replacement);return e}const FileErrorCodes={0:"No error occurred. System call completed successfully.",1:"Argument list too long.",2:"Permission denied.",3:"Address in use.",4:"Address not available.",5:"Address family not supported.",6:"Resource unavailable, or operation would block.",7:"Connection already in progress.",8:"Bad file descriptor.",9:"Bad message.",10:"Device or resource busy.",11:"Operation canceled.",12:"No child processes.",13:"Connection aborted.",14:"Connection refused.",15:"Connection reset.",16:"Resource deadlock would occur.",17:"Destination address required.",18:"Mathematics argument out of domain of function.",19:"Reserved.",20:"File exists.",21:"Bad address.",22:"File too large.",23:"Host is unreachable.",24:"Identifier removed.",25:"Illegal byte sequence.",26:"Operation in progress.",27:"Interrupted function.",28:"Invalid argument.",29:"I/O error.",30:"Socket is connected.",31:"There is a directory under that path.",32:"Too many levels of symbolic links.",33:"File descriptor value too large.",34:"Too many links.",35:"Message too large.",36:"Reserved.",37:"Filename too long.",38:"Network is down.",39:"Connection aborted by network.",40:"Network unreachable.",41:"Too many files open in system.",42:"No buffer space available.",43:"No such device.",44:"There is no such file or directory OR the parent directory does not exist.",45:"Executable file format error.",46:"No locks available.",47:"Reserved.",48:"Not enough space.",49:"No message of the desired type.",50:"Protocol not available.",51:"No space left on device.",52:"Function not supported.",53:"The socket is not connected.",54:"Not a directory or a symbolic link to a directory.",55:"Directory not empty.",56:"State not recoverable.",57:"Not a socket.",58:"Not supported, or operation not supported on socket.",59:"Inappropriate I/O control operation.",60:"No such device or address.",61:"Value too large to be stored in data type.",62:"Previous owner died.",63:"Operation not permitted.",64:"Broken pipe.",65:"Protocol error.",66:"Protocol not supported.",67:"Protocol wrong type for socket.",68:"Result too large.",69:"Read-only file system.",70:"Invalid seek.",71:"No such process.",72:"Reserved.",73:"Connection timed out.",74:"Text file busy.",75:"Cross-device link.",76:"Extension: Capabilities insufficient."};function getEmscriptenFsError(e){const t=typeof e=="object"?e==null?void 0:e.errno:null;if(t in FileErrorCodes)return FileErrorCodes[t]}function rethrowFileSystemError(e=""){return function(r,s,n){const i=n.value;n.value=function(...o){try{return i.apply(this,o)}catch(a){const c=typeof a=="object"?a==null?void 0:a.errno:null;if(c in FileErrorCodes){const d=FileErrorCodes[c],h=typeof o[0]=="string"?o[0]:null,P=h!==null?e.replaceAll("{path}",h):e;throw new Error(`${P}: ${d}`,{cause:a})}throw a}}}}const loadedRuntimes=new Map;function getLoadedRuntime(e){return loadedRuntimes.get(e)}(function(){var e;return typeof process<"u"&&((e=process.release)==null?void 0:e.name)==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"})();var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__decorateClass=(e,t,r,s)=>{for(var n=s>1?void 0:s?__getOwnPropDesc(t,r):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(n=(s?o(t,r,n):o(n))||n);return s&&n&&__defProp(t,r,n),n};const STRING="string",NUMBER="number",__private__dont__use=Symbol("__private__dont__use");class PHPExecutionFailureError extends Error{constructor(t,r,s){super(t),this.response=r,this.source=s}}var S,k,A,y,w,g,E,H,M,ee,B,te,L,re,D,se,q,ne,$,ie,W,oe,j,ae,z,le,G,ce,J,ue,Q,de;class BasePHP{constructor(e,t){u(this,M);u(this,B);u(this,L);u(this,D);u(this,q);u(this,$);u(this,W);u(this,j);u(this,z);u(this,G);u(this,J);u(this,Q);u(this,S,void 0);u(this,k,void 0);u(this,A,void 0);u(this,y,void 0);u(this,w,void 0);u(this,g,void 0);u(this,E,void 0);u(this,H,void 0);p(this,S,[]),p(this,y,!1),p(this,w,null),p(this,g,{}),p(this,E,new Map),p(this,H,[]),this.semaphore=new Semaphore({concurrency:1}),e!==void 0&&this.initializeRuntime(e),t&&(this.requestHandler=new PHPBrowser(new PHPRequestHandler(this,t)))}addEventListener(e,t){l(this,E).has(e)||l(this,E).set(e,new Set),l(this,E).get(e).add(t)}removeEventListener(e,t){var r;(r=l(this,E).get(e))==null||r.delete(t)}dispatchEvent(e){const t=l(this,E).get(e.type);if(t)for(const r of t)r(e)}async onMessage(e){l(this,H).push(e)}async setSpawnHandler(handler){typeof handler=="string"&&(handler=createSpawnHandler(eval(handler))),this[__private__dont__use].spawnProcess=handler}get absoluteUrl(){return this.requestHandler.requestHandler.absoluteUrl}get documentRoot(){return this.requestHandler.requestHandler.documentRoot}pathToInternalUrl(e){return this.requestHandler.requestHandler.pathToInternalUrl(e)}internalUrlToPath(e){return this.requestHandler.requestHandler.internalUrlToPath(e)}initializeRuntime(e){if(this[__private__dont__use])throw new Error("PHP runtime already initialized.");const t=getLoadedRuntime(e);if(!t)throw new Error("Invalid PHP runtime id.");this[__private__dont__use]=t,t.onMessage=async r=>{for(const s of l(this,H)){const n=await s(r);if(n)return n}return""},p(this,w,improveWASMErrorReporting(t)),this.dispatchEvent({type:"runtime.initialized"})}async setSapiName(e){if(this[__private__dont__use].ccall("wasm_set_sapi_name",NUMBER,[STRING],[e])!==0)throw new Error("Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?");p(this,A,e)}setPhpIniPath(e){if(l(this,y))throw new Error("Cannot set PHP ini path after calling run().");p(this,k,e),this[__private__dont__use].ccall("wasm_set_phpini_path",null,["string"],[e])}setPhpIniEntry(e,t){if(l(this,y))throw new Error("Cannot set PHP ini entries after calling run().");l(this,S).push([e,t])}chdir(e){this[__private__dont__use].FS.chdir(e)}async request(e,t){if(!this.requestHandler)throw new Error("No request handler available.");return this.requestHandler.request(e,t)}async run(e){const t=await this.semaphore.acquire();let r;try{if(l(this,y)||(f(this,M,ee).call(this),p(this,y,!0)),e.scriptPath&&!this.fileExists(e.scriptPath))throw new Error(`The script path "${e.scriptPath}" does not exist.`);f(this,j,ae).call(this,e.scriptPath||""),f(this,L,re).call(this,e.relativeUri||""),f(this,q,ne).call(this,e.method||"GET");const s=normalizeHeaders(e.headers||{}),n=s.host||"example.com:443";f(this,D,se).call(this,n,e.protocol||"http"),f(this,$,ie).call(this,s),e.body&&(r=f(this,W,oe).call(this,e.body)),typeof e.code=="string"&&f(this,J,ue).call(this," ?>"+e.code),f(this,z,le).call(this);const i=e.env||{};for(const a in i)f(this,G,ce).call(this,a,i[a]);const o=await f(this,Q,de).call(this);if(o.exitCode!==0){console.warn("PHP.run() output was:",o.text);const a=new PHPExecutionFailureError(`PHP.run() failed with exit code ${o.exitCode} and the following output: `+o.errors,o,"request");throw console.error(a),a}return o}catch(s){throw this.dispatchEvent({type:"request.error",error:s,source:s.source??"php-wasm"}),s}finally{try{r&&this[__private__dont__use].free(r)}finally{t(),this.dispatchEvent({type:"request.end"})}}}addServerGlobalEntry(e,t){l(this,g)[e]=t}defineConstant(e,t){let r={};try{r=JSON.parse(this.fileExists("/internal/consts.json")&&this.readFileAsText("/internal/consts.json")||"{}")}catch{}this.writeFile("/internal/consts.json",JSON.stringify({...r,[e]:t}))}mkdir(e){this[__private__dont__use].FS.mkdirTree(e)}mkdirTree(e){this.mkdir(e)}readFileAsText(e){return new TextDecoder().decode(this.readFileAsBuffer(e))}readFileAsBuffer(e){return this[__private__dont__use].FS.readFile(e)}writeFile(e,t){this[__private__dont__use].FS.writeFile(e,t)}unlink(e){this[__private__dont__use].FS.unlink(e)}mv(e,t){try{this[__private__dont__use].FS.rename(e,t)}catch(r){const s=getEmscriptenFsError(r);throw s?new Error(`Could not move ${e} to ${t}: ${s}`,{cause:r}):r}}rmdir(e,t={recursive:!0}){t!=null&&t.recursive&&this.listFiles(e).forEach(r=>{const s=`${e}/${r}`;this.isDir(s)?this.rmdir(s,t):this.unlink(s)}),this[__private__dont__use].FS.rmdir(e)}listFiles(e,t={prependPath:!1}){if(!this.fileExists(e))return[];try{const r=this[__private__dont__use].FS.readdir(e).filter(s=>s!=="."&&s!=="..");if(t.prependPath){const s=e.replace(/\/$/,"");return r.map(n=>`${s}/${n}`)}return r}catch(r){return console.error(r,{path:e}),[]}}isDir(e){return this.fileExists(e)?this[__private__dont__use].FS.isDir(this[__private__dont__use].FS.lookupPath(e).node.mode):!1}fileExists(e){try{return this[__private__dont__use].FS.lookupPath(e),!0}catch{return!1}}hotSwapPHPRuntime(e){const t=this[__private__dont__use].FS;try{this.exit()}catch{}if(this.initializeRuntime(e),l(this,k)&&this.setPhpIniPath(l(this,k)),l(this,A)&&this.setSapiName(l(this,A)),this.requestHandler){const r=this.documentRoot;copyFS(t,this[__private__dont__use].FS,r)}}exit(e=0){this.dispatchEvent({type:"runtime.beforedestroy"});try{this[__private__dont__use]._exit(e)}catch{}p(this,y,!1),p(this,w,null),delete this[__private__dont__use].onMessage,delete this[__private__dont__use]}}S=new WeakMap,k=new WeakMap,A=new WeakMap,y=new WeakMap,w=new WeakMap,g=new WeakMap,E=new WeakMap,H=new WeakMap,M=new WeakSet,ee=function(){if(this.setPhpIniEntry("auto_prepend_file","/internal/consts.php"),this.fileExists("/internal/consts.php")||this.writeFile("/internal/consts.php",`<?php
|
|
41
|
+
`);const i=n.reduce((c,u)=>c+u.length,0),o=new Uint8Array(i);let a=0;for(const c of n)o.set(typeof c=="string"?s.encode(c):c,a),a+=c.length;return{bytes:o,contentType:r}}function fileToUint8Array(e){return new Promise(t=>{const r=new FileReader;r.onload=()=>{t(new Uint8Array(r.result))},r.readAsArrayBuffer(e)})}class HttpCookieStore{constructor(){this.cookies={}}rememberCookiesFromResponseHeaders(t){if(t!=null&&t["set-cookie"])for(const r of t["set-cookie"])try{if(!r.includes("="))continue;const s=r.indexOf("="),n=r.substring(0,s),i=r.substring(s+1).split(";")[0];this.cookies[n]=i}catch(s){console.error(s)}}getCookieRequestHeader(){const t=[];for(const r in this.cookies)t.push(`${r}=${this.cookies[r]}`);return t.join("; ")}}var m,b,A,P,S,_,T,v,F,H,Z,N,X,O,ee;class PHPRequestHandler{constructor(t,r={}){d(this,H);d(this,N);d(this,O);d(this,m,void 0);d(this,b,void 0);d(this,A,void 0);d(this,P,void 0);d(this,S,void 0);d(this,_,void 0);d(this,T,void 0);d(this,v,void 0);d(this,F,void 0);p(this,v,new Semaphore({concurrency:1}));const{documentRoot:s="/www/",absoluteUrl:n=typeof location=="object"?location==null?void 0:location.href:"",rewriteRules:i=[]}=r;this.php=t,p(this,F,new HttpCookieStore),p(this,m,s);const o=new URL(n);p(this,A,o.hostname),p(this,P,o.port?Number(o.port):o.protocol==="https:"?443:80),p(this,b,(o.protocol||"").replace(":",""));const a=l(this,P)!==443&&l(this,P)!==80;p(this,S,[l(this,A),a?`:${l(this,P)}`:""].join("")),p(this,_,o.pathname.replace(/\/+$/,"")),p(this,T,[`${l(this,b)}://`,l(this,S),l(this,_)].join("")),this.rewriteRules=i}pathToInternalUrl(t){return`${this.absoluteUrl}${t}`}internalUrlToPath(t){const r=new URL(t);return r.pathname.startsWith(l(this,_))&&(r.pathname=r.pathname.slice(l(this,_).length)),toRelativeUrl(r)}get isRequestRunning(){return l(this,v).running>0}get absoluteUrl(){return l(this,T)}get documentRoot(){return l(this,m)}async request(t){const r=t.url.startsWith("http://")||t.url.startsWith("https://"),s=new URL(t.url.split("#")[0],r?void 0:DEFAULT_BASE_URL),n=applyRewriteRules(removePathPrefix(decodeURIComponent(s.pathname),l(this,_)),this.rewriteRules),i=joinPaths(l(this,m),n);return seemsLikeAPHPRequestHandlerPath(i)?await f(this,N,X).call(this,t,s):f(this,H,Z).call(this,i)}}m=new WeakMap,b=new WeakMap,A=new WeakMap,P=new WeakMap,S=new WeakMap,_=new WeakMap,T=new WeakMap,v=new WeakMap,F=new WeakMap,H=new WeakSet,Z=function(t){if(!this.php.fileExists(t))return new PHPResponse(404,{"x-file-type":["static"]},new TextEncoder().encode("404 File not found"));const r=this.php.readFileAsBuffer(t);return new PHPResponse(200,{"content-length":[`${r.byteLength}`],"content-type":[inferMimeType(t)],"accept-ranges":["bytes"],"cache-control":["public, max-age=0"]},r)},N=new WeakSet,X=async function(t,r){var n;if(l(this,v).running>0&&((n=t.headers)==null?void 0:n["x-request-issuer"])==="php")return console.warn("Possible deadlock: Called request() before the previous request() have finished. PHP likely issued an HTTP call to itself. Normally this would lead to infinite waiting as Request 1 holds the lock that the Request 2 is waiting to acquire. That's not useful, so PHPRequestHandler will return error 502 instead."),new PHPResponse(502,{},new TextEncoder().encode("502 Bad Gateway"));const s=await l(this,v).acquire();try{let i="GET";const o={host:l(this,S),...normalizeHeaders(t.headers||{}),cookie:l(this,F).getCookieRequestHeader()};let a=t.body;if(typeof a=="object"&&!(a instanceof Uint8Array)){i="POST";const{bytes:u,contentType:h}=await encodeAsMultipart(a);a=u,o["content-type"]=h}let c;try{c=f(this,O,ee).call(this,decodeURIComponent(r.pathname))}catch{return new PHPResponse(404,{},new TextEncoder().encode("404 File not found"))}try{const u=await this.php.run({relativeUri:ensurePathPrefix(toRelativeUrl(r),l(this,_)),protocol:l(this,b),method:t.method||i,$_SERVER:{REMOTE_ADDR:"127.0.0.1",DOCUMENT_ROOT:l(this,m),HTTPS:l(this,T).startsWith("https://")?"on":""},body:a,scriptPath:c,headers:o});return l(this,F).rememberCookiesFromResponseHeaders(u.headers),u}catch(u){const h=u;if(h!=null&&h.response)return h.response;throw u}}finally{s()}},O=new WeakSet,ee=function(t){let r=removePathPrefix(t,l(this,_));r=applyRewriteRules(r,this.rewriteRules),r.includes(".php")?r=r.split(".php")[0]+".php":this.php.isDir(`${l(this,m)}${r}`)?(r.endsWith("/")||(r=`${r}/`),r=`${r}index.php`):r="/index.php";const s=`${l(this,m)}${r}`;if(this.php.fileExists(s))return s;throw new Error(`File not found: ${s}`)};function inferMimeType(e){switch(e.split(".").pop()){case"css":return"text/css";case"js":return"application/javascript";case"png":return"image/png";case"jpg":case"jpeg":return"image/jpeg";case"gif":return"image/gif";case"svg":return"image/svg+xml";case"woff":return"font/woff";case"woff2":return"font/woff2";case"ttf":return"font/ttf";case"otf":return"font/otf";case"eot":return"font/eot";case"ico":return"image/x-icon";case"html":return"text/html";case"json":return"application/json";case"xml":return"application/xml";case"txt":case"md":return"text/plain";case"pdf":return"application/pdf";case"webp":return"image/webp";case"mp3":return"audio/mpeg";case"mp4":return"video/mp4";case"csv":return"text/csv";case"xls":return"application/vnd.ms-excel";case"xlsx":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";case"doc":return"application/msword";case"docx":return"application/vnd.openxmlformats-officedocument.wordprocessingml.document";case"ppt":return"application/vnd.ms-powerpoint";case"pptx":return"application/vnd.openxmlformats-officedocument.presentationml.presentation";case"zip":return"application/zip";case"rar":return"application/x-rar-compressed";case"tar":return"application/x-tar";case"gz":return"application/gzip";case"7z":return"application/x-7z-compressed";default:return"application-octet-stream"}}function seemsLikeAPHPRequestHandlerPath(e){return seemsLikeAPHPFile(e)||seemsLikeADirectoryRoot(e)}function seemsLikeAPHPFile(e){return e.endsWith(".php")||e.includes(".php/")}function seemsLikeADirectoryRoot(e){return!e.split("/").pop().includes(".")}function applyRewriteRules(e,t){for(const r of t)if(new RegExp(r.match).test(e))return e.replace(r.match,r.replacement);return e}const FileErrorCodes={0:"No error occurred. System call completed successfully.",1:"Argument list too long.",2:"Permission denied.",3:"Address in use.",4:"Address not available.",5:"Address family not supported.",6:"Resource unavailable, or operation would block.",7:"Connection already in progress.",8:"Bad file descriptor.",9:"Bad message.",10:"Device or resource busy.",11:"Operation canceled.",12:"No child processes.",13:"Connection aborted.",14:"Connection refused.",15:"Connection reset.",16:"Resource deadlock would occur.",17:"Destination address required.",18:"Mathematics argument out of domain of function.",19:"Reserved.",20:"File exists.",21:"Bad address.",22:"File too large.",23:"Host is unreachable.",24:"Identifier removed.",25:"Illegal byte sequence.",26:"Operation in progress.",27:"Interrupted function.",28:"Invalid argument.",29:"I/O error.",30:"Socket is connected.",31:"There is a directory under that path.",32:"Too many levels of symbolic links.",33:"File descriptor value too large.",34:"Too many links.",35:"Message too large.",36:"Reserved.",37:"Filename too long.",38:"Network is down.",39:"Connection aborted by network.",40:"Network unreachable.",41:"Too many files open in system.",42:"No buffer space available.",43:"No such device.",44:"There is no such file or directory OR the parent directory does not exist.",45:"Executable file format error.",46:"No locks available.",47:"Reserved.",48:"Not enough space.",49:"No message of the desired type.",50:"Protocol not available.",51:"No space left on device.",52:"Function not supported.",53:"The socket is not connected.",54:"Not a directory or a symbolic link to a directory.",55:"Directory not empty.",56:"State not recoverable.",57:"Not a socket.",58:"Not supported, or operation not supported on socket.",59:"Inappropriate I/O control operation.",60:"No such device or address.",61:"Value too large to be stored in data type.",62:"Previous owner died.",63:"Operation not permitted.",64:"Broken pipe.",65:"Protocol error.",66:"Protocol not supported.",67:"Protocol wrong type for socket.",68:"Result too large.",69:"Read-only file system.",70:"Invalid seek.",71:"No such process.",72:"Reserved.",73:"Connection timed out.",74:"Text file busy.",75:"Cross-device link.",76:"Extension: Capabilities insufficient."};function getEmscriptenFsError(e){const t=typeof e=="object"?e==null?void 0:e.errno:null;if(t in FileErrorCodes)return FileErrorCodes[t]}function rethrowFileSystemError(e=""){return function(r,s,n){const i=n.value;n.value=function(...o){try{return i.apply(this,o)}catch(a){const c=typeof a=="object"?a==null?void 0:a.errno:null;if(c in FileErrorCodes){const u=FileErrorCodes[c],h=typeof o[0]=="string"?o[0]:null,g=h!==null?e.replaceAll("{path}",h):e;throw new Error(`${g}: ${u}`,{cause:a})}throw a}}}}const loadedRuntimes=new Map;function getLoadedRuntime(e){return loadedRuntimes.get(e)}(function(){var e;return typeof process<"u"&&((e=process.release)==null?void 0:e.name)==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"})();var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__decorateClass=(e,t,r,s)=>{for(var n=s>1?void 0:s?__getOwnPropDesc(t,r):t,i=e.length-1,o;i>=0;i--)(o=e[i])&&(n=(s?o(t,r,n):o(n))||n);return s&&n&&__defProp(t,r,n),n};const STRING="string",NUMBER="number",__private__dont__use=Symbol("__private__dont__use");class PHPExecutionFailureError extends Error{constructor(t,r,s){super(t),this.response=r,this.source=s}}var R,x,k,y,w,E,C,I,te,M,re,U,se,B,ne,L,ie,D,oe,$,ae,q,le,j,ce,W,ue,z,de,G,he,J,pe,V,fe,Q,_e;class BasePHP{constructor(e,t){d(this,I);d(this,M);d(this,U);d(this,B);d(this,L);d(this,D);d(this,$);d(this,q);d(this,j);d(this,W);d(this,z);d(this,G);d(this,J);d(this,V);d(this,Q);d(this,R,void 0);d(this,x,void 0);d(this,k,void 0);d(this,y,void 0);d(this,w,void 0);d(this,E,void 0);d(this,C,void 0);p(this,R,[]),p(this,y,!1),p(this,w,null),p(this,E,new Map),p(this,C,[]),this.semaphore=new Semaphore({concurrency:1}),e!==void 0&&this.initializeRuntime(e),t&&(this.requestHandler=new PHPRequestHandler(this,t))}addEventListener(e,t){l(this,E).has(e)||l(this,E).set(e,new Set),l(this,E).get(e).add(t)}removeEventListener(e,t){var r;(r=l(this,E).get(e))==null||r.delete(t)}dispatchEvent(e){const t=l(this,E).get(e.type);if(t)for(const r of t)r(e)}async onMessage(e){l(this,C).push(e)}async setSpawnHandler(handler){typeof handler=="string"&&(handler=createSpawnHandler(eval(handler))),this[__private__dont__use].spawnProcess=handler}get absoluteUrl(){return this.requestHandler.absoluteUrl}get documentRoot(){return this.requestHandler.documentRoot}pathToInternalUrl(e){return this.requestHandler.pathToInternalUrl(e)}internalUrlToPath(e){return this.requestHandler.internalUrlToPath(e)}initializeRuntime(e){if(this[__private__dont__use])throw new Error("PHP runtime already initialized.");const t=getLoadedRuntime(e);if(!t)throw new Error("Invalid PHP runtime id.");this[__private__dont__use]=t,t.onMessage=async r=>{for(const s of l(this,C)){const n=await s(r);if(n)return n}return""},p(this,w,improveWASMErrorReporting(t)),this.dispatchEvent({type:"runtime.initialized"})}async setSapiName(e){if(this[__private__dont__use].ccall("wasm_set_sapi_name",NUMBER,[STRING],[e])!==0)throw new Error("Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?");p(this,k,e)}setPhpIniPath(e){if(l(this,y))throw new Error("Cannot set PHP ini path after calling run().");p(this,x,e),this[__private__dont__use].ccall("wasm_set_phpini_path",null,["string"],[e])}setPhpIniEntry(e,t){if(l(this,y))throw new Error("Cannot set PHP ini entries after calling run().");l(this,R).push([e,t])}chdir(e){this[__private__dont__use].FS.chdir(e)}async request(e){if(!this.requestHandler)throw new Error("No request handler available.");return this.requestHandler.request(e)}async run(e){const t=await this.semaphore.acquire();let r;try{if(l(this,y)||(f(this,M,re).call(this),p(this,y,!0)),e.scriptPath&&!this.fileExists(e.scriptPath))throw new Error(`The script path "${e.scriptPath}" does not exist.`);f(this,z,de).call(this,e.scriptPath||""),f(this,B,ne).call(this,e.relativeUri||""),f(this,q,le).call(this,e.method||"GET");const s=normalizeHeaders(e.headers||{}),n=s.host||"example.com:443",i=f(this,$,ae).call(this,n,e.protocol||"http");f(this,L,ie).call(this,n),f(this,D,oe).call(this,i),f(this,j,ce).call(this,s),e.body&&(r=f(this,W,ue).call(this,e.body)),typeof e.code=="string"&&f(this,V,fe).call(this," ?>"+e.code);const o=f(this,I,te).call(this,e.$_SERVER,s,i);for(const u in o)f(this,G,he).call(this,u,o[u]);const a=e.env||{};for(const u in a)f(this,J,pe).call(this,u,a[u]);const c=await f(this,Q,_e).call(this);if(c.exitCode!==0){console.warn("PHP.run() output was:",c.text);const u=new PHPExecutionFailureError(`PHP.run() failed with exit code ${c.exitCode} and the following output: `+c.errors,c,"request");throw console.error(u),u}return c}catch(s){throw this.dispatchEvent({type:"request.error",error:s,source:s.source??"php-wasm"}),s}finally{try{r&&this[__private__dont__use].free(r)}finally{t(),this.dispatchEvent({type:"request.end"})}}}defineConstant(e,t){let r={};try{r=JSON.parse(this.fileExists("/internal/consts.json")&&this.readFileAsText("/internal/consts.json")||"{}")}catch{}this.writeFile("/internal/consts.json",JSON.stringify({...r,[e]:t}))}mkdir(e){this[__private__dont__use].FS.mkdirTree(e)}mkdirTree(e){this.mkdir(e)}readFileAsText(e){return new TextDecoder().decode(this.readFileAsBuffer(e))}readFileAsBuffer(e){return this[__private__dont__use].FS.readFile(e)}writeFile(e,t){this[__private__dont__use].FS.writeFile(e,t)}unlink(e){this[__private__dont__use].FS.unlink(e)}mv(e,t){try{this[__private__dont__use].FS.rename(e,t)}catch(r){const s=getEmscriptenFsError(r);throw s?new Error(`Could not move ${e} to ${t}: ${s}`,{cause:r}):r}}rmdir(e,t={recursive:!0}){t!=null&&t.recursive&&this.listFiles(e).forEach(r=>{const s=`${e}/${r}`;this.isDir(s)?this.rmdir(s,t):this.unlink(s)}),this[__private__dont__use].FS.rmdir(e)}listFiles(e,t={prependPath:!1}){if(!this.fileExists(e))return[];try{const r=this[__private__dont__use].FS.readdir(e).filter(s=>s!=="."&&s!=="..");if(t.prependPath){const s=e.replace(/\/$/,"");return r.map(n=>`${s}/${n}`)}return r}catch(r){return console.error(r,{path:e}),[]}}isDir(e){return this.fileExists(e)?this[__private__dont__use].FS.isDir(this[__private__dont__use].FS.lookupPath(e).node.mode):!1}fileExists(e){try{return this[__private__dont__use].FS.lookupPath(e),!0}catch{return!1}}hotSwapPHPRuntime(e,t){const r=this[__private__dont__use].FS;try{this.exit()}catch{}this.initializeRuntime(e),l(this,x)&&this.setPhpIniPath(l(this,x)),l(this,k)&&this.setSapiName(l(this,k)),t&©FS(r,this[__private__dont__use].FS,t)}exit(e=0){this.dispatchEvent({type:"runtime.beforedestroy"});try{this[__private__dont__use]._exit(e)}catch{}p(this,y,!1),p(this,w,null),delete this[__private__dont__use].onMessage,delete this[__private__dont__use]}}R=new WeakMap,x=new WeakMap,k=new WeakMap,y=new WeakMap,w=new WeakMap,E=new WeakMap,C=new WeakMap,I=new WeakSet,te=function(e,t,r){const s={...e||{}};s.HTTPS=s.HTTPS||r===443?"on":"off";for(const n in t){let i="HTTP_";["content-type","content-length"].includes(n.toLowerCase())&&(i=""),s[`${i}${n.toUpperCase().replace(/-/g,"_")}`]=t[n]}return s},M=new WeakSet,re=function(){if(this.setPhpIniEntry("auto_prepend_file","/internal/consts.php"),this.fileExists("/internal/consts.php")||this.writeFile("/internal/consts.php",`<?php
|
|
42
42
|
if(file_exists('/internal/consts.json')) {
|
|
43
43
|
$consts = json_decode(file_get_contents('/internal/consts.json'), true);
|
|
44
44
|
foreach ($consts as $const => $value) {
|
|
@@ -46,7 +46,7 @@ ${bold} WASM ERROR${reset}${redBg}`);for(const t of e.split(`
|
|
|
46
46
|
define($const, $value);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
}`),l(this,
|
|
49
|
+
}`),l(this,R).length>0){const e=l(this,R).map(([t,r])=>`${t}=${r}`).join(`
|
|
50
50
|
`)+`
|
|
51
51
|
|
|
52
|
-
`;this[__private__dont__use].ccall("wasm_set_phpini_entries",null,[STRING],[e])}this[__private__dont__use].ccall("php_wasm_init",null,[],[])},
|
|
52
|
+
`;this[__private__dont__use].ccall("wasm_set_phpini_entries",null,[STRING],[e])}this[__private__dont__use].ccall("php_wasm_init",null,[],[])},U=new WeakSet,se=function(){const e="/internal/headers.json";if(!this.fileExists(e))throw new Error("SAPI Error: Could not find response headers file.");const t=JSON.parse(this.readFileAsText(e)),r={};for(const s of t.headers){if(!s.includes(": "))continue;const n=s.indexOf(": "),i=s.substring(0,n).toLowerCase(),o=s.substring(n+2);i in r||(r[i]=[]),r[i].push(o)}return{headers:r,httpStatusCode:t.status}},B=new WeakSet,ne=function(e){if(this[__private__dont__use].ccall("wasm_set_request_uri",null,[STRING],[e]),e.includes("?")){const t=e.substring(e.indexOf("?")+1);this[__private__dont__use].ccall("wasm_set_query_string",null,[STRING],[t])}},L=new WeakSet,ie=function(e){this[__private__dont__use].ccall("wasm_set_request_host",null,[STRING],[e])},D=new WeakSet,oe=function(e){this[__private__dont__use].ccall("wasm_set_request_port",null,[NUMBER],[e])},$=new WeakSet,ae=function(e,t){let r;try{r=parseInt(new URL(e).port,10)}catch{}return(!r||isNaN(r)||r===80)&&(r=t==="https"?443:80),r},q=new WeakSet,le=function(e){this[__private__dont__use].ccall("wasm_set_request_method",null,[STRING],[e])},j=new WeakSet,ce=function(e){e.cookie&&this[__private__dont__use].ccall("wasm_set_cookies",null,[STRING],[e.cookie]),e["content-type"]&&this[__private__dont__use].ccall("wasm_set_content_type",null,[STRING],[e["content-type"]]),e["content-length"]&&this[__private__dont__use].ccall("wasm_set_content_length",null,[NUMBER],[parseInt(e["content-length"],10)])},W=new WeakSet,ue=function(e){let t,r;typeof e=="string"?(console.warn("Passing a string as the request body is deprecated. Please use a Uint8Array instead. See https://github.com/WordPress/wordpress-playground/issues/997 for more details"),r=this[__private__dont__use].lengthBytesUTF8(e),t=r+1):(r=e.byteLength,t=e.byteLength);const s=this[__private__dont__use].malloc(t);if(!s)throw new Error("Could not allocate memory for the request body.");return typeof e=="string"?this[__private__dont__use].stringToUTF8(e,s,t+1):this[__private__dont__use].HEAPU8.set(e,s),this[__private__dont__use].ccall("wasm_set_request_body",null,[NUMBER],[s]),this[__private__dont__use].ccall("wasm_set_content_length",null,[NUMBER],[r]),s},z=new WeakSet,de=function(e){this[__private__dont__use].ccall("wasm_set_path_translated",null,[STRING],[e])},G=new WeakSet,he=function(e,t){this[__private__dont__use].ccall("wasm_add_SERVER_entry",null,[STRING,STRING],[e,t])},J=new WeakSet,pe=function(e,t){this[__private__dont__use].ccall("wasm_add_ENV_entry",null,[STRING,STRING],[e,t])},V=new WeakSet,fe=function(e){this[__private__dont__use].ccall("wasm_set_php_code",null,[STRING],[e])},Q=new WeakSet,_e=async function(){var n;let e,t;try{e=await new Promise((i,o)=>{var c;t=u=>{console.error(u),console.error(u.error);const h=new Error("Rethrown");h.cause=u.error,h.betterMessage=u.message,o(h)},(c=l(this,w))==null||c.addEventListener("error",t);const a=this[__private__dont__use].ccall("wasm_sapi_handle_request",NUMBER,[],[],{async:!0});return a instanceof Promise?a.then(i,o):i(a)})}catch(i){for(const u in this)typeof this[u]=="function"&&(this[u]=()=>{throw new Error("PHP runtime has crashed – see the earlier error for details.")});this.functionsMaybeMissingFromAsyncify=getFunctionsMaybeMissingFromAsyncify();const o=i,a="betterMessage"in o?o.betterMessage:o.message,c=new Error(a);throw c.cause=o,console.error(c),c}finally{(n=l(this,w))==null||n.removeEventListener("error",t)}const{headers:r,httpStatusCode:s}=f(this,U,se).call(this);return new PHPResponse(e===0?s:500,r,this.readFileAsBuffer("/internal/stdout"),this.readFileAsText("/internal/stderr"),e)};__decorateClass([rethrowFileSystemError('Could not create directory "{path}"')],BasePHP.prototype,"mkdir",1);__decorateClass([rethrowFileSystemError('Could not create directory "{path}"')],BasePHP.prototype,"mkdirTree",1);__decorateClass([rethrowFileSystemError('Could not read "{path}"')],BasePHP.prototype,"readFileAsText",1);__decorateClass([rethrowFileSystemError('Could not read "{path}"')],BasePHP.prototype,"readFileAsBuffer",1);__decorateClass([rethrowFileSystemError('Could not write to "{path}"')],BasePHP.prototype,"writeFile",1);__decorateClass([rethrowFileSystemError('Could not unlink "{path}"')],BasePHP.prototype,"unlink",1);__decorateClass([rethrowFileSystemError('Could not remove directory "{path}"')],BasePHP.prototype,"rmdir",1);__decorateClass([rethrowFileSystemError('Could not list files in "{path}"')],BasePHP.prototype,"listFiles",1);__decorateClass([rethrowFileSystemError('Could not stat "{path}"')],BasePHP.prototype,"isDir",1);__decorateClass([rethrowFileSystemError('Could not stat "{path}"')],BasePHP.prototype,"fileExists",1);function normalizeHeaders(e){const t={};for(const r in e)t[r.toLowerCase()]=e[r];return t}function copyFS(e,t,r){let s;try{s=e.lookupPath(r)}catch{return}if(!("contents"in s.node))return;if(!e.isDir(s.node.mode)){t.writeFile(r,e.readFile(r));return}t.mkdirTree(r);const n=e.readdir(r).filter(i=>i!=="."&&i!=="..");for(const i of n)copyFS(e,t,joinPaths(r,i))}function journalFSEvents(e,t,r=()=>{}){function s(){t=normalizePath(t);const i=e[__private__dont__use].FS,o=createFSHooks(i,h=>{if(h.path.startsWith(t))r(h);else if(h.operation==="RENAME"&&h.toPath.startsWith(t))for(const g of recordExistingPath(e,h.path,h.toPath))r(g)}),a={};for(const[h]of Object.entries(o))a[h]=i[h];function c(){for(const[h,g]of Object.entries(o))i[h]=function(...K){return g(...K),a[h].apply(this,K)}}function u(){for(const[h,g]of Object.entries(a))e[__private__dont__use].FS[h]=g}e[__private__dont__use].journal={bind:c,unbind:u},c()}e.addEventListener("runtime.initialized",s),e[__private__dont__use]&&s();function n(){e[__private__dont__use].journal.unbind(),delete e[__private__dont__use].journal}return e.addEventListener("runtime.beforedestroy",n),function(){return e.removeEventListener("runtime.initialized",s),e.removeEventListener("runtime.beforedestroy",n),e[__private__dont__use].journal.unbind()}}const createFSHooks=(e,t=()=>{})=>({write(r){t({operation:"WRITE",path:r.path,nodeType:"file"})},truncate(r){let s;typeof r=="string"?s=e.lookupPath(r,{follow:!0}).node:s=r,t({operation:"WRITE",path:e.getPath(s),nodeType:"file"})},unlink(r){t({operation:"DELETE",path:r,nodeType:"file"})},mknod(r,s){e.isFile(s)&&t({operation:"CREATE",path:r,nodeType:"file"})},mkdir(r){t({operation:"CREATE",path:r,nodeType:"directory"})},rmdir(r){t({operation:"DELETE",path:r,nodeType:"directory"})},rename(r,s){try{const n=e.lookupPath(r,{follow:!0}),i=e.lookupPath(s,{parent:!0}).path;t({operation:"RENAME",nodeType:e.isDir(n.node.mode)?"directory":"file",path:n.path,toPath:joinPaths(i,basename(s))})}catch{}}});function replayFSJournal(e,t){e[__private__dont__use].journal.unbind();try{for(const r of t)r.operation==="CREATE"?r.nodeType==="file"?e.writeFile(r.path," "):e.mkdir(r.path):r.operation==="DELETE"?r.nodeType==="file"?e.unlink(r.path):e.rmdir(r.path):r.operation==="WRITE"?e.writeFile(r.path,r.data):r.operation==="RENAME"&&e.mv(r.path,r.toPath)}finally{e[__private__dont__use].journal.bind()}}function*recordExistingPath(e,t,r){if(e.isDir(t)){yield{operation:"CREATE",path:r,nodeType:"directory"};for(const s of e.listFiles(t))yield*recordExistingPath(e,joinPaths(t,s),joinPaths(r,s))}else yield{operation:"CREATE",path:r,nodeType:"file"},yield{operation:"WRITE",nodeType:"file",path:r}}function normalizePath(e){return e.replace(/\/$/,"").replace(/\/\/+/g,"/")}function normalizeFilesystemOperations(e){const t={};for(let r=e.length-1;r>=0;r--){for(let s=r-1;s>=0;s--){const n=checkRelationship(e[r],e[s]);if(n==="none")continue;const i=e[r],o=e[s];if(i.operation==="RENAME"&&o.operation==="RENAME"){console.warn("[FS Journal] Normalizing a double rename is not yet supported:",{current:i,last:o});continue}(o.operation==="CREATE"||o.operation==="WRITE")&&(i.operation==="RENAME"?n==="same_node"?(t[s]=[],t[r]=[{...o,path:i.toPath},...t[r]||[]]):n==="descendant"&&(t[s]=[],t[r]=[{...o,path:joinPaths(i.toPath,o.path.substring(i.path.length))},...t[r]||[]]):i.operation==="WRITE"&&n==="same_node"?t[s]=[]:i.operation==="DELETE"&&n==="same_node"&&(t[s]=[],t[r]=[]))}if(Object.entries(t).length>0){const s=e.flatMap((n,i)=>i in t?t[i]:[n]);return normalizeFilesystemOperations(s)}}return e}function checkRelationship(e,t){const r=e.path,s=e.operation!=="WRITE"&&e.nodeType==="directory",n=t.operation!=="WRITE"&&t.nodeType==="directory",i=t.operation==="RENAME"?t.toPath:t.path;return i===r?"same_node":n&&r.startsWith(i+"/")?"ancestor":s&&i.startsWith(r+"/")?"descendant":"none"}async function hydrateUpdateFileOps(e,t){const s=t.filter(n=>n.operation==="WRITE").map(n=>hydrateOp(e,n));return await Promise.all(s),t}const hydrateLock=new Semaphore({concurrency:15});async function hydrateOp(e,t){const r=await hydrateLock.acquire();try{t.data=await e.readFileAsBuffer(t.path)}catch(s){console.warn(`Journal failed to hydrate a file on flush: the path ${t.path} no longer exists`),console.error(s)}r()}exports.hydrateUpdateFileOps=hydrateUpdateFileOps;exports.journalFSEvents=journalFSEvents;exports.normalizeFilesystemOperations=normalizeFilesystemOperations;exports.replayFSJournal=replayFSJournal;
|
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@ var Y = (e, t, r) => {
|
|
|
2
2
|
if (!t.has(e))
|
|
3
3
|
throw TypeError("Cannot " + r);
|
|
4
4
|
};
|
|
5
|
-
var l = (e, t, r) => (Y(e, t, "read from private field"), r ? r.call(e) : t.get(e)),
|
|
5
|
+
var l = (e, t, r) => (Y(e, t, "read from private field"), r ? r.call(e) : t.get(e)), d = (e, t, r) => {
|
|
6
6
|
if (t.has(e))
|
|
7
7
|
throw TypeError("Cannot add the same private member more than once");
|
|
8
8
|
t instanceof WeakSet ? t.add(e) : t.set(e, r);
|
|
@@ -61,8 +61,8 @@ if (currentJsRuntime === "NODE") {
|
|
|
61
61
|
r + i.byteLength
|
|
62
62
|
).arrayBuffer(), c = new Uint8Array(a);
|
|
63
63
|
new Uint8Array(i.buffer).set(c);
|
|
64
|
-
const
|
|
65
|
-
n.byobRequest.respond(
|
|
64
|
+
const u = c.byteLength;
|
|
65
|
+
n.byobRequest.respond(u), r += u, r >= s.size && n.close();
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
68
|
});
|
|
@@ -226,18 +226,40 @@ function extractPHPFunctionsFromStack(e) {
|
|
|
226
226
|
return [];
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
|
+
const SleepFinished = Symbol("SleepFinished");
|
|
230
|
+
function sleep(e) {
|
|
231
|
+
return new Promise((t) => {
|
|
232
|
+
setTimeout(() => t(SleepFinished), e);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
class AcquireTimeoutError extends Error {
|
|
236
|
+
constructor() {
|
|
237
|
+
super("Acquiring lock timed out");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
229
240
|
class Semaphore {
|
|
230
|
-
constructor({ concurrency: t }) {
|
|
231
|
-
this._running = 0, this.concurrency = t, this.queue = [];
|
|
241
|
+
constructor({ concurrency: t, timeout: r }) {
|
|
242
|
+
this._running = 0, this.concurrency = t, this.timeout = r, this.queue = [];
|
|
243
|
+
}
|
|
244
|
+
get remaining() {
|
|
245
|
+
return this.concurrency - this.running;
|
|
232
246
|
}
|
|
233
247
|
get running() {
|
|
234
248
|
return this._running;
|
|
235
249
|
}
|
|
236
250
|
async acquire() {
|
|
237
251
|
for (; ; )
|
|
238
|
-
if (this._running >= this.concurrency)
|
|
239
|
-
|
|
240
|
-
|
|
252
|
+
if (this._running >= this.concurrency) {
|
|
253
|
+
const t = new Promise((r) => {
|
|
254
|
+
this.queue.push(r);
|
|
255
|
+
});
|
|
256
|
+
this.timeout !== void 0 ? await Promise.race([t, sleep(this.timeout)]).then(
|
|
257
|
+
(r) => {
|
|
258
|
+
if (r === SleepFinished)
|
|
259
|
+
throw new AcquireTimeoutError();
|
|
260
|
+
}
|
|
261
|
+
) : await t;
|
|
262
|
+
} else {
|
|
241
263
|
this._running++;
|
|
242
264
|
let t = !1;
|
|
243
265
|
return () => {
|
|
@@ -413,94 +435,6 @@ class PHPResponse {
|
|
|
413
435
|
return new TextDecoder().decode(this.bytes);
|
|
414
436
|
}
|
|
415
437
|
}
|
|
416
|
-
var v, T;
|
|
417
|
-
class PHPBrowser {
|
|
418
|
-
/**
|
|
419
|
-
* @param server - The PHP server to browse.
|
|
420
|
-
* @param config - The browser configuration.
|
|
421
|
-
*/
|
|
422
|
-
constructor(t, r = {}) {
|
|
423
|
-
u(this, v, void 0);
|
|
424
|
-
u(this, T, void 0);
|
|
425
|
-
this.requestHandler = t, p(this, v, {}), p(this, T, {
|
|
426
|
-
handleRedirects: !1,
|
|
427
|
-
maxRedirects: 4,
|
|
428
|
-
...r
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
/**
|
|
432
|
-
* Sends the request to the server.
|
|
433
|
-
*
|
|
434
|
-
* When cookies are present in the response, this method stores
|
|
435
|
-
* them and sends them with any subsequent requests.
|
|
436
|
-
*
|
|
437
|
-
* When a redirection is present in the response, this method
|
|
438
|
-
* follows it by discarding a response and sending a subsequent
|
|
439
|
-
* request.
|
|
440
|
-
*
|
|
441
|
-
* @param request - The request.
|
|
442
|
-
* @param redirects - Internal. The number of redirects handled so far.
|
|
443
|
-
* @returns PHPRequestHandler response.
|
|
444
|
-
*/
|
|
445
|
-
async request(t, r = 0) {
|
|
446
|
-
const s = await this.requestHandler.request({
|
|
447
|
-
...t,
|
|
448
|
-
headers: {
|
|
449
|
-
...t.headers,
|
|
450
|
-
cookie: this.serializeCookies()
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
if (s.headers["set-cookie"] && this.setCookies(s.headers["set-cookie"]), l(this, T).handleRedirects && s.headers.location && r < l(this, T).maxRedirects) {
|
|
454
|
-
const n = new URL(
|
|
455
|
-
s.headers.location[0],
|
|
456
|
-
this.requestHandler.absoluteUrl
|
|
457
|
-
);
|
|
458
|
-
return this.request(
|
|
459
|
-
{
|
|
460
|
-
url: n.toString(),
|
|
461
|
-
method: "GET",
|
|
462
|
-
headers: {}
|
|
463
|
-
},
|
|
464
|
-
r + 1
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
return s;
|
|
468
|
-
}
|
|
469
|
-
/** @inheritDoc */
|
|
470
|
-
pathToInternalUrl(t) {
|
|
471
|
-
return this.requestHandler.pathToInternalUrl(t);
|
|
472
|
-
}
|
|
473
|
-
/** @inheritDoc */
|
|
474
|
-
internalUrlToPath(t) {
|
|
475
|
-
return this.requestHandler.internalUrlToPath(t);
|
|
476
|
-
}
|
|
477
|
-
/** @inheritDoc */
|
|
478
|
-
get absoluteUrl() {
|
|
479
|
-
return this.requestHandler.absoluteUrl;
|
|
480
|
-
}
|
|
481
|
-
/** @inheritDoc */
|
|
482
|
-
get documentRoot() {
|
|
483
|
-
return this.requestHandler.documentRoot;
|
|
484
|
-
}
|
|
485
|
-
setCookies(t) {
|
|
486
|
-
for (const r of t)
|
|
487
|
-
try {
|
|
488
|
-
if (!r.includes("="))
|
|
489
|
-
continue;
|
|
490
|
-
const s = r.indexOf("="), n = r.substring(0, s), i = r.substring(s + 1).split(";")[0];
|
|
491
|
-
l(this, v)[n] = i;
|
|
492
|
-
} catch (s) {
|
|
493
|
-
console.error(s);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
serializeCookies() {
|
|
497
|
-
const t = [];
|
|
498
|
-
for (const r in l(this, v))
|
|
499
|
-
t.push(`${r}=${l(this, v)[r]}`);
|
|
500
|
-
return t.join("; ");
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
v = new WeakMap(), T = new WeakMap();
|
|
504
438
|
const DEFAULT_BASE_URL = "http://example.com";
|
|
505
439
|
function toRelativeUrl(e) {
|
|
506
440
|
return e.toString().substring(e.origin.length);
|
|
@@ -513,16 +447,16 @@ function ensurePathPrefix(e, t) {
|
|
|
513
447
|
}
|
|
514
448
|
async function encodeAsMultipart(e) {
|
|
515
449
|
const t = `----${Math.random().toString(36).slice(2)}`, r = `multipart/form-data; boundary=${t}`, s = new TextEncoder(), n = [];
|
|
516
|
-
for (const [c,
|
|
450
|
+
for (const [c, u] of Object.entries(e))
|
|
517
451
|
n.push(`--${t}\r
|
|
518
|
-
`), n.push(`Content-Disposition: form-data; name="${c}"`),
|
|
519
|
-
`),
|
|
452
|
+
`), n.push(`Content-Disposition: form-data; name="${c}"`), u instanceof File && n.push(`; filename="${u.name}"`), n.push(`\r
|
|
453
|
+
`), u instanceof File && (n.push("Content-Type: application/octet-stream"), n.push(`\r
|
|
520
454
|
`)), n.push(`\r
|
|
521
|
-
`),
|
|
455
|
+
`), u instanceof File ? n.push(await fileToUint8Array(u)) : n.push(u), n.push(`\r
|
|
522
456
|
`);
|
|
523
457
|
n.push(`--${t}--\r
|
|
524
458
|
`);
|
|
525
|
-
const i = n.reduce((c,
|
|
459
|
+
const i = n.reduce((c, u) => c + u.length, 0), o = new Uint8Array(i);
|
|
526
460
|
let a = 0;
|
|
527
461
|
for (const c of n)
|
|
528
462
|
o.set(
|
|
@@ -539,7 +473,30 @@ function fileToUint8Array(e) {
|
|
|
539
473
|
}, r.readAsArrayBuffer(e);
|
|
540
474
|
});
|
|
541
475
|
}
|
|
542
|
-
|
|
476
|
+
class HttpCookieStore {
|
|
477
|
+
constructor() {
|
|
478
|
+
this.cookies = {};
|
|
479
|
+
}
|
|
480
|
+
rememberCookiesFromResponseHeaders(t) {
|
|
481
|
+
if (t != null && t["set-cookie"])
|
|
482
|
+
for (const r of t["set-cookie"])
|
|
483
|
+
try {
|
|
484
|
+
if (!r.includes("="))
|
|
485
|
+
continue;
|
|
486
|
+
const s = r.indexOf("="), n = r.substring(0, s), i = r.substring(s + 1).split(";")[0];
|
|
487
|
+
this.cookies[n] = i;
|
|
488
|
+
} catch (s) {
|
|
489
|
+
console.error(s);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
getCookieRequestHeader() {
|
|
493
|
+
const t = [];
|
|
494
|
+
for (const r in this.cookies)
|
|
495
|
+
t.push(`${r}=${this.cookies[r]}`);
|
|
496
|
+
return t.join("; ");
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
var m, b, A, P, S, _, T, v, F, H, Z, N, X, O, ee;
|
|
543
500
|
class PHPRequestHandler {
|
|
544
501
|
/**
|
|
545
502
|
* @param php - The PHP instance.
|
|
@@ -552,7 +509,7 @@ class PHPRequestHandler {
|
|
|
552
509
|
* @param fsPath - Absolute path of the static file to serve.
|
|
553
510
|
* @returns The response.
|
|
554
511
|
*/
|
|
555
|
-
|
|
512
|
+
d(this, H);
|
|
556
513
|
/**
|
|
557
514
|
* Runs the requested PHP file with all the request and $_SERVER
|
|
558
515
|
* superglobals populated.
|
|
@@ -560,7 +517,7 @@ class PHPRequestHandler {
|
|
|
560
517
|
* @param request - The request.
|
|
561
518
|
* @returns The response.
|
|
562
519
|
*/
|
|
563
|
-
|
|
520
|
+
d(this, N);
|
|
564
521
|
/**
|
|
565
522
|
* Resolve the requested path to the filesystem path of the requested PHP file.
|
|
566
523
|
*
|
|
@@ -570,55 +527,120 @@ class PHPRequestHandler {
|
|
|
570
527
|
* @throws {Error} If the requested path doesn't exist.
|
|
571
528
|
* @returns The resolved filesystem path.
|
|
572
529
|
*/
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
530
|
+
d(this, O);
|
|
531
|
+
d(this, m, void 0);
|
|
532
|
+
d(this, b, void 0);
|
|
533
|
+
d(this, A, void 0);
|
|
534
|
+
d(this, P, void 0);
|
|
535
|
+
d(this, S, void 0);
|
|
536
|
+
d(this, _, void 0);
|
|
537
|
+
d(this, T, void 0);
|
|
538
|
+
d(this, v, void 0);
|
|
539
|
+
d(this, F, void 0);
|
|
540
|
+
p(this, v, new Semaphore({ concurrency: 1 }));
|
|
583
541
|
const {
|
|
584
542
|
documentRoot: s = "/www/",
|
|
585
543
|
absoluteUrl: n = typeof location == "object" ? location == null ? void 0 : location.href : "",
|
|
586
544
|
rewriteRules: i = []
|
|
587
545
|
} = r;
|
|
588
|
-
this.php = t, p(this, m, s);
|
|
546
|
+
this.php = t, p(this, F, new HttpCookieStore()), p(this, m, s);
|
|
589
547
|
const o = new URL(n);
|
|
590
|
-
p(this,
|
|
591
|
-
const a = l(this,
|
|
592
|
-
p(this,
|
|
593
|
-
l(this,
|
|
594
|
-
a ? `:${l(this,
|
|
595
|
-
].join("")), p(this, _, o.pathname.replace(/\/+$/, "")), p(this,
|
|
596
|
-
`${l(this,
|
|
597
|
-
l(this,
|
|
548
|
+
p(this, A, o.hostname), p(this, P, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), p(this, b, (o.protocol || "").replace(":", ""));
|
|
549
|
+
const a = l(this, P) !== 443 && l(this, P) !== 80;
|
|
550
|
+
p(this, S, [
|
|
551
|
+
l(this, A),
|
|
552
|
+
a ? `:${l(this, P)}` : ""
|
|
553
|
+
].join("")), p(this, _, o.pathname.replace(/\/+$/, "")), p(this, T, [
|
|
554
|
+
`${l(this, b)}://`,
|
|
555
|
+
l(this, S),
|
|
598
556
|
l(this, _)
|
|
599
557
|
].join("")), this.rewriteRules = i;
|
|
600
558
|
}
|
|
601
|
-
/**
|
|
559
|
+
/**
|
|
560
|
+
* Converts a path to an absolute URL based at the PHPRequestHandler
|
|
561
|
+
* root.
|
|
562
|
+
*
|
|
563
|
+
* @param path The server path to convert to an absolute URL.
|
|
564
|
+
* @returns The absolute URL.
|
|
565
|
+
*/
|
|
602
566
|
pathToInternalUrl(t) {
|
|
603
567
|
return `${this.absoluteUrl}${t}`;
|
|
604
568
|
}
|
|
605
|
-
/**
|
|
569
|
+
/**
|
|
570
|
+
* Converts an absolute URL based at the PHPRequestHandler to a relative path
|
|
571
|
+
* without the server pathname and scope.
|
|
572
|
+
*
|
|
573
|
+
* @param internalUrl An absolute URL based at the PHPRequestHandler root.
|
|
574
|
+
* @returns The relative path.
|
|
575
|
+
*/
|
|
606
576
|
internalUrlToPath(t) {
|
|
607
577
|
const r = new URL(t);
|
|
608
578
|
return r.pathname.startsWith(l(this, _)) && (r.pathname = r.pathname.slice(l(this, _).length)), toRelativeUrl(r);
|
|
609
579
|
}
|
|
610
580
|
get isRequestRunning() {
|
|
611
|
-
return l(this,
|
|
581
|
+
return l(this, v).running > 0;
|
|
612
582
|
}
|
|
613
|
-
/**
|
|
583
|
+
/**
|
|
584
|
+
* The absolute URL of this PHPRequestHandler instance.
|
|
585
|
+
*/
|
|
614
586
|
get absoluteUrl() {
|
|
615
|
-
return l(this,
|
|
587
|
+
return l(this, T);
|
|
616
588
|
}
|
|
617
|
-
/**
|
|
589
|
+
/**
|
|
590
|
+
* The directory in the PHP filesystem where the server will look
|
|
591
|
+
* for the files to serve. Default: `/var/www`.
|
|
592
|
+
*/
|
|
618
593
|
get documentRoot() {
|
|
619
594
|
return l(this, m);
|
|
620
595
|
}
|
|
621
|
-
/**
|
|
596
|
+
/**
|
|
597
|
+
* Serves the request – either by serving a static file, or by
|
|
598
|
+
* dispatching it to the PHP runtime.
|
|
599
|
+
*
|
|
600
|
+
* The request() method mode behaves like a web server and only works if
|
|
601
|
+
* the PHP was initialized with a `requestHandler` option (which the online version
|
|
602
|
+
* of WordPress Playground does by default).
|
|
603
|
+
*
|
|
604
|
+
* In the request mode, you pass an object containing the request information
|
|
605
|
+
* (method, headers, body, etc.) and the path to the PHP file to run:
|
|
606
|
+
*
|
|
607
|
+
* ```ts
|
|
608
|
+
* const php = PHP.load('7.4', {
|
|
609
|
+
* requestHandler: {
|
|
610
|
+
* documentRoot: "/www"
|
|
611
|
+
* }
|
|
612
|
+
* })
|
|
613
|
+
* php.writeFile("/www/index.php", `<?php echo file_get_contents("php://input");`);
|
|
614
|
+
* const result = await php.request({
|
|
615
|
+
* method: "GET",
|
|
616
|
+
* headers: {
|
|
617
|
+
* "Content-Type": "text/plain"
|
|
618
|
+
* },
|
|
619
|
+
* body: "Hello world!",
|
|
620
|
+
* path: "/www/index.php"
|
|
621
|
+
* });
|
|
622
|
+
* // result.text === "Hello world!"
|
|
623
|
+
* ```
|
|
624
|
+
*
|
|
625
|
+
* The `request()` method cannot be used in conjunction with `cli()`.
|
|
626
|
+
*
|
|
627
|
+
* @example
|
|
628
|
+
* ```js
|
|
629
|
+
* const output = await php.request({
|
|
630
|
+
* method: 'GET',
|
|
631
|
+
* url: '/index.php',
|
|
632
|
+
* headers: {
|
|
633
|
+
* 'X-foo': 'bar',
|
|
634
|
+
* },
|
|
635
|
+
* body: {
|
|
636
|
+
* foo: 'bar',
|
|
637
|
+
* },
|
|
638
|
+
* });
|
|
639
|
+
* console.log(output.stdout); // "Hello world!"
|
|
640
|
+
* ```
|
|
641
|
+
*
|
|
642
|
+
* @param request - PHP Request data.
|
|
643
|
+
*/
|
|
622
644
|
async request(t) {
|
|
623
645
|
const r = t.url.startsWith("http://") || t.url.startsWith("https://"), s = new URL(
|
|
624
646
|
// Remove the hash part of the URL as it's not meant for the server.
|
|
@@ -631,10 +653,10 @@ class PHPRequestHandler {
|
|
|
631
653
|
),
|
|
632
654
|
this.rewriteRules
|
|
633
655
|
), i = joinPaths(l(this, m), n);
|
|
634
|
-
return seemsLikeAPHPRequestHandlerPath(i) ? await f(this,
|
|
656
|
+
return seemsLikeAPHPRequestHandlerPath(i) ? await f(this, N, X).call(this, t, s) : f(this, H, Z).call(this, i);
|
|
635
657
|
}
|
|
636
658
|
}
|
|
637
|
-
m = new WeakMap(),
|
|
659
|
+
m = new WeakMap(), b = new WeakMap(), A = new WeakMap(), P = new WeakMap(), S = new WeakMap(), _ = new WeakMap(), T = new WeakMap(), v = new WeakMap(), F = new WeakMap(), H = new WeakSet(), Z = function(t) {
|
|
638
660
|
if (!this.php.fileExists(t))
|
|
639
661
|
return new PHPResponse(
|
|
640
662
|
404,
|
|
@@ -659,9 +681,9 @@ m = new WeakMap(), F = new WeakMap(), N = new WeakMap(), R = new WeakMap(), x =
|
|
|
659
681
|
},
|
|
660
682
|
r
|
|
661
683
|
);
|
|
662
|
-
},
|
|
684
|
+
}, N = new WeakSet(), X = async function(t, r) {
|
|
663
685
|
var n;
|
|
664
|
-
if (l(this,
|
|
686
|
+
if (l(this, v).running > 0 && ((n = t.headers) == null ? void 0 : n["x-request-issuer"]) === "php")
|
|
665
687
|
return console.warn(
|
|
666
688
|
"Possible deadlock: Called request() before the previous request() have finished. PHP likely issued an HTTP call to itself. Normally this would lead to infinite waiting as Request 1 holds the lock that the Request 2 is waiting to acquire. That's not useful, so PHPRequestHandler will return error 502 instead."
|
|
667
689
|
), new PHPResponse(
|
|
@@ -669,26 +691,23 @@ m = new WeakMap(), F = new WeakMap(), N = new WeakMap(), R = new WeakMap(), x =
|
|
|
669
691
|
{},
|
|
670
692
|
new TextEncoder().encode("502 Bad Gateway")
|
|
671
693
|
);
|
|
672
|
-
const s = await l(this,
|
|
694
|
+
const s = await l(this, v).acquire();
|
|
673
695
|
try {
|
|
674
|
-
this.php.addServerGlobalEntry("REMOTE_ADDR", "127.0.0.1"), this.php.addServerGlobalEntry("DOCUMENT_ROOT", l(this, m)), this.php.addServerGlobalEntry(
|
|
675
|
-
"HTTPS",
|
|
676
|
-
l(this, C).startsWith("https://") ? "on" : ""
|
|
677
|
-
);
|
|
678
696
|
let i = "GET";
|
|
679
697
|
const o = {
|
|
680
|
-
host: l(this,
|
|
681
|
-
...normalizeHeaders(t.headers || {})
|
|
698
|
+
host: l(this, S),
|
|
699
|
+
...normalizeHeaders(t.headers || {}),
|
|
700
|
+
cookie: l(this, F).getCookieRequestHeader()
|
|
682
701
|
};
|
|
683
702
|
let a = t.body;
|
|
684
703
|
if (typeof a == "object" && !(a instanceof Uint8Array)) {
|
|
685
704
|
i = "POST";
|
|
686
|
-
const { bytes:
|
|
687
|
-
a =
|
|
705
|
+
const { bytes: u, contentType: h } = await encodeAsMultipart(a);
|
|
706
|
+
a = u, o["content-type"] = h;
|
|
688
707
|
}
|
|
689
708
|
let c;
|
|
690
709
|
try {
|
|
691
|
-
c = f(this,
|
|
710
|
+
c = f(this, O, ee).call(this, decodeURIComponent(r.pathname));
|
|
692
711
|
} catch {
|
|
693
712
|
return new PHPResponse(
|
|
694
713
|
404,
|
|
@@ -697,27 +716,35 @@ m = new WeakMap(), F = new WeakMap(), N = new WeakMap(), R = new WeakMap(), x =
|
|
|
697
716
|
);
|
|
698
717
|
}
|
|
699
718
|
try {
|
|
700
|
-
|
|
719
|
+
const u = await this.php.run({
|
|
701
720
|
relativeUri: ensurePathPrefix(
|
|
702
721
|
toRelativeUrl(r),
|
|
703
722
|
l(this, _)
|
|
704
723
|
),
|
|
705
|
-
protocol: l(this,
|
|
724
|
+
protocol: l(this, b),
|
|
706
725
|
method: t.method || i,
|
|
726
|
+
$_SERVER: {
|
|
727
|
+
REMOTE_ADDR: "127.0.0.1",
|
|
728
|
+
DOCUMENT_ROOT: l(this, m),
|
|
729
|
+
HTTPS: l(this, T).startsWith("https://") ? "on" : ""
|
|
730
|
+
},
|
|
707
731
|
body: a,
|
|
708
732
|
scriptPath: c,
|
|
709
733
|
headers: o
|
|
710
734
|
});
|
|
711
|
-
|
|
712
|
-
|
|
735
|
+
return l(this, F).rememberCookiesFromResponseHeaders(
|
|
736
|
+
u.headers
|
|
737
|
+
), u;
|
|
738
|
+
} catch (u) {
|
|
739
|
+
const h = u;
|
|
713
740
|
if (h != null && h.response)
|
|
714
741
|
return h.response;
|
|
715
|
-
throw
|
|
742
|
+
throw u;
|
|
716
743
|
}
|
|
717
744
|
} finally {
|
|
718
745
|
s();
|
|
719
746
|
}
|
|
720
|
-
},
|
|
747
|
+
}, O = new WeakSet(), ee = function(t) {
|
|
721
748
|
let r = removePathPrefix(t, l(this, _));
|
|
722
749
|
r = applyRewriteRules(r, this.rewriteRules), r.includes(".php") ? r = r.split(".php")[0] + ".php" : this.php.isDir(`${l(this, m)}${r}`) ? (r.endsWith("/") || (r = `${r}/`), r = `${r}index.php`) : r = "/index.php";
|
|
723
750
|
const s = `${l(this, m)}${r}`;
|
|
@@ -761,6 +788,38 @@ function inferMimeType(e) {
|
|
|
761
788
|
case "txt":
|
|
762
789
|
case "md":
|
|
763
790
|
return "text/plain";
|
|
791
|
+
case "pdf":
|
|
792
|
+
return "application/pdf";
|
|
793
|
+
case "webp":
|
|
794
|
+
return "image/webp";
|
|
795
|
+
case "mp3":
|
|
796
|
+
return "audio/mpeg";
|
|
797
|
+
case "mp4":
|
|
798
|
+
return "video/mp4";
|
|
799
|
+
case "csv":
|
|
800
|
+
return "text/csv";
|
|
801
|
+
case "xls":
|
|
802
|
+
return "application/vnd.ms-excel";
|
|
803
|
+
case "xlsx":
|
|
804
|
+
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
805
|
+
case "doc":
|
|
806
|
+
return "application/msword";
|
|
807
|
+
case "docx":
|
|
808
|
+
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
809
|
+
case "ppt":
|
|
810
|
+
return "application/vnd.ms-powerpoint";
|
|
811
|
+
case "pptx":
|
|
812
|
+
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
813
|
+
case "zip":
|
|
814
|
+
return "application/zip";
|
|
815
|
+
case "rar":
|
|
816
|
+
return "application/x-rar-compressed";
|
|
817
|
+
case "tar":
|
|
818
|
+
return "application/x-tar";
|
|
819
|
+
case "gz":
|
|
820
|
+
return "application/gzip";
|
|
821
|
+
case "7z":
|
|
822
|
+
return "application/x-7z-compressed";
|
|
764
823
|
default:
|
|
765
824
|
return "application-octet-stream";
|
|
766
825
|
}
|
|
@@ -873,8 +932,8 @@ function rethrowFileSystemError(e = "") {
|
|
|
873
932
|
} catch (a) {
|
|
874
933
|
const c = typeof a == "object" ? a == null ? void 0 : a.errno : null;
|
|
875
934
|
if (c in FileErrorCodes) {
|
|
876
|
-
const
|
|
877
|
-
throw new Error(`${
|
|
935
|
+
const u = FileErrorCodes[c], h = typeof o[0] == "string" ? o[0] : null, g = h !== null ? e.replaceAll("{path}", h) : e;
|
|
936
|
+
throw new Error(`${g}: ${u}`, {
|
|
878
937
|
cause: a
|
|
879
938
|
});
|
|
880
939
|
}
|
|
@@ -902,7 +961,7 @@ class PHPExecutionFailureError extends Error {
|
|
|
902
961
|
super(t), this.response = r, this.source = s;
|
|
903
962
|
}
|
|
904
963
|
}
|
|
905
|
-
var
|
|
964
|
+
var R, x, k, y, w, E, C, I, te, M, re, U, se, B, ne, L, ie, D, oe, $, ae, q, le, W, ce, j, ue, z, de, G, he, J, pe, V, fe, Q, _e;
|
|
906
965
|
class BasePHP {
|
|
907
966
|
/**
|
|
908
967
|
* Initializes a PHP runtime.
|
|
@@ -912,29 +971,38 @@ class BasePHP {
|
|
|
912
971
|
* @param serverOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
|
|
913
972
|
*/
|
|
914
973
|
constructor(e, t) {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
)
|
|
974
|
+
/**
|
|
975
|
+
* Prepares the $_SERVER entries for the PHP runtime.
|
|
976
|
+
*
|
|
977
|
+
* @param defaults Default entries to include in $_SERVER.
|
|
978
|
+
* @param headers HTTP headers to include in $_SERVER (as HTTP_ prefixed entries).
|
|
979
|
+
* @param port HTTP port, used to determine infer $_SERVER['HTTPS'] value if none
|
|
980
|
+
* was provided.
|
|
981
|
+
* @returns Computed $_SERVER entries.
|
|
982
|
+
*/
|
|
983
|
+
d(this, I);
|
|
984
|
+
d(this, M);
|
|
985
|
+
d(this, U);
|
|
986
|
+
d(this, B);
|
|
987
|
+
d(this, L);
|
|
988
|
+
d(this, D);
|
|
989
|
+
d(this, $);
|
|
990
|
+
d(this, q);
|
|
991
|
+
d(this, W);
|
|
992
|
+
d(this, j);
|
|
993
|
+
d(this, z);
|
|
994
|
+
d(this, G);
|
|
995
|
+
d(this, J);
|
|
996
|
+
d(this, V);
|
|
997
|
+
d(this, Q);
|
|
998
|
+
d(this, R, void 0);
|
|
999
|
+
d(this, x, void 0);
|
|
1000
|
+
d(this, k, void 0);
|
|
1001
|
+
d(this, y, void 0);
|
|
1002
|
+
d(this, w, void 0);
|
|
1003
|
+
d(this, E, void 0);
|
|
1004
|
+
d(this, C, void 0);
|
|
1005
|
+
p(this, R, []), p(this, y, !1), p(this, w, null), p(this, E, /* @__PURE__ */ new Map()), p(this, C, []), this.semaphore = new Semaphore({ concurrency: 1 }), e !== void 0 && this.initializeRuntime(e), t && (this.requestHandler = new PHPRequestHandler(this, t));
|
|
938
1006
|
}
|
|
939
1007
|
addEventListener(e, t) {
|
|
940
1008
|
l(this, E).has(e) || l(this, E).set(e, /* @__PURE__ */ new Set()), l(this, E).get(e).add(t);
|
|
@@ -951,7 +1019,7 @@ class BasePHP {
|
|
|
951
1019
|
}
|
|
952
1020
|
/** @inheritDoc */
|
|
953
1021
|
async onMessage(e) {
|
|
954
|
-
l(this,
|
|
1022
|
+
l(this, C).push(e);
|
|
955
1023
|
}
|
|
956
1024
|
/** @inheritDoc */
|
|
957
1025
|
async setSpawnHandler(handler) {
|
|
@@ -959,21 +1027,19 @@ class BasePHP {
|
|
|
959
1027
|
}
|
|
960
1028
|
/** @inheritDoc */
|
|
961
1029
|
get absoluteUrl() {
|
|
962
|
-
return this.requestHandler.
|
|
1030
|
+
return this.requestHandler.absoluteUrl;
|
|
963
1031
|
}
|
|
964
1032
|
/** @inheritDoc */
|
|
965
1033
|
get documentRoot() {
|
|
966
|
-
return this.requestHandler.
|
|
1034
|
+
return this.requestHandler.documentRoot;
|
|
967
1035
|
}
|
|
968
1036
|
/** @inheritDoc */
|
|
969
1037
|
pathToInternalUrl(e) {
|
|
970
|
-
return this.requestHandler.
|
|
1038
|
+
return this.requestHandler.pathToInternalUrl(e);
|
|
971
1039
|
}
|
|
972
1040
|
/** @inheritDoc */
|
|
973
1041
|
internalUrlToPath(e) {
|
|
974
|
-
return this.requestHandler.
|
|
975
|
-
e
|
|
976
|
-
);
|
|
1042
|
+
return this.requestHandler.internalUrlToPath(e);
|
|
977
1043
|
}
|
|
978
1044
|
initializeRuntime(e) {
|
|
979
1045
|
if (this[__private__dont__use])
|
|
@@ -982,7 +1048,7 @@ class BasePHP {
|
|
|
982
1048
|
if (!t)
|
|
983
1049
|
throw new Error("Invalid PHP runtime id.");
|
|
984
1050
|
this[__private__dont__use] = t, t.onMessage = async (r) => {
|
|
985
|
-
for (const s of l(this,
|
|
1051
|
+
for (const s of l(this, C)) {
|
|
986
1052
|
const n = await s(r);
|
|
987
1053
|
if (n)
|
|
988
1054
|
return n;
|
|
@@ -1003,13 +1069,13 @@ class BasePHP {
|
|
|
1003
1069
|
throw new Error(
|
|
1004
1070
|
"Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
|
|
1005
1071
|
);
|
|
1006
|
-
p(this,
|
|
1072
|
+
p(this, k, e);
|
|
1007
1073
|
}
|
|
1008
1074
|
/** @inheritDoc */
|
|
1009
1075
|
setPhpIniPath(e) {
|
|
1010
1076
|
if (l(this, y))
|
|
1011
1077
|
throw new Error("Cannot set PHP ini path after calling run().");
|
|
1012
|
-
p(this,
|
|
1078
|
+
p(this, x, e), this[__private__dont__use].ccall(
|
|
1013
1079
|
"wasm_set_phpini_path",
|
|
1014
1080
|
null,
|
|
1015
1081
|
["string"],
|
|
@@ -1020,44 +1086,47 @@ class BasePHP {
|
|
|
1020
1086
|
setPhpIniEntry(e, t) {
|
|
1021
1087
|
if (l(this, y))
|
|
1022
1088
|
throw new Error("Cannot set PHP ini entries after calling run().");
|
|
1023
|
-
l(this,
|
|
1089
|
+
l(this, R).push([e, t]);
|
|
1024
1090
|
}
|
|
1025
1091
|
/** @inheritDoc */
|
|
1026
1092
|
chdir(e) {
|
|
1027
1093
|
this[__private__dont__use].FS.chdir(e);
|
|
1028
1094
|
}
|
|
1029
1095
|
/** @inheritDoc */
|
|
1030
|
-
async request(e
|
|
1096
|
+
async request(e) {
|
|
1031
1097
|
if (!this.requestHandler)
|
|
1032
1098
|
throw new Error("No request handler available.");
|
|
1033
|
-
return this.requestHandler.request(e
|
|
1099
|
+
return this.requestHandler.request(e);
|
|
1034
1100
|
}
|
|
1035
1101
|
/** @inheritDoc */
|
|
1036
1102
|
async run(e) {
|
|
1037
1103
|
const t = await this.semaphore.acquire();
|
|
1038
1104
|
let r;
|
|
1039
1105
|
try {
|
|
1040
|
-
if (l(this, y) || (f(this, M,
|
|
1106
|
+
if (l(this, y) || (f(this, M, re).call(this), p(this, y, !0)), e.scriptPath && !this.fileExists(e.scriptPath))
|
|
1041
1107
|
throw new Error(
|
|
1042
1108
|
`The script path "${e.scriptPath}" does not exist.`
|
|
1043
1109
|
);
|
|
1044
|
-
f(this,
|
|
1045
|
-
const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443";
|
|
1046
|
-
f(this,
|
|
1047
|
-
const
|
|
1048
|
-
for (const
|
|
1049
|
-
f(this, G,
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1110
|
+
f(this, z, de).call(this, e.scriptPath || ""), f(this, B, ne).call(this, e.relativeUri || ""), f(this, q, le).call(this, e.method || "GET");
|
|
1111
|
+
const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443", i = f(this, $, ae).call(this, n, e.protocol || "http");
|
|
1112
|
+
f(this, L, ie).call(this, n), f(this, D, oe).call(this, i), f(this, W, ce).call(this, s), e.body && (r = f(this, j, ue).call(this, e.body)), typeof e.code == "string" && f(this, V, fe).call(this, " ?>" + e.code);
|
|
1113
|
+
const o = f(this, I, te).call(this, e.$_SERVER, s, i);
|
|
1114
|
+
for (const u in o)
|
|
1115
|
+
f(this, G, he).call(this, u, o[u]);
|
|
1116
|
+
const a = e.env || {};
|
|
1117
|
+
for (const u in a)
|
|
1118
|
+
f(this, J, pe).call(this, u, a[u]);
|
|
1119
|
+
const c = await f(this, Q, _e).call(this);
|
|
1120
|
+
if (c.exitCode !== 0) {
|
|
1121
|
+
console.warn("PHP.run() output was:", c.text);
|
|
1122
|
+
const u = new PHPExecutionFailureError(
|
|
1123
|
+
`PHP.run() failed with exit code ${c.exitCode} and the following output: ` + c.errors,
|
|
1124
|
+
c,
|
|
1056
1125
|
"request"
|
|
1057
1126
|
);
|
|
1058
|
-
throw console.error(
|
|
1127
|
+
throw console.error(u), u;
|
|
1059
1128
|
}
|
|
1060
|
-
return
|
|
1129
|
+
return c;
|
|
1061
1130
|
} catch (s) {
|
|
1062
1131
|
throw this.dispatchEvent({
|
|
1063
1132
|
type: "request.error",
|
|
@@ -1075,9 +1144,6 @@ class BasePHP {
|
|
|
1075
1144
|
}
|
|
1076
1145
|
}
|
|
1077
1146
|
}
|
|
1078
|
-
addServerGlobalEntry(e, t) {
|
|
1079
|
-
l(this, g)[e] = t;
|
|
1080
|
-
}
|
|
1081
1147
|
defineConstant(e, t) {
|
|
1082
1148
|
let r = {};
|
|
1083
1149
|
try {
|
|
@@ -1165,17 +1231,18 @@ class BasePHP {
|
|
|
1165
1231
|
* interrupting the operations of this PHP instance.
|
|
1166
1232
|
*
|
|
1167
1233
|
* @param runtime
|
|
1234
|
+
* @param cwd. Internal, the VFS path to recreate in the new runtime.
|
|
1235
|
+
* This arg is temporary and will be removed once BasePHP
|
|
1236
|
+
* is fully decoupled from the request handler and
|
|
1237
|
+
* accepts a constructor-level cwd argument.
|
|
1168
1238
|
*/
|
|
1169
|
-
hotSwapPHPRuntime(e) {
|
|
1170
|
-
const
|
|
1239
|
+
hotSwapPHPRuntime(e, t) {
|
|
1240
|
+
const r = this[__private__dont__use].FS;
|
|
1171
1241
|
try {
|
|
1172
1242
|
this.exit();
|
|
1173
1243
|
} catch {
|
|
1174
1244
|
}
|
|
1175
|
-
|
|
1176
|
-
const r = this.documentRoot;
|
|
1177
|
-
copyFS(t, this[__private__dont__use].FS, r);
|
|
1178
|
-
}
|
|
1245
|
+
this.initializeRuntime(e), l(this, x) && this.setPhpIniPath(l(this, x)), l(this, k) && this.setSapiName(l(this, k)), t && copyFS(r, this[__private__dont__use].FS, t);
|
|
1179
1246
|
}
|
|
1180
1247
|
exit(e = 0) {
|
|
1181
1248
|
this.dispatchEvent({
|
|
@@ -1188,7 +1255,17 @@ class BasePHP {
|
|
|
1188
1255
|
p(this, y, !1), p(this, w, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
|
|
1189
1256
|
}
|
|
1190
1257
|
}
|
|
1191
|
-
|
|
1258
|
+
R = new WeakMap(), x = new WeakMap(), k = new WeakMap(), y = new WeakMap(), w = new WeakMap(), E = new WeakMap(), C = new WeakMap(), I = new WeakSet(), te = function(e, t, r) {
|
|
1259
|
+
const s = {
|
|
1260
|
+
...e || {}
|
|
1261
|
+
};
|
|
1262
|
+
s.HTTPS = s.HTTPS || r === 443 ? "on" : "off";
|
|
1263
|
+
for (const n in t) {
|
|
1264
|
+
let i = "HTTP_";
|
|
1265
|
+
["content-type", "content-length"].includes(n.toLowerCase()) && (i = ""), s[`${i}${n.toUpperCase().replace(/-/g, "_")}`] = t[n];
|
|
1266
|
+
}
|
|
1267
|
+
return s;
|
|
1268
|
+
}, M = new WeakSet(), re = function() {
|
|
1192
1269
|
if (this.setPhpIniEntry("auto_prepend_file", "/internal/consts.php"), this.fileExists("/internal/consts.php") || this.writeFile(
|
|
1193
1270
|
"/internal/consts.php",
|
|
1194
1271
|
`<?php
|
|
@@ -1200,8 +1277,8 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1200
1277
|
}
|
|
1201
1278
|
}
|
|
1202
1279
|
}`
|
|
1203
|
-
), l(this,
|
|
1204
|
-
const e = l(this,
|
|
1280
|
+
), l(this, R).length > 0) {
|
|
1281
|
+
const e = l(this, R).map(([t, r]) => `${t}=${r}`).join(`
|
|
1205
1282
|
`) + `
|
|
1206
1283
|
|
|
1207
1284
|
`;
|
|
@@ -1213,7 +1290,7 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1213
1290
|
);
|
|
1214
1291
|
}
|
|
1215
1292
|
this[__private__dont__use].ccall("php_wasm_init", null, [], []);
|
|
1216
|
-
},
|
|
1293
|
+
}, U = new WeakSet(), se = function() {
|
|
1217
1294
|
const e = "/internal/headers.json";
|
|
1218
1295
|
if (!this.fileExists(e))
|
|
1219
1296
|
throw new Error(
|
|
@@ -1230,7 +1307,7 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1230
1307
|
headers: r,
|
|
1231
1308
|
httpStatusCode: t.status
|
|
1232
1309
|
};
|
|
1233
|
-
},
|
|
1310
|
+
}, B = new WeakSet(), ne = function(e) {
|
|
1234
1311
|
if (this[__private__dont__use].ccall(
|
|
1235
1312
|
"wasm_set_request_uri",
|
|
1236
1313
|
null,
|
|
@@ -1245,32 +1322,35 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1245
1322
|
[t]
|
|
1246
1323
|
);
|
|
1247
1324
|
}
|
|
1248
|
-
},
|
|
1325
|
+
}, L = new WeakSet(), ie = function(e) {
|
|
1249
1326
|
this[__private__dont__use].ccall(
|
|
1250
1327
|
"wasm_set_request_host",
|
|
1251
1328
|
null,
|
|
1252
1329
|
[STRING],
|
|
1253
1330
|
[e]
|
|
1254
1331
|
);
|
|
1332
|
+
}, D = new WeakSet(), oe = function(e) {
|
|
1333
|
+
this[__private__dont__use].ccall(
|
|
1334
|
+
"wasm_set_request_port",
|
|
1335
|
+
null,
|
|
1336
|
+
[NUMBER],
|
|
1337
|
+
[e]
|
|
1338
|
+
);
|
|
1339
|
+
}, $ = new WeakSet(), ae = function(e, t) {
|
|
1255
1340
|
let r;
|
|
1256
1341
|
try {
|
|
1257
1342
|
r = parseInt(new URL(e).port, 10);
|
|
1258
1343
|
} catch {
|
|
1259
1344
|
}
|
|
1260
|
-
(!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80),
|
|
1261
|
-
|
|
1262
|
-
null,
|
|
1263
|
-
[NUMBER],
|
|
1264
|
-
[r]
|
|
1265
|
-
), (t === "https" || !t && r === 443) && this.addServerGlobalEntry("HTTPS", "on");
|
|
1266
|
-
}, q = new WeakSet(), ne = function(e) {
|
|
1345
|
+
return (!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80), r;
|
|
1346
|
+
}, q = new WeakSet(), le = function(e) {
|
|
1267
1347
|
this[__private__dont__use].ccall(
|
|
1268
1348
|
"wasm_set_request_method",
|
|
1269
1349
|
null,
|
|
1270
1350
|
[STRING],
|
|
1271
1351
|
[e]
|
|
1272
1352
|
);
|
|
1273
|
-
},
|
|
1353
|
+
}, W = new WeakSet(), ce = function(e) {
|
|
1274
1354
|
e.cookie && this[__private__dont__use].ccall(
|
|
1275
1355
|
"wasm_set_cookies",
|
|
1276
1356
|
null,
|
|
@@ -1287,14 +1367,7 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1287
1367
|
[NUMBER],
|
|
1288
1368
|
[parseInt(e["content-length"], 10)]
|
|
1289
1369
|
);
|
|
1290
|
-
|
|
1291
|
-
let r = "HTTP_";
|
|
1292
|
-
["content-type", "content-length"].includes(t.toLowerCase()) && (r = ""), this.addServerGlobalEntry(
|
|
1293
|
-
`${r}${t.toUpperCase().replace(/-/g, "_")}`,
|
|
1294
|
-
e[t]
|
|
1295
|
-
);
|
|
1296
|
-
}
|
|
1297
|
-
}, W = new WeakSet(), oe = function(e) {
|
|
1370
|
+
}, j = new WeakSet(), ue = function(e) {
|
|
1298
1371
|
let t, r;
|
|
1299
1372
|
typeof e == "string" ? (console.warn(
|
|
1300
1373
|
"Passing a string as the request body is deprecated. Please use a Uint8Array instead. See https://github.com/WordPress/wordpress-playground/issues/997 for more details"
|
|
@@ -1317,45 +1390,44 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1317
1390
|
[NUMBER],
|
|
1318
1391
|
[r]
|
|
1319
1392
|
), s;
|
|
1320
|
-
},
|
|
1393
|
+
}, z = new WeakSet(), de = function(e) {
|
|
1321
1394
|
this[__private__dont__use].ccall(
|
|
1322
1395
|
"wasm_set_path_translated",
|
|
1323
1396
|
null,
|
|
1324
1397
|
[STRING],
|
|
1325
1398
|
[e]
|
|
1326
1399
|
);
|
|
1327
|
-
},
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
}, G = new WeakSet(), ce = function(e, t) {
|
|
1400
|
+
}, G = new WeakSet(), he = function(e, t) {
|
|
1401
|
+
this[__private__dont__use].ccall(
|
|
1402
|
+
"wasm_add_SERVER_entry",
|
|
1403
|
+
null,
|
|
1404
|
+
[STRING, STRING],
|
|
1405
|
+
[e, t]
|
|
1406
|
+
);
|
|
1407
|
+
}, J = new WeakSet(), pe = function(e, t) {
|
|
1336
1408
|
this[__private__dont__use].ccall(
|
|
1337
1409
|
"wasm_add_ENV_entry",
|
|
1338
1410
|
null,
|
|
1339
1411
|
[STRING, STRING],
|
|
1340
1412
|
[e, t]
|
|
1341
1413
|
);
|
|
1342
|
-
},
|
|
1414
|
+
}, V = new WeakSet(), fe = function(e) {
|
|
1343
1415
|
this[__private__dont__use].ccall(
|
|
1344
1416
|
"wasm_set_php_code",
|
|
1345
1417
|
null,
|
|
1346
1418
|
[STRING],
|
|
1347
1419
|
[e]
|
|
1348
1420
|
);
|
|
1349
|
-
}, Q = new WeakSet(),
|
|
1421
|
+
}, Q = new WeakSet(), _e = async function() {
|
|
1350
1422
|
var n;
|
|
1351
1423
|
let e, t;
|
|
1352
1424
|
try {
|
|
1353
1425
|
e = await new Promise((i, o) => {
|
|
1354
1426
|
var c;
|
|
1355
|
-
t = (
|
|
1356
|
-
console.error(
|
|
1427
|
+
t = (u) => {
|
|
1428
|
+
console.error(u), console.error(u.error);
|
|
1357
1429
|
const h = new Error("Rethrown");
|
|
1358
|
-
h.cause =
|
|
1430
|
+
h.cause = u.error, h.betterMessage = u.message, o(h);
|
|
1359
1431
|
}, (c = l(this, w)) == null || c.addEventListener(
|
|
1360
1432
|
"error",
|
|
1361
1433
|
t
|
|
@@ -1370,8 +1442,8 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1370
1442
|
return a instanceof Promise ? a.then(i, o) : i(a);
|
|
1371
1443
|
});
|
|
1372
1444
|
} catch (i) {
|
|
1373
|
-
for (const
|
|
1374
|
-
typeof this[
|
|
1445
|
+
for (const u in this)
|
|
1446
|
+
typeof this[u] == "function" && (this[u] = () => {
|
|
1375
1447
|
throw new Error(
|
|
1376
1448
|
"PHP runtime has crashed – see the earlier error for details."
|
|
1377
1449
|
);
|
|
@@ -1380,9 +1452,9 @@ S = new WeakMap(), k = new WeakMap(), A = new WeakMap(), y = new WeakMap(), w =
|
|
|
1380
1452
|
const o = i, a = "betterMessage" in o ? o.betterMessage : o.message, c = new Error(a);
|
|
1381
1453
|
throw c.cause = o, console.error(c), c;
|
|
1382
1454
|
} finally {
|
|
1383
|
-
(n = l(this, w)) == null || n.removeEventListener("error", t)
|
|
1455
|
+
(n = l(this, w)) == null || n.removeEventListener("error", t);
|
|
1384
1456
|
}
|
|
1385
|
-
const { headers: r, httpStatusCode: s } = f(this,
|
|
1457
|
+
const { headers: r, httpStatusCode: s } = f(this, U, se).call(this);
|
|
1386
1458
|
return new PHPResponse(
|
|
1387
1459
|
e === 0 ? s : 500,
|
|
1388
1460
|
r,
|
|
@@ -1453,28 +1525,28 @@ function journalFSEvents(e, t, r = () => {
|
|
|
1453
1525
|
if (h.path.startsWith(t))
|
|
1454
1526
|
r(h);
|
|
1455
1527
|
else if (h.operation === "RENAME" && h.toPath.startsWith(t))
|
|
1456
|
-
for (const
|
|
1528
|
+
for (const g of recordExistingPath(
|
|
1457
1529
|
e,
|
|
1458
1530
|
h.path,
|
|
1459
1531
|
h.toPath
|
|
1460
1532
|
))
|
|
1461
|
-
r(
|
|
1533
|
+
r(g);
|
|
1462
1534
|
}), a = {};
|
|
1463
1535
|
for (const [h] of Object.entries(o))
|
|
1464
1536
|
a[h] = i[h];
|
|
1465
1537
|
function c() {
|
|
1466
|
-
for (const [h,
|
|
1467
|
-
i[h] = function(...
|
|
1468
|
-
return
|
|
1538
|
+
for (const [h, g] of Object.entries(o))
|
|
1539
|
+
i[h] = function(...K) {
|
|
1540
|
+
return g(...K), a[h].apply(this, K);
|
|
1469
1541
|
};
|
|
1470
1542
|
}
|
|
1471
|
-
function
|
|
1472
|
-
for (const [h,
|
|
1473
|
-
e[__private__dont__use].FS[h] =
|
|
1543
|
+
function u() {
|
|
1544
|
+
for (const [h, g] of Object.entries(a))
|
|
1545
|
+
e[__private__dont__use].FS[h] = g;
|
|
1474
1546
|
}
|
|
1475
1547
|
e[__private__dont__use].journal = {
|
|
1476
1548
|
bind: c,
|
|
1477
|
-
unbind:
|
|
1549
|
+
unbind: u
|
|
1478
1550
|
}, c();
|
|
1479
1551
|
}
|
|
1480
1552
|
e.addEventListener("runtime.initialized", s), e[__private__dont__use] && s();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@php-wasm/fs-journal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Bindings to journal the PHP filesystem",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"main": "./index.cjs",
|
|
37
37
|
"module": "./index.js",
|
|
38
38
|
"license": "GPL-2.0-or-later",
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "ed0ec39040ab4cd69dc48a8eac157436b30f9d55",
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=18.18.0",
|
|
42
42
|
"npm": ">=8.11.0"
|