Skip to content
LibxaFrame
Sign In

Changelog

Every change, in order.

Features, fixes and breaking changes for each release, so an upgrade holds no surprises.

13 August 2026
Socket

v0.1.0

latest

A WebSocket server speaking the Pusher protocol, so Laravel Echo connects to it unchanged.

  • New The Pusher wire protocol: connection_established, subscribe and unsubscribe, ping and pong, subscription_succeeded, member_added and member_removed, and client-* events. Laravel Echo, pusher-js and pusher/pusher-php-server all work against it without a shim, which is the entire reason for implementing the protocol rather than inventing one
  • Breaking Built on ReactPHP, not Workerman. Laravel Reverb requires react/socket and ratchet/rfc6455 and no Workerman at all, so this uses the same stack. The previous bespoke protocol and its #[WsRoute] attribute API are gone — nothing that spoke to the old server speaks to this one
  • New Public, private and presence channels, told apart by the name prefix. The prefix is the whole rule, so a channel cannot be left unprotected by forgetting to declare it: naming it private- is the declaration
  • New A presence roster that counts people rather than connections. One user with two tabs is one member, and closing one tab is not leaving — which is the bug every presence implementation has first, and the one users notice
  • Security Signatures cover the socket id, so one minted for a connection cannot be replayed by another. Presence channel_data is verified byte-for-byte as sent rather than re-encoded: re-encoding produces different JSON, so correct signatures start failing, and the natural fix for that is to stop checking
  • Security The publishing API is signed with Pusher's own scheme. The signature covers the request body, so a captured publish cannot be edited and replayed, and carries a timestamp, so it cannot be replayed at all after ten minutes. pusher: and pusher_internal: names are reserved, since a forged member_added would corrupt every roster listening
  • Security A private or presence channel with no rule in routes/channels.php is refused. The alternative allows what nobody has written a rule for, which makes every private channel public until somebody remembers it exists
  • New A heartbeat. Connections that vanish without a FIN — a laptop lid closing, a phone changing network — are pinged and dropped, rather than staying in memory as members of every presence channel they joined
13 August 2026
Framework

v0.11.2

latest

Broadcasting, which had never worked, now does.

  • Fix broadcast(new SomethingHappened) was a fatal error. The helper called BroadcastManager::send(), a method that has never existed on that class, so every documented use of it raised "Call to undefined method" — which means nothing has ever been broadcast through it
  • New BroadcastManager::extend() lets a package register a broadcaster. A driver had to be a create<Name>Driver method on the manager, so the only way to add one was to edit the framework, which made broadcasting the single subsystem a package could not extend and a realtime package the obvious thing that could not be written
  • Improvement The unknown-driver exception lists what is available. "Driver [x] is not supported" without naming the alternatives turns a typo into a hunt through the framework
13 August 2026
LibAdmin

v0.6.0

latest

Roles and permissions are enforced. Until now they were furniture.

  • Security The admin JSON API had no authentication on any route. Thirteen routes, no middleware, so every one answered anybody who asked, from anywhere, with no session — including the audit trail, which holds the full contents of deleted records
  • Security POST /admin/api/login accepted any email and password without checking either, and replied {"token": "your-token-here"}. A client built against it believes it has authenticated somebody
  • Security The roles, permissions, role_user and permission_role tables shipped from the first release and nothing ever read them. Access control was authentication-only: any account that could log in could create, edit and delete every record of every registered resource. Every resource action, the media library and the audit trail check a permission now
  • Security An unknown answer is a denial: missing tables or a failed query means no, not yes. Failing open so as not to lock anyone out turns a broken migration into an unprotected panel, silently. An admin with no roles can do nothing, rather than everything
  • New admin:sync-permissions creates the four default roles, writes the permissions each resource implies, and grants each role what it is defined as having. Re-running only adds, so a permission revoked by hand stays revoked
  • Fix admin:assign-role and admin:revoke-role reported success and wrote nothing — so someone removing access from a departing colleague saw it confirmed and it had not happened. Revoking the last superadmin now needs --force
  • Removed The stubbed JSON API: login, logout, me and the eight resource methods, every one a TODO returning a fabricated success. A token-authenticated CRUD API is a feature to design, not a hole to patch
  • Breaking Existing admin accounts hold no roles, so after upgrading they can sign in and do nothing. Run admin:sync-permissions, then admin:assign-role <email> superadmin. The sync command detects this and prints the exact command, naming your accounts — it does not fix it for you, because granting superadmin to whichever account happens to be first is a privilege escalation performed by a migration
13 August 2026
LibAdmin

v0.5.0

stable

The audit trail records something. Until now it recorded nothing at all.

  • New audit_logs shipped from the first release, with two API endpoints to read it, and nothing ever wrote a row. The panel could create, edit and delete any record in the application and leave nothing behind saying who did it. Logins, failed logins, logouts, and every resource write are recorded now, with the acting admin, the resource and id, the IP and user agent, and the values
  • Security Old values are read before the write, not after. Snapshotting afterwards records the new values twice and loses the only copy of what was there before — and for a delete, the only copy anywhere
  • Security password, remember_token, api_token and secret are stored as [redacted]. An audit row is read by more people than the record it came from
  • Security Failed logins are recorded with the attempted address and no actor. That half is the more interesting one: a run of them against a single address is what a brute-force attempt looks like from inside the panel
  • Improvement Recording never throws. A trail that can take a request down with it is one that gets switched off by the first person it inconveniences
  • New GET /admin/api/audit-logs reads the table for real, filterable by event, resource type and admin, paginated and capped at 100 per page, with the value columns decoded rather than handed back as JSON inside JSON
13 August 2026
LibAdmin

v0.4.0

stable

The panel could not be logged into. Once that was fixed, nothing could be saved.

  • Security No form in the panel carried a CSRF token — login, create, edit, delete and logout all posted without one. With CSRF middleware on, which is the default, every write answered 419 and the panel could not be signed into at all. A test now asserts one token per form across every shipped view
  • Fix admin:make-resource generated a class that fataled the moment it was autoloaded: it declared static string $model against the base class's ?string, and PHP requires a redeclared typed property to match exactly. The command reported success and the file looked correct
  • Fix admin:make-user ignored its password argument, so the documented non-interactive form hung; with --no-interaction the prompt returned null and password_hash() threw a type error. It also claimed to assign --role while writing nothing
  • Fix The resource table rendered every column as plain text, so badges, booleans and images came out as raw values and their view partials were dead code. formatUsing() was stored and never applied, which meant dateTime() did nothing
  • Security The detail page cast the record to an array and printed every key, so a column deliberately left out of columns() was still shown in full one click away. The allow-list holds on every page that renders a record now
  • Fix Records created through the panel had empty timestamps, so anything sorting on created_at — the default resource sort included — treated them as the oldest rows in the table
  • Security A constraint violation rendered the driver's message at 500, naming the table and column. Create and edit ignored flashed errors entirely, so a failed save redirected back to a form that looked untouched
  • Removed The settings routes. index() rendered a view that was never written, so the page answered 500, and update() returned "Settings updated successfully" without writing anything anywhere
13 August 2026
Framework

v0.11.1

stable

Four silent failures, all found by building an application on the framework rather than reading it.

  • New Router::fallback(), a catch-all matched after every other route regardless of when it was registered. A wildcard at the bottom of routes/web.php is matched in registration order, and packages register their routes later, while their providers boot — so the wildcard swallowed every route a package added. Installing an admin panel 404'd the whole panel while both files looked correct
  • Fix Model::where($column, $value) threw "Unsupported SQL operator". Three arguments were forwarded unconditionally, and the builder decides operator-or-value by counting them, so the value was read as an operator. The most common query anyone writes against a model did not work
  • Fix The HTTP kernel is a shared instance. pushMiddleware() is documented as how packages register global middleware, but the kernel was unbound, so resolving it built a fresh object and the push landed on a kernel no request passed through. The middleware simply never ran
  • Fix Published views actually override the package's now. vendor:publish wrote a full copy of every view that the engine then ignored, because only the package's own directory was registered. Editing one had no effect and nothing said why
12 August 2026
Secure

v0.1.1

latest

Accepts framework 0.11.

  • Improvement The constraint was ^0.10.x, which below 1.0 excludes 0.11 entirely, so the package could not be installed alongside the framework release it was built against. No code changed: the tests pass unaltered
12 August 2026
Toolkit

v0.1.1

latest

Accepts framework 0.11.

  • Improvement Same constraint widening as Secure. Below 1.0 Composer treats the minor as the compatibility boundary, so ^0.10.0 will not resolve against 0.11
12 August 2026
Secure

v0.1.0

stable

Encryption you can rotate, an audit trail, and threat detection.

  • New More than one encryption key alive at once. Values carry the id of the key that wrote them, so an old key keeps decrypting what it wrote and rotating becomes two steps that can be weeks apart, rather than an event that makes everything unreadable
  • Security AES-256-GCM with the key id authenticated, so an altered payload is refused rather than decrypted into something plausible, and a payload cannot be pointed at a different key
  • New An audit trail recording who did what, to which record, and what it looked like before. recordChange stores only the fields that differ
  • Security Anything whose field name looks sensitive is replaced before it is written, recursively and case-insensitively, so a password nested inside a request payload is caught too
  • New Threat detection counting events per source against thresholds in a sliding window, with a middleware answering 429 for a blocked source
  • Improvement Audit writes never throw: a trail that can end the request turns a logging problem into an outage, under exactly the load where the trail matters most
  • New secure:key, secure:status and secure:prune. Nothing prunes automatically
12 August 2026
Toolkit

v0.1.0

stable

A profiler, a dumper and generators for the classes the framework has no maker for.

  • New A profiler recording spans you open explicitly, reported through a Server-Timing header that browsers display natively. That works for JSON, redirects and downloads, and it cannot alter the response body
  • Improvement Timings come from hrtime, not microtime: the system clock can move backwards, and a negative duration sends people hunting a bug in their own code
  • New A dumper that keeps types visible, reports string lengths, prints whole floats as 1.0, shows NAN and INF, and includes private properties with readable names
  • New Generators for services, actions, DTOs and repositories, including subdirectories. DTOs come out final readonly; actions get one method
  • Improvement Profiling follows the environment when unconfigured: on in local and testing, off everywhere else, so doing nothing gives the safe answer
12 August 2026
Framework

v0.11.0

stable

The Nova admin module is removed. It never worked.

  • Removed The Nova admin module. Its controllers took $resourceKey while its routes declared {resource}, so the container could not resolve the parameter and every Nova route raised an error rather than rendering anything
  • Breaking Libxa\Nova\* and NovaServiceProvider no longer exist. Removing public classes is why this is a minor bump rather than a patch
  • Fix Nova claimed the /admin prefix among the core providers, so it collided with any admin package a project installed and whichever registered first silently won. That collision is how the broken routes were finally noticed
12 August 2026
Framework

v0.10.3

stable

The column types a real schema needs.

  • New Blueprint::unsignedBigInteger(), the correct type for a foreign key referencing id(). bigInteger() is signed and unsignedInteger() is too narrow, so there was no right answer before
  • New Blueprint::ipAddress(), 45 characters, which is the longest an IPv6 address gets. The alternative people reach for is string(15), which holds every IPv4 address and silently truncates every IPv6 one
  • New Blueprint::primary() for composite primary keys, emitted inside CREATE TABLE because SQLite cannot add one with ALTER TABLE afterwards
12 August 2026
Framework

v0.10.2

stable

A package could not ship a migration, and nothing said so.

  • Fix ServiceProvider::loadMigrationsFrom() was guarded by a check for a migrator binding that nothing ever created, so the method silently did nothing and any package following the documented API shipped a migration that could never run
  • Fix migrate constructed its own Migrator, discarding whatever a service provider had registered during boot
  • Fix Migrator::addPath() ignores a path it already holds. With several places contributing paths, a duplicate ran every migration in it twice
12 August 2026
Installer

v1.0.0

latest

One command to create an application: libxa new my-app.

  • New libxa new my-app runs composer create-project and everything around it: the database chosen up front, front-end dependencies installed, a first commit, and a summary of what to run next
  • New SQLite, MySQL, MariaDB or PostgreSQL, asked for interactively or given with --database
  • New --git, --branch, --github[=visibility], --organization, --npm, --dev and --force
  • New One-line install scripts for Windows, macOS and Linux. Both install per-user and add the command to PATH, with no administrator rights
  • Improvement Choosing a database rewrites only DB_DRIVER, DB_PORT and DB_DATABASE, so the APP_KEY the skeleton generates survives
  • Improvement Shipped as a self-contained executable, so the installer needs nothing installed to run
  • Improvement Every prompt has a non-interactive answer, so the same commands run in CI rather than hanging on a question nothing can answer
12 August 2026
Starter kit

v0.4.0

latest

Routing works on a deployed server, which it had never done.

  • Fix Every route except the home page returned 404 once deployed. The kit shipped no .htaccess at all, so Apache looked for a file named login when asked for /login and returned its own 404 before PHP started
  • New src/public/.htaccess: the front controller rule, MultiViews off so Apache cannot resolve /about to about.php and bypass routing, directory indexes off, and one canonical URL per page
  • Security The Authorization header is restored after CGI and FastCGI strip it. Without it, API token authentication fails with nothing to say why
  • New A root .htaccess for shared hosting, where the document root is the project directory and cannot be moved: it rewrites into src/public/ and refuses vendor/, src/app/, src/storage/ and .env
  • New DEPLOYMENT.md, shipped inside the generated project, with working configuration for Apache, nginx, Caddy and shared hosting
  • Improvement DeploymentConfigTest fails in CI if the rewrite rules stop shipping, because the original bug was these files not existing
12 August 2026
Desktop

v0.4.0

latest

A rebuilt Sites page, and three settings that saved correctly and then changed nothing.

  • New The Sites page is a list beside a detail pane. The table had six controls and a full path in every row, so each per-site setting made the others narrower
  • New Preview renders in the page rather than in its own window, at a desktop, tablet or mobile width: looking at a site while changing its settings used to mean a window covering the settings
  • New A Node version per site, or Default to follow the global one
  • New Startup settings: launch at login, and start minimised as a tray application
  • New A fuller tray menu: quick access to sites, per-service start and stop, switching the default PHP version, and the configuration directory
  • Fix Changing a site’s PHP version did nothing. The setting saved, so the dropdown looked right, while nginx kept serving the old config and no php-cgi was ever started for the version chosen
  • Fix Switching the default PHP version had the same gap, and it decides which binary the service runs, so nothing took effect until the next launch
  • Fix A version’s FastCGI port no longer moves when another is added or removed. It used to be an index into a sorted list, so one change shifted every port after it and broke sites nobody had touched
  • Fix Auto-update could never find a release: the updater asked for draft releases, which the unauthenticated API does not return
  • Fix A terminal that launched and immediately died counted as success, ending the search with no window and no message
  • Removed The separate preview window, replaced by the one in the page
12 August 2026
Desktop

v0.3.0

stable

HTTPS for local sites, a preview window, and a terminal at any project.

  • New HTTPS for local sites. A per-machine certificate authority signs a certificate for any site with TLS switched on, covering the domain, its wildcard, localhost and 127.0.0.1
  • New One button trusts the root certificate. It does not prompt for elevation because the per-user store does not need any
  • Fix The per-site TLS toggle now does something. It had been in the data model and the IPC surface since 0.1.0, but nginx ignored it: a site marked secure was served over plain HTTP with nothing to indicate it
  • New Site preview: one window per site at a desktop, tablet or mobile viewport, in its own session partition
  • New Open a terminal at any project. Windows Terminal, PowerShell or cmd on Windows; Terminal on macOS; the common emulators on Linux, tried in order
  • Improvement Certificates last 396 days, under the 398 Chrome will accept, and renew a month before they lapse
  • Removed System information no longer lists the versions of the shell the app is built on. They describe the shell, not the environment being managed
12 August 2026
Framework

v0.10.1

stable

Presentation only. No API, behaviour or dependency changed.

  • Improvement The built-in error pages use the standard unpunctuated HTTP status phrases: 404 Not Found, 405 Method Not Allowed, 500 Server Error
  • Improvement The 405 page lists the permitted methods as Allowed: GET, POST, and titles read 404 | LibxaFrame
  • Improvement Em dashes removed from the source, the comments and the documentation
9 August 2026
Desktop

v0.2.0

stable

phpMyAdmin, and per-site PHP versions that are actually routed.

  • New phpMyAdmin: installed from the project’s own host with a published SHA-256, configured against the managed database, and served at phpmyadminlibxa.test
  • Security The phpMyAdmin vhost is bound to localhost: it administers the database as root, and nginx binds every interface
  • New phpMyAdmin runs on the newest installed PHP its release supports, rather than the newest PHP present
  • Fix Per-site PHP versions are now routed. One php-cgi per version in use, with each server block pointing at the matching port: the version dropdown had been recorded, displayed and ignored
  • Fix Orphaned php-cgi workers are stopped on quit, so a relaunch does not find its port taken and relocate the environment
  • Breaking Any site pinned to a version other than the default was silently served by the default until now, and moves to its configured version on upgrade
9 August 2026
Desktop

v0.1.0

stable

First release of the desktop environment.

  • New Supervises PHP-FPM, nginx and MariaDB as child processes, with combined logs and a stop that does not orphan workers
  • New Runtime installer: nginx, MariaDB, PHP 8.0–8.5 and Node 20–26, each verified against a publisher-supplied SHA-256 before extraction
  • New Site discovery: park a directory and every servable project inside it gets a local domain and a generated server block
  • New Scaffolds new LibxaFrame and Laravel applications, fetching a verified Composer when the machine has none
  • New Writes .test domains into a marked block of the hosts file, leaving every other entry, including Herd’s, untouched
  • New Self-update from the public releases repository, verified against the SHA-512 in latest.yml and installed only on request
  • New Custom window chrome and a tray menu, carrying the LibxaFrame mark
8 August 2026
Framework

v0.10.0

stable

Stability pass across the whole framework, and PHP 8.5 support.

  • New PHP 8.5 supported and tested in CI alongside 8.3 and 8.4
  • Improvement 197 tests covering the container, HTTP kernel, router, validation, Atlas, sessions and encryption
  • Fix Header name normalisation in Request, and a safe-referer check in Response so a redirect cannot be pointed off-site
  • Fix Router, route collection and pipeline corrected for middleware ordering and short-circuiting
  • Fix Atlas query builder, schema and migrator hardened against the edge cases the new tests found
  • Security CSRF, throttle and shared-errors middleware reviewed and corrected
  • Fix Vite manifest emits each asset once: duplicate tags were being produced for entries that shared a chunk
8 August 2026
Starter kit

v0.3.0

stable

Dependency resolution made reproducible, and PHP 8.5 in CI.

  • Fix Stability flags are per-package rather than global, so a dev requirement no longer loosens every other dependency
  • Fix config.platform.php pinned to 8.3: the lock file had been resolving packages that require 8.4.1 while the manifest declared ^8.3
  • Fix The path repository is non-canonical, so Packagist is still consulted and a published install resolves the same way a local one does
  • Improvement 30 tests, including one that fails if the lock file records a path dist
  • New PHP 8.5 added to the CI matrix

Upgrading?

The upgrade guide walks through every breaking change, in order, with the code to change.

Read the upgrade guide