Development¶
Contributing to the playground¶
The smallest safe workflow for most contributor changes is:
- identify the layer you need to touch
- make a targeted change
- run the narrowest relevant validation commands
- manually verify first boot, reload behavior, or UI changes when applicable
- update docs if the behavior or contributor workflow changed
Development commands¶
make deps
make prepare
make bundle
make serve
Common targeted syntax checks:
node --check src/shell/main.js
node --check sw.js
node --check php-worker.js
node --check src/runtime/bootstrap.js
node --check src/runtime/vfs.js
Documentation maintenance¶
Documentation source lives in docs/, and the site configuration lives in mkdocs.yml.
Preview docs locally¶
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements-docs.txt
mkdocs serve
Build docs locally¶
mkdocs build --strict
Use strict mode before opening a pull request so broken internal links or configuration issues are caught early.
GitHub Pages publishing¶
The Pages workflow in .github/workflows/pages.yml now publishes two things together:
- the main static playground app at the repository root
- the generated documentation site under
/docs/
The workflow:
- checks out the repository
- installs Node, PHP, and Python dependencies
- prepares runtime assets and builds the Omeka bundle
- builds the MkDocs site into the deploy artifact's
docs/directory - uploads the assembled artifact to GitHub Pages
This keeps the public URLs stable:
- app: https://ateeducacion.github.io/omeka-s-playground/
- docs: https://ateeducacion.github.io/omeka-s-playground/docs/
Documentation expectations for contributors¶
When you touch these areas, update the docs in the same pull request:
- runtime lifecycle or storage model
blueprint.jsonsemantics- local development or deployment workflows
- navigation or externally visible user workflows
Good docs changes in this repository should:
- describe the actual implementation, not generic Playground theory
- include concrete file paths
- explain both the feature and the safest way to maintain it
PHP CLI spawn handler¶
The playground registers a spawn handler on the @php-wasm runtime so
that PHP's proc_open() / exec() calls are intercepted in JavaScript and
handled in-process rather than silently failing.
What works¶
- PHP CLI commands — commands whose binary is
phpor an absolute path ending in/phpare executed in the same WASM runtime viaphp.run(). This enables Omeka'sOmeka\Stdlib\Cli::execute()to run PHP scripts such as the job dispatcher (application/omeka jobs:dispatch). - Inline code via
php -r "..."is also supported. - stdout / stderr / exit code are captured and propagated back to the calling PHP code.
What is still limited¶
| Area | Status | Reason |
|---|---|---|
| Background jobs | Synchronous | The dispatch strategy remains Synchronous. The spawn handler runs PHP scripts in the same single-threaded WASM instance, so true async dispatch is not possible. |
ImageMagick (convert) |
Blocked | No WASM ImageMagick binary is available. Thumbnails use GD or fall back to no-thumbnail mode. |
| Arbitrary binaries | Blocked | Only PHP binaries from the allowlist are permitted. Unknown commands receive exit code 127. |
| Recursive spawns | Depth-limited | A re-entrant guard (MAX_SPAWN_DEPTH = 3) prevents infinite recursion when a spawned PHP script itself calls exec(). |
| True parallelism | Not supported | All spawned commands execute synchronously in the same WASM instance. There is no subprocess isolation. |
Security model¶
The spawn handler uses a binary allowlist (PHP_BIN_ALLOWLIST in
src/runtime/spawn-handler.js). Commands not on the list are rejected
with a descriptive stderr message and exit code 127. The ImageMagick
guard in the Omeka\Cli override (src/runtime/bootstrap.js) is
checked first, before the command reaches exec().
Key files¶
src/runtime/spawn-handler.js— handler registration, allowlist, in-process executionsrc/runtime/php-loader.js— callsregisterSpawnHandler()after PHP initsrc/runtime/bootstrap.js—Omeka\Clioverride delegates PHP commands toexec()tests/spawn-handler.test.mjs— unit tests for allowlist and spawn logic