1.23.0
An application can be packed into one phar and booted read-only. Compiler::phar() packs what a compile
just produced, and the archive writes only under the directory named at the build and at the boot.
Added
Compiler::phar()— pack the compiled tree intovar/build/{context}.phar, on both thenew Compiler(...)andCompiler::fromInjector(...)shapes (#426)- The compile marker is a readable record (
.bear-compile.json: app, context, tmpDir, writeDir), and the pack reads the write directory from it instead of taking it again (#426) - The pack reads imports from the compiled
ImportAppConfigand stops the build when any application was never compiled, writes into the archive, or writes outside the write directory the host was compiled for (#426) - A boot that cannot rewrite its scripts - an archive, an immutable image - throws
CompiledForAnotherWriteDirExceptionnaming both write directories, instead of failing on the write (#426) - No file directly under the application root ships in an archive -
composer.json,autoload.php,preload.php,env.json,.envand the rest are the project's, not the artifact's - and no.env*file ships wherever it sits (#426) - The pack refuses an entry the archive does not carry, and refuses an output it could not remove first (#426)
Injector::getOverrideInstance()takes a$writeDir, likegetInstance(): an override injector in a read-only tree needs one too (#426)
Changed
ImportApp::appDir()replaces the$appDirproperty: the compiled container holds the object, and the build-time path is not the runtime one (#426)- The compile marker filename is
.bear-compile.json; a 1.22 marker reads as absent, so recompile after upgrading (#426) - Requires
ray/compiler ^1.16, whoseCompiledInjectoraccepts aphar://script directory (#426) - Requires
bear/app-meta ^1.12, which owns the write-directory layout:Meta::create()places an application and the Meta carries the base it was placed under (#426)
Removed
Injector\AppDirs(1.22):Injector\CompiledScripts::dir()answers where compiled scripts live,Meta::create()places an application, and$meta->writeDircarries the base it was placed under (#426)InvalidWriteDirException(1.22): a relative write directory is refused byBEAR\AppMeta\Exception\WriteDirNotAbsoluteException(#426)
Fixed
- A stream-URI
appDirsuch asphar://app.pharwithout a write directory throwsWriteDirRequiredException, instead of reporting the tmp directory it cannot create inside the artifact (#426)
Additional Notes
This section was added later (2026-08-17). Everything in this release is #426.
Upgrading from 1.22
.bear-compile.json, so a 1.22 .compile-marker reads as absent. A writable tree recompiles itself on the first boot; a read-only one cannot, and throws CompiledForAnotherWriteDirException.
composer update bear/package
php bin/compile.php prod-appThe names that went with it are in Removed above; all four were added in 1.22. Injector::getInstance() and Compiler are unchanged, so an application that never named them is unaffected.
Packing an archive
// bin/compile.php
$compiler = new Compiler('MyVendor\MyProject', $context, dirname(__DIR__), getenv('APP_WRITE_DIR') ?: null);
$code = $compiler();
exit($code === 0 ? $compiler->phar() : $code);APP_WRITE_DIR=/var/run/myapp php bin/compile.php
# Phar: /app/var/build/prod-cli-hal-app.phar (31.8MB, 7678 files)
# Writes: /var/run/myapp
APP_WRITE_DIR=/var/run/myapp php var/build/prod-cli-hal-app.phar get /index
# 200 OKThe archive can be moved, renamed, and its build tree deleted. The write directory is the one thing that must be the same absolute path at the build and at the boot - when they differ, the boot names both.