@php-wasm/node 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/jspi/php_8_4.js CHANGED
@@ -3,26 +3,12 @@
3
3
  // this code in Node.js as an ES module.
4
4
  import { createRequire } from 'module';
5
5
  const require = createRequire(import.meta.url);
6
- import { fileURLToPath } from 'url';
7
-
8
- /**
9
- * __filename and __dirname are not available in ES modules, so we need to
10
- * polyfill them to ensure the debug command (npx nx debug playground-cli)
11
- * works.
12
- *
13
- * @see https://nodejs.org/api/esm.html#no-__filename-or-__dirname
14
- */
6
+ // Note: The path module is currently needed by code injected by the php-wasm Dockerfile.
15
7
  import path from 'path';
16
- if (typeof __filename === 'undefined') {
17
- var __filename = fileURLToPath(import.meta.url);
18
- }
19
- if (typeof __dirname === 'undefined') {
20
- var __dirname = path.dirname(__filename);
21
- }
22
8
 
23
9
  const dependencyFilename = path.join(__dirname, '8_4_0', 'php_8_4.wasm');
24
10
  export { dependencyFilename };
25
- export const dependenciesTotalSize = 21290902;
11
+ export const dependenciesTotalSize = 21291444;
26
12
  export function init(RuntimeName, PHPLoader) {
27
13
  // The rest of the code comes from the built php.js file and esm-suffix.js
28
14
  // include: shell.js
@@ -7012,6 +6998,44 @@ export function init(RuntimeName, PHPLoader) {
7012
6998
  // The files from the preload directory are preloaded using the
7013
6999
  // auto_prepend_file php.ini directive.
7014
7000
  FS.mkdir('/internal/shared/preload');
7001
+ // Create stdout and stderr devices. We can't just use Emscripten's
7002
+ // default stdout and stderr devices because they stop processing data
7003
+ // on the first null byte. However, when dealing with binary data,
7004
+ // null bytes are valid and common.
7005
+ FS.registerDevice(FS.makedev(64, 0), {
7006
+ open: () => {},
7007
+ close: () => {},
7008
+ read: () => 0,
7009
+ write: (stream, buffer, offset, length, pos) => {
7010
+ const chunk = buffer.subarray(offset, offset + length);
7011
+ PHPWASM.onStdout(chunk);
7012
+ return length;
7013
+ },
7014
+ });
7015
+ FS.mkdev('/internal/stdout', FS.makedev(64, 0));
7016
+ FS.registerDevice(FS.makedev(63, 0), {
7017
+ open: () => {},
7018
+ close: () => {},
7019
+ read: () => 0,
7020
+ write: (stream, buffer, offset, length, pos) => {
7021
+ const chunk = buffer.subarray(offset, offset + length);
7022
+ PHPWASM.onStderr(chunk);
7023
+ return length;
7024
+ },
7025
+ });
7026
+ FS.mkdev('/internal/stderr', FS.makedev(63, 0));
7027
+ FS.registerDevice(FS.makedev(62, 0), {
7028
+ open: () => {},
7029
+ close: () => {},
7030
+ read: () => 0,
7031
+ write: (stream, buffer, offset, length, pos) => {
7032
+ const chunk = buffer.subarray(offset, offset + length);
7033
+ PHPWASM.onHeaders(chunk);
7034
+ return length;
7035
+ },
7036
+ });
7037
+ FS.mkdev('/internal/headers', FS.makedev(62, 0));
7038
+ // Handle events.
7015
7039
  PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE
7016
7040
  ? require('events').EventEmitter
7017
7041
  : class EventEmitter {
@@ -7052,9 +7076,71 @@ export function init(RuntimeName, PHPLoader) {
7052
7076
  }
7053
7077
  }
7054
7078
  };
7079
+ // Clean up the fd -> childProcess mapping when the fd is closed:
7080
+ const originalClose = FS.close;
7081
+ FS.close = function (stream) {
7082
+ originalClose(stream);
7083
+ delete PHPWASM.child_proc_by_fd[stream.fd];
7084
+ };
7055
7085
  PHPWASM.child_proc_by_fd = {};
7056
7086
  PHPWASM.child_proc_by_pid = {};
7057
7087
  PHPWASM.input_devices = {};
7088
+ const originalWrite = TTY.stream_ops.write;
7089
+ TTY.stream_ops.write = function (stream, ...rest) {
7090
+ const retval = originalWrite(stream, ...rest);
7091
+ // Implicit flush since PHP's fflush() doesn't seem to trigger the fsync event
7092
+ // @TODO: Fix this at the wasm level
7093
+ stream.tty.ops.fsync(stream.tty);
7094
+ return retval;
7095
+ };
7096
+ const originalPutChar = TTY.stream_ops.put_char;
7097
+ TTY.stream_ops.put_char = function (tty, val) {
7098
+ /**
7099
+ * Buffer newlines that Emscripten normally ignores.
7100
+ *
7101
+ * Emscripten doesn't do it by default because its default
7102
+ * print function is console.log that implicitly adds a newline. We are overwriting
7103
+ * it with an environment-specific function that outputs exaclty what it was given,
7104
+ * e.g. in Node.js it's process.stdout.write(). Therefore, we need to mak sure
7105
+ * all the newlines make it to the output buffer.
7106
+ */ if (val === 10) tty.output.push(val);
7107
+ return originalPutChar(tty, val);
7108
+ };
7109
+ },
7110
+ onHeaders: function (chunk) {
7111
+ if (Module['onHeaders']) {
7112
+ Module['onHeaders'](chunk);
7113
+ return;
7114
+ }
7115
+ console.log('headers', {
7116
+ chunk,
7117
+ });
7118
+ },
7119
+ onStdout: function (chunk) {
7120
+ if (Module['onStdout']) {
7121
+ Module['onStdout'](chunk);
7122
+ return;
7123
+ }
7124
+ if (ENVIRONMENT_IS_NODE) {
7125
+ process.stdout.write(chunk);
7126
+ } else {
7127
+ console.log('stdout', {
7128
+ chunk,
7129
+ });
7130
+ }
7131
+ },
7132
+ onStderr: function (chunk) {
7133
+ if (Module['onStderr']) {
7134
+ Module['onStderr'](chunk);
7135
+ return;
7136
+ }
7137
+ if (ENVIRONMENT_IS_NODE) {
7138
+ process.stderr.write(chunk);
7139
+ } else {
7140
+ console.warn('stderr', {
7141
+ chunk,
7142
+ });
7143
+ }
7058
7144
  },
7059
7145
  getAllWebSockets: function (sock) {
7060
7146
  const webSockets = new Set();
@@ -7236,7 +7322,7 @@ export function init(RuntimeName, PHPLoader) {
7236
7322
  argsArray.push(UTF8ToString(HEAPU32[charPointer >> 2]));
7237
7323
  }
7238
7324
  }
7239
- const cwdstr = cwdPtr ? UTF8ToString(cwdPtr) : null;
7325
+ const cwdstr = cwdPtr ? UTF8ToString(cwdPtr) : FS.cwd();
7240
7326
  let envObject = null;
7241
7327
  if (envLength) {
7242
7328
  envObject = {};
@@ -7309,6 +7395,15 @@ export function init(RuntimeName, PHPLoader) {
7309
7395
  PHPWASM.child_proc_by_fd[ProcInfo.stderrParentFd] = ProcInfo;
7310
7396
  PHPWASM.child_proc_by_pid[ProcInfo.pid] = ProcInfo;
7311
7397
  cp.on('exit', function (code) {
7398
+ for (const fd of [
7399
+ // The child process exited. Let's clean up its output streams:
7400
+ ProcInfo.stdoutChildFd,
7401
+ ProcInfo.stderrChildFd,
7402
+ ]) {
7403
+ if (FS.streams[fd] && !FS.isClosed(FS.streams[fd])) {
7404
+ FS.close(FS.streams[fd]);
7405
+ }
7406
+ }
7312
7407
  ProcInfo.exitCode = code;
7313
7408
  ProcInfo.exited = true;
7314
7409
  // Emit events for the wasm_poll_socket function.
@@ -7359,12 +7454,52 @@ export function init(RuntimeName, PHPLoader) {
7359
7454
  * listen to the 'exit' event.
7360
7455
  */ try {
7361
7456
  await new Promise((resolve, reject) => {
7362
- cp.on('spawn', resolve);
7363
- cp.on('error', reject);
7457
+ /**
7458
+ * There was no `await` between the `spawnProcess` call
7459
+ * and the `await` below so the process haven't had a chance
7460
+ * to run any of the exit-related callbacks yet.
7461
+ *
7462
+ * Good.
7463
+ *
7464
+ * Let's listen to all the lifecycle events and resolve
7465
+ * the promise when the process starts or immediately crashes.
7466
+ */ let resolved = false;
7467
+ cp.on('spawn', () => {
7468
+ if (resolved) return;
7469
+ resolved = true;
7470
+ resolve();
7471
+ });
7472
+ cp.on('error', (e) => {
7473
+ if (resolved) return;
7474
+ resolved = true;
7475
+ reject(e);
7476
+ });
7477
+ cp.on('exit', function (code) {
7478
+ if (resolved) return;
7479
+ resolved = true;
7480
+ if (code === 0) {
7481
+ resolve();
7482
+ } else {
7483
+ reject(
7484
+ new Error(`Process exited with code ${code}`)
7485
+ );
7486
+ }
7487
+ });
7488
+ /**
7489
+ * If the process haven't even started after 5 seconds, something
7490
+ * is wrong. Perhaps we're missing an event listener, or perhaps
7491
+ * the `spawnProcess` implementation failed to dispatch the relevant
7492
+ * event. Either way, let's crash to avoid blocking the proc_open()
7493
+ * call indefinitely.
7494
+ */ setTimeout(() => {
7495
+ if (resolved) return;
7496
+ resolved = true;
7497
+ reject(new Error('Process timed out'));
7498
+ }, 5e3);
7364
7499
  });
7365
7500
  } catch (e) {
7366
7501
  console.error(e);
7367
- wakeUp(1);
7502
+ wakeUp(ProcInfo.pid);
7368
7503
  return;
7369
7504
  }
7370
7505
  // Now we want to pass data from the STDIN source supplied by PHP
@@ -8078,14 +8213,7 @@ export function init(RuntimeName, PHPLoader) {
8078
8213
  const POLLNVAL = 32;
8079
8214
  return returnCallback((wakeUp) => {
8080
8215
  const polls = [];
8081
- if (socketd in PHPWASM.child_proc_by_fd) {
8082
- const procInfo = PHPWASM.child_proc_by_fd[socketd];
8083
- if (procInfo.exited) {
8084
- wakeUp(0);
8085
- return;
8086
- }
8087
- polls.push(PHPWASM.awaitEvent(procInfo.stdout, 'data'));
8088
- } else if (FS.isSocket(FS.getStream(socketd)?.node.mode)) {
8216
+ if (FS.isSocket(FS.getStream(socketd)?.node.mode)) {
8089
8217
  const sock = getSocketFromFD(socketd);
8090
8218
  if (!sock) {
8091
8219
  wakeUp(0);
@@ -8119,7 +8247,12 @@ export function init(RuntimeName, PHPLoader) {
8119
8247
  polls.push(PHPWASM.awaitConnection(ws));
8120
8248
  lookingFor.add('POLLOUT');
8121
8249
  }
8122
- if (events & POLLHUP) {
8250
+ if (
8251
+ events & POLLHUP ||
8252
+ events & POLLIN ||
8253
+ events & POLLOUT ||
8254
+ events & POLLERR
8255
+ ) {
8123
8256
  polls.push(PHPWASM.awaitClose(ws));
8124
8257
  lookingFor.add('POLLHUP');
8125
8258
  }
@@ -8128,6 +8261,13 @@ export function init(RuntimeName, PHPLoader) {
8128
8261
  lookingFor.add('POLLERR');
8129
8262
  }
8130
8263
  }
8264
+ } else if (socketd in PHPWASM.child_proc_by_fd) {
8265
+ const procInfo = PHPWASM.child_proc_by_fd[socketd];
8266
+ if (procInfo.exited) {
8267
+ wakeUp(0);
8268
+ return;
8269
+ }
8270
+ polls.push(PHPWASM.awaitEvent(procInfo.stdout, 'data'));
8131
8271
  } else {
8132
8272
  setTimeout(function () {
8133
8273
  wakeUp(1);
@@ -8419,13 +8559,6 @@ export function init(RuntimeName, PHPLoader) {
8419
8559
  (___wrap_select = Module['___wrap_select'] =
8420
8560
  wasmExports['__wrap_select'])(a0, a1, a2, a3, a4));
8421
8561
 
8422
- var _wasm_add_cli_arg = (Module['_wasm_add_cli_arg'] = (a0) =>
8423
- (_wasm_add_cli_arg = Module['_wasm_add_cli_arg'] =
8424
- wasmExports['wasm_add_cli_arg'])(a0));
8425
-
8426
- var _run_cli = (Module['_run_cli'] = () =>
8427
- (_run_cli = Module['_run_cli'] = wasmExports['run_cli'])());
8428
-
8429
8562
  var _wasm_set_sapi_name = (Module['_wasm_set_sapi_name'] = (a0) =>
8430
8563
  (_wasm_set_sapi_name = Module['_wasm_set_sapi_name'] =
8431
8564
  wasmExports['wasm_set_sapi_name'])(a0));
@@ -8434,6 +8567,13 @@ export function init(RuntimeName, PHPLoader) {
8434
8567
  (_wasm_set_phpini_path = Module['_wasm_set_phpini_path'] =
8435
8568
  wasmExports['wasm_set_phpini_path'])(a0));
8436
8569
 
8570
+ var _wasm_add_cli_arg = (Module['_wasm_add_cli_arg'] = (a0) =>
8571
+ (_wasm_add_cli_arg = Module['_wasm_add_cli_arg'] =
8572
+ wasmExports['wasm_add_cli_arg'])(a0));
8573
+
8574
+ var _run_cli = (Module['_run_cli'] = () =>
8575
+ (_run_cli = Module['_run_cli'] = wasmExports['run_cli'])());
8576
+
8437
8577
  var _wasm_add_SERVER_entry = (Module['_wasm_add_SERVER_entry'] = (a0, a1) =>
8438
8578
  (_wasm_add_SERVER_entry = Module['_wasm_add_SERVER_entry'] =
8439
8579
  wasmExports['wasm_add_SERVER_entry'])(a0, a1));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/node",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "PHP.wasm for Node.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "license": "GPL-2.0-or-later",
40
40
  "types": "index.d.ts",
41
- "gitHead": "8bff9428d68d3c4a5e84c6cd633e82bf8512a4e3",
41
+ "gitHead": "977f8e90eabb2c8d4eed75677ddd9fb6c13274ae",
42
42
  "engines": {
43
43
  "node": ">=20.18.3",
44
44
  "npm": ">=10.1.0"
@@ -50,12 +50,12 @@
50
50
  "wasm-feature-detect": "1.8.0",
51
51
  "ws": "8.18.1",
52
52
  "yargs": "17.7.2",
53
- "@php-wasm/node-polyfills": "1.1.1",
54
- "@php-wasm/universal": "1.1.1",
55
- "@php-wasm/util": "1.1.1",
56
- "@php-wasm/logger": "1.1.1",
57
- "@wp-playground/common": "1.1.1",
58
- "@wp-playground/wordpress": "1.1.1"
53
+ "@php-wasm/node-polyfills": "1.1.3",
54
+ "@php-wasm/universal": "1.1.3",
55
+ "@php-wasm/util": "1.1.3",
56
+ "@php-wasm/logger": "1.1.3",
57
+ "@wp-playground/common": "1.1.3",
58
+ "@wp-playground/wordpress": "1.1.3"
59
59
  },
60
60
  "overrides": {
61
61
  "rollup": "^4.34.6",