@php-wasm/universal 0.1.60 → 0.2.0

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 CHANGED
@@ -1,10 +1,10 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const E=Symbol("error"),S=Symbol("message");class v extends Event{constructor(e,t={}){super(e),this[E]=t.error===void 0?null:t.error,this[S]=t.message===void 0?"":t.message}get error(){return this[E]}get message(){return this[S]}}Object.defineProperty(v.prototype,"error",{enumerable:!0});Object.defineProperty(v.prototype,"message",{enumerable:!0});const B=typeof globalThis.ErrorEvent=="function"?globalThis.ErrorEvent:v;class C extends EventTarget{constructor(){super(...arguments),this.listenersCount=0}addEventListener(e,t){++this.listenersCount,super.addEventListener(e,t)}removeEventListener(e,t){--this.listenersCount,super.removeEventListener(e,t)}hasListeners(){return this.listenersCount>0}}function M(s){s.asm={...s.asm};const e=new C;for(const t in s.asm)if(typeof s.asm[t]=="function"){const r=s.asm[t];s.asm[t]=function(...n){try{return r(...n)}catch(o){if(!(o instanceof Error))throw o;if("exitCode"in o&&o?.exitCode===0)return;const i=q(o,s.lastAsyncifyStackSource?.stack);if(s.lastAsyncifyStackSource&&(o.cause=s.lastAsyncifyStackSource),!e.hasListeners())throw z(i),o;e.dispatchEvent(new B("error",{error:o,message:i}))}}}return e}let w=[];function D(){return w}function q(s,e){if(s.message==="unreachable"){let t=W;e||(t+=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=Symbol("error"),S=Symbol("message");class v extends Event{constructor(e,t={}){super(e),this[R]=t.error===void 0?null:t.error,this[S]=t.message===void 0?"":t.message}get error(){return this[R]}get message(){return this[S]}}Object.defineProperty(v.prototype,"error",{enumerable:!0});Object.defineProperty(v.prototype,"message",{enumerable:!0});const D=typeof globalThis.ErrorEvent=="function"?globalThis.ErrorEvent:v;function U(s){return s instanceof Error?"exitCode"in s&&s?.exitCode===0||s?.name==="ExitStatus"&&"status"in s&&s.status===0:!1}class A extends EventTarget{constructor(){super(...arguments),this.listenersCount=0}addEventListener(e,t){++this.listenersCount,super.addEventListener(e,t)}removeEventListener(e,t){--this.listenersCount,super.removeEventListener(e,t)}hasListeners(){return this.listenersCount>0}}function q(s){s.asm={...s.asm};const e=new A;for(const t in s.asm)if(typeof s.asm[t]=="function"){const r=s.asm[t];s.asm[t]=function(...n){try{return r(...n)}catch(o){if(!(o instanceof Error))throw o;const i=W(o,s.lastAsyncifyStackSource?.stack);if(s.lastAsyncifyStackSource&&(o.cause=s.lastAsyncifyStackSource),e.hasListeners()){e.dispatchEvent(new D("error",{error:o,message:i}));return}throw U(o)||V(i),o}}}return e}let w=[];function j(){return w}function W(s,e){if(s.message==="unreachable"){let t=z;e||(t+=`
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 }).
5
5
 
6
- `),w=G(e||s.stack||"");for(const r of w)t+=` * ${r}
7
- `;return t}return s.message}const W=`
6
+ `),w=Y(e||s.stack||"");for(const r of w)t+=` * ${r}
7
+ `;return t}return s.message}const z=`
8
8
  "unreachable" WASM instruction executed.
9
9
 
10
10
  The typical reason is a PHP function missing from the ASYNCIFY_ONLY
@@ -28,13 +28,13 @@ the Dockerfile, you'll need to trigger this error again with long stack
28
28
  traces enabled. In node.js, you can do it using the --stack-trace-limit=100
29
29
  CLI option:
30
30
 
31
- `,x="\x1B[41m",j="\x1B[1m",H="\x1B[0m",T="\x1B[K";let k=!1;function z(s){if(!k){k=!0,console.log(`${x}
31
+ `,x="\x1B[41m",G="\x1B[1m",H="\x1B[0m",T="\x1B[K";let k=!1;function V(s){if(!k){k=!0,console.log(`${x}
32
32
  ${T}
33
- ${j} WASM ERROR${H}${x}`);for(const e of s.split(`
34
- `))console.log(`${T} ${e} `);console.log(`${H}`)}}function G(s){try{const e=s.split(`
35
- `).slice(1).map(t=>{const r=t.trim().substring(3).split(" ");return{fn:r.length>=2?r[0]:"<unknown>",isWasm:t.includes("wasm://")}}).filter(({fn:t,isWasm:r})=>r&&!t.startsWith("dynCall_")&&!t.startsWith("invoke_")).map(({fn:t})=>t);return Array.from(new Set(e))}catch{return[]}}class y{constructor(e,t,r,n="",o=0){this.httpStatusCode=e,this.headers=t,this.bytes=r,this.exitCode=o,this.errors=n}static fromRawData(e){return new y(e.httpStatusCode,e.headers,e.bytes,e.errors,e.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 R=["8.2","8.1","8.0","7.4","7.3","7.2","7.1","7.0","5.6"],V=R[0],Y=R;class U{#e;#t;constructor(e,t={}){this.requestHandler=e,this.#e={},this.#t={handleRedirects:!1,maxRedirects:4,...t}}async request(e,t=0){const r=await this.requestHandler.request({...e,headers:{...e.headers,cookie:this.#r()}});if(r.headers["set-cookie"]&&this.#s(r.headers["set-cookie"]),this.#t.handleRedirects&&r.headers.location&&t<this.#t.maxRedirects){const n=new URL(r.headers.location[0],this.requestHandler.absoluteUrl);return this.request({url:n.toString(),method:"GET",headers:{}},t+1)}return r}pathToInternalUrl(e){return this.requestHandler.pathToInternalUrl(e)}internalUrlToPath(e){return this.requestHandler.internalUrlToPath(e)}get absoluteUrl(){return this.requestHandler.absoluteUrl}get documentRoot(){return this.requestHandler.documentRoot}#s(e){for(const t of e)try{if(!t.includes("="))continue;const r=t.indexOf("="),n=t.substring(0,r),o=t.substring(r+1).split(";")[0];this.#e[n]=o}catch(r){console.error(r)}}#r(){const e=[];for(const t in this.#e)e.push(`${t}=${this.#e[t]}`);return e.join("; ")}}class J{constructor({concurrency:e}){this._running=0,this.concurrency=e,this.queue=[]}get running(){return this._running}async acquire(){for(;;)if(this._running>=this.concurrency)await new Promise(e=>this.queue.push(e));else return this._running++,()=>{this._running--,this.queue.length>0&&this.queue.shift()()}}async run(e){const t=await this.acquire();try{return await e()}finally{t()}}}const A="http://example.com";function P(s){return s.toString().substring(s.origin.length)}function b(s,e){return!e||!s.startsWith(e)?s:s.substring(e.length)}function O(s,e){return!e||s.startsWith(e)?s:e+s}class I{#e;#t;#s;#r;#o;#n;#i;#a;#l;constructor(e,t={}){this.#a=new J({concurrency:1});const{documentRoot:r="/www/",absoluteUrl:n=typeof location=="object"?location?.href:"",isStaticFilePath:o=()=>!1}=t;this.php=e,this.#e=r,this.#l=o;const i=new URL(n);this.#s=i.hostname,this.#r=i.port?Number(i.port):i.protocol==="https:"?443:80,this.#t=(i.protocol||"").replace(":","");const l=this.#r!==443&&this.#r!==80;this.#o=[this.#s,l?`:${this.#r}`:""].join(""),this.#n=i.pathname.replace(/\/+$/,""),this.#i=[`${this.#t}://`,this.#o,this.#n].join("")}pathToInternalUrl(e){return`${this.absoluteUrl}${e}`}internalUrlToPath(e){const t=new URL(e);return t.pathname.startsWith(this.#n)&&(t.pathname=t.pathname.slice(this.#n.length)),P(t)}get isRequestRunning(){return this.#a.running>0}get absoluteUrl(){return this.#i}get documentRoot(){return this.#e}async request(e){const t=e.url.startsWith("http://")||e.url.startsWith("https://"),r=new URL(e.url,t?void 0:A),n=b(r.pathname,this.#n);return this.#l(n)?this.#c(n):await this.#h(e,r)}#c(e){const t=`${this.#e}${e}`;if(!this.php.fileExists(t))return new y(404,{},new TextEncoder().encode("404 File not found"));const r=this.php.readFileAsBuffer(t);return new y(200,{"content-length":[`${r.byteLength}`],"content-type":[Q(t)],"accept-ranges":["bytes"],"cache-control":["public, max-age=0"]},r)}async#h(e,t){const r=await this.#a.acquire();try{this.php.addServerGlobalEntry("DOCUMENT_ROOT",this.#e),this.php.addServerGlobalEntry("HTTPS",this.#i.startsWith("https://")?"on":"");let n="GET";const o={host:this.#o,...L(e.headers||{})},i=[];if(e.files&&Object.keys(e.files).length){n="POST";for(const u in e.files){const m=e.files[u];i.push({key:u,name:m.name,type:m.type,data:new Uint8Array(await m.arrayBuffer())})}o["content-type"]?.startsWith("multipart/form-data")&&(e.formData=K(e.body||""),o["content-type"]="application/x-www-form-urlencoded",delete e.body)}let l;e.formData!==void 0?(n="POST",o["content-type"]=o["content-type"]||"application/x-www-form-urlencoded",l=new URLSearchParams(e.formData).toString()):l=e.body;let c;try{c=this.#u(t.pathname)}catch{return new y(404,{},new TextEncoder().encode("404 File not found"))}return await this.php.run({relativeUri:O(P(t),this.#n),protocol:this.#t,method:e.method||n,body:l,fileInfos:i,scriptPath:c,headers:o})}finally{r()}}#u(e){let t=b(e,this.#n);t.includes(".php")?t=t.split(".php")[0]+".php":(t.endsWith("/")||(t+="/"),t.endsWith("index.php")||(t+="index.php"));const r=`${this.#e}${t}`;if(this.php.fileExists(r))return r;if(!this.php.fileExists(`${this.#e}/index.php`))throw new Error(`File not found: ${r}`);return`${this.#e}/index.php`}}function K(s){const e={},t=s.match(/--(.*)\r\n/);if(!t)return e;const r=t[1],n=s.split(`--${r}`);return n.shift(),n.pop(),n.forEach(o=>{const i=o.indexOf(`\r
33
+ ${G} WASM ERROR${H}${x}`);for(const e of s.split(`
34
+ `))console.log(`${T} ${e} `);console.log(`${H}`)}}function Y(s){try{const e=s.split(`
35
+ `).slice(1).map(t=>{const r=t.trim().substring(3).split(" ");return{fn:r.length>=2?r[0]:"<unknown>",isWasm:t.includes("wasm://")}}).filter(({fn:t,isWasm:r})=>r&&!t.startsWith("dynCall_")&&!t.startsWith("invoke_")).map(({fn:t})=>t);return Array.from(new Set(e))}catch{return[]}}class y{constructor(e,t,r,n="",o=0){this.httpStatusCode=e,this.headers=t,this.bytes=r,this.exitCode=o,this.errors=n}static fromRawData(e){return new y(e.httpStatusCode,e.headers,e.bytes,e.errors,e.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 E=["8.2","8.1","8.0","7.4","7.3","7.2","7.1","7.0","5.6"],J=E[0],K=E;class O{#e;#t;constructor(e,t={}){this.requestHandler=e,this.#e={},this.#t={handleRedirects:!1,maxRedirects:4,...t}}async request(e,t=0){const r=await this.requestHandler.request({...e,headers:{...e.headers,cookie:this.#r()}});if(r.headers["set-cookie"]&&this.#s(r.headers["set-cookie"]),this.#t.handleRedirects&&r.headers.location&&t<this.#t.maxRedirects){const n=new URL(r.headers.location[0],this.requestHandler.absoluteUrl);return this.request({url:n.toString(),method:"GET",headers:{}},t+1)}return r}pathToInternalUrl(e){return this.requestHandler.pathToInternalUrl(e)}internalUrlToPath(e){return this.requestHandler.internalUrlToPath(e)}get absoluteUrl(){return this.requestHandler.absoluteUrl}get documentRoot(){return this.requestHandler.documentRoot}#s(e){for(const t of e)try{if(!t.includes("="))continue;const r=t.indexOf("="),n=t.substring(0,r),o=t.substring(r+1).split(";")[0];this.#e[n]=o}catch(r){console.error(r)}}#r(){const e=[];for(const t in this.#e)e.push(`${t}=${this.#e[t]}`);return e.join("; ")}}class Z{constructor({concurrency:e}){this._running=0,this.concurrency=e,this.queue=[]}get running(){return this._running}async acquire(){for(;;)if(this._running>=this.concurrency)await new Promise(e=>this.queue.push(e));else{this._running++;let e=!1;return()=>{e||(e=!0,this._running--,this.queue.length>0&&this.queue.shift()())}}}async run(e){const t=await this.acquire();try{return await e()}finally{t()}}}const I="http://example.com";function P(s){return s.toString().substring(s.origin.length)}function b(s,e){return!e||!s.startsWith(e)?s:s.substring(e.length)}function L(s,e){return!e||s.startsWith(e)?s:e+s}class N{#e;#t;#s;#r;#o;#n;#i;#a;#l;constructor(e,t={}){this.#a=new Z({concurrency:1});const{documentRoot:r="/www/",absoluteUrl:n=typeof location=="object"?location?.href:"",isStaticFilePath:o=()=>!1}=t;this.php=e,this.#e=r,this.#l=o;const i=new URL(n);this.#s=i.hostname,this.#r=i.port?Number(i.port):i.protocol==="https:"?443:80,this.#t=(i.protocol||"").replace(":","");const l=this.#r!==443&&this.#r!==80;this.#o=[this.#s,l?`:${this.#r}`:""].join(""),this.#n=i.pathname.replace(/\/+$/,""),this.#i=[`${this.#t}://`,this.#o,this.#n].join("")}pathToInternalUrl(e){return`${this.absoluteUrl}${e}`}internalUrlToPath(e){const t=new URL(e);return t.pathname.startsWith(this.#n)&&(t.pathname=t.pathname.slice(this.#n.length)),P(t)}get isRequestRunning(){return this.#a.running>0}get absoluteUrl(){return this.#i}get documentRoot(){return this.#e}async request(e){const t=e.url.startsWith("http://")||e.url.startsWith("https://"),r=new URL(e.url,t?void 0:I),n=b(r.pathname,this.#n);return this.#l(n)?this.#c(n):await this.#h(e,r)}#c(e){const t=`${this.#e}${e}`;if(!this.php.fileExists(t))return new y(404,{},new TextEncoder().encode("404 File not found"));const r=this.php.readFileAsBuffer(t);return new y(200,{"content-length":[`${r.byteLength}`],"content-type":[X(t)],"accept-ranges":["bytes"],"cache-control":["public, max-age=0"]},r)}async#h(e,t){const r=await this.#a.acquire();try{this.php.addServerGlobalEntry("DOCUMENT_ROOT",this.#e),this.php.addServerGlobalEntry("HTTPS",this.#i.startsWith("https://")?"on":"");let n="GET";const o={host:this.#o,...$(e.headers||{})},i=[];if(e.files&&Object.keys(e.files).length){n="POST";for(const c in e.files){const m=e.files[c];i.push({key:c,name:m.name,type:m.type,data:new Uint8Array(await m.arrayBuffer())})}o["content-type"]?.startsWith("multipart/form-data")&&(e.formData=Q(e.body||""),o["content-type"]="application/x-www-form-urlencoded",delete e.body)}let l;e.formData!==void 0?(n="POST",o["content-type"]=o["content-type"]||"application/x-www-form-urlencoded",l=new URLSearchParams(e.formData).toString()):l=e.body;let h;try{h=this.#u(t.pathname)}catch{return new y(404,{},new TextEncoder().encode("404 File not found"))}return await this.php.run({relativeUri:L(P(t),this.#n),protocol:this.#t,method:e.method||n,body:l,fileInfos:i,scriptPath:h,headers:o})}finally{r()}}#u(e){let t=b(e,this.#n);t.includes(".php")?t=t.split(".php")[0]+".php":(t.endsWith("/")||(t+="/"),t.endsWith("index.php")||(t+="index.php"));const r=`${this.#e}${t}`;if(this.php.fileExists(r))return r;if(!this.php.fileExists(`${this.#e}/index.php`))throw new Error(`File not found: ${r}`);return`${this.#e}/index.php`}}function Q(s){const e={},t=s.match(/--(.*)\r\n/);if(!t)return e;const r=t[1],n=s.split(`--${r}`);return n.shift(),n.pop(),n.forEach(o=>{const i=o.indexOf(`\r
36
36
  \r
37
- `),l=o.substring(0,i).trim(),c=o.substring(i+4).trim(),u=l.match(/name="([^"]+)"/);if(u){const m=u[1];e[m]=c}}),e}function Q(s){switch(s.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"}}const F={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 p(s=""){return function(t,r,n){const o=n.value;n.value=function(...i){try{return o.apply(this,i)}catch(l){const c=typeof l=="object"?l?.errno:null;if(c in F){const u=F[c],m=typeof i[0]=="string"?i[0]:null,$=m!==null?s.replaceAll("{path}",m):s;throw new Error(`${$}: ${u}`,{cause:l})}throw l}}}}async function X(s,e={},t=[]){let r,n;const o=new Promise(c=>{n=c}),i=new Promise(c=>{r=c}),l=s.init(ee,{onAbort(c){console.error("WASM aborted: "),console.error(c)},ENV:{},locateFile:c=>c,...e,noInitialRun:!0,onRuntimeInitialized(){e.onRuntimeInitialized&&e.onRuntimeInitialized(),r()},monitorRunDependencies(c){c===0&&(delete l.monitorRunDependencies,n())}});for(const{default:c}of t)c(l);return t.length||n(),await o,await i,_.push(l),_.length-1}const _=[];function Z(s){return _[s]}const ee=function(){return typeof process<"u"&&process.release?.name==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"}();var te=Object.defineProperty,re=Object.getOwnPropertyDescriptor,f=(s,e,t,r)=>{for(var n=r>1?void 0:r?re(e,t):e,o=s.length-1,i;o>=0;o--)(i=s[o])&&(n=(r?i(e,t,n):i(n))||n);return r&&n&&te(e,t,n),n};const h="string",g="number",a=Symbol("__private__dont__use");class d{constructor(e,t){this.#e=[],this.#t=!1,this.#s=null,this.#r={},e!==void 0&&this.initializeRuntime(e),t&&(this.requestHandler=new U(new I(this,t)))}#e;#t;#s;#r;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[a])throw new Error("PHP runtime already initialized.");const t=Z(e);if(!t)throw new Error("Invalid PHP runtime id.");this[a]=t,this.#s=M(t)}setPhpIniPath(e){if(this.#t)throw new Error("Cannot set PHP ini path after calling run().");this[a].ccall("wasm_set_phpini_path",null,["string"],[e])}setPhpIniEntry(e,t){if(this.#t)throw new Error("Cannot set PHP ini entries after calling run().");this.#e.push([e,t])}chdir(e){this[a].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){this.#t||(this.#o(),this.#t=!0),this.#u(e.scriptPath||""),this.#i(e.relativeUri||""),this.#l(e.method||"GET");const{host:t,...r}={host:"example.com:443",...L(e.headers||{})};if(this.#a(t,e.protocol||"http"),this.#c(r),e.body&&this.#h(e.body),e.fileInfos)for(const n of e.fileInfos)this.#p(n);return e.code&&this.#f(" ?>"+e.code),this.#d(),await this.#m()}#o(){if(this.#e.length>0){const e=this.#e.map(([t,r])=>`${t}=${r}`).join(`
37
+ `),l=o.substring(0,i).trim(),h=o.substring(i+4).trim(),c=l.match(/name="([^"]+)"/);if(c){const m=c[1];e[m]=h}}),e}function X(s){switch(s.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"}}const F={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 p(s=""){return function(t,r,n){const o=n.value;n.value=function(...i){try{return o.apply(this,i)}catch(l){const h=typeof l=="object"?l?.errno:null;if(h in F){const c=F[h],m=typeof i[0]=="string"?i[0]:null,M=m!==null?s.replaceAll("{path}",m):s;throw new Error(`${M}: ${c}`,{cause:l})}throw l}}}}async function ee(s,e={},t=[]){const[r,n,o]=C(),[i,l]=C(),h=s.init(re,{onAbort(c){o(c),l(),console.error(c)},ENV:{},locateFile:c=>c,...e,noInitialRun:!0,onRuntimeInitialized(){e.onRuntimeInitialized&&e.onRuntimeInitialized(),n()},monitorRunDependencies(c){c===0&&(delete h.monitorRunDependencies,l())}});return await Promise.all(t.map(({default:c})=>c(h))),t.length||l(),await i,await r,_.push(h),_.length-1}const _=[];function te(s){return _[s]}const re=function(){return typeof process<"u"&&process.release?.name==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"}(),C=()=>{const s=[],e=new Promise((t,r)=>{s.push(t,r)});return s.unshift(e),s};var se=Object.defineProperty,ne=Object.getOwnPropertyDescriptor,f=(s,e,t,r)=>{for(var n=r>1?void 0:r?ne(e,t):e,o=s.length-1,i;o>=0;o--)(i=s[o])&&(n=(r?i(e,t,n):i(n))||n);return r&&n&&se(e,t,n),n};const u="string",g="number",a=Symbol("__private__dont__use");class d{constructor(e,t){this.#e=[],this.#t=!1,this.#s=null,this.#r={},this.#o=[],e!==void 0&&this.initializeRuntime(e),t&&(this.requestHandler=new O(new N(this,t)))}#e;#t;#s;#r;#o;async onMessage(e){this.#o.push(e)}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[a])throw new Error("PHP runtime already initialized.");const t=te(e);if(!t)throw new Error("Invalid PHP runtime id.");this[a]=t,t.onMessage=r=>{for(const n of this.#o)n(r)},this.#s=q(t)}setPhpIniPath(e){if(this.#t)throw new Error("Cannot set PHP ini path after calling run().");this[a].ccall("wasm_set_phpini_path",null,["string"],[e])}setPhpIniEntry(e,t){if(this.#t)throw new Error("Cannot set PHP ini entries after calling run().");this.#e.push([e,t])}chdir(e){this[a].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){this.#t||(this.#n(),this.#t=!0),this.#d(e.scriptPath||""),this.#a(e.relativeUri||""),this.#c(e.method||"GET");const{host:t,...r}={host:"example.com:443",...$(e.headers||{})};if(this.#l(t,e.protocol||"http"),this.#h(r),e.body&&this.#u(e.body),e.fileInfos)for(const n of e.fileInfos)this.#f(n);return e.code&&this.#m(" ?>"+e.code),this.#p(),await this.#y()}#n(){if(this.#e.length>0){const e=this.#e.map(([t,r])=>`${t}=${r}`).join(`
38
38
  `)+`
39
39
 
40
- `;this[a].ccall("wasm_set_phpini_entries",null,[h],[e])}this[a].ccall("php_wasm_init",null,[],[])}#n(){const e="/tmp/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 n of t.headers){if(!n.includes(": "))continue;const o=n.indexOf(": "),i=n.substring(0,o).toLowerCase(),l=n.substring(o+2);i in r||(r[i]=[]),r[i].push(l)}return{headers:r,httpStatusCode:t.status}}#i(e){if(this[a].ccall("wasm_set_request_uri",null,[h],[e]),e.includes("?")){const t=e.substring(e.indexOf("?")+1);this[a].ccall("wasm_set_query_string",null,[h],[t])}}#a(e,t){this[a].ccall("wasm_set_request_host",null,[h],[e]);let r;try{r=parseInt(new URL(e).port,10)}catch{}(!r||isNaN(r)||r===80)&&(r=t==="https"?443:80),this[a].ccall("wasm_set_request_port",null,[g],[r]),(t==="https"||!t&&r===443)&&this.addServerGlobalEntry("HTTPS","on")}#l(e){this[a].ccall("wasm_set_request_method",null,[h],[e])}#c(e){e.cookie&&this[a].ccall("wasm_set_cookies",null,[h],[e.cookie]),e["content-type"]&&this[a].ccall("wasm_set_content_type",null,[h],[e["content-type"]]),e["content-length"]&&this[a].ccall("wasm_set_content_length",null,[g],[parseInt(e["content-length"],10)]);for(const t in e){let r="HTTP_";["content-type","content-length"].includes(t.toLowerCase())&&(r=""),this.addServerGlobalEntry(`${r}${t.toUpperCase().replace(/-/g,"_")}`,e[t])}}#h(e){this[a].ccall("wasm_set_request_body",null,[h],[e]),this[a].ccall("wasm_set_content_length",null,[g],[new TextEncoder().encode(e).length])}#u(e){this[a].ccall("wasm_set_path_translated",null,[h],[e])}addServerGlobalEntry(e,t){this.#r[e]=t}#d(){for(const e in this.#r)this[a].ccall("wasm_add_SERVER_entry",null,[h,h],[e,this.#r[e]])}#p(e){const{key:t,name:r,type:n,data:o}=e,i=`/tmp/${Math.random().toFixed(20)}`;this.writeFile(i,o);const l=0;this[a].ccall("wasm_add_uploaded_file",null,[h,h,h,h,g,g],[t,r,n,i,l,o.byteLength])}#f(e){this[a].ccall("wasm_set_php_code",null,[h],[e])}async#m(){let e,t;try{e=await new Promise((o,i)=>{t=c=>{const u=new Error("Rethrown");u.cause=c.error,u.betterMessage=c.message,i(u)},this.#s?.addEventListener("error",t);const l=this[a].ccall("wasm_sapi_handle_request",g,[],[]);return l instanceof Promise?l.then(o,i):o(l)})}catch(o){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=D();const i=o,l="betterMessage"in i?i.betterMessage:i.message,c=new Error(l);throw c.cause=i,c}finally{this.#s?.removeEventListener("error",t),this.#r={}}const{headers:r,httpStatusCode:n}=this.#n();return new y(n,r,this.readFileAsBuffer("/tmp/stdout"),this.readFileAsText("/tmp/stderr"),e)}mkdir(e){this[a].FS.mkdirTree(e)}mkdirTree(e){this.mkdir(e)}readFileAsText(e){return new TextDecoder().decode(this.readFileAsBuffer(e))}readFileAsBuffer(e){return this[a].FS.readFile(e)}writeFile(e,t){this[a].FS.writeFile(e,t)}unlink(e){this[a].FS.unlink(e)}mv(e,t){this[a].FS.rename(e,t)}rmdir(e,t={recursive:!0}){t?.recursive&&this.listFiles(e).forEach(r=>{const n=`${e}/${r}`;this.isDir(n)?this.rmdir(n,t):this.unlink(n)}),this[a].FS.rmdir(e)}listFiles(e,t={prependPath:!1}){if(!this.fileExists(e))return[];try{const r=this[a].FS.readdir(e).filter(n=>n!=="."&&n!=="..");if(t.prependPath){const n=e.replace(/\/$/,"");return r.map(o=>`${n}/${o}`)}return r}catch(r){return console.error(r,{path:e}),[]}}isDir(e){return this.fileExists(e)?this[a].FS.isDir(this[a].FS.lookupPath(e).node.mode):!1}fileExists(e){try{return this[a].FS.lookupPath(e),!0}catch{return!1}}}f([p('Could not create directory "{path}"')],d.prototype,"mkdir",1);f([p('Could not create directory "{path}"')],d.prototype,"mkdirTree",1);f([p('Could not read "{path}"')],d.prototype,"readFileAsText",1);f([p('Could not read "{path}"')],d.prototype,"readFileAsBuffer",1);f([p('Could not write to "{path}"')],d.prototype,"writeFile",1);f([p('Could not unlink "{path}"')],d.prototype,"unlink",1);f([p('Could not move "{path}"')],d.prototype,"mv",1);f([p('Could not remove directory "{path}"')],d.prototype,"rmdir",1);f([p('Could not list files in "{path}"')],d.prototype,"listFiles",1);f([p('Could not stat "{path}"')],d.prototype,"isDir",1);f([p('Could not stat "{path}"')],d.prototype,"fileExists",1);function L(s){const e={};for(const t in s)e[t.toLowerCase()]=s[t];return e}function N(s){return!(s instanceof d)}function se(s){return!N(s)}exports.BasePHP=d;exports.DEFAULT_BASE_URL=A;exports.LatestSupportedPHPVersion=V;exports.PHPBrowser=U;exports.PHPRequestHandler=I;exports.PHPResponse=y;exports.SupportedPHPVersions=R;exports.SupportedPHPVersionsList=Y;exports.UnhandledRejectionsTarget=C;exports.__private__dont__use=a;exports.ensurePathPrefix=O;exports.isLocalPHP=N;exports.isRemotePHP=se;exports.loadPHPRuntime=X;exports.removePathPrefix=b;exports.rethrowFileSystemError=p;exports.toRelativeUrl=P;
40
+ `;this[a].ccall("wasm_set_phpini_entries",null,[u],[e])}this[a].ccall("php_wasm_init",null,[],[])}#i(){const e="/tmp/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 n of t.headers){if(!n.includes(": "))continue;const o=n.indexOf(": "),i=n.substring(0,o).toLowerCase(),l=n.substring(o+2);i in r||(r[i]=[]),r[i].push(l)}return{headers:r,httpStatusCode:t.status}}#a(e){if(this[a].ccall("wasm_set_request_uri",null,[u],[e]),e.includes("?")){const t=e.substring(e.indexOf("?")+1);this[a].ccall("wasm_set_query_string",null,[u],[t])}}#l(e,t){this[a].ccall("wasm_set_request_host",null,[u],[e]);let r;try{r=parseInt(new URL(e).port,10)}catch{}(!r||isNaN(r)||r===80)&&(r=t==="https"?443:80),this[a].ccall("wasm_set_request_port",null,[g],[r]),(t==="https"||!t&&r===443)&&this.addServerGlobalEntry("HTTPS","on")}#c(e){this[a].ccall("wasm_set_request_method",null,[u],[e])}#h(e){e.cookie&&this[a].ccall("wasm_set_cookies",null,[u],[e.cookie]),e["content-type"]&&this[a].ccall("wasm_set_content_type",null,[u],[e["content-type"]]),e["content-length"]&&this[a].ccall("wasm_set_content_length",null,[g],[parseInt(e["content-length"],10)]);for(const t in e){let r="HTTP_";["content-type","content-length"].includes(t.toLowerCase())&&(r=""),this.addServerGlobalEntry(`${r}${t.toUpperCase().replace(/-/g,"_")}`,e[t])}}#u(e){this[a].ccall("wasm_set_request_body",null,[u],[e]),this[a].ccall("wasm_set_content_length",null,[g],[new TextEncoder().encode(e).length])}#d(e){this[a].ccall("wasm_set_path_translated",null,[u],[e])}addServerGlobalEntry(e,t){this.#r[e]=t}#p(){for(const e in this.#r)this[a].ccall("wasm_add_SERVER_entry",null,[u,u],[e,this.#r[e]])}#f(e){const{key:t,name:r,type:n,data:o}=e,i=`/tmp/${Math.random().toFixed(20)}`;this.writeFile(i,o);const l=0;this[a].ccall("wasm_add_uploaded_file",null,[u,u,u,u,g,g],[t,r,n,i,l,o.byteLength])}#m(e){this[a].ccall("wasm_set_php_code",null,[u],[e])}async#y(){let e,t;try{e=await new Promise((o,i)=>{t=h=>{const c=new Error("Rethrown");c.cause=h.error,c.betterMessage=h.message,i(c)},this.#s?.addEventListener("error",t);const l=this[a].ccall("wasm_sapi_handle_request",g,[],[]);return l instanceof Promise?l.then(o,i):o(l)})}catch(o){for(const c in this)typeof this[c]=="function"&&(this[c]=()=>{throw new Error("PHP runtime has crashed – see the earlier error for details.")});this.functionsMaybeMissingFromAsyncify=j();const i=o,l="betterMessage"in i?i.betterMessage:i.message,h=new Error(l);throw h.cause=i,h}finally{this.#s?.removeEventListener("error",t),this.#r={}}const{headers:r,httpStatusCode:n}=this.#i();return new y(n,r,this.readFileAsBuffer("/tmp/stdout"),this.readFileAsText("/tmp/stderr"),e)}mkdir(e){this[a].FS.mkdirTree(e)}mkdirTree(e){this.mkdir(e)}readFileAsText(e){return new TextDecoder().decode(this.readFileAsBuffer(e))}readFileAsBuffer(e){return this[a].FS.readFile(e)}writeFile(e,t){this[a].FS.writeFile(e,t)}unlink(e){this[a].FS.unlink(e)}mv(e,t){this[a].FS.rename(e,t)}rmdir(e,t={recursive:!0}){t?.recursive&&this.listFiles(e).forEach(r=>{const n=`${e}/${r}`;this.isDir(n)?this.rmdir(n,t):this.unlink(n)}),this[a].FS.rmdir(e)}listFiles(e,t={prependPath:!1}){if(!this.fileExists(e))return[];try{const r=this[a].FS.readdir(e).filter(n=>n!=="."&&n!=="..");if(t.prependPath){const n=e.replace(/\/$/,"");return r.map(o=>`${n}/${o}`)}return r}catch(r){return console.error(r,{path:e}),[]}}isDir(e){return this.fileExists(e)?this[a].FS.isDir(this[a].FS.lookupPath(e).node.mode):!1}fileExists(e){try{return this[a].FS.lookupPath(e),!0}catch{return!1}}}f([p('Could not create directory "{path}"')],d.prototype,"mkdir",1);f([p('Could not create directory "{path}"')],d.prototype,"mkdirTree",1);f([p('Could not read "{path}"')],d.prototype,"readFileAsText",1);f([p('Could not read "{path}"')],d.prototype,"readFileAsBuffer",1);f([p('Could not write to "{path}"')],d.prototype,"writeFile",1);f([p('Could not unlink "{path}"')],d.prototype,"unlink",1);f([p('Could not move "{path}"')],d.prototype,"mv",1);f([p('Could not remove directory "{path}"')],d.prototype,"rmdir",1);f([p('Could not list files in "{path}"')],d.prototype,"listFiles",1);f([p('Could not stat "{path}"')],d.prototype,"isDir",1);f([p('Could not stat "{path}"')],d.prototype,"fileExists",1);function $(s){const e={};for(const t in s)e[t.toLowerCase()]=s[t];return e}function B(s){return!(s instanceof d)}function oe(s){return!B(s)}exports.BasePHP=d;exports.DEFAULT_BASE_URL=I;exports.LatestSupportedPHPVersion=J;exports.PHPBrowser=O;exports.PHPRequestHandler=N;exports.PHPResponse=y;exports.SupportedPHPVersions=E;exports.SupportedPHPVersionsList=K;exports.UnhandledRejectionsTarget=A;exports.__private__dont__use=a;exports.ensurePathPrefix=L;exports.isExitCodeZero=U;exports.isLocalPHP=B;exports.isRemotePHP=oe;exports.loadPHPRuntime=ee;exports.removePathPrefix=b;exports.rethrowFileSystemError=p;exports.toRelativeUrl=P;
package/index.js CHANGED
@@ -20,7 +20,10 @@ class b extends Event {
20
20
  Object.defineProperty(b.prototype, "error", { enumerable: !0 });
21
21
  Object.defineProperty(b.prototype, "message", { enumerable: !0 });
22
22
  const A = typeof globalThis.ErrorEvent == "function" ? globalThis.ErrorEvent : b;
23
- class O extends EventTarget {
23
+ function I(s) {
24
+ return s instanceof Error ? "exitCode" in s && s?.exitCode === 0 || s?.name === "ExitStatus" && "status" in s && s.status === 0 : !1;
25
+ }
26
+ class N extends EventTarget {
24
27
  constructor() {
25
28
  super(...arguments), this.listenersCount = 0;
26
29
  }
@@ -34,11 +37,11 @@ class O extends EventTarget {
34
37
  return this.listenersCount > 0;
35
38
  }
36
39
  }
37
- function I(s) {
40
+ function $(s) {
38
41
  s.asm = {
39
42
  ...s.asm
40
43
  };
41
- const e = new O();
44
+ const e = new N();
42
45
  for (const t in s.asm)
43
46
  if (typeof s.asm[t] == "function") {
44
47
  const r = s.asm[t];
@@ -48,38 +51,38 @@ function I(s) {
48
51
  } catch (o) {
49
52
  if (!(o instanceof Error))
50
53
  throw o;
51
- if ("exitCode" in o && o?.exitCode === 0)
52
- return;
53
- const i = $(
54
+ const i = M(
54
55
  o,
55
56
  s.lastAsyncifyStackSource?.stack
56
57
  );
57
- if (s.lastAsyncifyStackSource && (o.cause = s.lastAsyncifyStackSource), !e.hasListeners())
58
- throw D(i), o;
59
- e.dispatchEvent(
60
- new A("error", {
61
- error: o,
62
- message: i
63
- })
64
- );
58
+ if (s.lastAsyncifyStackSource && (o.cause = s.lastAsyncifyStackSource), e.hasListeners()) {
59
+ e.dispatchEvent(
60
+ new A("error", {
61
+ error: o,
62
+ message: i
63
+ })
64
+ );
65
+ return;
66
+ }
67
+ throw I(o) || q(i), o;
65
68
  }
66
69
  };
67
70
  }
68
71
  return e;
69
72
  }
70
73
  let w = [];
71
- function N() {
74
+ function L() {
72
75
  return w;
73
76
  }
74
- function $(s, e) {
77
+ function M(s, e) {
75
78
  if (s.message === "unreachable") {
76
- let t = L;
79
+ let t = B;
77
80
  e || (t += `
78
81
 
79
82
  This stack trace is lacking. For a better one initialize
80
83
  the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
81
84
 
82
- `), w = B(
85
+ `), w = W(
83
86
  e || s.stack || ""
84
87
  );
85
88
  for (const r of w)
@@ -89,7 +92,7 @@ the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
89
92
  }
90
93
  return s.message;
91
94
  }
92
- const L = `
95
+ const B = `
93
96
  "unreachable" WASM instruction executed.
94
97
 
95
98
  The typical reason is a PHP function missing from the ASYNCIFY_ONLY
@@ -113,20 +116,20 @@ the Dockerfile, you'll need to trigger this error again with long stack
113
116
  traces enabled. In node.js, you can do it using the --stack-trace-limit=100
114
117
  CLI option:
115
118
 
116
- `, R = "\x1B[41m", M = "\x1B[1m", E = "\x1B[0m", S = "\x1B[K";
119
+ `, E = "\x1B[41m", D = "\x1B[1m", R = "\x1B[0m", S = "\x1B[K";
117
120
  let x = !1;
118
- function D(s) {
121
+ function q(s) {
119
122
  if (!x) {
120
- x = !0, console.log(`${R}
123
+ x = !0, console.log(`${E}
121
124
  ${S}
122
- ${M} WASM ERROR${E}${R}`);
125
+ ${D} WASM ERROR${R}${E}`);
123
126
  for (const e of s.split(`
124
127
  `))
125
128
  console.log(`${S} ${e} `);
126
- console.log(`${E}`);
129
+ console.log(`${R}`);
127
130
  }
128
131
  }
129
- function B(s) {
132
+ function W(s) {
130
133
  try {
131
134
  const e = s.split(`
132
135
  `).slice(1).map((t) => {
@@ -178,7 +181,7 @@ class g {
178
181
  return new TextDecoder().decode(this.bytes);
179
182
  }
180
183
  }
181
- const C = [
184
+ const H = [
182
185
  "8.2",
183
186
  "8.1",
184
187
  "8.0",
@@ -188,8 +191,8 @@ const C = [
188
191
  "7.1",
189
192
  "7.0",
190
193
  "5.6"
191
- ], ee = C[0], te = C;
192
- class q {
194
+ ], re = H[0], se = H;
195
+ class j {
193
196
  #e;
194
197
  #t;
195
198
  /**
@@ -275,7 +278,7 @@ class q {
275
278
  return e.join("; ");
276
279
  }
277
280
  }
278
- class W {
281
+ class z {
279
282
  constructor({ concurrency: e }) {
280
283
  this._running = 0, this.concurrency = e, this.queue = [];
281
284
  }
@@ -286,10 +289,13 @@ class W {
286
289
  for (; ; )
287
290
  if (this._running >= this.concurrency)
288
291
  await new Promise((e) => this.queue.push(e));
289
- else
290
- return this._running++, () => {
291
- this._running--, this.queue.length > 0 && this.queue.shift()();
292
+ else {
293
+ this._running++;
294
+ let e = !1;
295
+ return () => {
296
+ e || (e = !0, this._running--, this.queue.length > 0 && this.queue.shift()());
292
297
  };
298
+ }
293
299
  }
294
300
  async run(e) {
295
301
  const t = await this.acquire();
@@ -300,17 +306,17 @@ class W {
300
306
  }
301
307
  }
302
308
  }
303
- const j = "http://example.com";
309
+ const G = "http://example.com";
304
310
  function T(s) {
305
311
  return s.toString().substring(s.origin.length);
306
312
  }
307
313
  function k(s, e) {
308
314
  return !e || !s.startsWith(e) ? s : s.substring(e.length);
309
315
  }
310
- function z(s, e) {
316
+ function V(s, e) {
311
317
  return !e || s.startsWith(e) ? s : e + s;
312
318
  }
313
- class G {
319
+ class Y {
314
320
  #e;
315
321
  #t;
316
322
  #s;
@@ -325,7 +331,7 @@ class G {
325
331
  * @param config - Request Handler configuration.
326
332
  */
327
333
  constructor(e, t = {}) {
328
- this.#a = new W({ concurrency: 1 });
334
+ this.#a = new z({ concurrency: 1 });
329
335
  const {
330
336
  documentRoot: r = "/www/",
331
337
  absoluteUrl: n = typeof location == "object" ? location?.href : "",
@@ -368,7 +374,7 @@ class G {
368
374
  async request(e) {
369
375
  const t = e.url.startsWith("http://") || e.url.startsWith("https://"), r = new URL(
370
376
  e.url,
371
- t ? void 0 : j
377
+ t ? void 0 : G
372
378
  ), n = k(
373
379
  r.pathname,
374
380
  this.#n
@@ -397,7 +403,7 @@ class G {
397
403
  // @TODO: Infer the content-type from the arrayBuffer instead of the file path.
398
404
  // The code below won't return the correct mime-type if the extension
399
405
  // was tampered with.
400
- "content-type": [Y(t)],
406
+ "content-type": [K(t)],
401
407
  "accept-ranges": ["bytes"],
402
408
  "cache-control": ["public, max-age=0"]
403
409
  },
@@ -421,20 +427,20 @@ class G {
421
427
  let n = "GET";
422
428
  const o = {
423
429
  host: this.#o,
424
- ...H(e.headers || {})
430
+ ...U(e.headers || {})
425
431
  }, i = [];
426
432
  if (e.files && Object.keys(e.files).length) {
427
433
  n = "POST";
428
- for (const u in e.files) {
429
- const m = e.files[u];
434
+ for (const c in e.files) {
435
+ const m = e.files[c];
430
436
  i.push({
431
- key: u,
437
+ key: c,
432
438
  name: m.name,
433
439
  type: m.type,
434
440
  data: new Uint8Array(await m.arrayBuffer())
435
441
  });
436
442
  }
437
- o["content-type"]?.startsWith("multipart/form-data") && (e.formData = V(
443
+ o["content-type"]?.startsWith("multipart/form-data") && (e.formData = J(
438
444
  e.body || ""
439
445
  ), o["content-type"] = "application/x-www-form-urlencoded", delete e.body);
440
446
  }
@@ -442,9 +448,9 @@ class G {
442
448
  e.formData !== void 0 ? (n = "POST", o["content-type"] = o["content-type"] || "application/x-www-form-urlencoded", l = new URLSearchParams(
443
449
  e.formData
444
450
  ).toString()) : l = e.body;
445
- let c;
451
+ let h;
446
452
  try {
447
- c = this.#u(t.pathname);
453
+ h = this.#u(t.pathname);
448
454
  } catch {
449
455
  return new g(
450
456
  404,
@@ -453,7 +459,7 @@ class G {
453
459
  );
454
460
  }
455
461
  return await this.php.run({
456
- relativeUri: z(
462
+ relativeUri: V(
457
463
  T(t),
458
464
  this.#n
459
465
  ),
@@ -461,7 +467,7 @@ class G {
461
467
  method: e.method || n,
462
468
  body: l,
463
469
  fileInfos: i,
464
- scriptPath: c,
470
+ scriptPath: h,
465
471
  headers: o
466
472
  });
467
473
  } finally {
@@ -488,7 +494,7 @@ class G {
488
494
  return `${this.#e}/index.php`;
489
495
  }
490
496
  }
491
- function V(s) {
497
+ function J(s) {
492
498
  const e = {}, t = s.match(/--(.*)\r\n/);
493
499
  if (!t)
494
500
  return e;
@@ -496,14 +502,14 @@ function V(s) {
496
502
  return n.shift(), n.pop(), n.forEach((o) => {
497
503
  const i = o.indexOf(`\r
498
504
  \r
499
- `), l = o.substring(0, i).trim(), c = o.substring(i + 4).trim(), u = l.match(/name="([^"]+)"/);
500
- if (u) {
501
- const m = u[1];
502
- e[m] = c;
505
+ `), l = o.substring(0, i).trim(), h = o.substring(i + 4).trim(), c = l.match(/name="([^"]+)"/);
506
+ if (c) {
507
+ const m = c[1];
508
+ e[m] = h;
503
509
  }
504
510
  }), e;
505
511
  }
506
- function Y(s) {
512
+ function K(s) {
507
513
  switch (s.split(".").pop()) {
508
514
  case "css":
509
515
  return "text/css";
@@ -543,7 +549,7 @@ function Y(s) {
543
549
  return "application-octet-stream";
544
550
  }
545
551
  }
546
- const F = {
552
+ const C = {
547
553
  0: "No error occurred. System call completed successfully.",
548
554
  1: "Argument list too long.",
549
555
  2: "Permission denied.",
@@ -629,10 +635,10 @@ function p(s = "") {
629
635
  try {
630
636
  return o.apply(this, i);
631
637
  } catch (l) {
632
- const c = typeof l == "object" ? l?.errno : null;
633
- if (c in F) {
634
- const u = F[c], m = typeof i[0] == "string" ? i[0] : null, U = m !== null ? s.replaceAll("{path}", m) : s;
635
- throw new Error(`${U}: ${u}`, {
638
+ const h = typeof l == "object" ? l?.errno : null;
639
+ if (h in C) {
640
+ const c = C[h], m = typeof i[0] == "string" ? i[0] : null, O = m !== null ? s.replaceAll("{path}", m) : s;
641
+ throw new Error(`${O}: ${c}`, {
636
642
  cause: l
637
643
  });
638
644
  }
@@ -641,15 +647,10 @@ function p(s = "") {
641
647
  };
642
648
  };
643
649
  }
644
- async function re(s, e = {}, t = []) {
645
- let r, n;
646
- const o = new Promise((c) => {
647
- n = c;
648
- }), i = new Promise((c) => {
649
- r = c;
650
- }), l = s.init(K, {
650
+ async function ne(s, e = {}, t = []) {
651
+ const [r, n, o] = F(), [i, l] = F(), h = s.init(Q, {
651
652
  onAbort(c) {
652
- console.error("WASM aborted: "), console.error(c);
653
+ o(c), l(), console.error(c);
653
654
  },
654
655
  ENV: {},
655
656
  // Emscripten sometimes prepends a '/' to the path, which
@@ -659,29 +660,36 @@ async function re(s, e = {}, t = []) {
659
660
  ...e,
660
661
  noInitialRun: !0,
661
662
  onRuntimeInitialized() {
662
- e.onRuntimeInitialized && e.onRuntimeInitialized(), r();
663
+ e.onRuntimeInitialized && e.onRuntimeInitialized(), n();
663
664
  },
664
665
  monitorRunDependencies(c) {
665
- c === 0 && (delete l.monitorRunDependencies, n());
666
+ c === 0 && (delete h.monitorRunDependencies, l());
666
667
  }
667
668
  });
668
- for (const { default: c } of t)
669
- c(l);
670
- return t.length || n(), await o, await i, P.push(l), P.length - 1;
669
+ return await Promise.all(
670
+ t.map(
671
+ ({ default: c }) => c(h)
672
+ )
673
+ ), t.length || l(), await i, await r, P.push(h), P.length - 1;
671
674
  }
672
675
  const P = [];
673
- function J(s) {
676
+ function Z(s) {
674
677
  return P[s];
675
678
  }
676
- const K = function() {
679
+ const Q = function() {
677
680
  return typeof process < "u" && process.release?.name === "node" ? "NODE" : typeof window < "u" ? "WEB" : typeof WorkerGlobalScope < "u" && self instanceof WorkerGlobalScope ? "WORKER" : "NODE";
678
- }();
679
- var Q = Object.defineProperty, X = Object.getOwnPropertyDescriptor, f = (s, e, t, r) => {
680
- for (var n = r > 1 ? void 0 : r ? X(e, t) : e, o = s.length - 1, i; o >= 0; o--)
681
+ }(), F = () => {
682
+ const s = [], e = new Promise((t, r) => {
683
+ s.push(t, r);
684
+ });
685
+ return s.unshift(e), s;
686
+ };
687
+ var X = Object.defineProperty, ee = Object.getOwnPropertyDescriptor, f = (s, e, t, r) => {
688
+ for (var n = r > 1 ? void 0 : r ? ee(e, t) : e, o = s.length - 1, i; o >= 0; o--)
681
689
  (i = s[o]) && (n = (r ? i(e, t, n) : i(n)) || n);
682
- return r && n && Q(e, t, n), n;
690
+ return r && n && X(e, t, n), n;
683
691
  };
684
- const h = "string", y = "number", a = Symbol("__private__dont__use");
692
+ const u = "string", y = "number", a = Symbol("__private__dont__use");
685
693
  class d {
686
694
  /**
687
695
  * Initializes a PHP runtime.
@@ -691,14 +699,19 @@ class d {
691
699
  * @param serverOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
692
700
  */
693
701
  constructor(e, t) {
694
- this.#e = [], this.#t = !1, this.#s = null, this.#r = {}, e !== void 0 && this.initializeRuntime(e), t && (this.requestHandler = new q(
695
- new G(this, t)
702
+ this.#e = [], this.#t = !1, this.#s = null, this.#r = {}, this.#o = [], e !== void 0 && this.initializeRuntime(e), t && (this.requestHandler = new j(
703
+ new Y(this, t)
696
704
  ));
697
705
  }
698
706
  #e;
699
707
  #t;
700
708
  #s;
701
709
  #r;
710
+ #o;
711
+ /** @inheritDoc */
712
+ async onMessage(e) {
713
+ this.#o.push(e);
714
+ }
702
715
  /** @inheritDoc */
703
716
  get absoluteUrl() {
704
717
  return this.requestHandler.requestHandler.absoluteUrl;
@@ -720,10 +733,13 @@ class d {
720
733
  initializeRuntime(e) {
721
734
  if (this[a])
722
735
  throw new Error("PHP runtime already initialized.");
723
- const t = J(e);
736
+ const t = Z(e);
724
737
  if (!t)
725
738
  throw new Error("Invalid PHP runtime id.");
726
- this[a] = t, this.#s = I(t);
739
+ this[a] = t, t.onMessage = (r) => {
740
+ for (const n of this.#o)
741
+ n(r);
742
+ }, this.#s = $(t);
727
743
  }
728
744
  /** @inheritDoc */
729
745
  setPhpIniPath(e) {
@@ -754,17 +770,17 @@ class d {
754
770
  }
755
771
  /** @inheritDoc */
756
772
  async run(e) {
757
- this.#t || (this.#o(), this.#t = !0), this.#u(e.scriptPath || ""), this.#i(e.relativeUri || ""), this.#l(e.method || "GET");
773
+ this.#t || (this.#n(), this.#t = !0), this.#d(e.scriptPath || ""), this.#a(e.relativeUri || ""), this.#c(e.method || "GET");
758
774
  const { host: t, ...r } = {
759
775
  host: "example.com:443",
760
- ...H(e.headers || {})
776
+ ...U(e.headers || {})
761
777
  };
762
- if (this.#a(t, e.protocol || "http"), this.#c(r), e.body && this.#h(e.body), e.fileInfos)
778
+ if (this.#l(t, e.protocol || "http"), this.#h(r), e.body && this.#u(e.body), e.fileInfos)
763
779
  for (const n of e.fileInfos)
764
- this.#p(n);
765
- return e.code && this.#f(" ?>" + e.code), this.#d(), await this.#m();
780
+ this.#f(n);
781
+ return e.code && this.#m(" ?>" + e.code), this.#p(), await this.#y();
766
782
  }
767
- #o() {
783
+ #n() {
768
784
  if (this.#e.length > 0) {
769
785
  const e = this.#e.map(([t, r]) => `${t}=${r}`).join(`
770
786
  `) + `
@@ -773,13 +789,13 @@ class d {
773
789
  this[a].ccall(
774
790
  "wasm_set_phpini_entries",
775
791
  null,
776
- [h],
792
+ [u],
777
793
  [e]
778
794
  );
779
795
  }
780
796
  this[a].ccall("php_wasm_init", null, [], []);
781
797
  }
782
- #n() {
798
+ #i() {
783
799
  const e = "/tmp/headers.json";
784
800
  if (!this.fileExists(e))
785
801
  throw new Error(
@@ -797,27 +813,27 @@ class d {
797
813
  httpStatusCode: t.status
798
814
  };
799
815
  }
800
- #i(e) {
816
+ #a(e) {
801
817
  if (this[a].ccall(
802
818
  "wasm_set_request_uri",
803
819
  null,
804
- [h],
820
+ [u],
805
821
  [e]
806
822
  ), e.includes("?")) {
807
823
  const t = e.substring(e.indexOf("?") + 1);
808
824
  this[a].ccall(
809
825
  "wasm_set_query_string",
810
826
  null,
811
- [h],
827
+ [u],
812
828
  [t]
813
829
  );
814
830
  }
815
831
  }
816
- #a(e, t) {
832
+ #l(e, t) {
817
833
  this[a].ccall(
818
834
  "wasm_set_request_host",
819
835
  null,
820
- [h],
836
+ [u],
821
837
  [e]
822
838
  );
823
839
  let r;
@@ -832,24 +848,24 @@ class d {
832
848
  [r]
833
849
  ), (t === "https" || !t && r === 443) && this.addServerGlobalEntry("HTTPS", "on");
834
850
  }
835
- #l(e) {
851
+ #c(e) {
836
852
  this[a].ccall(
837
853
  "wasm_set_request_method",
838
854
  null,
839
- [h],
855
+ [u],
840
856
  [e]
841
857
  );
842
858
  }
843
- #c(e) {
859
+ #h(e) {
844
860
  e.cookie && this[a].ccall(
845
861
  "wasm_set_cookies",
846
862
  null,
847
- [h],
863
+ [u],
848
864
  [e.cookie]
849
865
  ), e["content-type"] && this[a].ccall(
850
866
  "wasm_set_content_type",
851
867
  null,
852
- [h],
868
+ [u],
853
869
  [e["content-type"]]
854
870
  ), e["content-length"] && this[a].ccall(
855
871
  "wasm_set_content_length",
@@ -865,11 +881,11 @@ class d {
865
881
  );
866
882
  }
867
883
  }
868
- #h(e) {
884
+ #u(e) {
869
885
  this[a].ccall(
870
886
  "wasm_set_request_body",
871
887
  null,
872
- [h],
888
+ [u],
873
889
  [e]
874
890
  ), this[a].ccall(
875
891
  "wasm_set_content_length",
@@ -878,23 +894,23 @@ class d {
878
894
  [new TextEncoder().encode(e).length]
879
895
  );
880
896
  }
881
- #u(e) {
897
+ #d(e) {
882
898
  this[a].ccall(
883
899
  "wasm_set_path_translated",
884
900
  null,
885
- [h],
901
+ [u],
886
902
  [e]
887
903
  );
888
904
  }
889
905
  addServerGlobalEntry(e, t) {
890
906
  this.#r[e] = t;
891
907
  }
892
- #d() {
908
+ #p() {
893
909
  for (const e in this.#r)
894
910
  this[a].ccall(
895
911
  "wasm_add_SERVER_entry",
896
912
  null,
897
- [h, h],
913
+ [u, u],
898
914
  [e, this.#r[e]]
899
915
  );
900
916
  }
@@ -907,32 +923,32 @@ class d {
907
923
  *
908
924
  * @param fileInfo - File details
909
925
  */
910
- #p(e) {
926
+ #f(e) {
911
927
  const { key: t, name: r, type: n, data: o } = e, i = `/tmp/${Math.random().toFixed(20)}`;
912
928
  this.writeFile(i, o);
913
929
  const l = 0;
914
930
  this[a].ccall(
915
931
  "wasm_add_uploaded_file",
916
932
  null,
917
- [h, h, h, h, y, y],
933
+ [u, u, u, u, y, y],
918
934
  [t, r, n, i, l, o.byteLength]
919
935
  );
920
936
  }
921
- #f(e) {
937
+ #m(e) {
922
938
  this[a].ccall(
923
939
  "wasm_set_php_code",
924
940
  null,
925
- [h],
941
+ [u],
926
942
  [e]
927
943
  );
928
944
  }
929
- async #m() {
945
+ async #y() {
930
946
  let e, t;
931
947
  try {
932
948
  e = await new Promise((o, i) => {
933
- t = (c) => {
934
- const u = new Error("Rethrown");
935
- u.cause = c.error, u.betterMessage = c.message, i(u);
949
+ t = (h) => {
950
+ const c = new Error("Rethrown");
951
+ c.cause = h.error, c.betterMessage = h.message, i(c);
936
952
  }, this.#s?.addEventListener(
937
953
  "error",
938
954
  t
@@ -946,19 +962,19 @@ class d {
946
962
  return l instanceof Promise ? l.then(o, i) : o(l);
947
963
  });
948
964
  } catch (o) {
949
- for (const u in this)
950
- typeof this[u] == "function" && (this[u] = () => {
965
+ for (const c in this)
966
+ typeof this[c] == "function" && (this[c] = () => {
951
967
  throw new Error(
952
968
  "PHP runtime has crashed – see the earlier error for details."
953
969
  );
954
970
  });
955
- this.functionsMaybeMissingFromAsyncify = N();
956
- const i = o, l = "betterMessage" in i ? i.betterMessage : i.message, c = new Error(l);
957
- throw c.cause = i, c;
971
+ this.functionsMaybeMissingFromAsyncify = L();
972
+ const i = o, l = "betterMessage" in i ? i.betterMessage : i.message, h = new Error(l);
973
+ throw h.cause = i, h;
958
974
  } finally {
959
975
  this.#s?.removeEventListener("error", t), this.#r = {};
960
976
  }
961
- const { headers: r, httpStatusCode: n } = this.#n();
977
+ const { headers: r, httpStatusCode: n } = this.#i();
962
978
  return new g(
963
979
  n,
964
980
  r,
@@ -1056,33 +1072,34 @@ f([
1056
1072
  f([
1057
1073
  p('Could not stat "{path}"')
1058
1074
  ], d.prototype, "fileExists", 1);
1059
- function H(s) {
1075
+ function U(s) {
1060
1076
  const e = {};
1061
1077
  for (const t in s)
1062
1078
  e[t.toLowerCase()] = s[t];
1063
1079
  return e;
1064
1080
  }
1065
- function Z(s) {
1081
+ function te(s) {
1066
1082
  return !(s instanceof d);
1067
1083
  }
1068
- function se(s) {
1069
- return !Z(s);
1084
+ function oe(s) {
1085
+ return !te(s);
1070
1086
  }
1071
1087
  export {
1072
1088
  d as BasePHP,
1073
- j as DEFAULT_BASE_URL,
1074
- ee as LatestSupportedPHPVersion,
1075
- q as PHPBrowser,
1076
- G as PHPRequestHandler,
1089
+ G as DEFAULT_BASE_URL,
1090
+ re as LatestSupportedPHPVersion,
1091
+ j as PHPBrowser,
1092
+ Y as PHPRequestHandler,
1077
1093
  g as PHPResponse,
1078
- C as SupportedPHPVersions,
1079
- te as SupportedPHPVersionsList,
1080
- O as UnhandledRejectionsTarget,
1094
+ H as SupportedPHPVersions,
1095
+ se as SupportedPHPVersionsList,
1096
+ N as UnhandledRejectionsTarget,
1081
1097
  a as __private__dont__use,
1082
- z as ensurePathPrefix,
1083
- Z as isLocalPHP,
1084
- se as isRemotePHP,
1085
- re as loadPHPRuntime,
1098
+ V as ensurePathPrefix,
1099
+ I as isExitCodeZero,
1100
+ te as isLocalPHP,
1101
+ oe as isRemotePHP,
1102
+ ne as loadPHPRuntime,
1086
1103
  k as removePathPrefix,
1087
1104
  p as rethrowFileSystemError,
1088
1105
  T as toRelativeUrl
package/lib/base-php.d.ts CHANGED
@@ -2,7 +2,7 @@ import { PHPBrowser } from './php-browser';
2
2
  import { PHPRequestHandlerConfiguration } from './php-request-handler';
3
3
  import { PHPResponse } from './php-response';
4
4
  import type { PHPRuntimeId } from './load-php-runtime';
5
- import { IsomorphicLocalPHP, PHPRequest, PHPRunOptions, RmDirOptions, ListFilesOptions } from './universal-php';
5
+ import { IsomorphicLocalPHP, MessageListener, PHPRequest, PHPRunOptions, RmDirOptions, ListFilesOptions } from './universal-php';
6
6
  export declare const __private__dont__use: unique symbol;
7
7
  /**
8
8
  * An environment-agnostic wrapper around the Emscripten PHP runtime
@@ -25,6 +25,8 @@ export declare abstract class BasePHP implements IsomorphicLocalPHP {
25
25
  */
26
26
  constructor(PHPRuntimeId?: PHPRuntimeId, serverOptions?: PHPRequestHandlerConfiguration);
27
27
  /** @inheritDoc */
28
+ onMessage(listener: MessageListener): Promise<void>;
29
+ /** @inheritDoc */
28
30
  get absoluteUrl(): string;
29
31
  /** @inheritDoc */
30
32
  get documentRoot(): string;
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { FileInfo, IsomorphicLocalPHP, IsomorphicRemotePHP, PHPOutput, PHPRunOptions, UniversalPHP, ListFilesOptions, RmDirOptions, HTTPMethod, PHPRequest, PHPRequestHeaders, RequestHandler, } from './universal-php';
1
+ export type { FileInfo, IsomorphicLocalPHP, IsomorphicRemotePHP, MessageListener, PHPOutput, PHPRunOptions, UniversalPHP, ListFilesOptions, RmDirOptions, HTTPMethod, PHPRequest, PHPRequestHeaders, RequestHandler, } from './universal-php';
2
2
  export { UnhandledRejectionsTarget } from './wasm-error-reporting';
3
3
  export { PHPResponse } from './php-response';
4
4
  export type { PHPResponseData } from './php-response';
@@ -16,3 +16,4 @@ export { PHPRequestHandler } from './php-request-handler';
16
16
  export type { PHPBrowserConfiguration } from './php-browser';
17
17
  export { PHPBrowser } from './php-browser';
18
18
  export { DEFAULT_BASE_URL, ensurePathPrefix, removePathPrefix, toRelativeUrl, } from './urls';
19
+ export { isExitCodeZero } from './is-exit-code-zero';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Check if the Emscripten-thrown error is an exit code 0 error.
3
+ *
4
+ * @param e The error to check
5
+ * @returns True if the error is an exit code 0 error
6
+ */
7
+ export declare function isExitCodeZero(e: any): boolean;
@@ -146,4 +146,6 @@ export type EmscriptenOptions = {
146
146
  quit?: (status: number, toThrow: any) => void;
147
147
  onRuntimeInitialized?: () => void;
148
148
  monitorRunDependencies?: (left: number) => void;
149
+ onMessage?: (listener: EmscriptenMessageListener) => void;
149
150
  } & Record<string, any>;
151
+ export type EmscriptenMessageListener = (type: string, data: string) => void;
@@ -73,7 +73,7 @@ export interface RequestHandler {
73
73
  * }
74
74
  * })
75
75
  * php.writeFile("/www/index.php", `<?php echo file_get_contents("php://input");`);
76
- * const result = await php.run({
76
+ * const result = await php.request({
77
77
  * method: "GET",
78
78
  * headers: {
79
79
  * "Content-Type": "text/plain"
@@ -303,7 +303,48 @@ export interface IsomorphicLocalPHP extends RequestHandler {
303
303
  * @param options - PHP runtime options.
304
304
  */
305
305
  run(options: PHPRunOptions): Promise<PHPResponse>;
306
+ /**
307
+ * Listens to message sent by the PHP code.
308
+ *
309
+ * To dispatch messages, call:
310
+ *
311
+ * post_message_to_js(string $data)
312
+ *
313
+ * Arguments:
314
+ * $data (string) – Data to pass to JavaScript.
315
+ *
316
+ * @example
317
+ *
318
+ * ```ts
319
+ * const php = await PHP.load('8.0');
320
+ *
321
+ * php.onMessage(
322
+ * // The data is always passed as a string
323
+ * function (data: string) {
324
+ * // Let's decode and log the data:
325
+ * console.log(JSON.parse(data));
326
+ * }
327
+ * );
328
+ *
329
+ * // Now that we have a listener in place, let's
330
+ * // dispatch a message:
331
+ * await php.run({
332
+ * code: `<?php
333
+ * post_message_to_js(
334
+ * json_encode([
335
+ * 'post_id' => '15',
336
+ * 'post_title' => 'This is a blog post!'
337
+ * ])
338
+ * ));
339
+ * `,
340
+ * });
341
+ * ```
342
+ *
343
+ * @param listener Callback function to handle the message.
344
+ */
345
+ onMessage(listener: MessageListener): void;
306
346
  }
347
+ export type MessageListener = (data: string) => void;
307
348
  export type IsomorphicRemotePHP = Remote<IsomorphicLocalPHP>;
308
349
  export type UniversalPHP = IsomorphicLocalPHP | IsomorphicRemotePHP;
309
350
  export type HTTPMethod = 'GET' | 'POST' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'PUT' | 'DELETE';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/universal",
3
- "version": "0.1.60",
3
+ "version": "0.2.0",
4
4
  "description": "PHP.wasm – emscripten bindings for PHP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,5 +36,9 @@
36
36
  "main": "./index.cjs",
37
37
  "module": "./index.js",
38
38
  "license": "GPL-2.0-or-later",
39
- "gitHead": "3046803036b19d2c73c63cb01dfb37b1c222d847"
39
+ "gitHead": "cd4062de74f7f18058d3f962e124d0fdff78b5a7",
40
+ "engines": {
41
+ "node": ">=16.15.1",
42
+ "npm": ">=8.11.0"
43
+ }
40
44
  }