diff --git a/package.json b/package.json index 2ae4c8ecf..699b6105d 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,7 @@ "test:phpunit-structured-evidence": "tsx tests/phpunit-structured-evidence.test.ts", "test:phpunit-runtime-rejection": "tsx tests/phpunit-runtime-rejection.test.ts", "test:playground-worker-runtime-rejection": "tsx tests/playground-worker-runtime-rejection.test.ts", + "test:playground-node-dns-integration": "node --import tsx tests/playground-node-dns.integration.test.ts", "test:php-wasm-extension-manifests": "tsx tests/php-wasm-extension-manifests.test.ts", "test:browser-task-builder": "tsx tests/browser-task-builder.test.ts", "test:browser-runtime-generic-invoker": "tsx tests/browser-runtime-generic-invoker.test.ts", diff --git a/patches/@php-wasm+node+3.1.46.patch b/patches/@php-wasm+node+3.1.46.patch new file mode 100644 index 000000000..c1514a4b8 --- /dev/null +++ b/patches/@php-wasm+node+3.1.46.patch @@ -0,0 +1,343 @@ +diff --git a/node_modules/@php-wasm/node/index.cjs b/node_modules/@php-wasm/node/index.cjs +index ee94a10..50832b3 100644 +--- a/node_modules/@php-wasm/node/index.cjs ++++ b/node_modules/@php-wasm/node/index.cjs +@@ -28,18 +28,19 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge + var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + + // packages/php-wasm/node/src/index.ts +-var src_exports = {}; +-__export(src_exports, { ++var index_exports = {}; ++__export(index_exports, { + FileLockManagerForPosix: () => FileLockManagerForPosix, + FileLockManagerForWindows: () => FileLockManagerForWindows, + bindUserSpace: () => bindUserSpace, + createNodeFsMountHandler: () => createNodeFsMountHandler, + getPHPLoaderModule: () => getPHPLoaderModule, + loadNodeRuntime: () => loadNodeRuntime, ++ serializeDnsRecords: () => serializeDnsRecords, + useHostFilesystem: () => useHostFilesystem, + withNetworking: () => withNetworking + }); +-module.exports = __toCommonJS(src_exports); ++module.exports = __toCommonJS(index_exports); + + // packages/php-wasm/node/src/lib/get-php-loader-module.ts + var import_universal = require("@php-wasm/universal"); +@@ -433,6 +434,23 @@ var import_universal9 = require("@php-wasm/universal"); + + // packages/php-wasm/node/src/lib/wasm-user-space.ts + var import_promises = require("dns/promises"); ++function serializeDnsRecords(type, results) { ++ const encode = (value) => Buffer.from(String(value)).toString("hex"); ++ const record = (kind, ...fields) => [kind, ...fields.map(encode)].join(" "); ++ if (["A", "AAAA", "CNAME", "NS", "PTR"].includes(type)) ++ return results.map((value) => record(type, value)).join("\n"); ++ if (type === "CAA") ++ return results.flatMap(({ critical, issue, issuewild, iodef }) => [ ++ ...issue ? [record("CAA", critical, "issue", issue)] : [], ++ ...issuewild ? [record("CAA", critical, "issuewild", issuewild)] : [], ++ ...iodef ? [record("CAA", critical, "iodef", iodef)] : [] ++ ]).join("\n"); ++ if (type === "MX") ++ return results.map(({ priority, exchange }) => record("MX", priority, exchange)).join("\n"); ++ if (type === "TXT") ++ return results.map((entries) => record("TXT", entries.join(""), ...entries)).join("\n"); ++ return ""; ++} + function bindUserSpace({ fileLockManager }, { + pid, + memory, +@@ -818,6 +836,7 @@ function bindUserSpace({ fileLockManager }, { + return -EINVAL; + } + } ++ // TODO: Double check waiting for lock. PHP 8.5 has been observed waiting for a lock. + case F_SETLKW: + case F_SETLK: { + js_wasm_trace("fcntl(%d, F_SETLK)", fd); +@@ -1128,12 +1147,97 @@ function bindUserSpace({ fileLockManager }, { + }); + return address; + } ++ async function dnsResolve(hostname, type) { ++ const encode = (value) => Buffer.from(String(value)).toString("hex"); ++ const record = (kind, ...fields) => [kind, ...fields.map(encode)].join(" "); ++ try { ++ switch (type) { ++ case "A": ++ return serializeDnsRecords(type, await (0, import_promises.resolve4)(hostname)); ++ case "AAAA": ++ return serializeDnsRecords(type, await (0, import_promises.resolve6)(hostname)); ++ case "CAA": ++ return serializeDnsRecords( ++ type, ++ await (0, import_promises.resolveCaa)(hostname) ++ ); ++ case "CNAME": ++ return serializeDnsRecords( ++ type, ++ await (0, import_promises.resolveCname)(hostname) ++ ); ++ case "MX": ++ return serializeDnsRecords(type, await (0, import_promises.resolveMx)(hostname)); ++ case "NAPTR": ++ return (await (0, import_promises.resolveNaptr)(hostname)).map( ++ ({ ++ flags, ++ service, ++ regexp, ++ replacement, ++ order, ++ preference ++ }) => record( ++ "NAPTR", ++ order, ++ preference, ++ flags, ++ service, ++ regexp, ++ replacement ++ ) ++ ).join("\n"); ++ case "NS": ++ return serializeDnsRecords(type, await (0, import_promises.resolveNs)(hostname)); ++ case "PTR": ++ return serializeDnsRecords( ++ type, ++ await (0, import_promises.resolvePtr)(hostname) ++ ); ++ case "SOA": { ++ const { ++ nsname, ++ hostmaster, ++ serial, ++ refresh, ++ retry, ++ expire, ++ minttl ++ } = await (0, import_promises.resolveSoa)(hostname); ++ return record( ++ "SOA", ++ nsname, ++ hostmaster, ++ serial, ++ refresh, ++ retry, ++ expire, ++ minttl ++ ); ++ } ++ case "SRV": ++ return (await (0, import_promises.resolveSrv)(hostname)).map( ++ ({ priority, weight, port, name }) => record("SRV", priority, weight, port, name) ++ ).join("\n"); ++ case "TXT": ++ return serializeDnsRecords( ++ type, ++ await (0, import_promises.resolveTxt)(hostname) ++ ); ++ default: ++ return ""; ++ } ++ } catch { ++ return ""; ++ } ++ } + return { + fcntl64, + flock, + fd_close, + js_release_file_locks, +- gethostbyname ++ gethostbyname, ++ dnsResolve + }; + } + +@@ -1875,7 +1979,7 @@ function resolveXdebugExtraFiles(version, xdebugOptions) { + var import_util = require("@php-wasm/util"); + var import_os = require("os"); + +-// node_modules/wasm-feature-detect/dist/esm/index.js ++// ../../workspace/node_modules/wasm-feature-detect/dist/esm/index.js + var jspi = () => (async () => "Suspending" in WebAssembly)(); + + // packages/php-wasm/node/src/lib/load-runtime.ts +@@ -2142,6 +2246,7 @@ function statPathFollowSymlinks(path3) { + createNodeFsMountHandler, + getPHPLoaderModule, + loadNodeRuntime, ++ serializeDnsRecords, + useHostFilesystem, + withNetworking + }); +diff --git a/node_modules/@php-wasm/node/index.js b/node_modules/@php-wasm/node/index.js +index 9f13b82..549404e 100644 +--- a/node_modules/@php-wasm/node/index.js ++++ b/node_modules/@php-wasm/node/index.js +@@ -1,8 +1,7 @@ + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { +- if (typeof require !== "undefined") +- return require.apply(this, arguments); ++ if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + +@@ -407,7 +406,37 @@ import { + } from "@php-wasm/universal"; + + // packages/php-wasm/node/src/lib/wasm-user-space.ts +-import { lookup as lookup2 } from "dns/promises"; ++import { ++ lookup as lookup2, ++ resolve4, ++ resolve6, ++ resolveCaa, ++ resolveCname, ++ resolveMx, ++ resolveNaptr, ++ resolveNs, ++ resolvePtr, ++ resolveSoa, ++ resolveSrv, ++ resolveTxt ++} from "dns/promises"; ++function serializeDnsRecords(type, results) { ++ const encode = (value) => Buffer.from(String(value)).toString("hex"); ++ const record = (kind, ...fields) => [kind, ...fields.map(encode)].join(" "); ++ if (["A", "AAAA", "CNAME", "NS", "PTR"].includes(type)) ++ return results.map((value) => record(type, value)).join("\n"); ++ if (type === "CAA") ++ return results.flatMap(({ critical, issue, issuewild, iodef }) => [ ++ ...issue ? [record("CAA", critical, "issue", issue)] : [], ++ ...issuewild ? [record("CAA", critical, "issuewild", issuewild)] : [], ++ ...iodef ? [record("CAA", critical, "iodef", iodef)] : [] ++ ]).join("\n"); ++ if (type === "MX") ++ return results.map(({ priority, exchange }) => record("MX", priority, exchange)).join("\n"); ++ if (type === "TXT") ++ return results.map((entries) => record("TXT", entries.join(""), ...entries)).join("\n"); ++ return ""; ++} + function bindUserSpace({ fileLockManager }, { + pid, + memory, +@@ -793,6 +822,7 @@ function bindUserSpace({ fileLockManager }, { + return -EINVAL; + } + } ++ // TODO: Double check waiting for lock. PHP 8.5 has been observed waiting for a lock. + case F_SETLKW: + case F_SETLK: { + js_wasm_trace("fcntl(%d, F_SETLK)", fd); +@@ -1103,12 +1133,97 @@ function bindUserSpace({ fileLockManager }, { + }); + return address; + } ++ async function dnsResolve(hostname, type) { ++ const encode = (value) => Buffer.from(String(value)).toString("hex"); ++ const record = (kind, ...fields) => [kind, ...fields.map(encode)].join(" "); ++ try { ++ switch (type) { ++ case "A": ++ return serializeDnsRecords(type, await resolve4(hostname)); ++ case "AAAA": ++ return serializeDnsRecords(type, await resolve6(hostname)); ++ case "CAA": ++ return serializeDnsRecords( ++ type, ++ await resolveCaa(hostname) ++ ); ++ case "CNAME": ++ return serializeDnsRecords( ++ type, ++ await resolveCname(hostname) ++ ); ++ case "MX": ++ return serializeDnsRecords(type, await resolveMx(hostname)); ++ case "NAPTR": ++ return (await resolveNaptr(hostname)).map( ++ ({ ++ flags, ++ service, ++ regexp, ++ replacement, ++ order, ++ preference ++ }) => record( ++ "NAPTR", ++ order, ++ preference, ++ flags, ++ service, ++ regexp, ++ replacement ++ ) ++ ).join("\n"); ++ case "NS": ++ return serializeDnsRecords(type, await resolveNs(hostname)); ++ case "PTR": ++ return serializeDnsRecords( ++ type, ++ await resolvePtr(hostname) ++ ); ++ case "SOA": { ++ const { ++ nsname, ++ hostmaster, ++ serial, ++ refresh, ++ retry, ++ expire, ++ minttl ++ } = await resolveSoa(hostname); ++ return record( ++ "SOA", ++ nsname, ++ hostmaster, ++ serial, ++ refresh, ++ retry, ++ expire, ++ minttl ++ ); ++ } ++ case "SRV": ++ return (await resolveSrv(hostname)).map( ++ ({ priority, weight, port, name }) => record("SRV", priority, weight, port, name) ++ ).join("\n"); ++ case "TXT": ++ return serializeDnsRecords( ++ type, ++ await resolveTxt(hostname) ++ ); ++ default: ++ return ""; ++ } ++ } catch { ++ return ""; ++ } ++ } + return { + fcntl64, + flock, + fd_close, + js_release_file_locks, +- gethostbyname ++ gethostbyname, ++ dnsResolve + }; + } + +@@ -2124,6 +2239,7 @@ export { + createNodeFsMountHandler, + getPHPLoaderModule, + loadNodeRuntime, ++ serializeDnsRecords, + useHostFilesystem, + withNetworking + }; diff --git a/patches/@php-wasm+node-8-4+3.1.46.patch b/patches/@php-wasm+node-8-4+3.1.46.patch new file mode 100644 index 000000000..9981f8bd6 --- /dev/null +++ b/patches/@php-wasm+node-8-4+3.1.46.patch @@ -0,0 +1,515 @@ +diff --git a/node_modules/@php-wasm/node-8-4/asyncify/php_8_4.js b/node_modules/@php-wasm/node-8-4/asyncify/php_8_4.js +index 37aadcc..c87527c 100644 +--- a/node_modules/@php-wasm/node-8-4/asyncify/php_8_4.js ++++ b/node_modules/@php-wasm/node-8-4/asyncify/php_8_4.js +@@ -13,10 +13,10 @@ const currentDirPath = + typeof __dirname !== 'undefined' + ? __dirname + : path.dirname(fileURLToPath(import.meta.url)); +-const dependencyFilename = path.join(currentDirPath, '8_4_23', 'php_8_4.wasm'); ++const dependencyFilename = path.join(currentDirPath, '8_4_24', 'php_8_4.wasm'); + export { dependencyFilename }; +-export const dependenciesTotalSize = 25411820; +-const phpVersionString = '8.4.23'; ++export const dependenciesTotalSize = 25423547; ++const phpVersionString = '8.4.24'; + export function init(RuntimeName, PHPLoader) { + // The rest of the code comes from the built php.js file and esm-suffix.js + // include: shell.js +@@ -9437,8 +9437,7 @@ export function init(RuntimeName, PHPLoader) { + * Descriptor 0 was not provided, so the child process must observe EOF. + * Closing stdin explicitly lets spawn handlers distinguish that case from + * a valid pipe whose first bytes have not arrived yet. +- */ +- cp.stdin.end(); ++ */ cp.stdin.end(); + } + return ProcInfo.pid; + }); +@@ -9951,7 +9950,7 @@ export function init(RuntimeName, PHPLoader) { + var Asyncify = { + instrumentWasmImports(imports) { + var importPattern = +- /^(invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiii|invoke_iiiiiiiiii|invoke_v|invoke_vi|invoke_vii|invoke_viidii|invoke_viii|invoke_viiii|invoke_viiiii|invoke_viiiiii|invoke_viiiiiii|invoke_viiiiiiiii|invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiiii|invoke_iij|invoke_iiji|invoke_iiij|invoke_iijii|invoke_iijiji|invoke_jii|invoke_jiii|invoke_viijii|invoke_vji|js_open_process|_js_open_process|_asyncjs__js_open_process|js_popen_to_file|_js_popen_to_file|_asyncjs__js_popen_to_file|__syscall_fcntl64|___syscall_fcntl64|_asyncjs___syscall_fcntl64|js_release_file_locks|_js_release_file_locks|_async_js_release_file_locks|js_flock|_js_flock|_async_js_flock|js_fd_read|_js_fd_read|fd_close|_fd_close|_asyncjs__fd_close|close|_close|js_module_onMessage|zend_hash_str_find|_js_module_onMessage|_asyncjs__js_module_onMessage|js_waitpid|_js_waitpid|_asyncjs__js_waitpid|wasm_poll_socket|_wasm_poll_socket|_asyncjs__wasm_poll_socket|_wasm_shutdown|_asyncjs__wasm_shutdown|recv|_recv|setsockopt|_setsockopt|wasm_connect|_wasm_connect|__asyncjs__.*)$/; ++ /^(invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiii|invoke_iiiiiiiiii|invoke_v|invoke_vi|invoke_vii|invoke_viidii|invoke_viii|invoke_viiii|invoke_viiiii|invoke_viiiiii|invoke_viiiiiii|invoke_viiiiiiiii|invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiiii|invoke_iij|invoke_iiji|invoke_iiij|invoke_iijii|invoke_iijiji|invoke_jii|invoke_jiii|invoke_viijii|invoke_vji|js_open_process|_js_open_process|_asyncjs__js_open_process|js_popen_to_file|_js_popen_to_file|_asyncjs__js_popen_to_file|__syscall_fcntl64|___syscall_fcntl64|_asyncjs___syscall_fcntl64|js_release_file_locks|_js_release_file_locks|_async_js_release_file_locks|js_flock|_js_flock|_async_js_flock|js_fd_read|_js_fd_read|fd_close|_fd_close|_asyncjs__fd_close|close|_close|js_module_onMessage|zend_hash_str_find|_js_module_onMessage|_asyncjs__js_module_onMessage|js_waitpid|_js_waitpid|_asyncjs__js_waitpid|wasm_poll_socket|_wasm_poll_socket|_asyncjs__wasm_poll_socket|_wasm_shutdown|_asyncjs__wasm_shutdown|recv|_recv|setsockopt|_setsockopt|wasm_connect|_wasm_connect|wasm_dns_resolve|_wasm_dns_resolve|_asyncjs__wasm_dns_resolve|__asyncjs__.*)$/; + for (let [x, original] of Object.entries(imports)) { + if (typeof original == 'function') { + let isAsyncifyImport = +@@ -10430,6 +10429,27 @@ export function init(RuntimeName, PHPLoader) { + // end include: postlibrary.js + var ASM_CONSTS = {}; + ++ function wasm_dns_resolve(host, type) { ++ if ( ++ typeof Module['userSpace'] === 'undefined' || ++ !Module['userSpace'].dnsResolve ++ ) ++ return 0; ++ return Asyncify.handleSleep((wakeUp) => { ++ Module['userSpace'] ++ .dnsResolve(UTF8ToString(host), UTF8ToString(type)) ++ .then((value) => { ++ const size = lengthBytesUTF8(value) + 1; ++ const result = _malloc(size); ++ stringToUTF8(value, result, size); ++ wakeUp(result); ++ }) ++ .catch(() => wakeUp(0)); ++ }); ++ } ++ ++ wasm_dns_resolve.sig = 'iii'; ++ + function js_popen_to_file(command, mode, exitCodePtr) { + const returnCallback = (resolver) => Asyncify.handleSleep(resolver); + if (!command) return 1; +@@ -12037,110 +12057,110 @@ export function init(RuntimeName, PHPLoader) { + wasmExports['__indirect_function_table']; + } + +- var _core_globals = (Module['_core_globals'] = 15550176); ++ var _core_globals = (Module['_core_globals'] = 15550576); + +- var _php_ini_opened_path = (Module['_php_ini_opened_path'] = 15439056); ++ var _php_ini_opened_path = (Module['_php_ini_opened_path'] = 15439456); + +- var _php_ini_scanned_path = (Module['_php_ini_scanned_path'] = 15439060); ++ var _php_ini_scanned_path = (Module['_php_ini_scanned_path'] = 15439460); + +- var _php_ini_scanned_files = (Module['_php_ini_scanned_files'] = 15439064); ++ var _php_ini_scanned_files = (Module['_php_ini_scanned_files'] = 15439464); + +- var _sapi_module = (Module['_sapi_module'] = 15434232); ++ var _sapi_module = (Module['_sapi_module'] = 15434632); + +- var _sapi_globals = (Module['_sapi_globals'] = 15434376); ++ var _sapi_globals = (Module['_sapi_globals'] = 15434776); + +- var _module_registry = (Module['_module_registry'] = 15552136); ++ var _module_registry = (Module['_module_registry'] = 15552536); + +- var _zend_ce_closure = (Module['_zend_ce_closure'] = 15545788); ++ var _zend_ce_closure = (Module['_zend_ce_closure'] = 15546188); + +- var _compiler_globals = (Module['_compiler_globals'] = 15553688); ++ var _compiler_globals = (Module['_compiler_globals'] = 15554088); + +- var _executor_globals = (Module['_executor_globals'] = 15554104); ++ var _executor_globals = (Module['_executor_globals'] = 15554504); + +- var _zend_compile_file = (Module['_zend_compile_file'] = 15555496); ++ var _zend_compile_file = (Module['_zend_compile_file'] = 15555896); + +- var _zend_ce_exception = (Module['_zend_ce_exception'] = 15551260); ++ var _zend_ce_exception = (Module['_zend_ce_exception'] = 15551660); + +- var _zend_ce_error = (Module['_zend_ce_error'] = 15551376); ++ var _zend_ce_error = (Module['_zend_ce_error'] = 15551776); + + var _zend_throw_exception_hook = (Module['_zend_throw_exception_hook'] = +- 15551252); ++ 15551652); + +- var _zend_ce_throwable = (Module['_zend_ce_throwable'] = 15551256); ++ var _zend_ce_throwable = (Module['_zend_ce_throwable'] = 15551656); + +- var _zend_execute_ex = (Module['_zend_execute_ex'] = 15552516); ++ var _zend_execute_ex = (Module['_zend_execute_ex'] = 15552916); + +- var _zend_execute_internal = (Module['_zend_execute_internal'] = 15552520); ++ var _zend_execute_internal = (Module['_zend_execute_internal'] = 15552920); + +- var _zend_pass_function = (Module['_zend_pass_function'] = 14916368); ++ var _zend_pass_function = (Module['_zend_pass_function'] = 14916352); + +- var _zend_extensions = (Module['_zend_extensions'] = 15551004); ++ var _zend_extensions = (Module['_zend_extensions'] = 15551404); + +- var _gc_collect_cycles = (Module['_gc_collect_cycles'] = 15552512); ++ var _gc_collect_cycles = (Module['_gc_collect_cycles'] = 15552912); + +- var _zend_empty_array = (Module['_zend_empty_array'] = 14931280); ++ var _zend_empty_array = (Module['_zend_empty_array'] = 14931264); + +- var _zend_ce_aggregate = (Module['_zend_ce_aggregate'] = 15433600); ++ var _zend_ce_aggregate = (Module['_zend_ce_aggregate'] = 15434e3); + +- var _zend_ce_iterator = (Module['_zend_ce_iterator'] = 15433604); ++ var _zend_ce_iterator = (Module['_zend_ce_iterator'] = 15434004); + +- var _zend_ce_countable = (Module['_zend_ce_countable'] = 15433616); ++ var _zend_ce_countable = (Module['_zend_ce_countable'] = 15434016); + +- var _std_object_handlers = (Module['_std_object_handlers'] = 14930768); ++ var _std_object_handlers = (Module['_std_object_handlers'] = 14930752); + +- var _zend_empty_string = (Module['_zend_empty_string'] = 15432112); ++ var _zend_empty_string = (Module['_zend_empty_string'] = 15432512); + +- var _zend_known_strings = (Module['_zend_known_strings'] = 15432116); ++ var _zend_known_strings = (Module['_zend_known_strings'] = 15432516); + + var _zend_string_init_interned = (Module['_zend_string_init_interned'] = +- 15432180); ++ 15432580); + +- var _zend_write = (Module['_zend_write'] = 15553604); ++ var _zend_write = (Module['_zend_write'] = 15554004); + +- var _zend_error_cb = (Module['_zend_error_cb'] = 15553608); ++ var _zend_error_cb = (Module['_zend_error_cb'] = 15554008); + +- var _zend_post_startup_cb = (Module['_zend_post_startup_cb'] = 15553576); ++ var _zend_post_startup_cb = (Module['_zend_post_startup_cb'] = 15553976); + + var ___memory_base = (Module['___memory_base'] = 0); + + var ___table_base = (Module['___table_base'] = 1); + +- var _stderr = (Module['_stderr'] = 15425296); ++ var _stderr = (Module['_stderr'] = 15425280); + +- var ___THREW__ = (Module['___THREW__'] = 15903860); ++ var ___THREW__ = (Module['___THREW__'] = 15904260); + +- var ___threwValue = (Module['___threwValue'] = 15903864); ++ var ___threwValue = (Module['___threwValue'] = 15904264); + +- var _stdout = (Module['_stdout'] = 15425600); ++ var _stdout = (Module['_stdout'] = 15425584); + +- var _timezone = (Module['_timezone'] = 15890784); ++ var _timezone = (Module['_timezone'] = 15891184); + +- var _tzname = (Module['_tzname'] = 15890792); ++ var _tzname = (Module['_tzname'] = 15891192); + +- var ___heap_base = 16952528; ++ var ___heap_base = 16952928; + + var __ZNSt3__25ctypeIcE2idE = (Module['__ZNSt3__25ctypeIcE2idE'] = +- 15903940); ++ 15904340); + + var __ZTVN10__cxxabiv120__si_class_type_infoE = (Module[ + '__ZTVN10__cxxabiv120__si_class_type_infoE' +- ] = 15425848); ++ ] = 15425832); + + var __ZTVN10__cxxabiv117__class_type_infoE = (Module[ + '__ZTVN10__cxxabiv117__class_type_infoE' +- ] = 15425808); ++ ] = 15425792); + + var __ZTVN10__cxxabiv121__vmi_class_type_infoE = (Module[ + '__ZTVN10__cxxabiv121__vmi_class_type_infoE' +- ] = 15425900); ++ ] = 15425884); + + var __ZTISt20bad_array_new_length = (Module[ + '__ZTISt20bad_array_new_length' +- ] = 15425972); ++ ] = 15425956); + +- var __ZTVSt12length_error = (Module['__ZTVSt12length_error'] = 15426016); ++ var __ZTVSt12length_error = (Module['__ZTVSt12length_error'] = 15426e3); + +- var __ZTISt12length_error = (Module['__ZTISt12length_error'] = 15426036); ++ var __ZTISt12length_error = (Module['__ZTISt12length_error'] = 15426020); + + var wasmImports = { + /** @export */ __assert_fail: ___assert_fail, +@@ -12295,6 +12315,7 @@ export function init(RuntimeName, PHPLoader) { + /** @export */ strptime: _strptime, + /** @export */ swapcontext: _swapcontext, + /** @export */ wasm_close: _wasm_close, ++ /** @export */ wasm_dns_resolve, + /** @export */ wasm_poll_socket, + /** @export */ wasm_setsockopt: _wasm_setsockopt, + /** @export */ wasm_recv: _wasm_recv, +diff --git a/node_modules/@php-wasm/node-8-4/jspi/php_8_4.js b/node_modules/@php-wasm/node-8-4/jspi/php_8_4.js +index ff2b976..7aaf803 100644 +--- a/node_modules/@php-wasm/node-8-4/jspi/php_8_4.js ++++ b/node_modules/@php-wasm/node-8-4/jspi/php_8_4.js +@@ -13,10 +13,10 @@ const currentDirPath = + typeof __dirname !== 'undefined' + ? __dirname + : path.dirname(fileURLToPath(import.meta.url)); +-const dependencyFilename = path.join(currentDirPath, '8_4_23', 'php_8_4.wasm'); ++const dependencyFilename = path.join(currentDirPath, '8_4_24', 'php_8_4.wasm'); + export { dependencyFilename }; +-export const dependenciesTotalSize = 24758936; +-const phpVersionString = '8.4.23'; ++export const dependenciesTotalSize = 24769329; ++const phpVersionString = '8.4.24'; + export function init(RuntimeName, PHPLoader) { + // The rest of the code comes from the built php.js file and esm-suffix.js + // include: shell.js +@@ -9312,8 +9312,7 @@ export function init(RuntimeName, PHPLoader) { + * Descriptor 0 was not provided, so the child process must observe EOF. + * Closing stdin explicitly lets spawn handlers distinguish that case from + * a valid pipe whose first bytes have not arrived yet. +- */ +- cp.stdin.end(); ++ */ cp.stdin.end(); + } + return ProcInfo.pid; + }); +@@ -9818,7 +9817,7 @@ export function init(RuntimeName, PHPLoader) { + var Asyncify = { + instrumentWasmImports(imports) { + var importPattern = +- /^(js_open_process|js_fd_read|js_waitpid|js_process_status|js_create_input_device|wasm_setsockopt|wasm_shutdown|wasm_close|wasm_recv|wasm_connect|__syscall_fcntl64|js_flock|js_release_file_locks|js_waitpid|invoke_.*|__asyncjs__.*)$/; ++ /^(js_open_process|js_fd_read|js_waitpid|js_process_status|js_create_input_device|wasm_setsockopt|wasm_shutdown|wasm_close|wasm_recv|wasm_connect|wasm_dns_resolve|__syscall_fcntl64|js_flock|js_release_file_locks|js_waitpid|invoke_.*|__asyncjs__.*)$/; + for (let [x, original] of Object.entries(imports)) { + if (typeof original == 'function') { + let isAsyncifyImport = +@@ -10075,6 +10074,26 @@ export function init(RuntimeName, PHPLoader) { + // end include: postlibrary.js + var ASM_CONSTS = {}; + ++ function __asyncjs__wasm_dns_resolve(host, type) { ++ return Asyncify.handleAsync(async () => { ++ if ( ++ typeof Module['userSpace'] === 'undefined' || ++ !Module['userSpace'].dnsResolve ++ ) ++ return 0; ++ const value = await Module['userSpace'].dnsResolve( ++ UTF8ToString(host), ++ UTF8ToString(type) ++ ); ++ const size = lengthBytesUTF8(value) + 1; ++ const result = _malloc(size); ++ stringToUTF8(value, result, size); ++ return result; ++ }); ++ } ++ ++ __asyncjs__wasm_dns_resolve.sig = 'iii'; ++ + function __asyncjs__js_popen_to_file(command, mode, exitCodePtr) { + return Asyncify.handleAsync(async () => { + const returnCallback = (resolver) => new Promise(resolver); +@@ -11875,158 +11894,159 @@ export function init(RuntimeName, PHPLoader) { + } + + var _spl_ce_RuntimeException = (Module['_spl_ce_RuntimeException'] = +- 15540476); ++ 15540588); + +- var _file_globals = (Module['_file_globals'] = 15551848); ++ var _file_globals = (Module['_file_globals'] = 15551960); + +- var _core_globals = (Module['_core_globals'] = 15551376); ++ var _core_globals = (Module['_core_globals'] = 15551488); + +- var _php_ini_opened_path = (Module['_php_ini_opened_path'] = 15440256); ++ var _php_ini_opened_path = (Module['_php_ini_opened_path'] = 15440368); + +- var _php_ini_scanned_path = (Module['_php_ini_scanned_path'] = 15440260); ++ var _php_ini_scanned_path = (Module['_php_ini_scanned_path'] = 15440372); + +- var _php_ini_scanned_files = (Module['_php_ini_scanned_files'] = 15440264); ++ var _php_ini_scanned_files = (Module['_php_ini_scanned_files'] = 15440376); + +- var _sapi_module = (Module['_sapi_module'] = 15435432); ++ var _sapi_module = (Module['_sapi_module'] = 15435544); + +- var _sapi_globals = (Module['_sapi_globals'] = 15435576); ++ var _sapi_globals = (Module['_sapi_globals'] = 15435688); + +- var _module_registry = (Module['_module_registry'] = 15553336); ++ var _module_registry = (Module['_module_registry'] = 15553448); + +- var _zend_ce_closure = (Module['_zend_ce_closure'] = 15546988); ++ var _zend_ce_closure = (Module['_zend_ce_closure'] = 15547100); + +- var _compiler_globals = (Module['_compiler_globals'] = 15554888); ++ var _compiler_globals = (Module['_compiler_globals'] = 15555e3); + +- var _executor_globals = (Module['_executor_globals'] = 15555304); ++ var _executor_globals = (Module['_executor_globals'] = 15555416); + +- var _zend_compile_file = (Module['_zend_compile_file'] = 15556696); ++ var _zend_compile_file = (Module['_zend_compile_file'] = 15556808); + +- var _zend_compile_string = (Module['_zend_compile_string'] = 15556700); ++ var _zend_compile_string = (Module['_zend_compile_string'] = 15556812); + +- var _zend_ce_unit_enum = (Module['_zend_ce_unit_enum'] = 15434924); ++ var _zend_ce_unit_enum = (Module['_zend_ce_unit_enum'] = 15435036); + +- var _zend_ce_backed_enum = (Module['_zend_ce_backed_enum'] = 15434928); ++ var _zend_ce_backed_enum = (Module['_zend_ce_backed_enum'] = 15435040); + +- var _zend_ce_exception = (Module['_zend_ce_exception'] = 15552460); ++ var _zend_ce_exception = (Module['_zend_ce_exception'] = 15552572); + +- var _zend_ce_error = (Module['_zend_ce_error'] = 15552576); ++ var _zend_ce_error = (Module['_zend_ce_error'] = 15552688); + + var _zend_throw_exception_hook = (Module['_zend_throw_exception_hook'] = +- 15552452); ++ 15552564); + +- var _zend_ce_throwable = (Module['_zend_ce_throwable'] = 15552456); ++ var _zend_ce_throwable = (Module['_zend_ce_throwable'] = 15552568); + + var _zend_ce_division_by_zero_error = (Module[ + '_zend_ce_division_by_zero_error' +- ] = 15552588); ++ ] = 15552700); + + var _zend_ce_unhandled_match_error = (Module[ + '_zend_ce_unhandled_match_error' +- ] = 15552592); ++ ] = 15552704); + +- var _zend_execute_ex = (Module['_zend_execute_ex'] = 15553716); ++ var _zend_execute_ex = (Module['_zend_execute_ex'] = 15553828); + +- var _zend_execute_internal = (Module['_zend_execute_internal'] = 15553720); ++ var _zend_execute_internal = (Module['_zend_execute_internal'] = 15553832); + +- var _empty_fcall_info = (Module['_empty_fcall_info'] = 11244064); ++ var _empty_fcall_info = (Module['_empty_fcall_info'] = 11243680); + + var _empty_fcall_info_cache = (Module['_empty_fcall_info_cache'] = +- 11244112); ++ 11243728); + +- var _zend_pass_function = (Module['_zend_pass_function'] = 14917024); ++ var _zend_pass_function = (Module['_zend_pass_function'] = 14916752); + +- var _zend_extensions = (Module['_zend_extensions'] = 15552204); ++ var _zend_extensions = (Module['_zend_extensions'] = 15552316); + +- var _gc_collect_cycles = (Module['_gc_collect_cycles'] = 15553712); ++ var _gc_collect_cycles = (Module['_gc_collect_cycles'] = 15553824); + +- var _zend_empty_array = (Module['_zend_empty_array'] = 14931936); ++ var _zend_empty_array = (Module['_zend_empty_array'] = 14931664); + +- var _zend_ce_traversable = (Module['_zend_ce_traversable'] = 15434796); ++ var _zend_ce_traversable = (Module['_zend_ce_traversable'] = 15434908); + +- var _zend_ce_aggregate = (Module['_zend_ce_aggregate'] = 15434800); ++ var _zend_ce_aggregate = (Module['_zend_ce_aggregate'] = 15434912); + +- var _zend_ce_iterator = (Module['_zend_ce_iterator'] = 15434804); ++ var _zend_ce_iterator = (Module['_zend_ce_iterator'] = 15434916); + +- var _zend_ce_serializable = (Module['_zend_ce_serializable'] = 15434808); ++ var _zend_ce_serializable = (Module['_zend_ce_serializable'] = 15434920); + +- var _zend_ce_arrayaccess = (Module['_zend_ce_arrayaccess'] = 15434812); ++ var _zend_ce_arrayaccess = (Module['_zend_ce_arrayaccess'] = 15434924); + +- var _zend_ce_countable = (Module['_zend_ce_countable'] = 15434816); ++ var _zend_ce_countable = (Module['_zend_ce_countable'] = 15434928); + +- var _zend_ce_stringable = (Module['_zend_ce_stringable'] = 15434820); ++ var _zend_ce_stringable = (Module['_zend_ce_stringable'] = 15434932); + +- var _std_object_handlers = (Module['_std_object_handlers'] = 14931424); ++ var _std_object_handlers = (Module['_std_object_handlers'] = 14931152); + +- var _zend_empty_string = (Module['_zend_empty_string'] = 15433312); ++ var _zend_empty_string = (Module['_zend_empty_string'] = 15433424); + +- var _zend_known_strings = (Module['_zend_known_strings'] = 15433316); ++ var _zend_known_strings = (Module['_zend_known_strings'] = 15433428); + + var _zend_string_init_interned = (Module['_zend_string_init_interned'] = +- 15433380); ++ 15433492); + +- var _zend_one_char_string = (Module['_zend_one_char_string'] = 15433392); ++ var _zend_one_char_string = (Module['_zend_one_char_string'] = 15433504); + +- var _zend_write = (Module['_zend_write'] = 15554804); ++ var _zend_write = (Module['_zend_write'] = 15554916); + +- var _zend_error_cb = (Module['_zend_error_cb'] = 15554808); ++ var _zend_error_cb = (Module['_zend_error_cb'] = 15554920); + +- var _zend_post_startup_cb = (Module['_zend_post_startup_cb'] = 15554776); ++ var _zend_post_startup_cb = (Module['_zend_post_startup_cb'] = 15554888); + + var ___memory_base = (Module['___memory_base'] = 0); + + var ___table_base = (Module['___table_base'] = 1); + +- var _stderr = (Module['_stderr'] = 15426192); ++ var _stderr = (Module['_stderr'] = 15425920); + +- var _stdout = (Module['_stdout'] = 15426496); ++ var _stdout = (Module['_stdout'] = 15426224); + +- var _stdin = (Module['_stdin'] = 15426344); ++ var _stdin = (Module['_stdin'] = 15426072); + + var __playground_zend_side_module_data_exports = (Module[ + '__playground_zend_side_module_data_exports' +- ] = 14932752); ++ ] = 14932480); + + var __playground_zend_side_module_function_exports = (Module[ + '__playground_zend_side_module_function_exports' +- ] = 14932848); ++ ] = 14932576); + +- var _z_errmsg = (Module['_z_errmsg'] = 14933840); ++ var _z_errmsg = (Module['_z_errmsg'] = 14933568); + +- var _timezone = (Module['_timezone'] = 15891984); ++ var _timezone = (Module['_timezone'] = 15892096); + +- var _tzname = (Module['_tzname'] = 15891992); ++ var _tzname = (Module['_tzname'] = 15892104); + +- var ___heap_base = 16954256; ++ var ___heap_base = 16954368; + + var __ZNSt3__25ctypeIcE2idE = (Module['__ZNSt3__25ctypeIcE2idE'] = +- 15905660); ++ 15905772); + +- var __ZSt7nothrow = (Module['__ZSt7nothrow'] = 13694442); ++ var __ZSt7nothrow = (Module['__ZSt7nothrow'] = 13693930); + + var __ZTVN10__cxxabiv120__si_class_type_infoE = (Module[ + '__ZTVN10__cxxabiv120__si_class_type_infoE' +- ] = 15426784); ++ ] = 15426512); + + var __ZTVN10__cxxabiv117__class_type_infoE = (Module[ + '__ZTVN10__cxxabiv117__class_type_infoE' +- ] = 15426744); ++ ] = 15426472); + + var __ZTVN10__cxxabiv121__vmi_class_type_infoE = (Module[ + '__ZTVN10__cxxabiv121__vmi_class_type_infoE' +- ] = 15426836); ++ ] = 15426564); + + var __ZTISt20bad_array_new_length = (Module[ + '__ZTISt20bad_array_new_length' +- ] = 15426956); ++ ] = 15426684); + +- var __ZTVSt12length_error = (Module['__ZTVSt12length_error'] = 15427032); ++ var __ZTVSt12length_error = (Module['__ZTVSt12length_error'] = 15426760); + +- var __ZTISt12length_error = (Module['__ZTISt12length_error'] = 15427052); ++ var __ZTISt12length_error = (Module['__ZTISt12length_error'] = 15426780); + + var wasmImports = { + /** @export */ __assert_fail: ___assert_fail, + /** @export */ __asyncjs__js_module_onMessage, + /** @export */ __asyncjs__js_popen_to_file, ++ /** @export */ __asyncjs__wasm_dns_resolve, + /** @export */ __asyncjs__wasm_poll_socket, + /** @export */ __call_sighandler: ___call_sighandler, + /** @export */ __syscall_accept4: ___syscall_accept4, diff --git a/patches/README.md b/patches/README.md index 694b2cb90..22d31da1d 100644 --- a/patches/README.md +++ b/patches/README.md @@ -17,3 +17,24 @@ the released CLI's log-only behavior. Without this narrow terminalization, a poisoned PHP-WASM worker remains alive and leaves the parent request pending until the recipe timeout. Remove the patch after the Playground CLI ships the same worker terminalization behavior. + +`@php-wasm+node+3.1.46.patch`, `@php-wasm+node-8-4+3.1.46.patch`, and the +compressed WASM files in +`playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/` are the Node +DNS resolver bridge and rebuilt PHP 8.4 artifacts from WordPress Playground PR +[#4172](https://github.com/WordPress/wordpress-playground/pull/4172) at immutable +commit `828a14d84db0048317295443562e82aa94e0be7b`. The lifecycle script verifies +the expanded Asyncify WASM as +`336a287c9e8addf683a42d001640daeedb8be419c3ae95497dcd59401e47ad90` and the +JSPI WASM as +`439bd91ccddfdaba7381bbd915aa17652edb8d50bd7fd2c5c81a25e33cbf8776` +before installing them. The matching loaders are upstream Git blobs +`c87527c4ec9fedfec5541a8107ac6fd7d6f2ec9a` and +`7aaf803af7022b4cc856fad675a8c1ecacb4c1c4`; the Node bundle is built from the +same commit's `packages/php-wasm/node` source. + +This overlay repairs WP Codebox's default programmatic PHP 8.4 runtime only. +Explicit PHP 5.2, 7.4, 8.0, 8.1, 8.2, 8.3, and 8.5 selections still use the +released 3.1.46 artifacts and are not claimed as repaired. Remove both patches, +the compressed artifacts, and the lifecycle materialization after a published +Playground package release contains the same Node bridge and PHP 8.4 artifacts. diff --git a/patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/asyncify-php_8_4.wasm.gz b/patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/asyncify-php_8_4.wasm.gz new file mode 100644 index 000000000..ba636dd58 Binary files /dev/null and b/patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/asyncify-php_8_4.wasm.gz differ diff --git a/patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/jspi-php_8_4.wasm.gz b/patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/jspi-php_8_4.wasm.gz new file mode 100644 index 000000000..b2386f8e3 Binary files /dev/null and b/patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/jspi-php_8_4.wasm.gz differ diff --git a/scripts/apply-development-patches.mjs b/scripts/apply-development-patches.mjs index bc89c7435..7e0413d21 100644 --- a/scripts/apply-development-patches.mjs +++ b/scripts/apply-development-patches.mjs @@ -1,11 +1,36 @@ import { execFileSync } from "node:child_process" -import { existsSync } from "node:fs" -import { resolve } from "node:path" +import { createHash } from "node:crypto" +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs" +import { dirname, resolve } from "node:path" +import { gunzipSync } from "node:zlib" -const patchPackageBin = resolve(import.meta.dirname, "..", "node_modules", "patch-package", "index.js") +const packageRoot = resolve(import.meta.dirname, "..") +const patchPackageBin = resolve(packageRoot, "node_modules", "patch-package", "index.js") if (existsSync(patchPackageBin)) { execFileSync(process.execPath, [patchPackageBin], { stdio: "inherit" }) + for (const overlay of [ + { + source: "patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/asyncify-php_8_4.wasm.gz", + target: "node_modules/@php-wasm/node-8-4/asyncify/8_4_24/php_8_4.wasm", + sha256: "336a287c9e8addf683a42d001640daeedb8be419c3ae95497dcd59401e47ad90", + }, + { + source: "patches/playground-node-dns-828a14d84db0048317295443562e82aa94e0be7b/jspi-php_8_4.wasm.gz", + target: "node_modules/@php-wasm/node-8-4/jspi/8_4_24/php_8_4.wasm", + sha256: "439bd91ccddfdaba7381bbd915aa17652edb8d50bd7fd2c5c81a25e33cbf8776", + }, + ]) { + const source = resolve(packageRoot, overlay.source) + const target = resolve(packageRoot, overlay.target) + const bytes = gunzipSync(readFileSync(source)) + const digest = createHash("sha256").update(bytes).digest("hex") + if (digest !== overlay.sha256) { + throw new Error(`Playground overlay checksum mismatch for ${overlay.source}: ${digest}`) + } + mkdirSync(dirname(target), { recursive: true }) + writeFileSync(target, bytes) + } } else { process.stdout.write("Skipping development patches in the production package.\n") } diff --git a/scripts/package-release-artifact.ts b/scripts/package-release-artifact.ts index 085f74ff5..f1e5de96e 100644 --- a/scripts/package-release-artifact.ts +++ b/scripts/package-release-artifact.ts @@ -48,7 +48,7 @@ try { cwd: packageRoot, maxBuffer: 1024 * 1024 * 20, }) - await execFileAsync(process.execPath, [resolve(repoRoot, "node_modules", "patch-package", "index.js")], { + await execFileAsync(process.execPath, [join(packageRoot, "scripts", "apply-development-patches.mjs")], { cwd: packageRoot, maxBuffer: 1024 * 1024 * 20, }) diff --git a/tests/playground-node-dns.integration.test.ts b/tests/playground-node-dns.integration.test.ts new file mode 100644 index 000000000..93896141f --- /dev/null +++ b/tests/playground-node-dns.integration.test.ts @@ -0,0 +1,58 @@ +import assert from "node:assert/strict" +import { execFile } from "node:child_process" +import { mkdtemp, rm, writeFile } from "node:fs/promises" +import { tmpdir } from "node:os" +import { join, resolve } from "node:path" +import { promisify } from "node:util" + +const execFileAsync = promisify(execFile) +const repositoryRoot = resolve(import.meta.dirname, "..") +const root = await mkdtemp(join(tmpdir(), "wp-codebox-playground-node-dns-")) +const recipePath = join(root, "recipe.json") + +try { + await writeFile(recipePath, `${JSON.stringify({ + schema: "wp-codebox/workspace-recipe/v1", + runtime: { backend: "wordpress-playground", wp: "latest", phpVersion: "8.4", blueprint: { steps: [] } }, + workflow: { + steps: [{ + command: "wordpress.run-php", + args: ["code=" + String.raw`$records = dns_get_record( 'example.com', DNS_A | DNS_AAAA ); +$valid_records = array_values( array_filter( $records, static function ( $record ) { + $address = 'A' === ( $record['type'] ?? '' ) ? ( $record['ip'] ?? '' ) : ( $record['ipv6'] ?? '' ); + return in_array( $record['type'] ?? '', array( 'A', 'AAAA' ), true ) + && false !== filter_var( $address, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ); +} ) ); +echo wp_json_encode( array( + 'php_version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, + 'records' => $valid_records, + 'public_url' => wp_http_validate_url( 'https://example.com/' ), +) );`], + }], + }, + })}\n`) + + const result = await execFileAsync(process.execPath, ["packages/cli/dist/index.js", "recipe-run", "--recipe", recipePath, "--json"], { + cwd: repositoryRoot, + timeout: 300_000, + maxBuffer: 2 * 1024 * 1024, + }) + const output = JSON.parse(result.stdout) as { + executions?: Array<{ command?: string; stdout?: string }> + } + const stdout = output.executions?.find((execution) => execution.command === "wordpress.run-php")?.stdout + assert.ok(stdout, "the real WP Codebox runtime must return PHP output") + const proof = JSON.parse(stdout) as { + php_version?: string + records?: Array<{ type?: string; ip?: string; ipv6?: string }> + public_url?: string | false + } + assert.equal(proof.php_version, "8.4", "the proof must exercise the overlaid default programmatic PHP version") + assert.ok(proof.records && proof.records.length > 0, "dns_get_record() must return at least one public A or AAAA record") + assert.ok(proof.records.every((record) => (record.type === "A" && record.ip) || (record.type === "AAAA" && record.ipv6))) + assert.equal(proof.public_url, "https://example.com/", "WordPress must accept the public target after real DNS resolution") +} finally { + await rm(root, { recursive: true, force: true }) +} + +console.log("playground Node DNS integration passed") diff --git a/tests/release-package-coverage.test.ts b/tests/release-package-coverage.test.ts index de1283d50..d79d7e97b 100644 --- a/tests/release-package-coverage.test.ts +++ b/tests/release-package-coverage.test.ts @@ -105,6 +105,8 @@ try { await lstat(join(packagePath, "package.json")) } + await assertPlaygroundNodeDnsOverlay(root) + const cliEntrypoint = join(root, "packages", "cli", "dist", "index.js") assert.equal((await lstat(cliEntrypoint)).mode & 0o777, 0o755, `${cliEntrypoint} must be executable after extraction`) const { stdout: version } = await execFileAsync(process.execPath, [cliEntrypoint, "--version"]) @@ -205,3 +207,16 @@ async function assertPackagedReadonlyMaterialization(root: string): Promise { + const binaries = [ + ["asyncify", "336a287c9e8addf683a42d001640daeedb8be419c3ae95497dcd59401e47ad90"], + ["jspi", "439bd91ccddfdaba7381bbd915aa17652edb8d50bd7fd2c5c81a25e33cbf8776"], + ] as const + for (const [mode, expected] of binaries) { + const bytes = await readFile(join(root, "node_modules", "@php-wasm", "node-8-4", mode, "8_4_24", "php_8_4.wasm")) + assert.equal(createHash("sha256").update(bytes).digest("hex"), expected, `packaged ${mode} PHP 8.4 DNS WASM changed`) + } + const nodeBundle = await readFile(join(root, "node_modules", "@php-wasm", "node", "index.js"), "utf8") + assert.match(nodeBundle, /async function dnsResolve\(hostname, type\)/, "packaged Node runtime must contain the DNS resolver bridge") +}