# Composer Dependency Upgrades - Feb 2026 ## Summary of Upgrades | Package | From | To | Code Changes | | ------------------------ | ------ | ------ | ------------------------------------------------------------ | | spatie/laravel-data | 4.14.0 | 4.19.1 | Constraint only (`"4.14"` -> `"^4.14"`) | | spatie/eloquent-sortable | 4.5.2 | 5.0.0 | None | | resend/resend-laravel | 0.17.0 | 1.2.0 | None | | symfony/http-client | 7.4.5 | 8.x | None | | symfony/mailgun-mailer | 7.4.0 | 8.x | None | | darkaonline/l5-swagger | 9.0.1 | 10.x | None | | livewire/livewire | 3.7.10 | 4.x | Config key renames | | laravel/passport | 12.4.2 | 13.x | Middleware, service provider, factory override, test updates | --- ## Livewire 3 -> 4 ### Config Changes (`config/livewire.php`) | Old Key | New Key | | ------------------ | ----------------------- | | `layout` | `component_layout` | | `lazy_placeholder` | `component_placeholder` | ### What We Didn't Need to Change - `wire:model` behavior: Our usage (`wire:model="barcode"` without `.live`) works the same in v4 (deferred by default in both v3 and v4). - `wire-elements/modal` v3.0.4: Already compatible with Livewire 4 (requires `^3.2.3|^4.0`). - `Route::get()` with Livewire component: Still works in v4. `Route::livewire()` is recommended but not required. - Component tag closing: All our `` tags were already properly self-closed. - `wire:transition` / `wire:scroll`: Not used in this app. ### Potential Gotchas for Next Time - **`wire:model.blur` / `.change` behavior changed**: In v4, these modifiers now control client-side state sync timing too. Add `.live` before them if you want old behavior: `wire:model.live.blur`. - **Component tags must be closed**: Unclosed `` tags are interpreted as slot content in v4. - **`@livewireStyles`/`@livewireScripts`**: Still work with `inject_assets => true`, but you can use `@livewireScriptConfig` if bundling Livewire into your JS build. --- ## Laravel Passport 12 -> 13 ### Breaking Changes Encountered #### 1. `Passport::hashClientSecrets()` Removed Secrets are now ALWAYS hashed in v13. Remove all calls to `Passport::hashClientSecrets()`. **Files fixed:** - `modules/Auth/AuthServiceProvider.php` - Removed the call - `tests/Feature/Scopes/Api/Http/Middleware/CheckDecoCredentialsTest.php` - Removed from tests #### 2. `CheckClientCredentials` Middleware Renamed to `CheckToken` All credential-checking middleware were renamed: | Old Name | New Name | | ----------------------------------- | ----------------------- | | `CheckClientCredentials` | `CheckToken` | | `CheckClientCredentialsForAnyScope` | `CheckTokenForAnyScope` | | `CheckScopes` | `CheckToken` | | `CheckForAnyScope` | `CheckTokenForAnyScope` | | `CheckCredentials` (abstract) | `ValidateToken` | **Files fixed:** - `app/Http/Kernel.php` - Updated import and all 3 middleware group references #### 3. `ClientRepository::create()` Now Protected The `create()` method on `ClientRepository` is now `protected`. Use the named factory methods instead: | Old | New | | ---------------------------------------- | -------------------------------------------------- | | `$repo->create(null, $name, '')` | `$repo->createClientCredentialsGrantClient($name)` | | `$repo->createPersonalAccessClient(...)` | `$repo->createPersonalAccessGrantClient($name)` | The new methods return a `Client` with `$client->plainSecret` property containing the unhashed secret. **Files fixed:** - `tests/Feature/Http/Controllers/Api/V1/AirWaybillMilestone/AirWaybillMilestoneControllerTest.php` - `tests/Feature/Scopes/Api/Http/Middleware/CheckDecoCredentialsTest.php` - `scopes/Api/Tests/Http/Controllers/V1/Outbound/PickupControllerTest.php` - `scopes/Api/Tests/Pest.php` #### 4. `setSecretAttribute()` No Longer Exists Passport 13 uses an Eloquent `Attribute` mutator for `secret` that auto-hashes on assignment. Instead of manually setting secrets: ```php // Old (v12) $client->setSecretAttribute($secret); $client->save(); // New (v13) - just set the attribute, it auto-hashes $client->secret = $secret; $client->save(); // Or better - use the factory/repository which exposes plainSecret $client = $repo->createClientCredentialsGrantClient($name); $plainSecret = $client->plainSecret; // Available immediately after creation ``` #### 5. No Database Migration Needed (Backward Compatible) Passport 13 introduces new column names (`owner_type`/`owner_id`, `redirect_uris`, `grant_types`, `scopes`) but is **fully backward compatible** with the old schema: - `ClientRepository::create()` auto-detects columns via `getColumnListing()` and writes to whichever exist - `Client::redirectUris()` accessor falls back to reading `redirect` column - `Client::grantTypes()` accessor infers from `personal_access_client`/`password_client` columns - `Client::firstParty()` checks for `user_id` first, falls back to `owner_id` The Passport 13 **factory** writes to new columns, so we override it with `modules/Auth/Database/Factories/ClientFactory.php` that maps to the old schema. The `Client` model's `newFactory()` method returns our custom factory. #### 6. `config/passport.php` Cleanup Removed deprecated config keys: - `client_uuids` - UUIDs are now always used (default in v13) - `personal_access_client` - Personal access clients table removed ### What We Didn't Need to Change - `Passport::useTokenModel()` - Still works the same - `Passport::useClientModel()` - Still works the same - `Passport::ignoreRoutes()` - Still works - `Token` model (custom) extending `Laravel\Passport\Token` - Still compatible - `AccessTokenController` - Still exists, `TokenController` still extends it - `auth('passport')->client()` - Still works in middleware - `Token::findFromRequest()` - Still works (JWT parsing unchanged) ### Production Deployment Notes - No database migration required - Passport 13 is backward compatible with the old schema - Existing hashed secrets remain valid since v12 was already hashing them - If you want to migrate to the new schema in the future, see https://github.com/laravel/passport/blob/13.x/UPGRADE.md for the official migration - The `oauth_personal_access_clients` table is redundant in v13 and can be dropped - When migrating to new schema: remove the custom `ClientFactory` override and `newFactory()` from the Client model