+

@@ -349,6 +360,7 @@ + + + + + + diff --git a/packages/wordpress-wasm/build/worker-thread.js b/packages/wordpress-wasm/build/worker-thread.js new file mode 100644 index 0000000000..be0f081e84 --- /dev/null +++ b/packages/wordpress-wasm/build/worker-thread.js @@ -0,0 +1,237 @@ +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; + +// packages/wordpress-wasm/src/requests_transport_fetch.php +var require_requests_transport_fetch = __commonJS({ + "packages/wordpress-wasm/src/requests_transport_fetch.php"(exports, module2) { + module2.exports = ` $headers, + 'data' => $data, + 'url' => $url, + 'method' => $options['type'], + ) ) ); + + $js = <<headers = vrzno_eval( $js ); + + return $this->headers; + } + + public function request_multiple( $requests, $options ) { + $responses = array(); + $class = get_class( $this ); + foreach ( $requests as $id => $request ) { + try { + $handler = new $class(); + $responses[ $id ] = $handler->request( $request['url'], $request['headers'], $request['data'], $request['options'] ); + $request['options']['hooks']->dispatch( 'transport.internal.parse_response', array( &$responses[ $id ], $request ) ); + } catch ( Requests_Exception $e ) { + $responses[ $id ] = $e; + } + if ( ! is_string( $responses[ $id ] ) ) { + $request['options']['hooks']->dispatch( 'multiple.request.complete', array( &$responses[ $id ], $id ) ); + } + } + + return $responses; + } + + protected static function format_get( $url, $data ) { + if ( ! empty( $data ) ) { + $query = ''; + $url_parts = parse_url( $url ); + if ( empty( $url_parts['query'] ) ) { + $url_parts['query'] = ''; + } else { + $query = $url_parts['query']; + } + $query .= '&' . http_build_query( $data, null, '&' ); + $query = trim( $query, '&' ); + if ( empty( $url_parts['query'] ) ) { + $url .= '?' . $query; + } else { + $url = str_replace( $url_parts['query'], $query, $url ); + } + } + + return $url; + } + + public static function test( $capabilities = array() ) { + if ( ! function_exists( 'vrzno_eval' ) ) { + return false; + } + + if ( vrzno_eval( "typeof XMLHttpRequest;" ) !== 'function' ) { + return false; + } + + return true; + } + +} + +if(defined('USE_FETCH_FOR_REQUESTS') && USE_FETCH_FOR_REQUESTS) { + Requests::add_transport( 'Requests_Transport_Fetch' ); + add_filter('http_request_host_is_external', function($arg) { + return true; + }); +} +`; + } +}); + +// packages/wordpress-wasm/src/worker-thread.js +var import_php_wasm3 = require("php-wasm"); +var import_php_wasm_browser2 = require("php-wasm-browser"); + +// packages/wordpress-wasm/src/config.js +var import_php_wasm = require("php-wasm"); +var import_php_wasm2 = require("php-wasm"); +var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; +var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; +var wpJsCacheBuster = ""; + +// packages/wordpress-wasm/src/index.js +var import_php_wasm_browser = require("php-wasm-browser"); +var isUploadedFilePath = (path) => { + return path.startsWith("/wp-content/uploads/") || path.startsWith("/wp-content/plugins/") || path.startsWith("/wp-content/themes/") && !path.startsWith("/wp-content/themes/twentytwentytwo/"); +}; + +// packages/wordpress-wasm/src/worker-thread.js +(0, import_php_wasm_browser2.initializeWorkerThread)(startWordPress); +var DOCROOT = "/wordpress"; +async function startWordPress({ absoluteUrl }) { + const [phpLoaderModule, wpLoaderModule] = await Promise.all([ + import(`/php.js?${import_php_wasm2.phpJsHash}`), + import(`/wp.js?${wpJsCacheBuster}`) + ]); + const php = await (0, import_php_wasm_browser2.loadPHPWithProgress)(phpLoaderModule, [wpLoaderModule]); + patchWordPressFiles(php, absoluteUrl); + const server = new import_php_wasm3.PHPServer(php, { + documentRoot: DOCROOT, + absoluteUrl, + isStaticFilePath: isUploadedFilePath + }); + return new import_php_wasm3.PHPBrowser(server); +} +function patchWordPressFiles(php, absoluteUrl) { + function patchFile(path, callback) { + php.writeFile( + path, + callback(php.readFileAsText(path)) + ); + } + patchFile( + `${DOCROOT}/wp-config.php`, + (contents) => contents + ` + define('USE_FETCH_FOR_REQUESTS', false); + define('WP_HOME', '${JSON.stringify(DOCROOT)}'); + + // The original version of this function crashes WASM WordPress, let's define an empty one instead. + function wp_new_blog_notification(...$args){} + ` + ); + patchFile( + `${DOCROOT}/wp-includes/plugin.php`, + (contents) => contents + ` + function _wasm_wp_force_site_url() { + return ${JSON.stringify(absoluteUrl)}; + } + add_filter( "option_home", '_wasm_wp_force_site_url', 10000 ); + add_filter( "option_siteurl", '_wasm_wp_force_site_url', 10000 ); + ` + ); + const transports = [ + `${DOCROOT}/wp-includes/Requests/Transport/fsockopen.php`, + `${DOCROOT}/wp-includes/Requests/Transport/cURL.php` + ]; + for (const transport of transports) { + patchFile(transport, (contents) => contents.replace( + "public static function test", + "public static function test( $capabilities = array() ) { return false; } public static function test2" + )); + } + patchFile(`${DOCROOT}/wp-includes/default-filters.php`, (contents) => contents.replace( + /add_filter[^;]+wp_maybe_grant_site_health_caps[^;]+;/i, + "" + )); + php.mkdirTree(`${DOCROOT}/wp-content/mu-plugins`); + php.writeFile( + `${DOCROOT}/wp-content/mu-plugins/requests_transport_fetch.php`, + require_requests_transport_fetch() + ); +} diff --git a/src/wordpress-wasm/example-app.tsx b/src/wordpress-wasm/example-app.tsx index 2555621885..b936080ef2 100644 --- a/src/wordpress-wasm/example-app.tsx +++ b/src/wordpress-wasm/example-app.tsx @@ -215,12 +215,14 @@ function wireProgressBar() { infiniteWrapper.classList.remove('mode-infinite'); infiniteWrapper.classList.add('mode-finite'); } - if( caption && caption.length ) { + if (caption && caption.length) { const captionElement = document.querySelector( '.progress-bar-overlay-caption' ) as HTMLElement; - captionElement.innerText= caption; + if (captionElement) { + captionElement.innerText = caption; + } } const progressBarEl = document.querySelector( From eafbb0a1becc329c7e4437a74225255dad28ffa0 Mon Sep 17 00:00:00 2001 From: dufresnesteven Date: Tue, 29 Nov 2022 15:34:49 +0900 Subject: [PATCH 4/7] Revert "Clean up." This reverts commit ee2d968fc4cce214150dced08084cd980c4731e0. --- .../php-wasm-browser/build-module/index.js | 613 ----------------- packages/php-wasm-browser/build/index.js | 635 ------------------ packages/php-wasm/build-module/index.js | 475 ------------- packages/php-wasm/build/index.js | 497 -------------- .../build-module/example-app.js | 214 ------ packages/wordpress-wasm/build-module/index.js | 62 -- .../build-module/service-worker.js | 33 - .../build-module/worker-thread.js | 244 ------- packages/wordpress-wasm/build/example-app.js | 207 ------ packages/wordpress-wasm/build/index.js | 75 --- .../wordpress-wasm/build/service-worker.js | 26 - packages/wordpress-wasm/build/wordpress.html | 273 -------- .../wordpress-wasm/build/worker-thread.js | 237 ------- src/wordpress-wasm/example-app.tsx | 6 +- 14 files changed, 2 insertions(+), 3595 deletions(-) delete mode 100644 packages/php-wasm-browser/build-module/index.js delete mode 100644 packages/php-wasm-browser/build/index.js delete mode 100644 packages/php-wasm/build-module/index.js delete mode 100644 packages/php-wasm/build/index.js delete mode 100644 packages/wordpress-wasm/build-module/example-app.js delete mode 100644 packages/wordpress-wasm/build-module/index.js delete mode 100644 packages/wordpress-wasm/build-module/service-worker.js delete mode 100644 packages/wordpress-wasm/build-module/worker-thread.js delete mode 100644 packages/wordpress-wasm/build/example-app.js delete mode 100644 packages/wordpress-wasm/build/index.js delete mode 100644 packages/wordpress-wasm/build/service-worker.js delete mode 100644 packages/wordpress-wasm/build/wordpress.html delete mode 100644 packages/wordpress-wasm/build/worker-thread.js diff --git a/packages/php-wasm-browser/build-module/index.js b/packages/php-wasm-browser/build-module/index.js deleted file mode 100644 index 5cbccb235b..0000000000 --- a/packages/php-wasm-browser/build-module/index.js +++ /dev/null @@ -1,613 +0,0 @@ -// packages/php-wasm-browser/src/worker-thread/index.js -import { startPHP, PHPBrowser, PHPServer } from "php-wasm"; - -// packages/php-wasm-browser/src/messaging.js -var DEFAULT_REPLY_TIMEOUT = 25e3; -var lastMessageId = 0; -function postMessageExpectReply(messageTarget, message, ...postMessageArgs) { - const messageId = ++lastMessageId; - messageTarget.postMessage( - { - ...message, - messageId - }, - ...postMessageArgs - ); - return messageId; -} -async function awaitReply(messageTarget, messageId, timeout = DEFAULT_REPLY_TIMEOUT) { - return new Promise((resolve, reject) => { - const responseHandler = (event) => { - if (event.data.type === "response" && event.data.messageId === messageId) { - messageTarget.removeEventListener("message", responseHandler); - clearTimeout(failOntimeout); - resolve(event.data.result); - } - }; - const failOntimeout = setTimeout(() => { - reject(new Error("Request timed out")); - messageTarget.removeEventListener("message", responseHandler); - }, timeout); - messageTarget.addEventListener("message", responseHandler); - }); -} -function responseTo(messageId, result) { - return { - type: "response", - messageId, - result - }; -} -function messageHandler(handler) { - return async function(event, respond) { - const result = await handler(event.data); - if (event.data.messageId) { - respond(responseTo(event.data.messageId, result)); - } - }; -} -function postMessageHandler(handler) { - return async function(event) { - const result = await handler(event.data); - if (event.data.messageId) { - window.parent.postMessage( - responseTo(event.data.messageId, result), - event.origin - ); - } - }; -} - -// packages/php-wasm-browser/src/urls.js -var DEFAULT_BASE_URL = "http://example.com"; -function getPathQueryFragment(url) { - return url.toString().substring(url.origin.length); -} -function isURLScoped(url) { - return url.pathname.startsWith(`/scope:`); -} -function getURLScope(url) { - if (isURLScoped(url)) { - return url.pathname.split("/")[1].split(":")[1]; - } - return null; -} -function setURLScope(url, scope) { - if (!scope) { - return url; - } - const newUrl = new URL(url); - if (isURLScoped(newUrl)) { - const parts = newUrl.pathname.split("/"); - parts[1] = `scope:${scope}`; - newUrl.pathname = parts.join("/"); - } else { - const suffix = newUrl.pathname === "/" ? "" : newUrl.pathname; - newUrl.pathname = `/scope:${scope}${suffix}`; - } - return newUrl; -} -function removeURLScope(url) { - if (!isURLScoped(url)) { - return url; - } - const newUrl = new URL(url); - const parts = newUrl.pathname.split("/"); - newUrl.pathname = "/" + parts.slice(2).join("/"); - return newUrl; -} - -// packages/php-wasm-browser/src/worker-thread/environment.js -var webEnvironment = { - name: "WEB", - setMessageListener(handler) { - window.addEventListener( - "message", - (event) => handler( - event, - (response) => event.source.postMessage(response, "*") - ), - false - ); - }, - postMessageToParent(message) { - window.parent.postMessage(message, "*"); - } -}; -var webWorkerEnvironment = { - name: "WORKER", - setMessageListener(handler) { - onmessage = (event) => { - handler(event, postMessage); - }; - }, - postMessageToParent(message) { - postMessage(message); - } -}; -var currentEnvironment = function() { - if (typeof window !== "undefined") { - return webEnvironment; - } else if (typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope) { - return webWorkerEnvironment; - } else { - throw new Error(`Unsupported environment`); - } -}(); -var environment_default = currentEnvironment; - -// packages/php-wasm-browser/src/download-monitor.js -var FALLBACK_FILE_SIZE = 5 * 1024 * 1024; -var DownloadMonitor = class extends EventTarget { - constructor(assetsSizes) { - super(); - this.assetsSizes = assetsSizes; - this.monitorWebAssemblyStreaming(); - this.phpArgs = { - dataFileDownloads: this._createDataFileDownloadsProxy() - }; - } - _createDataFileDownloadsProxy() { - const self2 = this; - const dataFileDownloads = {}; - return new Proxy(dataFileDownloads, { - set(obj, file, progress) { - self2._notify(file, progress.loaded, progress.total); - obj[file] = new Proxy(JSON.parse(JSON.stringify(progress)), { - set(nestedObj, prop, value) { - nestedObj[prop] = value; - self2._notify(file, nestedObj.loaded, nestedObj.total); - return true; - } - }); - return true; - } - }); - } - monitorWebAssemblyStreaming() { - const self2 = this; - const _instantiateStreaming = WebAssembly.instantiateStreaming; - WebAssembly.instantiateStreaming = (response, ...args) => { - const file = response.url.substring( - new URL(response.url).origin.length + 1 - ); - const reportingResponse = cloneResponseMonitorProgress( - response, - ({ loaded, total }) => self2._notify(file, loaded, total) - ); - return _instantiateStreaming(reportingResponse, ...args); - }; - } - _notify(file, loaded, total) { - if (!total) { - const filename = new URL(file, DEFAULT_BASE_URL).pathname.split("/").pop(); - total = this.assetsSizes[filename]; - } - this.dispatchEvent( - new CustomEvent("progress", { - detail: { - file, - loaded, - total: total || Math.min(loaded, FALLBACK_FILE_SIZE), - fallbackUsed: !total - } - }) - ); - } -}; -function cloneResponseMonitorProgress(response, onProgress) { - const contentLength = response.headers.get("content-length"); - let total = parseInt(contentLength, 10) || FALLBACK_FILE_SIZE; - return new Response( - new ReadableStream( - { - async start(controller) { - const reader = response.body.getReader(); - let loaded = 0; - for (; ; ) { - try { - const { done, value } = await reader.read(); - if (value) { - loaded += value.byteLength; - } - if (done) { - onProgress({ loaded, total: loaded, done }); - controller.close(); - break; - } else { - onProgress({ loaded, total, done }); - controller.enqueue(value); - } - } catch (e) { - console.error({ e }); - controller.error(e); - break; - } - } - } - } - ), - { - status: response.status, - statusText: response.statusText, - headers: response.headers - } - ); -} - -// packages/php-wasm-browser/src/worker-thread/index.js -async function initializeWorkerThread(bootBrowser = defaultBootBrowser) { - environment_default.setMessageListener( - messageHandler(handleMessage) - ); - let phpBrowser; - async function handleMessage(message) { - if (message.type === "initialize_php") { - phpBrowser = await bootBrowser({ - absoluteUrl: message.absoluteUrl - }); - } else if (message.type === "is_alive") { - return true; - } else if (message.type === "run_php") { - return await phpBrowser.server.php.run(message.code); - } else if (message.type === "request") { - const parsedUrl = new URL( - message.request.path, - DEFAULT_BASE_URL - ); - return await phpBrowser.request({ - ...message.request, - path: parsedUrl.pathname, - _GET: parsedUrl.search - }); - } else { - console.warn( - `[WASM Worker] "${message.type}" event received but it has no handler.` - ); - } - } -} -async function defaultBootBrowser({ absoluteUrl }) { - return new PHPBrowser( - new PHPServer( - await PHP.create("/php.js", phpArgs), - { - absoluteUrl: absoluteUrl || location.origin - } - ) - ); -} -async function loadPHPWithProgress(phpLoaderModule, dataDependenciesModules = [], phpArgs2 = {}) { - const modules = [phpLoaderModule, ...dataDependenciesModules]; - const assetsSizes = modules.reduce((acc, module) => { - acc[module.dependencyFilename] = module.dependenciesTotalSize; - return acc; - }, {}); - const downloadMonitor = new DownloadMonitor(assetsSizes); - downloadMonitor.addEventListener( - "progress", - (e) => environment_default.postMessageToParent({ - type: "download_progress", - ...e.detail - }) - ); - return await startPHP( - phpLoaderModule, - environment_default.name, - { - ...phpArgs2, - ...downloadMonitor.phpArgs - }, - dataDependenciesModules - ); -} - -// packages/php-wasm-browser/src/worker-thread-api.js -var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); -var noop = () => { -}; -async function startPHPWorkerThread({ - backend, - absoluteUrl, - scope, - onDownloadProgress = noop -}) { - while (true) { - try { - await backend.sendMessage({ type: "is_alive" }, 50); - break; - } catch (e) { - } - await sleep(50); - } - if (scope) { - absoluteUrl = setURLScope(new URL(absoluteUrl), scope).toString(); - } - backend.addMessageListener((e) => { - if (e.data.type === "download_progress") { - onDownloadProgress(e.data); - } - }); - await backend.sendMessage({ - type: "initialize_php", - absoluteUrl - }); - return { - pathToInternalUrl(path) { - return `${absoluteUrl}${path}`; - }, - internalUrlToPath(internalUrl) { - return getPathQueryFragment(removeURLScope(new URL(internalUrl))); - }, - async eval(code) { - return await backend.sendMessage({ - type: "run_php", - code - }); - }, - async HTTPRequest(request) { - return await backend.sendMessage({ - type: "request", - request - }); - } - }; -} -function getWorkerThreadBackend(key, url) { - const backends = { - webworker: webWorkerBackend, - shared_worker: sharedWorkerBackend, - iframe: iframeBackend - }; - const backend = backends[key]; - if (!backend) { - const availableKeys = Object.keys(backends).join(", "); - throw new Error( - `Unknown worker backend: "${key}". Choices: ${availableKeys}` - ); - } - return backend(url); -} -function webWorkerBackend(workerURL) { - const worker = new Worker(workerURL); - return { - async sendMessage(message, timeout) { - const messageId = postMessageExpectReply(worker, message); - const response = await awaitReply(worker, messageId, timeout); - return response; - }, - addMessageListener(listener) { - worker.onmessage = listener; - } - }; -} -function sharedWorkerBackend(workerURL) { - const worker = new SharedWorker(workerURL); - worker.port.start(); - return { - async sendMessage(message, timeout) { - const messageId = postMessageExpectReply(worker.port, message); - const response = await awaitReply(worker.port, messageId, timeout); - return response; - }, - addMessageListener(listener) { - worker.port.onmessage = listener; - } - }; -} -function iframeBackend(workerDocumentURL) { - const iframe = document.createElement("iframe"); - iframe.src = workerDocumentURL; - iframe.style.display = "none"; - document.body.appendChild(iframe); - return { - async sendMessage(message, timeout) { - const messageId = postMessageExpectReply( - iframe.contentWindow, - message, - "*" - ); - const response = await awaitReply(window, messageId, timeout); - return response; - }, - addMessageListener(listener) { - window.addEventListener( - "message", - (e) => { - if (e.source === iframe.contentWindow) { - listener(e); - } - }, - false - ); - } - }; -} - -// packages/php-wasm-browser/src/service-worker.js -async function registerServiceWorker({ broadcastChannel, url, onRequest, scope }) { - if (!broadcastChannel) { - throw new Error("Missing the required `broadcastChannel` option."); - } - if (!navigator.serviceWorker) { - throw new Error("Service workers are not supported in this browser."); - } - const registration = await navigator.serviceWorker.register(url); - await registration.update(); - broadcastChannel.addEventListener( - "message", - async function onMessage(event) { - if (scope && event.data.scope !== scope) { - return; - } - console.debug( - `[Main] "${event.data.type}" message received from a service worker` - ); - let result; - if (event.data.type === "request") { - result = await onRequest(event.data.request); - } else { - throw new Error( - `[Main] Unexpected message received from the service-worker: "${event.data.type}"` - ); - } - if (event.data.messageId) { - broadcastChannel.postMessage( - responseTo(event.data.messageId, result) - ); - } - console.debug(`[Main] "${event.data.type}" message processed`, { - result - }); - } - ); - navigator.serviceWorker.startMessages(); -} -function initializeServiceWorker({ - broadcastChannel, - shouldForwardRequestToPHPServer = (request, unscopedUrl) => seemsLikeAPHPServerPath(unscopedUrl.pathname) -}) { - if (!broadcastChannel) { - throw new Error("Missing the required `broadcastChannel` option."); - } - self.addEventListener("activate", (event) => { - event.waitUntil(clients.claim()); - }); - self.addEventListener("fetch", (event) => { - const url = new URL(event.request.url); - const unscopedUrl = removeURLScope(url); - if (!shouldForwardRequestToPHPServer(event.request, unscopedUrl)) { - if (isURLScoped(url)) { - event.preventDefault(); - return event.respondWith( - new Promise(async (accept) => { - const newRequest = await cloneRequest(event.request, { - url: unscopedUrl - }); - accept(fetch(newRequest)); - }) - ); - } - return; - } - event.preventDefault(); - return event.respondWith( - new Promise(async (accept) => { - console.log( - `[ServiceWorker] Serving request: ${getPathQueryFragment( - removeURLScope(url) - )}` - ); - const { post, files } = await parsePost(event.request); - const requestHeaders = {}; - for (const pair of event.request.headers.entries()) { - requestHeaders[pair[0]] = pair[1]; - } - const requestedPath = getPathQueryFragment(url); - let phpResponse; - try { - const message = { - type: "request", - scope: getURLScope(url), - request: { - path: requestedPath, - method: event.request.method, - files, - _POST: post, - headers: requestHeaders - } - }; - console.log( - "[ServiceWorker] Forwarding a request to the main app", - { - message - } - ); - const messageId = postMessageExpectReply( - broadcastChannel, - message - ); - phpResponse = await awaitReply(broadcastChannel, messageId); - console.log( - "[ServiceWorker] Response received from the main app", - { - phpResponse - } - ); - } catch (e) { - console.error(e, { requestedPath }); - throw e; - } - accept( - new Response(phpResponse.body, { - headers: phpResponse.headers, - status: phpResponse.statusCode - }) - ); - }) - ); - }); -} -function seemsLikeAPHPServerPath(path) { - return seemsLikeAPHPFile(path) || seemsLikeADirectoryRoot(path); -} -function seemsLikeAPHPFile(path) { - return path.endsWith(".php") || path.includes(".php/"); -} -function seemsLikeADirectoryRoot(path) { - const lastSegment = path.split("/").pop(); - return !lastSegment.includes("."); -} -async function parsePost(request) { - if (request.method !== "POST") { - return { post: void 0, files: void 0 }; - } - try { - const formData = await request.clone().formData(); - const post = {}; - const files = {}; - for (const key of formData.keys()) { - const value = formData.get(key); - if (value instanceof File) { - files[key] = value; - } else { - post[key] = value; - } - } - return { post, files }; - } catch (e) { - } - return { post: await request.clone().json(), files: {} }; -} -async function cloneRequest(request, overrides) { - const body = ["GET", "HEAD"].includes(request.method) || "body" in overrides ? void 0 : await request.blob(); - return new Request(overrides.url || request.url, { - body, - method: request.method, - headers: request.headers, - referrer: request.referrer, - referrerPolicy: request.referrerPolicy, - mode: request.mode === "navigate" ? "same-origin" : request.mode, - credentials: request.credentials, - cache: request.cache, - redirect: request.redirect, - integrity: request.integrity, - ...overrides - }); -} -export { - awaitReply, - cloneResponseMonitorProgress, - environment_default as environment, - getWorkerThreadBackend, - initializeServiceWorker, - initializeWorkerThread, - loadPHPWithProgress, - messageHandler, - postMessageExpectReply, - postMessageHandler, - registerServiceWorker, - responseTo, - seemsLikeAPHPServerPath, - startPHPWorkerThread -}; diff --git a/packages/php-wasm-browser/build/index.js b/packages/php-wasm-browser/build/index.js deleted file mode 100644 index 911dc483d0..0000000000 --- a/packages/php-wasm-browser/build/index.js +++ /dev/null @@ -1,635 +0,0 @@ -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// packages/php-wasm-browser/src/index.js -var src_exports = {}; -__export(src_exports, { - awaitReply: () => awaitReply, - cloneResponseMonitorProgress: () => cloneResponseMonitorProgress, - environment: () => environment_default, - getWorkerThreadBackend: () => getWorkerThreadBackend, - initializeServiceWorker: () => initializeServiceWorker, - initializeWorkerThread: () => initializeWorkerThread, - loadPHPWithProgress: () => loadPHPWithProgress, - messageHandler: () => messageHandler, - postMessageExpectReply: () => postMessageExpectReply, - postMessageHandler: () => postMessageHandler, - registerServiceWorker: () => registerServiceWorker, - responseTo: () => responseTo, - seemsLikeAPHPServerPath: () => seemsLikeAPHPServerPath, - startPHPWorkerThread: () => startPHPWorkerThread -}); -module.exports = __toCommonJS(src_exports); - -// packages/php-wasm-browser/src/worker-thread/index.js -var import_php_wasm = require("php-wasm"); - -// packages/php-wasm-browser/src/messaging.js -var DEFAULT_REPLY_TIMEOUT = 25e3; -var lastMessageId = 0; -function postMessageExpectReply(messageTarget, message, ...postMessageArgs) { - const messageId = ++lastMessageId; - messageTarget.postMessage( - { - ...message, - messageId - }, - ...postMessageArgs - ); - return messageId; -} -async function awaitReply(messageTarget, messageId, timeout = DEFAULT_REPLY_TIMEOUT) { - return new Promise((resolve, reject) => { - const responseHandler = (event) => { - if (event.data.type === "response" && event.data.messageId === messageId) { - messageTarget.removeEventListener("message", responseHandler); - clearTimeout(failOntimeout); - resolve(event.data.result); - } - }; - const failOntimeout = setTimeout(() => { - reject(new Error("Request timed out")); - messageTarget.removeEventListener("message", responseHandler); - }, timeout); - messageTarget.addEventListener("message", responseHandler); - }); -} -function responseTo(messageId, result) { - return { - type: "response", - messageId, - result - }; -} -function messageHandler(handler) { - return async function(event, respond) { - const result = await handler(event.data); - if (event.data.messageId) { - respond(responseTo(event.data.messageId, result)); - } - }; -} -function postMessageHandler(handler) { - return async function(event) { - const result = await handler(event.data); - if (event.data.messageId) { - window.parent.postMessage( - responseTo(event.data.messageId, result), - event.origin - ); - } - }; -} - -// packages/php-wasm-browser/src/urls.js -var DEFAULT_BASE_URL = "http://example.com"; -function getPathQueryFragment(url) { - return url.toString().substring(url.origin.length); -} -function isURLScoped(url) { - return url.pathname.startsWith(`/scope:`); -} -function getURLScope(url) { - if (isURLScoped(url)) { - return url.pathname.split("/")[1].split(":")[1]; - } - return null; -} -function setURLScope(url, scope) { - if (!scope) { - return url; - } - const newUrl = new URL(url); - if (isURLScoped(newUrl)) { - const parts = newUrl.pathname.split("/"); - parts[1] = `scope:${scope}`; - newUrl.pathname = parts.join("/"); - } else { - const suffix = newUrl.pathname === "/" ? "" : newUrl.pathname; - newUrl.pathname = `/scope:${scope}${suffix}`; - } - return newUrl; -} -function removeURLScope(url) { - if (!isURLScoped(url)) { - return url; - } - const newUrl = new URL(url); - const parts = newUrl.pathname.split("/"); - newUrl.pathname = "/" + parts.slice(2).join("/"); - return newUrl; -} - -// packages/php-wasm-browser/src/worker-thread/environment.js -var webEnvironment = { - name: "WEB", - setMessageListener(handler) { - window.addEventListener( - "message", - (event) => handler( - event, - (response) => event.source.postMessage(response, "*") - ), - false - ); - }, - postMessageToParent(message) { - window.parent.postMessage(message, "*"); - } -}; -var webWorkerEnvironment = { - name: "WORKER", - setMessageListener(handler) { - onmessage = (event) => { - handler(event, postMessage); - }; - }, - postMessageToParent(message) { - postMessage(message); - } -}; -var currentEnvironment = function() { - if (typeof window !== "undefined") { - return webEnvironment; - } else if (typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope) { - return webWorkerEnvironment; - } else { - throw new Error(`Unsupported environment`); - } -}(); -var environment_default = currentEnvironment; - -// packages/php-wasm-browser/src/download-monitor.js -var FALLBACK_FILE_SIZE = 5 * 1024 * 1024; -var DownloadMonitor = class extends EventTarget { - constructor(assetsSizes) { - super(); - this.assetsSizes = assetsSizes; - this.monitorWebAssemblyStreaming(); - this.phpArgs = { - dataFileDownloads: this._createDataFileDownloadsProxy() - }; - } - _createDataFileDownloadsProxy() { - const self2 = this; - const dataFileDownloads = {}; - return new Proxy(dataFileDownloads, { - set(obj, file, progress) { - self2._notify(file, progress.loaded, progress.total); - obj[file] = new Proxy(JSON.parse(JSON.stringify(progress)), { - set(nestedObj, prop, value) { - nestedObj[prop] = value; - self2._notify(file, nestedObj.loaded, nestedObj.total); - return true; - } - }); - return true; - } - }); - } - monitorWebAssemblyStreaming() { - const self2 = this; - const _instantiateStreaming = WebAssembly.instantiateStreaming; - WebAssembly.instantiateStreaming = (response, ...args) => { - const file = response.url.substring( - new URL(response.url).origin.length + 1 - ); - const reportingResponse = cloneResponseMonitorProgress( - response, - ({ loaded, total }) => self2._notify(file, loaded, total) - ); - return _instantiateStreaming(reportingResponse, ...args); - }; - } - _notify(file, loaded, total) { - if (!total) { - const filename = new URL(file, DEFAULT_BASE_URL).pathname.split("/").pop(); - total = this.assetsSizes[filename]; - } - this.dispatchEvent( - new CustomEvent("progress", { - detail: { - file, - loaded, - total: total || Math.min(loaded, FALLBACK_FILE_SIZE), - fallbackUsed: !total - } - }) - ); - } -}; -function cloneResponseMonitorProgress(response, onProgress) { - const contentLength = response.headers.get("content-length"); - let total = parseInt(contentLength, 10) || FALLBACK_FILE_SIZE; - return new Response( - new ReadableStream( - { - async start(controller) { - const reader = response.body.getReader(); - let loaded = 0; - for (; ; ) { - try { - const { done, value } = await reader.read(); - if (value) { - loaded += value.byteLength; - } - if (done) { - onProgress({ loaded, total: loaded, done }); - controller.close(); - break; - } else { - onProgress({ loaded, total, done }); - controller.enqueue(value); - } - } catch (e) { - console.error({ e }); - controller.error(e); - break; - } - } - } - } - ), - { - status: response.status, - statusText: response.statusText, - headers: response.headers - } - ); -} - -// packages/php-wasm-browser/src/worker-thread/index.js -async function initializeWorkerThread(bootBrowser = defaultBootBrowser) { - environment_default.setMessageListener( - messageHandler(handleMessage) - ); - let phpBrowser; - async function handleMessage(message) { - if (message.type === "initialize_php") { - phpBrowser = await bootBrowser({ - absoluteUrl: message.absoluteUrl - }); - } else if (message.type === "is_alive") { - return true; - } else if (message.type === "run_php") { - return await phpBrowser.server.php.run(message.code); - } else if (message.type === "request") { - const parsedUrl = new URL( - message.request.path, - DEFAULT_BASE_URL - ); - return await phpBrowser.request({ - ...message.request, - path: parsedUrl.pathname, - _GET: parsedUrl.search - }); - } else { - console.warn( - `[WASM Worker] "${message.type}" event received but it has no handler.` - ); - } - } -} -async function defaultBootBrowser({ absoluteUrl }) { - return new import_php_wasm.PHPBrowser( - new import_php_wasm.PHPServer( - await PHP.create("/php.js", phpArgs), - { - absoluteUrl: absoluteUrl || location.origin - } - ) - ); -} -async function loadPHPWithProgress(phpLoaderModule, dataDependenciesModules = [], phpArgs2 = {}) { - const modules = [phpLoaderModule, ...dataDependenciesModules]; - const assetsSizes = modules.reduce((acc, module2) => { - acc[module2.dependencyFilename] = module2.dependenciesTotalSize; - return acc; - }, {}); - const downloadMonitor = new DownloadMonitor(assetsSizes); - downloadMonitor.addEventListener( - "progress", - (e) => environment_default.postMessageToParent({ - type: "download_progress", - ...e.detail - }) - ); - return await (0, import_php_wasm.startPHP)( - phpLoaderModule, - environment_default.name, - { - ...phpArgs2, - ...downloadMonitor.phpArgs - }, - dataDependenciesModules - ); -} - -// packages/php-wasm-browser/src/worker-thread-api.js -var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); -var noop = () => { -}; -async function startPHPWorkerThread({ - backend, - absoluteUrl, - scope, - onDownloadProgress = noop -}) { - while (true) { - try { - await backend.sendMessage({ type: "is_alive" }, 50); - break; - } catch (e) { - } - await sleep(50); - } - if (scope) { - absoluteUrl = setURLScope(new URL(absoluteUrl), scope).toString(); - } - backend.addMessageListener((e) => { - if (e.data.type === "download_progress") { - onDownloadProgress(e.data); - } - }); - await backend.sendMessage({ - type: "initialize_php", - absoluteUrl - }); - return { - pathToInternalUrl(path) { - return `${absoluteUrl}${path}`; - }, - internalUrlToPath(internalUrl) { - return getPathQueryFragment(removeURLScope(new URL(internalUrl))); - }, - async eval(code) { - return await backend.sendMessage({ - type: "run_php", - code - }); - }, - async HTTPRequest(request) { - return await backend.sendMessage({ - type: "request", - request - }); - } - }; -} -function getWorkerThreadBackend(key, url) { - const backends = { - webworker: webWorkerBackend, - shared_worker: sharedWorkerBackend, - iframe: iframeBackend - }; - const backend = backends[key]; - if (!backend) { - const availableKeys = Object.keys(backends).join(", "); - throw new Error( - `Unknown worker backend: "${key}". Choices: ${availableKeys}` - ); - } - return backend(url); -} -function webWorkerBackend(workerURL) { - const worker = new Worker(workerURL); - return { - async sendMessage(message, timeout) { - const messageId = postMessageExpectReply(worker, message); - const response = await awaitReply(worker, messageId, timeout); - return response; - }, - addMessageListener(listener) { - worker.onmessage = listener; - } - }; -} -function sharedWorkerBackend(workerURL) { - const worker = new SharedWorker(workerURL); - worker.port.start(); - return { - async sendMessage(message, timeout) { - const messageId = postMessageExpectReply(worker.port, message); - const response = await awaitReply(worker.port, messageId, timeout); - return response; - }, - addMessageListener(listener) { - worker.port.onmessage = listener; - } - }; -} -function iframeBackend(workerDocumentURL) { - const iframe = document.createElement("iframe"); - iframe.src = workerDocumentURL; - iframe.style.display = "none"; - document.body.appendChild(iframe); - return { - async sendMessage(message, timeout) { - const messageId = postMessageExpectReply( - iframe.contentWindow, - message, - "*" - ); - const response = await awaitReply(window, messageId, timeout); - return response; - }, - addMessageListener(listener) { - window.addEventListener( - "message", - (e) => { - if (e.source === iframe.contentWindow) { - listener(e); - } - }, - false - ); - } - }; -} - -// packages/php-wasm-browser/src/service-worker.js -async function registerServiceWorker({ broadcastChannel, url, onRequest, scope }) { - if (!broadcastChannel) { - throw new Error("Missing the required `broadcastChannel` option."); - } - if (!navigator.serviceWorker) { - throw new Error("Service workers are not supported in this browser."); - } - const registration = await navigator.serviceWorker.register(url); - await registration.update(); - broadcastChannel.addEventListener( - "message", - async function onMessage(event) { - if (scope && event.data.scope !== scope) { - return; - } - console.debug( - `[Main] "${event.data.type}" message received from a service worker` - ); - let result; - if (event.data.type === "request") { - result = await onRequest(event.data.request); - } else { - throw new Error( - `[Main] Unexpected message received from the service-worker: "${event.data.type}"` - ); - } - if (event.data.messageId) { - broadcastChannel.postMessage( - responseTo(event.data.messageId, result) - ); - } - console.debug(`[Main] "${event.data.type}" message processed`, { - result - }); - } - ); - navigator.serviceWorker.startMessages(); -} -function initializeServiceWorker({ - broadcastChannel, - shouldForwardRequestToPHPServer = (request, unscopedUrl) => seemsLikeAPHPServerPath(unscopedUrl.pathname) -}) { - if (!broadcastChannel) { - throw new Error("Missing the required `broadcastChannel` option."); - } - self.addEventListener("activate", (event) => { - event.waitUntil(clients.claim()); - }); - self.addEventListener("fetch", (event) => { - const url = new URL(event.request.url); - const unscopedUrl = removeURLScope(url); - if (!shouldForwardRequestToPHPServer(event.request, unscopedUrl)) { - if (isURLScoped(url)) { - event.preventDefault(); - return event.respondWith( - new Promise(async (accept) => { - const newRequest = await cloneRequest(event.request, { - url: unscopedUrl - }); - accept(fetch(newRequest)); - }) - ); - } - return; - } - event.preventDefault(); - return event.respondWith( - new Promise(async (accept) => { - console.log( - `[ServiceWorker] Serving request: ${getPathQueryFragment( - removeURLScope(url) - )}` - ); - const { post, files } = await parsePost(event.request); - const requestHeaders = {}; - for (const pair of event.request.headers.entries()) { - requestHeaders[pair[0]] = pair[1]; - } - const requestedPath = getPathQueryFragment(url); - let phpResponse; - try { - const message = { - type: "request", - scope: getURLScope(url), - request: { - path: requestedPath, - method: event.request.method, - files, - _POST: post, - headers: requestHeaders - } - }; - console.log( - "[ServiceWorker] Forwarding a request to the main app", - { - message - } - ); - const messageId = postMessageExpectReply( - broadcastChannel, - message - ); - phpResponse = await awaitReply(broadcastChannel, messageId); - console.log( - "[ServiceWorker] Response received from the main app", - { - phpResponse - } - ); - } catch (e) { - console.error(e, { requestedPath }); - throw e; - } - accept( - new Response(phpResponse.body, { - headers: phpResponse.headers, - status: phpResponse.statusCode - }) - ); - }) - ); - }); -} -function seemsLikeAPHPServerPath(path) { - return seemsLikeAPHPFile(path) || seemsLikeADirectoryRoot(path); -} -function seemsLikeAPHPFile(path) { - return path.endsWith(".php") || path.includes(".php/"); -} -function seemsLikeADirectoryRoot(path) { - const lastSegment = path.split("/").pop(); - return !lastSegment.includes("."); -} -async function parsePost(request) { - if (request.method !== "POST") { - return { post: void 0, files: void 0 }; - } - try { - const formData = await request.clone().formData(); - const post = {}; - const files = {}; - for (const key of formData.keys()) { - const value = formData.get(key); - if (value instanceof File) { - files[key] = value; - } else { - post[key] = value; - } - } - return { post, files }; - } catch (e) { - } - return { post: await request.clone().json(), files: {} }; -} -async function cloneRequest(request, overrides) { - const body = ["GET", "HEAD"].includes(request.method) || "body" in overrides ? void 0 : await request.blob(); - return new Request(overrides.url || request.url, { - body, - method: request.method, - headers: request.headers, - referrer: request.referrer, - referrerPolicy: request.referrerPolicy, - mode: request.mode === "navigate" ? "same-origin" : request.mode, - credentials: request.credentials, - cache: request.cache, - redirect: request.redirect, - integrity: request.integrity, - ...overrides - }); -} diff --git a/packages/php-wasm/build-module/index.js b/packages/php-wasm/build-module/index.js deleted file mode 100644 index dcb3d784fa..0000000000 --- a/packages/php-wasm/build-module/index.js +++ /dev/null @@ -1,475 +0,0 @@ -// packages/php-wasm/src/php.js -var STR = "string"; -var NUM = "number"; -async function startPHP(phpLoaderModule, phpEnv, phpModuleArgs = {}, dataDependenciesModules = []) { - let resolvePhpReady, resolveDepsReady; - const depsReady = new Promise((resolve) => { - resolveDepsReady = resolve; - }); - const phpReady = new Promise((resolve) => { - resolvePhpReady = resolve; - }); - const streams = { - stdout: [], - stderr: [] - }; - const loadPHPRuntime = phpLoaderModule.default; - const PHPRuntime = loadPHPRuntime(phpEnv, { - onAbort(reason) { - console.error("WASM aborted: "); - console.error(reason); - }, - print: (...chunks) => streams.stdout.push(...chunks), - printErr: (...chunks) => streams.stderr.push(...chunks), - ...phpModuleArgs, - noInitialRun: true, - onRuntimeInitialized() { - if (phpModuleArgs.onRuntimeInitialized) { - phpModuleArgs.onRuntimeInitialized(); - } - resolvePhpReady(); - }, - monitorRunDependencies(nbLeft) { - if (nbLeft === 0) { - delete PHPRuntime.monitorRunDependencies; - resolveDepsReady(); - } - } - }); - for (const { default: loadDataModule } of dataDependenciesModules) { - loadDataModule(PHPRuntime); - } - if (!dataDependenciesModules.length) { - resolveDepsReady(); - } - await depsReady; - await phpReady; - return new PHP( - PHPRuntime, - streams - ); -} -var PHP = class { - #streams; - #Runtime; - constructor(Runtime, streams) { - this.#Runtime = Runtime; - this.#streams = streams; - this.mkdirTree("/usr/local/etc"); - this.writeFile("/usr/local/etc/php.ini", `[PHP] -error_reporting = E_ERROR | E_PARSE -display_errors = 1 -html_errors = 1 -display_startup_errors = On -session.save_path=/home/web_user - `); - Runtime.ccall("pib_init", NUM, [STR], []); - } - run(code) { - const exitCode = this.#Runtime.ccall("pib_run", NUM, [STR], [`?>${code}`]); - const response = { - exitCode, - stdout: this.#streams.stdout.join("\n"), - stderr: this.#streams.stderr - }; - this.#refresh(); - return response; - } - #refresh() { - this.#Runtime.ccall("pib_refresh", NUM, [], []); - this.#streams.stdout = []; - this.#streams.stderr = []; - } - mkdirTree(path) { - this.#Runtime.FS.mkdirTree(path); - } - readFileAsText(path) { - return new TextDecoder().decode(this.readFileAsBuffer(path)); - } - readFileAsBuffer(path) { - return this.#Runtime.FS.readFile(path); - } - writeFile(path, data) { - return this.#Runtime.FS.writeFile(path, data); - } - unlink(path) { - this.#Runtime.FS.unlink(path); - } - fileExists(path) { - try { - this.#Runtime.FS.lookupPath(path); - return true; - } catch (e) { - return false; - } - } - initUploadedFilesHash() { - this.#Runtime.ccall("pib_init_uploaded_files_hash", null, [], []); - } - registerUploadedFile(tmpPath) { - this.#Runtime.ccall("pib_register_uploaded_file", null, [STR], [tmpPath]); - } - destroyUploadedFilesHash() { - this.#Runtime.ccall("pib_destroy_uploaded_files_hash", null, [], []); - } -}; - -// packages/php-wasm/src/php-server.js -var PHPServer = class { - DOCROOT; - SCHEMA; - HOSTNAME; - PORT; - HOST; - PATHNAME; - ABSOLUTE_URL; - constructor(php, { - documentRoot = "/var/www/", - absoluteUrl, - isStaticFilePath = () => false - }) { - this.php = php; - this.DOCROOT = documentRoot; - this.isStaticFilePath = isStaticFilePath; - const url = new URL(absoluteUrl); - this.HOSTNAME = url.hostname; - this.PORT = url.port ? url.port : url.protocol === "https:" ? 443 : 80; - this.SCHEMA = (url.protocol || "").replace(":", ""); - this.HOST = `${this.HOSTNAME}:${this.PORT}`; - this.PATHNAME = url.pathname.replace(/\/+$/, ""); - this.ABSOLUTE_URL = `${this.SCHEMA}://${this.HOSTNAME}:${this.PORT}${this.PATHNAME}`; - } - async request(request) { - const unprefixedPath = this.withoutPathname(request.path); - if (this.isStaticFilePath(unprefixedPath)) { - return this.serveStaticFile(unprefixedPath); - } else { - return await this.dispatchToPHP(request); - } - } - withoutPathname(path) { - if (!this.PATHNAME) { - return path; - } - return path.substr(this.PATHNAME.length); - } - serveStaticFile(path) { - const fsPath = `${this.DOCROOT}${path}`; - if (!this.php.fileExists(fsPath)) { - return { - body: "404 File not found", - headers: {}, - statusCode: 404, - exitCode: 0, - rawError: "" - }; - } - const arrayBuffer = this.php.readFileAsBuffer(fsPath); - return { - body: arrayBuffer, - headers: { - "Content-length": arrayBuffer.byteLength, - "Content-type": inferMimeType(fsPath), - "Accept-Ranges": "bytes", - "Cache-Control": "public, max-age=0" - }, - exitCode: 0, - rawError: "" - }; - } - async dispatchToPHP(request) { - const _FILES = await this.prepare_FILES(request.files); - try { - const output = await this.php.run(`_GET, 1), $_GET); - - $_POST = $request->_POST; - $_FILES = $request->_FILES; - - if ( !is_null($request->_COOKIE) ) { - foreach ($request->_COOKIE as $key => $value) { - fwrite($stdErr, 'Setting Cookie: ' . $key . " => " . $value . " -"); - $_COOKIE[$key] = urldecode($value); - } - } - - $_SESSION = $request->_SESSION; - - foreach( $request->headers as $name => $value ) { - $server_key = 'HTTP_' . strtoupper(str_replace('-', '_', $name)); - $_SERVER[$server_key] = $value; - } - - fwrite($stdErr, json_encode(['session' => $_SESSION]) . " -"); - - $docroot = ${JSON.stringify(this.DOCROOT)}; - - $script = ltrim($request->path, '/'); - - $path = $request->path; - $path = preg_replace('/^\\/php-wasm/', '', $path); - - $_SERVER['PATH'] = '/'; - $_SERVER['REQUEST_URI'] = $path . ($request->_GET ?: ''); - $_SERVER['HTTP_HOST'] = ${JSON.stringify(this.HOST)}; - $_SERVER['REMOTE_ADDR'] = ${JSON.stringify(this.HOSTNAME)}; - $_SERVER['SERVER_NAME'] = ${JSON.stringify(this.ABSOLUTE_URL)}; - $_SERVER['SERVER_PORT'] = ${JSON.stringify(this.PORT)}; - $_SERVER['HTTP_USER_AGENT'] = ${JSON.stringify(navigator.userAgent)}; - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; - $_SERVER['REQUEST_METHOD'] = $request->method; - $_SERVER['SCRIPT_FILENAME'] = $docroot . '/' . $script; - $_SERVER['SCRIPT_NAME'] = $docroot . '/' . $script; - $_SERVER['PHP_SELF'] = $docroot . '/' . $script; - $_SERVER['DOCUMENT_ROOT'] = '/'; - $_SERVER['HTTPS'] = ${JSON.stringify(this.ABSOLUTE_URL.startsWith("https://") ? "on" : "")}; - chdir($docroot); - - // === INCLUDE THE REQUESTED PHP FILE === - - // Ensure the resolved path points to an existing file. If not, - // let's fall back to index.php - $candidate_path = $docroot . '/' . ltrim('${this.resolvePHPFilePath(request.path)}', '/'); - if ( file_exists( $candidate_path ) ) { - require_once $candidate_path; - } else { - require_once $docroot . '/index.php'; - } - `); - return this.parseResponse(output); - } finally { - this.cleanup_FILES(_FILES); - } - } - resolvePHPFilePath(requestedPath) { - let filePath = this.withoutPathname(requestedPath); - if (filePath.includes(".php")) { - filePath = filePath.split(".php")[0] + ".php"; - } else { - if (!filePath.endsWith("/")) { - filePath += "/"; - } - if (!filePath.endsWith("index.php")) { - filePath += "index.php"; - } - } - return filePath; - } - async prepare_FILES(files = {}) { - if (Object.keys(files).length) { - this.php.initUploadedFilesHash(); - } - const _FILES = {}; - for (const [key, value] of Object.entries(files)) { - const tmpName = Math.random().toFixed(20); - const tmpPath = `/tmp/${tmpName}`; - this.php.writeFile( - tmpPath, - new Uint8Array(await value.arrayBuffer()) - ); - _FILES[key] = { - name: value.name, - type: value.type, - tmp_name: tmpPath, - error: 0, - size: value.size - }; - this.php.registerUploadedFile(tmpPath); - } - return _FILES; - } - cleanup_FILES(_FILES = {}) { - if (Object.keys(_FILES).length) { - this.php.destroyUploadedFilesHash(); - } - for (const [, value] of Object.entries(_FILES)) { - if (this.php.fileExists(value.tmp_name)) { - this.php.unlink(value.tmp_name); - } - } - } - parseResponse(result) { - const response = { - body: result.stdout, - headers: {}, - exitCode: result.exitCode, - rawError: result.stderr - }; - for (const row of result.stderr) { - if (!row || !row.trim()) { - continue; - } - try { - const [name, value] = JSON.parse(row); - if (name === "headers") { - response.headers = this.parseHeaders(value); - break; - } - if (name === "status_code") { - response.statusCode = value; - } - } catch (e) { - } - } - if (!response.statusCode) { - response.statusCode = 200; - } - delete response.headers["x-frame-options"]; - return response; - } - parseHeaders(rawHeaders) { - const parsed = {}; - for (const header of rawHeaders) { - const splitAt = header.indexOf(":"); - const [name, value] = [ - header.substring(0, splitAt).toLowerCase(), - header.substring(splitAt + 2) - ]; - if (!(name in parsed)) { - parsed[name] = []; - } - parsed[name].push(value); - } - return parsed; - } -}; -function inferMimeType(path) { - const extension = path.split(".").pop(); - switch (extension) { - 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"; - } -} - -// packages/php-wasm/src/php-browser.js -var PHPBrowser = class { - constructor(server, config = {}) { - this.server = server; - this.cookies = {}; - this.config = { - handleRedirects: false, - maxRedirects: 4, - ...config - }; - } - async request(request, redirects = 0) { - const response = await this.server.request({ - ...request, - _COOKIE: this.cookies - }); - if (response.headers["set-cookie"]) { - this.setCookies(response.headers["set-cookie"]); - } - if (this.config.handleRedirects && response.headers.location && redirects < this.config.maxRedirects) { - const parsedUrl = new URL( - response.headers.location[0], - this.server.ABSOLUTE_URL - ); - return this.request( - { - path: parsedUrl.pathname, - method: "GET", - _GET: parsedUrl.search, - headers: {} - }, - redirects + 1 - ); - } - return response; - } - setCookies(cookies) { - for (const cookie of cookies) { - try { - const value = cookie.split("=")[1].split(";")[0]; - const name = cookie.split("=")[0]; - this.cookies[name] = value; - } catch (e) { - console.error(e); - } - } - } -}; - -// packages/php-wasm/src/index.js -var phpJsHash = ""; -export { - PHPBrowser, - PHPServer, - phpJsHash, - startPHP -}; diff --git a/packages/php-wasm/build/index.js b/packages/php-wasm/build/index.js deleted file mode 100644 index a7251fded3..0000000000 --- a/packages/php-wasm/build/index.js +++ /dev/null @@ -1,497 +0,0 @@ -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// packages/php-wasm/src/index.js -var src_exports = {}; -__export(src_exports, { - PHPBrowser: () => PHPBrowser, - PHPServer: () => PHPServer, - phpJsHash: () => phpJsHash, - startPHP: () => startPHP -}); -module.exports = __toCommonJS(src_exports); - -// packages/php-wasm/src/php.js -var STR = "string"; -var NUM = "number"; -async function startPHP(phpLoaderModule, phpEnv, phpModuleArgs = {}, dataDependenciesModules = []) { - let resolvePhpReady, resolveDepsReady; - const depsReady = new Promise((resolve) => { - resolveDepsReady = resolve; - }); - const phpReady = new Promise((resolve) => { - resolvePhpReady = resolve; - }); - const streams = { - stdout: [], - stderr: [] - }; - const loadPHPRuntime = phpLoaderModule.default; - const PHPRuntime = loadPHPRuntime(phpEnv, { - onAbort(reason) { - console.error("WASM aborted: "); - console.error(reason); - }, - print: (...chunks) => streams.stdout.push(...chunks), - printErr: (...chunks) => streams.stderr.push(...chunks), - ...phpModuleArgs, - noInitialRun: true, - onRuntimeInitialized() { - if (phpModuleArgs.onRuntimeInitialized) { - phpModuleArgs.onRuntimeInitialized(); - } - resolvePhpReady(); - }, - monitorRunDependencies(nbLeft) { - if (nbLeft === 0) { - delete PHPRuntime.monitorRunDependencies; - resolveDepsReady(); - } - } - }); - for (const { default: loadDataModule } of dataDependenciesModules) { - loadDataModule(PHPRuntime); - } - if (!dataDependenciesModules.length) { - resolveDepsReady(); - } - await depsReady; - await phpReady; - return new PHP( - PHPRuntime, - streams - ); -} -var PHP = class { - #streams; - #Runtime; - constructor(Runtime, streams) { - this.#Runtime = Runtime; - this.#streams = streams; - this.mkdirTree("/usr/local/etc"); - this.writeFile("/usr/local/etc/php.ini", `[PHP] -error_reporting = E_ERROR | E_PARSE -display_errors = 1 -html_errors = 1 -display_startup_errors = On -session.save_path=/home/web_user - `); - Runtime.ccall("pib_init", NUM, [STR], []); - } - run(code) { - const exitCode = this.#Runtime.ccall("pib_run", NUM, [STR], [`?>${code}`]); - const response = { - exitCode, - stdout: this.#streams.stdout.join("\n"), - stderr: this.#streams.stderr - }; - this.#refresh(); - return response; - } - #refresh() { - this.#Runtime.ccall("pib_refresh", NUM, [], []); - this.#streams.stdout = []; - this.#streams.stderr = []; - } - mkdirTree(path) { - this.#Runtime.FS.mkdirTree(path); - } - readFileAsText(path) { - return new TextDecoder().decode(this.readFileAsBuffer(path)); - } - readFileAsBuffer(path) { - return this.#Runtime.FS.readFile(path); - } - writeFile(path, data) { - return this.#Runtime.FS.writeFile(path, data); - } - unlink(path) { - this.#Runtime.FS.unlink(path); - } - fileExists(path) { - try { - this.#Runtime.FS.lookupPath(path); - return true; - } catch (e) { - return false; - } - } - initUploadedFilesHash() { - this.#Runtime.ccall("pib_init_uploaded_files_hash", null, [], []); - } - registerUploadedFile(tmpPath) { - this.#Runtime.ccall("pib_register_uploaded_file", null, [STR], [tmpPath]); - } - destroyUploadedFilesHash() { - this.#Runtime.ccall("pib_destroy_uploaded_files_hash", null, [], []); - } -}; - -// packages/php-wasm/src/php-server.js -var PHPServer = class { - DOCROOT; - SCHEMA; - HOSTNAME; - PORT; - HOST; - PATHNAME; - ABSOLUTE_URL; - constructor(php, { - documentRoot = "/var/www/", - absoluteUrl, - isStaticFilePath = () => false - }) { - this.php = php; - this.DOCROOT = documentRoot; - this.isStaticFilePath = isStaticFilePath; - const url = new URL(absoluteUrl); - this.HOSTNAME = url.hostname; - this.PORT = url.port ? url.port : url.protocol === "https:" ? 443 : 80; - this.SCHEMA = (url.protocol || "").replace(":", ""); - this.HOST = `${this.HOSTNAME}:${this.PORT}`; - this.PATHNAME = url.pathname.replace(/\/+$/, ""); - this.ABSOLUTE_URL = `${this.SCHEMA}://${this.HOSTNAME}:${this.PORT}${this.PATHNAME}`; - } - async request(request) { - const unprefixedPath = this.withoutPathname(request.path); - if (this.isStaticFilePath(unprefixedPath)) { - return this.serveStaticFile(unprefixedPath); - } else { - return await this.dispatchToPHP(request); - } - } - withoutPathname(path) { - if (!this.PATHNAME) { - return path; - } - return path.substr(this.PATHNAME.length); - } - serveStaticFile(path) { - const fsPath = `${this.DOCROOT}${path}`; - if (!this.php.fileExists(fsPath)) { - return { - body: "404 File not found", - headers: {}, - statusCode: 404, - exitCode: 0, - rawError: "" - }; - } - const arrayBuffer = this.php.readFileAsBuffer(fsPath); - return { - body: arrayBuffer, - headers: { - "Content-length": arrayBuffer.byteLength, - "Content-type": inferMimeType(fsPath), - "Accept-Ranges": "bytes", - "Cache-Control": "public, max-age=0" - }, - exitCode: 0, - rawError: "" - }; - } - async dispatchToPHP(request) { - const _FILES = await this.prepare_FILES(request.files); - try { - const output = await this.php.run(`_GET, 1), $_GET); - - $_POST = $request->_POST; - $_FILES = $request->_FILES; - - if ( !is_null($request->_COOKIE) ) { - foreach ($request->_COOKIE as $key => $value) { - fwrite($stdErr, 'Setting Cookie: ' . $key . " => " . $value . " -"); - $_COOKIE[$key] = urldecode($value); - } - } - - $_SESSION = $request->_SESSION; - - foreach( $request->headers as $name => $value ) { - $server_key = 'HTTP_' . strtoupper(str_replace('-', '_', $name)); - $_SERVER[$server_key] = $value; - } - - fwrite($stdErr, json_encode(['session' => $_SESSION]) . " -"); - - $docroot = ${JSON.stringify(this.DOCROOT)}; - - $script = ltrim($request->path, '/'); - - $path = $request->path; - $path = preg_replace('/^\\/php-wasm/', '', $path); - - $_SERVER['PATH'] = '/'; - $_SERVER['REQUEST_URI'] = $path . ($request->_GET ?: ''); - $_SERVER['HTTP_HOST'] = ${JSON.stringify(this.HOST)}; - $_SERVER['REMOTE_ADDR'] = ${JSON.stringify(this.HOSTNAME)}; - $_SERVER['SERVER_NAME'] = ${JSON.stringify(this.ABSOLUTE_URL)}; - $_SERVER['SERVER_PORT'] = ${JSON.stringify(this.PORT)}; - $_SERVER['HTTP_USER_AGENT'] = ${JSON.stringify(navigator.userAgent)}; - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; - $_SERVER['REQUEST_METHOD'] = $request->method; - $_SERVER['SCRIPT_FILENAME'] = $docroot . '/' . $script; - $_SERVER['SCRIPT_NAME'] = $docroot . '/' . $script; - $_SERVER['PHP_SELF'] = $docroot . '/' . $script; - $_SERVER['DOCUMENT_ROOT'] = '/'; - $_SERVER['HTTPS'] = ${JSON.stringify(this.ABSOLUTE_URL.startsWith("https://") ? "on" : "")}; - chdir($docroot); - - // === INCLUDE THE REQUESTED PHP FILE === - - // Ensure the resolved path points to an existing file. If not, - // let's fall back to index.php - $candidate_path = $docroot . '/' . ltrim('${this.resolvePHPFilePath(request.path)}', '/'); - if ( file_exists( $candidate_path ) ) { - require_once $candidate_path; - } else { - require_once $docroot . '/index.php'; - } - `); - return this.parseResponse(output); - } finally { - this.cleanup_FILES(_FILES); - } - } - resolvePHPFilePath(requestedPath) { - let filePath = this.withoutPathname(requestedPath); - if (filePath.includes(".php")) { - filePath = filePath.split(".php")[0] + ".php"; - } else { - if (!filePath.endsWith("/")) { - filePath += "/"; - } - if (!filePath.endsWith("index.php")) { - filePath += "index.php"; - } - } - return filePath; - } - async prepare_FILES(files = {}) { - if (Object.keys(files).length) { - this.php.initUploadedFilesHash(); - } - const _FILES = {}; - for (const [key, value] of Object.entries(files)) { - const tmpName = Math.random().toFixed(20); - const tmpPath = `/tmp/${tmpName}`; - this.php.writeFile( - tmpPath, - new Uint8Array(await value.arrayBuffer()) - ); - _FILES[key] = { - name: value.name, - type: value.type, - tmp_name: tmpPath, - error: 0, - size: value.size - }; - this.php.registerUploadedFile(tmpPath); - } - return _FILES; - } - cleanup_FILES(_FILES = {}) { - if (Object.keys(_FILES).length) { - this.php.destroyUploadedFilesHash(); - } - for (const [, value] of Object.entries(_FILES)) { - if (this.php.fileExists(value.tmp_name)) { - this.php.unlink(value.tmp_name); - } - } - } - parseResponse(result) { - const response = { - body: result.stdout, - headers: {}, - exitCode: result.exitCode, - rawError: result.stderr - }; - for (const row of result.stderr) { - if (!row || !row.trim()) { - continue; - } - try { - const [name, value] = JSON.parse(row); - if (name === "headers") { - response.headers = this.parseHeaders(value); - break; - } - if (name === "status_code") { - response.statusCode = value; - } - } catch (e) { - } - } - if (!response.statusCode) { - response.statusCode = 200; - } - delete response.headers["x-frame-options"]; - return response; - } - parseHeaders(rawHeaders) { - const parsed = {}; - for (const header of rawHeaders) { - const splitAt = header.indexOf(":"); - const [name, value] = [ - header.substring(0, splitAt).toLowerCase(), - header.substring(splitAt + 2) - ]; - if (!(name in parsed)) { - parsed[name] = []; - } - parsed[name].push(value); - } - return parsed; - } -}; -function inferMimeType(path) { - const extension = path.split(".").pop(); - switch (extension) { - 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"; - } -} - -// packages/php-wasm/src/php-browser.js -var PHPBrowser = class { - constructor(server, config = {}) { - this.server = server; - this.cookies = {}; - this.config = { - handleRedirects: false, - maxRedirects: 4, - ...config - }; - } - async request(request, redirects = 0) { - const response = await this.server.request({ - ...request, - _COOKIE: this.cookies - }); - if (response.headers["set-cookie"]) { - this.setCookies(response.headers["set-cookie"]); - } - if (this.config.handleRedirects && response.headers.location && redirects < this.config.maxRedirects) { - const parsedUrl = new URL( - response.headers.location[0], - this.server.ABSOLUTE_URL - ); - return this.request( - { - path: parsedUrl.pathname, - method: "GET", - _GET: parsedUrl.search, - headers: {} - }, - redirects + 1 - ); - } - return response; - } - setCookies(cookies) { - for (const cookie of cookies) { - try { - const value = cookie.split("=")[1].split(";")[0]; - const name = cookie.split("=")[0]; - this.cookies[name] = value; - } catch (e) { - console.error(e); - } - } - } -}; - -// packages/php-wasm/src/index.js -var phpJsHash = ""; diff --git a/packages/wordpress-wasm/build-module/example-app.js b/packages/wordpress-wasm/build-module/example-app.js deleted file mode 100644 index d638ea64d7..0000000000 --- a/packages/wordpress-wasm/build-module/example-app.js +++ /dev/null @@ -1,214 +0,0 @@ -// packages/wordpress-wasm/src/index.js -import { - postMessageExpectReply, - awaitReply, - responseTo, - registerServiceWorker, - startPHPWorkerThread, - getWorkerThreadBackend -} from "php-wasm-browser"; - -// packages/wordpress-wasm/src/config.js -import { phpJsHash } from "php-wasm"; -import { phpJsHash as phpJsHash2 } from "php-wasm"; -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; -var wordPressSiteUrl = serviceWorkerOrigin; -var wasmWorkerUrl = "http://127.0.0.1:8778/iframe-worker.html?0891786456959600"; -var wasmWorkerBackend = "iframe"; - -// packages/wordpress-wasm/src/index.js -async function bootWordPress({ - assignScope = true, - onWasmDownloadProgress -}) { - assertNotInfiniteLoadingLoop(); - const scope = assignScope ? Math.random().toFixed(16) : void 0; - const workerThread = await startPHPWorkerThread({ - backend: getWorkerThreadBackend(wasmWorkerBackend, wasmWorkerUrl), - absoluteUrl: wordPressSiteUrl, - scope, - onDownloadProgress: onWasmDownloadProgress - }); - await registerServiceWorker({ - url: serviceWorkerUrl, - broadcastChannel: new BroadcastChannel("wordpress-wasm"), - onRequest: async (request) => { - return await workerThread.HTTPRequest(request); - }, - scope - }); - return workerThread; -} -function assertNotInfiniteLoadingLoop() { - let isBrowserInABrowser = false; - try { - isBrowserInABrowser = window.parent !== window && window.parent.IS_WASM_WORDPRESS; - } catch (e) { - } - if (isBrowserInABrowser) { - throw new Error( - "The service worker did not load correctly. This is a bug, please report it on https://github.com/WordPress/wordpress-wasm/issues" - ); - } - window.IS_WASM_WORDPRESS = true; -} - -// packages/wordpress-wasm/src/macros.js -async function login(workerThread, user = "admin", password = "password") { - await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-login.php") - }); - await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-login.php"), - method: "POST", - _POST: { - log: user, - pwd: password, - rememberme: "forever" - } - }); -} -async function installPlugin(workerThread, pluginZipFile, options = {}) { - options = { - activate: true, - ...options - }; - const pluginForm = await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-admin/plugin-install.php?tab=upload") - }); - const pluginFormPage = new DOMParser().parseFromString(pluginForm.body, "text/html"); - const pluginFormData = new FormData(pluginFormPage.querySelector(".wp-upload-form")); - const { pluginzip, ...postData } = Object.fromEntries(pluginFormData.entries()); - if (options.activate) { - const pluginInstalledResponse = await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-admin/update.php?action=upload-plugin"), - method: "POST", - _POST: postData, - files: { pluginzip: pluginZipFile } - }); - const pluginInstalledPage = new DOMParser().parseFromString(pluginInstalledResponse.body, "text/html"); - const activateButtonHref = pluginInstalledPage.querySelector("#wpbody-content .button.button-primary").attributes.href.value; - const activatePluginUrl = new URL( - activateButtonHref, - workerThread.pathToInternalUrl("/wp-admin/") - ).toString(); - await workerThread.HTTPRequest({ - path: activatePluginUrl - }); - } -} - -// packages/wordpress-wasm/src/example-app.js -import { cloneResponseMonitorProgress, postMessageHandler } from "php-wasm-browser"; -function setupAddressBar(wasmWorker) { - const addressBar = document.querySelector("#address-bar"); - wpFrame.addEventListener("load", (e) => { - addressBar.value = wasmWorker.internalUrlToPath( - e.currentTarget.contentWindow.location.href - ); - }); - document.querySelector("#address-bar-form").addEventListener("submit", (e) => { - e.preventDefault(); - let requestedPath = addressBar.value; - const isDirectory = !requestedPath.split("/").pop().includes("."); - if (isDirectory && !requestedPath.endsWith("/")) { - requestedPath += "/"; - } - wpFrame.src = wasmWorker.pathToInternalUrl( - requestedPath - ); - }); -} -var FetchProgressBar = class { - constructor({ - expectedRequests, - min = 0, - max = 100 - }) { - this.expectedRequests = expectedRequests; - this.progress = {}; - this.min = min; - this.max = max; - this.el = document.querySelector(".progress-bar.is-finite"); - const wpFrame2 = document.querySelector("#wp"); - const hideProgressBar = () => { - document.querySelector("body.is-loading").classList.remove("is-loading"); - wpFrame2.removeEventListener("load", hideProgressBar); - }; - wpFrame2.addEventListener("load", hideProgressBar); - } - onDataChunk = ({ file, loaded, total }) => { - if (Object.keys(this.progress).length === 0) { - this.setFinite(); - } - this.progress[file] = loaded / total; - const progressSum = Object.entries(this.progress).reduce( - (acc, [_, percentFinished]) => acc + percentFinished, - 0 - ); - const totalProgress = Math.min(1, progressSum / this.expectedRequests); - const scaledProgressPercentage = this.min + (this.max - this.min) * totalProgress; - this.setProgress(scaledProgressPercentage); - }; - setProgress(percent) { - this.el.style.width = `${percent}%`; - } - setFinite() { - const classList = document.querySelector( - ".progress-bar-wrapper.mode-infinite" - ).classList; - classList.remove("mode-infinite"); - classList.add("mode-finite"); - } -}; -var wpFrame = document.querySelector("#wp"); -async function main() { - const preinstallPlugin = query.get("plugin"); - let progressBar; - let pluginResponse; - if (preinstallPlugin) { - pluginResponse = await fetch("/plugin-proxy?plugin=" + preinstallPlugin); - progressBar = new FetchProgressBar({ - expectedRequests: 3, - max: 80 - }); - } else { - progressBar = new FetchProgressBar({ expectedRequests: 2 }); - } - const workerThread = await bootWordPress({ - onWasmDownloadProgress: progressBar.onDataChunk - }); - if (appMode === "browser") { - setupAddressBar(workerThread); - } - if (preinstallPlugin) { - const progressPluginResponse = cloneResponseMonitorProgress( - pluginResponse, - (progress) => progressBar.onDataChunk({ file: preinstallPlugin, ...progress }) - ); - const blob = await progressPluginResponse.blob(); - const pluginFile = new File([blob], preinstallPlugin); - progressBar.el.classList.add("indeterminate"); - progressBar.setProgress(80); - progressBar.setProgress(85); - await login(workerThread, "admin", "password"); - progressBar.setProgress(100); - await installPlugin(workerThread, pluginFile); - } - if (query.get("rpc")) { - console.log("Registering an RPC handler"); - window.addEventListener("message", postMessageHandler(async (data) => { - if (data.type === "rpc") { - return await workerThread[data.method](...data.args); - } else if (data.type === "go_to") { - wpFrame.src = workerThread.pathToInternalUrl(data.path); - } else if (data.type === "is_alive") { - return true; - } - })); - } - const initialUrl = query.get("url") || "/"; - wpFrame.src = workerThread.pathToInternalUrl(initialUrl); -} -main(); diff --git a/packages/wordpress-wasm/build-module/index.js b/packages/wordpress-wasm/build-module/index.js deleted file mode 100644 index b892ca2d46..0000000000 --- a/packages/wordpress-wasm/build-module/index.js +++ /dev/null @@ -1,62 +0,0 @@ -// packages/wordpress-wasm/src/index.js -import { - postMessageExpectReply, - awaitReply, - responseTo, - registerServiceWorker, - startPHPWorkerThread, - getWorkerThreadBackend -} from "php-wasm-browser"; - -// packages/wordpress-wasm/src/config.js -import { phpJsHash } from "php-wasm"; -import { phpJsHash as phpJsHash2 } from "php-wasm"; -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; -var wordPressSiteUrl = serviceWorkerOrigin; -var wasmWorkerUrl = "http://127.0.0.1:8778/iframe-worker.html?0891786456959600"; -var wasmWorkerBackend = "iframe"; - -// packages/wordpress-wasm/src/index.js -async function bootWordPress({ - assignScope = true, - onWasmDownloadProgress -}) { - assertNotInfiniteLoadingLoop(); - const scope = assignScope ? Math.random().toFixed(16) : void 0; - const workerThread = await startPHPWorkerThread({ - backend: getWorkerThreadBackend(wasmWorkerBackend, wasmWorkerUrl), - absoluteUrl: wordPressSiteUrl, - scope, - onDownloadProgress: onWasmDownloadProgress - }); - await registerServiceWorker({ - url: serviceWorkerUrl, - broadcastChannel: new BroadcastChannel("wordpress-wasm"), - onRequest: async (request) => { - return await workerThread.HTTPRequest(request); - }, - scope - }); - return workerThread; -} -function assertNotInfiniteLoadingLoop() { - let isBrowserInABrowser = false; - try { - isBrowserInABrowser = window.parent !== window && window.parent.IS_WASM_WORDPRESS; - } catch (e) { - } - if (isBrowserInABrowser) { - throw new Error( - "The service worker did not load correctly. This is a bug, please report it on https://github.com/WordPress/wordpress-wasm/issues" - ); - } - window.IS_WASM_WORDPRESS = true; -} -var isUploadedFilePath = (path) => { - return path.startsWith("/wp-content/uploads/") || path.startsWith("/wp-content/plugins/") || path.startsWith("/wp-content/themes/") && !path.startsWith("/wp-content/themes/twentytwentytwo/"); -}; -export { - bootWordPress, - isUploadedFilePath -}; diff --git a/packages/wordpress-wasm/build-module/service-worker.js b/packages/wordpress-wasm/build-module/service-worker.js deleted file mode 100644 index e64a532f71..0000000000 --- a/packages/wordpress-wasm/build-module/service-worker.js +++ /dev/null @@ -1,33 +0,0 @@ -// packages/wordpress-wasm/src/service-worker.js -import { initializeServiceWorker, seemsLikeAPHPServerPath } from "php-wasm-browser"; - -// packages/wordpress-wasm/src/index.js -import { - postMessageExpectReply, - awaitReply, - responseTo, - registerServiceWorker, - startPHPWorkerThread, - getWorkerThreadBackend -} from "php-wasm-browser"; - -// packages/wordpress-wasm/src/config.js -import { phpJsHash } from "php-wasm"; -import { phpJsHash as phpJsHash2 } from "php-wasm"; -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; - -// packages/wordpress-wasm/src/index.js -var isUploadedFilePath = (path) => { - return path.startsWith("/wp-content/uploads/") || path.startsWith("/wp-content/plugins/") || path.startsWith("/wp-content/themes/") && !path.startsWith("/wp-content/themes/twentytwentytwo/"); -}; - -// packages/wordpress-wasm/src/service-worker.js -initializeServiceWorker({ - broadcastChannel: new BroadcastChannel("wordpress-wasm"), - shouldForwardRequestToPHPServer -}); -function shouldForwardRequestToPHPServer(request, unscopedUrl) { - const path = unscopedUrl.pathname; - return !path.startsWith("/plugin-proxy") && (seemsLikeAPHPServerPath(path) || isUploadedFilePath(path)); -} diff --git a/packages/wordpress-wasm/build-module/worker-thread.js b/packages/wordpress-wasm/build-module/worker-thread.js deleted file mode 100644 index d95ea02f62..0000000000 --- a/packages/wordpress-wasm/build-module/worker-thread.js +++ /dev/null @@ -1,244 +0,0 @@ -var __getOwnPropNames = Object.getOwnPropertyNames; -var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; - -// packages/wordpress-wasm/src/requests_transport_fetch.php -var require_requests_transport_fetch = __commonJS({ - "packages/wordpress-wasm/src/requests_transport_fetch.php"(exports, module) { - module.exports = ` $headers, - 'data' => $data, - 'url' => $url, - 'method' => $options['type'], - ) ) ); - - $js = <<headers = vrzno_eval( $js ); - - return $this->headers; - } - - public function request_multiple( $requests, $options ) { - $responses = array(); - $class = get_class( $this ); - foreach ( $requests as $id => $request ) { - try { - $handler = new $class(); - $responses[ $id ] = $handler->request( $request['url'], $request['headers'], $request['data'], $request['options'] ); - $request['options']['hooks']->dispatch( 'transport.internal.parse_response', array( &$responses[ $id ], $request ) ); - } catch ( Requests_Exception $e ) { - $responses[ $id ] = $e; - } - if ( ! is_string( $responses[ $id ] ) ) { - $request['options']['hooks']->dispatch( 'multiple.request.complete', array( &$responses[ $id ], $id ) ); - } - } - - return $responses; - } - - protected static function format_get( $url, $data ) { - if ( ! empty( $data ) ) { - $query = ''; - $url_parts = parse_url( $url ); - if ( empty( $url_parts['query'] ) ) { - $url_parts['query'] = ''; - } else { - $query = $url_parts['query']; - } - $query .= '&' . http_build_query( $data, null, '&' ); - $query = trim( $query, '&' ); - if ( empty( $url_parts['query'] ) ) { - $url .= '?' . $query; - } else { - $url = str_replace( $url_parts['query'], $query, $url ); - } - } - - return $url; - } - - public static function test( $capabilities = array() ) { - if ( ! function_exists( 'vrzno_eval' ) ) { - return false; - } - - if ( vrzno_eval( "typeof XMLHttpRequest;" ) !== 'function' ) { - return false; - } - - return true; - } - -} - -if(defined('USE_FETCH_FOR_REQUESTS') && USE_FETCH_FOR_REQUESTS) { - Requests::add_transport( 'Requests_Transport_Fetch' ); - add_filter('http_request_host_is_external', function($arg) { - return true; - }); -} -`; - } -}); - -// packages/wordpress-wasm/src/worker-thread.js -import { PHP, PHPServer, PHPBrowser } from "php-wasm"; -import { loadPHPWithProgress, initializeWorkerThread } from "php-wasm-browser"; - -// packages/wordpress-wasm/src/config.js -import { phpJsHash } from "php-wasm"; -import { phpJsHash as phpJsHash2 } from "php-wasm"; -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; -var wpJsCacheBuster = ""; - -// packages/wordpress-wasm/src/index.js -import { - postMessageExpectReply, - awaitReply, - responseTo, - registerServiceWorker, - startPHPWorkerThread, - getWorkerThreadBackend -} from "php-wasm-browser"; -var isUploadedFilePath = (path) => { - return path.startsWith("/wp-content/uploads/") || path.startsWith("/wp-content/plugins/") || path.startsWith("/wp-content/themes/") && !path.startsWith("/wp-content/themes/twentytwentytwo/"); -}; - -// packages/wordpress-wasm/src/worker-thread.js -initializeWorkerThread(startWordPress); -var DOCROOT = "/wordpress"; -async function startWordPress({ absoluteUrl }) { - const [phpLoaderModule, wpLoaderModule] = await Promise.all([ - import(`/php.js?${phpJsHash2}`), - import(`/wp.js?${wpJsCacheBuster}`) - ]); - const php = await loadPHPWithProgress(phpLoaderModule, [wpLoaderModule]); - patchWordPressFiles(php, absoluteUrl); - const server = new PHPServer(php, { - documentRoot: DOCROOT, - absoluteUrl, - isStaticFilePath: isUploadedFilePath - }); - return new PHPBrowser(server); -} -function patchWordPressFiles(php, absoluteUrl) { - function patchFile(path, callback) { - php.writeFile( - path, - callback(php.readFileAsText(path)) - ); - } - patchFile( - `${DOCROOT}/wp-config.php`, - (contents) => contents + ` - define('USE_FETCH_FOR_REQUESTS', false); - define('WP_HOME', '${JSON.stringify(DOCROOT)}'); - - // The original version of this function crashes WASM WordPress, let's define an empty one instead. - function wp_new_blog_notification(...$args){} - ` - ); - patchFile( - `${DOCROOT}/wp-includes/plugin.php`, - (contents) => contents + ` - function _wasm_wp_force_site_url() { - return ${JSON.stringify(absoluteUrl)}; - } - add_filter( "option_home", '_wasm_wp_force_site_url', 10000 ); - add_filter( "option_siteurl", '_wasm_wp_force_site_url', 10000 ); - ` - ); - const transports = [ - `${DOCROOT}/wp-includes/Requests/Transport/fsockopen.php`, - `${DOCROOT}/wp-includes/Requests/Transport/cURL.php` - ]; - for (const transport of transports) { - patchFile(transport, (contents) => contents.replace( - "public static function test", - "public static function test( $capabilities = array() ) { return false; } public static function test2" - )); - } - patchFile(`${DOCROOT}/wp-includes/default-filters.php`, (contents) => contents.replace( - /add_filter[^;]+wp_maybe_grant_site_health_caps[^;]+;/i, - "" - )); - php.mkdirTree(`${DOCROOT}/wp-content/mu-plugins`); - php.writeFile( - `${DOCROOT}/wp-content/mu-plugins/requests_transport_fetch.php`, - require_requests_transport_fetch() - ); -} diff --git a/packages/wordpress-wasm/build/example-app.js b/packages/wordpress-wasm/build/example-app.js deleted file mode 100644 index e78fd58b3f..0000000000 --- a/packages/wordpress-wasm/build/example-app.js +++ /dev/null @@ -1,207 +0,0 @@ -// packages/wordpress-wasm/src/index.js -var import_php_wasm_browser = require("php-wasm-browser"); - -// packages/wordpress-wasm/src/config.js -var import_php_wasm = require("php-wasm"); -var import_php_wasm2 = require("php-wasm"); -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; -var wordPressSiteUrl = serviceWorkerOrigin; -var wasmWorkerUrl = "http://127.0.0.1:8778/iframe-worker.html?0891786456959600"; -var wasmWorkerBackend = "iframe"; - -// packages/wordpress-wasm/src/index.js -async function bootWordPress({ - assignScope = true, - onWasmDownloadProgress -}) { - assertNotInfiniteLoadingLoop(); - const scope = assignScope ? Math.random().toFixed(16) : void 0; - const workerThread = await (0, import_php_wasm_browser.startPHPWorkerThread)({ - backend: (0, import_php_wasm_browser.getWorkerThreadBackend)(wasmWorkerBackend, wasmWorkerUrl), - absoluteUrl: wordPressSiteUrl, - scope, - onDownloadProgress: onWasmDownloadProgress - }); - await (0, import_php_wasm_browser.registerServiceWorker)({ - url: serviceWorkerUrl, - broadcastChannel: new BroadcastChannel("wordpress-wasm"), - onRequest: async (request) => { - return await workerThread.HTTPRequest(request); - }, - scope - }); - return workerThread; -} -function assertNotInfiniteLoadingLoop() { - let isBrowserInABrowser = false; - try { - isBrowserInABrowser = window.parent !== window && window.parent.IS_WASM_WORDPRESS; - } catch (e) { - } - if (isBrowserInABrowser) { - throw new Error( - "The service worker did not load correctly. This is a bug, please report it on https://github.com/WordPress/wordpress-wasm/issues" - ); - } - window.IS_WASM_WORDPRESS = true; -} - -// packages/wordpress-wasm/src/macros.js -async function login(workerThread, user = "admin", password = "password") { - await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-login.php") - }); - await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-login.php"), - method: "POST", - _POST: { - log: user, - pwd: password, - rememberme: "forever" - } - }); -} -async function installPlugin(workerThread, pluginZipFile, options = {}) { - options = { - activate: true, - ...options - }; - const pluginForm = await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-admin/plugin-install.php?tab=upload") - }); - const pluginFormPage = new DOMParser().parseFromString(pluginForm.body, "text/html"); - const pluginFormData = new FormData(pluginFormPage.querySelector(".wp-upload-form")); - const { pluginzip, ...postData } = Object.fromEntries(pluginFormData.entries()); - if (options.activate) { - const pluginInstalledResponse = await workerThread.HTTPRequest({ - path: workerThread.pathToInternalUrl("/wp-admin/update.php?action=upload-plugin"), - method: "POST", - _POST: postData, - files: { pluginzip: pluginZipFile } - }); - const pluginInstalledPage = new DOMParser().parseFromString(pluginInstalledResponse.body, "text/html"); - const activateButtonHref = pluginInstalledPage.querySelector("#wpbody-content .button.button-primary").attributes.href.value; - const activatePluginUrl = new URL( - activateButtonHref, - workerThread.pathToInternalUrl("/wp-admin/") - ).toString(); - await workerThread.HTTPRequest({ - path: activatePluginUrl - }); - } -} - -// packages/wordpress-wasm/src/example-app.js -var import_php_wasm_browser2 = require("php-wasm-browser"); -function setupAddressBar(wasmWorker) { - const addressBar = document.querySelector("#address-bar"); - wpFrame.addEventListener("load", (e) => { - addressBar.value = wasmWorker.internalUrlToPath( - e.currentTarget.contentWindow.location.href - ); - }); - document.querySelector("#address-bar-form").addEventListener("submit", (e) => { - e.preventDefault(); - let requestedPath = addressBar.value; - const isDirectory = !requestedPath.split("/").pop().includes("."); - if (isDirectory && !requestedPath.endsWith("/")) { - requestedPath += "/"; - } - wpFrame.src = wasmWorker.pathToInternalUrl( - requestedPath - ); - }); -} -var FetchProgressBar = class { - constructor({ - expectedRequests, - min = 0, - max = 100 - }) { - this.expectedRequests = expectedRequests; - this.progress = {}; - this.min = min; - this.max = max; - this.el = document.querySelector(".progress-bar.is-finite"); - const wpFrame2 = document.querySelector("#wp"); - const hideProgressBar = () => { - document.querySelector("body.is-loading").classList.remove("is-loading"); - wpFrame2.removeEventListener("load", hideProgressBar); - }; - wpFrame2.addEventListener("load", hideProgressBar); - } - onDataChunk = ({ file, loaded, total }) => { - if (Object.keys(this.progress).length === 0) { - this.setFinite(); - } - this.progress[file] = loaded / total; - const progressSum = Object.entries(this.progress).reduce( - (acc, [_, percentFinished]) => acc + percentFinished, - 0 - ); - const totalProgress = Math.min(1, progressSum / this.expectedRequests); - const scaledProgressPercentage = this.min + (this.max - this.min) * totalProgress; - this.setProgress(scaledProgressPercentage); - }; - setProgress(percent) { - this.el.style.width = `${percent}%`; - } - setFinite() { - const classList = document.querySelector( - ".progress-bar-wrapper.mode-infinite" - ).classList; - classList.remove("mode-infinite"); - classList.add("mode-finite"); - } -}; -var wpFrame = document.querySelector("#wp"); -async function main() { - const preinstallPlugin = query.get("plugin"); - let progressBar; - let pluginResponse; - if (preinstallPlugin) { - pluginResponse = await fetch("/plugin-proxy?plugin=" + preinstallPlugin); - progressBar = new FetchProgressBar({ - expectedRequests: 3, - max: 80 - }); - } else { - progressBar = new FetchProgressBar({ expectedRequests: 2 }); - } - const workerThread = await bootWordPress({ - onWasmDownloadProgress: progressBar.onDataChunk - }); - if (appMode === "browser") { - setupAddressBar(workerThread); - } - if (preinstallPlugin) { - const progressPluginResponse = (0, import_php_wasm_browser2.cloneResponseMonitorProgress)( - pluginResponse, - (progress) => progressBar.onDataChunk({ file: preinstallPlugin, ...progress }) - ); - const blob = await progressPluginResponse.blob(); - const pluginFile = new File([blob], preinstallPlugin); - progressBar.el.classList.add("indeterminate"); - progressBar.setProgress(80); - progressBar.setProgress(85); - await login(workerThread, "admin", "password"); - progressBar.setProgress(100); - await installPlugin(workerThread, pluginFile); - } - if (query.get("rpc")) { - console.log("Registering an RPC handler"); - window.addEventListener("message", (0, import_php_wasm_browser2.postMessageHandler)(async (data) => { - if (data.type === "rpc") { - return await workerThread[data.method](...data.args); - } else if (data.type === "go_to") { - wpFrame.src = workerThread.pathToInternalUrl(data.path); - } else if (data.type === "is_alive") { - return true; - } - })); - } - const initialUrl = query.get("url") || "/"; - wpFrame.src = workerThread.pathToInternalUrl(initialUrl); -} -main(); diff --git a/packages/wordpress-wasm/build/index.js b/packages/wordpress-wasm/build/index.js deleted file mode 100644 index 68e8490dc0..0000000000 --- a/packages/wordpress-wasm/build/index.js +++ /dev/null @@ -1,75 +0,0 @@ -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// packages/wordpress-wasm/src/index.js -var src_exports = {}; -__export(src_exports, { - bootWordPress: () => bootWordPress, - isUploadedFilePath: () => isUploadedFilePath -}); -module.exports = __toCommonJS(src_exports); -var import_php_wasm_browser = require("php-wasm-browser"); - -// packages/wordpress-wasm/src/config.js -var import_php_wasm = require("php-wasm"); -var import_php_wasm2 = require("php-wasm"); -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; -var wordPressSiteUrl = serviceWorkerOrigin; -var wasmWorkerUrl = "http://127.0.0.1:8778/iframe-worker.html?0891786456959600"; -var wasmWorkerBackend = "iframe"; - -// packages/wordpress-wasm/src/index.js -async function bootWordPress({ - assignScope = true, - onWasmDownloadProgress -}) { - assertNotInfiniteLoadingLoop(); - const scope = assignScope ? Math.random().toFixed(16) : void 0; - const workerThread = await (0, import_php_wasm_browser.startPHPWorkerThread)({ - backend: (0, import_php_wasm_browser.getWorkerThreadBackend)(wasmWorkerBackend, wasmWorkerUrl), - absoluteUrl: wordPressSiteUrl, - scope, - onDownloadProgress: onWasmDownloadProgress - }); - await (0, import_php_wasm_browser.registerServiceWorker)({ - url: serviceWorkerUrl, - broadcastChannel: new BroadcastChannel("wordpress-wasm"), - onRequest: async (request) => { - return await workerThread.HTTPRequest(request); - }, - scope - }); - return workerThread; -} -function assertNotInfiniteLoadingLoop() { - let isBrowserInABrowser = false; - try { - isBrowserInABrowser = window.parent !== window && window.parent.IS_WASM_WORDPRESS; - } catch (e) { - } - if (isBrowserInABrowser) { - throw new Error( - "The service worker did not load correctly. This is a bug, please report it on https://github.com/WordPress/wordpress-wasm/issues" - ); - } - window.IS_WASM_WORDPRESS = true; -} -var isUploadedFilePath = (path) => { - return path.startsWith("/wp-content/uploads/") || path.startsWith("/wp-content/plugins/") || path.startsWith("/wp-content/themes/") && !path.startsWith("/wp-content/themes/twentytwentytwo/"); -}; diff --git a/packages/wordpress-wasm/build/service-worker.js b/packages/wordpress-wasm/build/service-worker.js deleted file mode 100644 index 8c57b8634f..0000000000 --- a/packages/wordpress-wasm/build/service-worker.js +++ /dev/null @@ -1,26 +0,0 @@ -// packages/wordpress-wasm/src/service-worker.js -var import_php_wasm_browser2 = require("php-wasm-browser"); - -// packages/wordpress-wasm/src/index.js -var import_php_wasm_browser = require("php-wasm-browser"); - -// packages/wordpress-wasm/src/config.js -var import_php_wasm = require("php-wasm"); -var import_php_wasm2 = require("php-wasm"); -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; - -// packages/wordpress-wasm/src/index.js -var isUploadedFilePath = (path) => { - return path.startsWith("/wp-content/uploads/") || path.startsWith("/wp-content/plugins/") || path.startsWith("/wp-content/themes/") && !path.startsWith("/wp-content/themes/twentytwentytwo/"); -}; - -// packages/wordpress-wasm/src/service-worker.js -(0, import_php_wasm_browser2.initializeServiceWorker)({ - broadcastChannel: new BroadcastChannel("wordpress-wasm"), - shouldForwardRequestToPHPServer -}); -function shouldForwardRequestToPHPServer(request, unscopedUrl) { - const path = unscopedUrl.pathname; - return !path.startsWith("/plugin-proxy") && ((0, import_php_wasm_browser2.seemsLikeAPHPServerPath)(path) || isUploadedFilePath(path)); -} diff --git a/packages/wordpress-wasm/build/wordpress.html b/packages/wordpress-wasm/build/wordpress.html deleted file mode 100644 index 95cbf90693..0000000000 --- a/packages/wordpress-wasm/build/wordpress.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - WordPress code embed! - - - -
- - - - - - - diff --git a/packages/wordpress-wasm/build/worker-thread.js b/packages/wordpress-wasm/build/worker-thread.js deleted file mode 100644 index be0f081e84..0000000000 --- a/packages/wordpress-wasm/build/worker-thread.js +++ /dev/null @@ -1,237 +0,0 @@ -var __getOwnPropNames = Object.getOwnPropertyNames; -var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; - -// packages/wordpress-wasm/src/requests_transport_fetch.php -var require_requests_transport_fetch = __commonJS({ - "packages/wordpress-wasm/src/requests_transport_fetch.php"(exports, module2) { - module2.exports = ` $headers, - 'data' => $data, - 'url' => $url, - 'method' => $options['type'], - ) ) ); - - $js = <<headers = vrzno_eval( $js ); - - return $this->headers; - } - - public function request_multiple( $requests, $options ) { - $responses = array(); - $class = get_class( $this ); - foreach ( $requests as $id => $request ) { - try { - $handler = new $class(); - $responses[ $id ] = $handler->request( $request['url'], $request['headers'], $request['data'], $request['options'] ); - $request['options']['hooks']->dispatch( 'transport.internal.parse_response', array( &$responses[ $id ], $request ) ); - } catch ( Requests_Exception $e ) { - $responses[ $id ] = $e; - } - if ( ! is_string( $responses[ $id ] ) ) { - $request['options']['hooks']->dispatch( 'multiple.request.complete', array( &$responses[ $id ], $id ) ); - } - } - - return $responses; - } - - protected static function format_get( $url, $data ) { - if ( ! empty( $data ) ) { - $query = ''; - $url_parts = parse_url( $url ); - if ( empty( $url_parts['query'] ) ) { - $url_parts['query'] = ''; - } else { - $query = $url_parts['query']; - } - $query .= '&' . http_build_query( $data, null, '&' ); - $query = trim( $query, '&' ); - if ( empty( $url_parts['query'] ) ) { - $url .= '?' . $query; - } else { - $url = str_replace( $url_parts['query'], $query, $url ); - } - } - - return $url; - } - - public static function test( $capabilities = array() ) { - if ( ! function_exists( 'vrzno_eval' ) ) { - return false; - } - - if ( vrzno_eval( "typeof XMLHttpRequest;" ) !== 'function' ) { - return false; - } - - return true; - } - -} - -if(defined('USE_FETCH_FOR_REQUESTS') && USE_FETCH_FOR_REQUESTS) { - Requests::add_transport( 'Requests_Transport_Fetch' ); - add_filter('http_request_host_is_external', function($arg) { - return true; - }); -} -`; - } -}); - -// packages/wordpress-wasm/src/worker-thread.js -var import_php_wasm3 = require("php-wasm"); -var import_php_wasm_browser2 = require("php-wasm-browser"); - -// packages/wordpress-wasm/src/config.js -var import_php_wasm = require("php-wasm"); -var import_php_wasm2 = require("php-wasm"); -var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; -var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; -var wpJsCacheBuster = ""; - -// packages/wordpress-wasm/src/index.js -var import_php_wasm_browser = require("php-wasm-browser"); -var isUploadedFilePath = (path) => { - return path.startsWith("/wp-content/uploads/") || path.startsWith("/wp-content/plugins/") || path.startsWith("/wp-content/themes/") && !path.startsWith("/wp-content/themes/twentytwentytwo/"); -}; - -// packages/wordpress-wasm/src/worker-thread.js -(0, import_php_wasm_browser2.initializeWorkerThread)(startWordPress); -var DOCROOT = "/wordpress"; -async function startWordPress({ absoluteUrl }) { - const [phpLoaderModule, wpLoaderModule] = await Promise.all([ - import(`/php.js?${import_php_wasm2.phpJsHash}`), - import(`/wp.js?${wpJsCacheBuster}`) - ]); - const php = await (0, import_php_wasm_browser2.loadPHPWithProgress)(phpLoaderModule, [wpLoaderModule]); - patchWordPressFiles(php, absoluteUrl); - const server = new import_php_wasm3.PHPServer(php, { - documentRoot: DOCROOT, - absoluteUrl, - isStaticFilePath: isUploadedFilePath - }); - return new import_php_wasm3.PHPBrowser(server); -} -function patchWordPressFiles(php, absoluteUrl) { - function patchFile(path, callback) { - php.writeFile( - path, - callback(php.readFileAsText(path)) - ); - } - patchFile( - `${DOCROOT}/wp-config.php`, - (contents) => contents + ` - define('USE_FETCH_FOR_REQUESTS', false); - define('WP_HOME', '${JSON.stringify(DOCROOT)}'); - - // The original version of this function crashes WASM WordPress, let's define an empty one instead. - function wp_new_blog_notification(...$args){} - ` - ); - patchFile( - `${DOCROOT}/wp-includes/plugin.php`, - (contents) => contents + ` - function _wasm_wp_force_site_url() { - return ${JSON.stringify(absoluteUrl)}; - } - add_filter( "option_home", '_wasm_wp_force_site_url', 10000 ); - add_filter( "option_siteurl", '_wasm_wp_force_site_url', 10000 ); - ` - ); - const transports = [ - `${DOCROOT}/wp-includes/Requests/Transport/fsockopen.php`, - `${DOCROOT}/wp-includes/Requests/Transport/cURL.php` - ]; - for (const transport of transports) { - patchFile(transport, (contents) => contents.replace( - "public static function test", - "public static function test( $capabilities = array() ) { return false; } public static function test2" - )); - } - patchFile(`${DOCROOT}/wp-includes/default-filters.php`, (contents) => contents.replace( - /add_filter[^;]+wp_maybe_grant_site_health_caps[^;]+;/i, - "" - )); - php.mkdirTree(`${DOCROOT}/wp-content/mu-plugins`); - php.writeFile( - `${DOCROOT}/wp-content/mu-plugins/requests_transport_fetch.php`, - require_requests_transport_fetch() - ); -} diff --git a/src/wordpress-wasm/example-app.tsx b/src/wordpress-wasm/example-app.tsx index b936080ef2..2555621885 100644 --- a/src/wordpress-wasm/example-app.tsx +++ b/src/wordpress-wasm/example-app.tsx @@ -215,14 +215,12 @@ function wireProgressBar() { infiniteWrapper.classList.remove('mode-infinite'); infiniteWrapper.classList.add('mode-finite'); } - if (caption && caption.length) { + if( caption && caption.length ) { const captionElement = document.querySelector( '.progress-bar-overlay-caption' ) as HTMLElement; - if (captionElement) { - captionElement.innerText = caption; - } + captionElement.innerText= caption; } const progressBarEl = document.querySelector( From 7c29728e775117ea67fbfee71a4643226f10b2d0 Mon Sep 17 00:00:00 2001 From: dufresnesteven Date: Tue, 29 Nov 2022 15:35:32 +0900 Subject: [PATCH 5/7] Clean up. --- src/wordpress-wasm/example-app.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wordpress-wasm/example-app.tsx b/src/wordpress-wasm/example-app.tsx index 2555621885..b936080ef2 100644 --- a/src/wordpress-wasm/example-app.tsx +++ b/src/wordpress-wasm/example-app.tsx @@ -215,12 +215,14 @@ function wireProgressBar() { infiniteWrapper.classList.remove('mode-infinite'); infiniteWrapper.classList.add('mode-finite'); } - if( caption && caption.length ) { + if (caption && caption.length) { const captionElement = document.querySelector( '.progress-bar-overlay-caption' ) as HTMLElement; - captionElement.innerText= caption; + if (captionElement) { + captionElement.innerText = caption; + } } const progressBarEl = document.querySelector( From 2adbdda30cd13da38c44737626205aaf2a2bef5f Mon Sep 17 00:00:00 2001 From: dufresnesteven Date: Tue, 29 Nov 2022 15:36:53 +0900 Subject: [PATCH 6/7] Remove empty space. --- src/wordpress-wasm/example-app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wordpress-wasm/example-app.tsx b/src/wordpress-wasm/example-app.tsx index b936080ef2..330de25424 100644 --- a/src/wordpress-wasm/example-app.tsx +++ b/src/wordpress-wasm/example-app.tsx @@ -262,7 +262,7 @@ class ProgressObserver { this.#onProgress = onProgress; } - partialObserver( progressBudget, caption = '') { + partialObserver(progressBudget, caption = '') { const id = ++this.#lastObserverId; this.#observedProgresses[id] = 0; return ({ loaded, total }) => { From fc16731f9332b51f4a5d93262b9213d6a3cddc90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Tue, 6 Dec 2022 14:45:21 +0100 Subject: [PATCH 7/7] Include the installed theme/plugin name in the caption --- src/wordpress-wasm/example-app.tsx | 39 +++++++++++++++++++++++++----- src/wordpress-wasm/wordpress.html | 2 ++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/wordpress-wasm/example-app.tsx b/src/wordpress-wasm/example-app.tsx index 330de25424..e9a4a9e687 100644 --- a/src/wordpress-wasm/example-app.tsx +++ b/src/wordpress-wasm/example-app.tsx @@ -43,7 +43,10 @@ async function main() { const progress = wireProgressBar(); const workerThread = await bootWordPress({ - onWasmDownloadProgress: progress.partialObserver(bootProgress, 'Preparing WordPress...', ), + onWasmDownloadProgress: progress.partialObserver( + bootProgress, + 'Preparing WordPress...' + ), }); const appMode = query.get('mode') === 'seamless' ? 'seamless' : 'browser'; if (appMode === 'browser') { @@ -60,7 +63,12 @@ async function main() { const fetchPluginFile = async (preinstallPlugin) => { const response = cloneResponseMonitorProgress( await fetch('/plugin-proxy?plugin=' + preinstallPlugin), - progress.partialObserver(progressBudgetPerPlugin * 0.66, 'Installing plugins...') + progress.partialObserver( + progressBudgetPerPlugin * 0.66, + `Installing ${zipNameToHumanName( + preinstallPlugin + )} plugin...` + ) ); return new File([await response.blob()], preinstallPlugin); }; @@ -97,7 +105,10 @@ async function main() { // Download the theme file const response = cloneResponseMonitorProgress( await fetch('/plugin-proxy?theme=' + preinstallTheme), - progress.partialObserver(installThemeProgress - 10, `Installing theme...`) + progress.partialObserver( + installThemeProgress - 10, + `Installing ${zipNameToHumanName(preinstallTheme)} theme...` + ) ); const themeFile = new File([await response.blob()], preinstallTheme); @@ -215,7 +226,7 @@ function wireProgressBar() { infiniteWrapper.classList.remove('mode-infinite'); infiniteWrapper.classList.add('mode-finite'); } - if (caption && caption.length) { + if (caption && caption.length) { const captionElement = document.querySelector( '.progress-bar-overlay-caption' ) as HTMLElement; @@ -256,7 +267,11 @@ const enum ProgressType { class ProgressObserver { #observedProgresses: Record = {}; #lastObserverId = 0; - #onProgress: (progress: number, mode: ProgressType, caption?: string) => void; + #onProgress: ( + progress: number, + mode: ProgressType, + caption?: string + ) => void; constructor(onProgress) { this.#onProgress = onProgress; @@ -267,7 +282,11 @@ class ProgressObserver { this.#observedProgresses[id] = 0; return ({ loaded, total }) => { this.#observedProgresses[id] = (loaded / total) * progressBudget; - this.#onProgress(this.totalProgress, ProgressType.REAL_TIME, caption); + this.#onProgress( + this.totalProgress, + ProgressType.REAL_TIME, + caption + ); }; } @@ -285,4 +304,12 @@ class ProgressObserver { } } +function zipNameToHumanName(zipName) { + const mixedCaseName = zipName.split('.').shift()!.replace('-', ' '); + return ( + mixedCaseName.charAt(0).toUpperCase() + + mixedCaseName.slice(1).toLowerCase() + ); +} + main(); diff --git a/src/wordpress-wasm/wordpress.html b/src/wordpress-wasm/wordpress.html index 22d0aa62a2..9befc1001e 100644 --- a/src/wordpress-wasm/wordpress.html +++ b/src/wordpress-wasm/wordpress.html @@ -285,6 +285,8 @@ .progress-bar-overlay-caption { font-weight: 400; + font-family: -apple-system, BlinkMacSystemFont, sans-serif; + font-size: 1.1rem; } .ide-panel {