Releases: velkymx/vibefw
Release list
VibeFW v2.1 Release Notes
v2.1 is the largest single release in VibeFW's history. Building on the concurrency architecture introduced in v2.0, it ships the full SPA scaffolding stack, an extensive security hardening pass, a turnkey project setup experience, and 13 patch versions worth of correctness and reliability fixes.
What Changed in v2.1
For new projects — composer create-project velkymx/vibefw my-app now gets you a fully working app in one command. No manual .env setup, no key generation, no empty database.
For SPA projects — php fw make:spa scaffolds a complete Vue 3 + TypeScript + Vite frontend with authentication, routing, and VibeUI components in a single interactive command. php fw dev then starts both servers concurrently.
For all projects — 30+ security fixes land automatically on composer update. Nothing breaks; everything gets safer. Highlights include a complete Sanitizer rewrite, Fiber instance leak elimination, timing-attack hardening in auth flows, and storage permission tightening across the board.
New in the box — Fw\Support\Hash for future-proof password hashing, Fw\Auth\EmailVerification for confirmation flows, five new CLI commands, and configurable CORS origins.
Upgrading from v2.0? v2.1 is fully backwards compatible — run
composer update velkymx/vibefwand you're done. See the Upgrading from v2.0 section at the bottom of this document for recommended (optional) adoptions.
What's New
SPA Scaffolding — php fw make:spa
Run one command to scaffold a complete, production-ready Vue 3 + TypeScript + Vite frontend wired to a PHP API backend.
php fw make:spaWhat you get:
- Vue 3 + TypeScript frontend in
/frontend/using VibeUI 0.7+ components - 4-page starter — Home, Login, Register, Dashboard — with dark mode support throughout
- Full auth flow — Bearer token login/register/logout, Axios 401 interceptor for server-side revocation
- Vue Router 5 with authenticated route guards
- Pinia state management
- Vite 7 dev server with API proxy to
localhost:8000 - PHP API controllers —
Api/Auth/LoginController,Api/Auth/RegisterController,Api/StatsController - Database migrations installed and run (users, jobs, remember token, password resets, personal access tokens, email verifications)
- CORS pre-configured for the Vite dev server
- TypeScript API types — typed interfaces for all API responses
- Vitest + Playwright test scaffolding
- Frontend README with auth flow, API reference, and VibeUI cheat sheet
After scaffolding, start the full stack with:
php fw devphp fw dev — Concurrent Dev Server
New command that runs the PHP backend and Vite frontend concurrently via pcntl_fork, so you get a single terminal for the full stack.
Backend: http://localhost:8000
Frontend: http://localhost:5173
Falls back gracefully if pcntl is unavailable, printing the commands to run separately.
Turnkey Project Setup
composer create-project velkymx/vibefw my-app
cd my-appThat's it. The post-install hook automatically:
- Creates
.envwith a secureAPP_KEY - Sets up
storage/directories - Creates the SQLite database file
No manual cp .env.example .env or key generation required. Also available for cloned repos:
php fw setupNew CLI Commands
| Command | Description |
|---|---|
php fw make:spa |
Scaffold Vue 3 + TypeScript SPA starter |
php fw dev |
Start backend + frontend dev servers concurrently |
php fw setup |
First-time project initialization |
php fw env:sync |
Sync .env keys to frontend/.env.local with VITE_ prefix |
php fw security:check |
Focused security audit (permissions, debug flags, exposed files, hardcoded credentials) |
Fw\Support\Hash
New utility class for password hashing:
use Fw\Support\Hash;
$hash = Hash::make($password); // PASSWORD_DEFAULT algorithm
$valid = Hash::check($password, $hash); // true/false
$stale = Hash::needsRehash($hash); // true if algorithm or cost changed
$hash = Hash::make($password, ['cost' => 12]); // custom costUses PASSWORD_DEFAULT so the algorithm automatically upgrades as PHP evolves.
Fw\Auth\EmailVerification
Foundation class for email confirmation flows. Supports token generation, single-use verification with timing-attack protection, and automatic expiry cleanup. Opt-in — no routes or sending logic included.
Queue Security: allowClasses()
FileDriver and DatabaseDriver now expose an explicit deserialization allowlist on top of the default HMAC verification:
$queue->driver()->allowClasses([
SendWelcomeEmail::class,
ProcessPayment::class,
]);CORS Configuration
CorsMiddleware now reads from $app->config('cors') for per-project overrides:
// config/app.php
'cors' => [
'allowed_origins' => array_filter(array_map('trim', explode(',', env('CORS_ALLOWED_ORIGINS', '*')))),
'supports_credentials' => true,
],make:spa automatically writes CORS_ALLOWED_ORIGINS to .env to allow the Vite dev server.
Security Hardening
v2.1 includes 30+ targeted security fixes. Highlights by area:
Authentication & Sessions
- Remember token replay — Token rotated on every use; old token invalidated immediately
- Remember cookie
Secureflag — Set totrueon HTTPS automatically, respects trusted proxy headers Auth logout()order —clearRememberToken()now runs before context teardown- Logout Bearer token revocation — Token cannot be replayed after logout
- UUID session user IDs —
Auth::user()andAuth::id()now accept both integer and string (UUID) primary keys RegisterControllerTOCTOU race — Duplicate email race caught at the DB unique constraint level
SQL & QueryBuilder
- SQL injection via alias expressions —
validateIdentifier()tightened to reject arbitrary SQL inASaliases - SQL injection via aggregate functions —
COUNT(*) OR 1=1; --patterns now rejected - Foreign key action injection —
onDelete()/onUpdate()validate against a whitelist BelongsToManyunquoted identifiers — All identifiers ineagerLoad(),detach(),pluck()now quotedDatabaseDrivertable name injection — Constructor validates table names at construction timeMigratorpath traversal — Migration files validated withrealpath()to stay within migrations directory
Cryptography & Tokens
Str::ulid()entropy — Fixed from 50-bit to correct 80-bit per the ULID specEmailVerificationsingle-use tokens — Verification links now consumed on first usePersonalAccessTokentoken hash isolation — Rotating the configured prefix no longer invalidates existing tokensAuth::getUserFromRememberToken()integer overflow —(int)cast replaced withctype_digit()+ constant-time dummy comparison
Input Validation & Sanitization
Sanitizerrewrite —json(),float(),url()hardened;stripTags()no longer accepts an allowlist (was insecure)- Validator ReDoS —
validateAlpha()/validateAlphaNum()reject inputs over 65KB before reaching the Unicode regex Router::validateConstraint()ReDoS — Replaced blacklist approach with a whitelist that rejects all parenthesized groupsQueryWatcherReDoS —normalizeQueryPattern()capped at 8KB input
Async & HTTP
- SSRF in
AsyncHttp—validateHost()rejects private IPs, loopback, and cloud metadata addresses AsyncHttpheader injection — Headers validated against\r\nbefore sendingSpaAuthMiddlewareorigin bypass — Missing origin headers now rejected in production; dev mode restricted to localhostView::resolvePath()path traversal — View names validated withrealpath()
Infrastructure
- Storage permissions — All cache, log, queue, and config cache directories changed from
0755→0750; log files set to0640 ErrorHandlerpath leakage — Debug pages stripBASE_PATHfrom file pathsStreamedResponsesecurity headers —X-Content-Type-Options,X-Frame-Options,Referrer-Policynow included- CSP
unsafe-inlineremoved — No longer included inscript-srcorstyle-src - CSRF silent failure —
ensureSession()throwsRuntimeExceptionon premature output instead of silently disabling CSRF protection
Reliability & Correctness
Fiber / Worker Mode
ContainerFiber instance leak —spl_object_id()keying replaced withWeakMap<Fiber, array>for automatic GCModelstrict mode leak —$globalStrictModereset between requestsPasswordReset/Gate/ApiTokenstatic leaks — All wired intoHttpKernel::resetState()- View output buffer leak — Exception inside a fragment cache block no longer leaves buffers open across requests
Deferredfiber resurrection crash —resolve()/reject()checkisTerminated()before resuming a Fiber
Async
Deferred::race()never settles — Replaced polling withonSettle()listener that fires immediately on resolutionDeferred::race()memory leak — Losing deferreds release references after the race settles
Cache
- Null TTL semantics —
set($k, $v, null)now stores indefinitely per PSR-16 in bothFileCacheandOpcacheCache FileCache::gc()orphaned lock files —.locksidecars cleaned up alongside expired entriesOpcacheCache::increment()race — Atomic via sidecar lock fileViewCachetemp file race —tempnam()replacesuniqid()for OS-guaranteed uniqueness
Model & Database
...
VibeFw Framework v2.0.0
This is a major release that transforms the framework from a traditional request-response library into a production-grade, fiber-safe foundation for high-concurrency PHP 8.4+ applications.
Benchmark Results
Running on FrankenPHP (Worker Mode) with 4 workers on Apple M2 (MacBook Air), the refactored framework achieves massive throughput improvements. After applying Container Fast-Paths and Route Pre-loading, we observed a >150% increase in performance over early v2 dev builds.
Command: wrk -t8 -c200 -d30s http://localhost:8081/health
| Metric | Result |
|---|---|
| Requests per Second | 40,058.37 |
| Average Latency | 5.15ms |
| Total Requests (30s) | 1,202,023 |
| Memory Stability | Stable (Zero leaks after 1.2M+ requests) |
🛠 Upgrading from v1.0.5
VibeFW v2.0.0 introduces breaking changes to core execution patterns. Follow this guide to migrate your application.
1. Update Kernel Execution
The HttpKernel::handle() method no longer emits the response. You must now capture the returned object and emit it using the new SapiEmitter.
Old (v1.0.5):
$app->run(); // Implicitly called $kernel->handle($req, $res) which echoed outputNew (v2.0.0):
$response = $app->getKernel()->handle($request);
(new SapiEmitter())->emit($response);2. Mandatory QueryBuilder Re-assignment
The QueryBuilder is now immutable. Method chaining remains supported, but you must assign the result back to a variable if branching your queries.
Old (v1.0.5):
$query = $db->table('users');
$query->where('active', 1); // Modified $query in placeNew (v2.0.0):
$query = $db->table('users')->where('active', 1); // Returns new instance3. Request Property Access
Direct modification of Request properties is no longer allowed as they are now readonly. If you were manually overriding $_GET values on the Request object, you must now inject those values during construction or via the Middleware pipeline.
4. Resettable Interface
If you have custom services that store data in-memory (static arrays or class properties), they should now implement Fw\Support\ResettableInterface and be registered in the Container. This ensures they are automatically cleared between requests in worker mode.
Summary of Changes
Performance & Async Improvements
- True Non-Blocking I/O: Refactored
AsyncHttpto use non-blocking socket streams and theEventLoopwatcher system. - Event Loop Optimization: Removed "busy-wait" loops in the Kernel. The framework now yields control back to the loop while waiting for Fiber completion.
- Boot Optimization: Routes and global middleware are now pre-loaded once at boot time in worker mode.
- Container Fast-Path: Added a high-speed resolution path for global singletons.
State Integrity & Safety
- Fiber-Scoped Singletons: The
Containernow isolates request-scoped services per Fiber. - Fiber-Safe Context:
RequestContextnow uses aWeakMapkeyed by the current Fiber to prevent data leakage between concurrent requests. - Leak Detection: Added a "State Integrity Check" in
HttpKernelthat throws aRuntimeExceptionif request state from a previous execution is detected. - Memory Management: Services like
MemoryCacheandQueryWatcherare now automatically reset after every request.
Release 1.0.5
Nothing new. Just a release with new packagist config and install instructions
Fw Framework v1.0.4
- Fixed array response handling: The framework now correctly handles array responses from controllers by converting them to JSON responses with proper headers. Previously, calling
setHeader()on the Response object would fail because the method doesn't exist. - Fixed
json_encode()on Model instances producing wrong output:Modelnow implements\JsonSerializable, delegating totoArray(). Previously, passing a model directly tojson_encode()would silently serialize internal object state instead of the model's attributes, with no warning.Collectionwas already correctly implemented.
Changed Methods
RequestFiber.php:233: Changed$this->app->response->setHeader('Content-Type', 'application/json')to$this->app->response->header('Content-Type', 'application/json')Component.php:315: Changed$this->app->response->setHeader('Content-Type', 'application/json')to$this->app->response->header('Content-Type', 'application/json')Component.php:326: Changed$this->app->response->setHeader('Location', $url)to$this->app->response->header('Location', $url')src/Model/Model.php: Addedimplements \JsonSerializableto the class declaration and addedjsonSerialize(): arraymethod that delegates totoArray()
Impact
- Controllers returning arrays will now work correctly
- JSON responses will have proper Content-Type headers
- Redirect functionality in components will work properly
- No breaking changes - maintains backward compatibility
Migration
No migration steps required. This is a bug fix that improves existing functionality.
Notes
This release fixes a critical bug that prevented array responses from working correctly in API controllers. The framework now properly handles array responses by converting them to JSON with appropriate headers.
Fw Framework v1.0.3
This release fixes a critical bug that prevented array responses from working correctly in API controllers. The framework now properly handles array responses by converting them to JSON with appropriate headers.
Bug Fixes
Core Framework
- Fixed array response handling: The framework now correctly handles array responses from controllers by converting them to JSON responses with proper headers. Previously, calling
setHeader()on the Response object would fail because the method doesn't exist.
Changed Methods
RequestFiber.php:233: Changed$this->app->response->setHeader('Content-Type', 'application/json')to$this->app->response->header('Content-Type', 'application/json')Component.php:315: Changed$this->app->response->setHeader('Content-Type', 'application/json')to$this->app->response->header('Content-Type', 'application/json')Component.php:326: Changed$this->app->response->setHeader('Location', $url)to$this->app->response->header('Location', $url')
Impact
- Controllers returning arrays will now work correctly
- JSON responses will have proper Content-Type headers
- Redirect functionality in components will work properly
- No breaking changes - maintains backward compatibility
Fw Framework v1.0.2
This is a maintenance release focused on resolving a significant encapsulation bug within the ORM relationship logic that affected many-to-many queries.
Bug Fixes
**Fixed: Protected Property Access in BelongsToMany**
We identified an issue where the BelongsToMany relationship class was unable to retrieve the primary key of related models because it was attempting to access a protected static property from outside the class hierarchy.
- Impact: This bug previously caused errors when calling
$model->relationship()->get()or during eager loading if the primary key was not explicitly provided. - Resolution: Introduced a public accessor
Model::getKeyName()to safely expose the primary key name to relationship handlers and other internal components.
Internal Changes
- Enhanced Encapsulation: Added
public static function getKeyName()to the baseModelclass. - Relationship Cleanup: Standardized
BelongsToMany.phpto use the new accessor, ensuring it no longer relies on direct property access which can be restricted by PHP's visibility rules. - Eager Loading Stability: Fixed an edge case where eager loading would fail to pluck the correct parent keys due to the visibility issue mentioned above.
Migration & Workarounds
If you were previously using a manual workaround like the one below:
// Old Workaround
$categoryIds = $post->categories()->pluck('category_id');
$categories = Category::whereIn('id', $categoryIds)->get();You can now simplify your code back to the standard, expressive syntax:
// New & Fixed
$categories = $post->categories()->get();Release 1.0.1
This is a mainenance release only
- Add support for static files with CLI server
- Add helpers documentation
Fw Framework v1.0.0
🐺 Fw Framework v1.0.0 - "Alpha Super Awesome Cool Dynamite Wolf"
The first official release of Fw - a blazing fast PHP framework built for speed, simplicity, and vibes.
🚀 Performance
- 13,593 requests/second on Mac M2 with FrankenPHP
- 17x faster than Laravel
- 9x faster than Symfony
- 14.8ms average latency under load
✨ Key Features
Speed First
- Fiber-based async I/O with PHP 8.4
- FrankenPHP worker mode support for 5-10x throughput
- Lazy session loading - no overhead on stateless requests
- Zero runtime dependencies
Modern PHP
- PHP 8.4+ with property hooks and asymmetric visibility
- Result<T,E> and Option monads for explicit error handling
- 100% type coverage
- Built-in security headers and CSRF protection
Developer Experience
- Elegant ORM with relationships, eager loading, and migrations
- Fluent query builder
- Built-in auth (session + API tokens)
- Powerful CLI generators (
php fw make:model,php fw make:controller) - Quill.js rich text editor integration
Vibe Coding Ready
- Clean, expressive syntax
- Sensible defaults everywhere
- Minimal boilerplate
- AI-friendly codebase structure
📦 Quick Start
git clone https://github.com/velkymx/fw myapp
cd myapp
composer install
php fw serve🔗 Links
- GitHub: https://github.com/velkymx/fw
- Author: https://blog.ajb.bz
📄 License
MIT License © 2026 Alan Bollinger
Built for developers who want to ship fast and enjoy the process. 🐺⚡