output:
Chunk ID: 412ebd
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1256
Output:
---
name: developing-with-fortify
description: Laravel Fortify headless authentication backend development. Activate when implementing authentication features including login, registration, password reset, email verification, two-factor authentication (2FA/TOTP), profile updates, headless auth, authentication scaffolding, or auth guards in Laravel applications.
---

# Laravel Fortify Development

Fortify is a headless authentication backend that provides authentication routes and controllers for Laravel applications.

## Documentation

Use `search-docs` for detailed Laravel Fortify patterns and documentation.

## Usage

- **Routes**: Use `list-routes` with `only_vendor: true` and `action: "Fortify"` to see all registered endpoints
- **Actions**: Check `app/Actions/Fortify/` for customizable business logic (user creation, password validation, etc.)
- **Config**: See `config/fortify.php` for all options including features, guards, rate limiters, and username field
- **Contracts**: Look in `Laravel\Fortify\Contracts\` for overridable response classes (`LoginResponse`, `LogoutResponse`, etc.)
- **Views**: All view callbacks are set in `FortifyServiceProvider::boot()` using `Fortify::loginView()`, `Fortify::registerView()`, etc.

## Available Features

Enable in `config/fortify.php` features array:

- `Features::registration()` - User registration
- `Features::resetPasswords()` - Password reset via email
- `Features::emailVerification()` - Requires User to implement `MustVerifyEmail`
- `Features::updateProfileInformation()` - Profile updates
- `Features::updatePasswords()` - Password changes
- `Features::twoFactorAuthentication()` - 2FA with QR codes and recovery codes

> Use `search-docs` for feature configuration options and customization patterns.

## Setup Workflows

### Two-Factor Authentication Setup

```
- [ ] Add TwoFactorAuthenticatable trait to User model
- [ ] Enable feature in config/fortify.php
- [ ] Run migrations for 2FA columns
- [ ] Set up view callbacks in FortifyServiceProvider
- [ ] Create 2FA management UI
- [ ] Test QR code and recovery codes
```

> Use `search-docs` for TOTP implementation and recovery code handling patterns.

### Email Verification Setup

```
- [ ] Enable emailVerification feature in config
- [ ] Implement MustVerifyEmail interface on User model
- [ ] Set up verifyEmailView callback
- [ ] Add verified middleware to protected routes
- [ ] Test verification email flow
```

> Use `search-docs` for MustVerifyEmail implementation patterns.

### Password Reset Setup

```
- [ ] Enable resetPasswords feature in config
- [ ] Set up requestPasswordResetLinkView callback
- [ ] Set up resetPasswordView callback
- [ ] Define password.reset named route (if views disabled)
- [ ] Test reset email and link flow
```

> Use `search-docs` for custom password reset flow patterns.

### SPA Authentication Setup

```
- [ ] Set 'views' => false in config/fortify.php
- [ ] Install and configure Laravel Sanctum
- [ ] Use 'web' guard in fortify config
- [ ] Set up CSRF token handling
- [ ] Test XHR authentication flows
```

> Use `search-docs` for integration and SPA authentication patterns.

## Best Practices

### Custom Authentication Logic

Override authentication behavior using `Fortify::authenticateUsing()` for custom user retrieval or `Fortify::authenticateThrough()` to customize the authentication pipeline. Override response contracts in `AppServiceProvider` for custom redirects.

### Registration Customization

Modify `app/Actions/Fortify/CreateNewUser.php` to customize user creation logic, validation rules, and additional fields.

### Rate Limiting

Configure via `fortify.limiters.login` in config. Default configuration throttles by username + IP combination.

## Key Endpoints

| Feature                | Method   | Endpoint                                    |
|------------------------|----------|---------------------------------------------|
| Login                  | POST     | `/login`                                    |
| Logout                 | POST     | `/logout`                                   |
| Register               | POST     | `/register`                                 |
| Password Reset Request | POST     | `/forgot-password`                          |
| Password Reset         | POST     | `/reset-password`                           |
| Email Verify Notice    | GET      | `/email/verify`                             |
| Resend Verification    | POST     | `/email/verification-notification`          |
| Password Confirm       | POST     | `/user/confirm-password`                    |
| Enable 2FA             | POST     | `/user/two-factor-authentication`           |
| Confirm 2FA            | POST     | `/user/confirmed-two-factor-authentication` |
| 2FA Challenge          | POST     | `/two-factor-challenge`                     |
| Get QR Code            | GET      | `/user/two-factor-qr-code`                  |
| Recovery Codes         | GET/POST | `/user/two-factor-recovery-codes`           |


output:
Chunk ID: 1dc50f
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1275
Output:
---
name: pest-testing
description: "Use this skill for Pest PHP testing in Laravel projects only. Trigger whenever any test is being written, edited, fixed, or refactored — including fixing tests that broke after a code change, adding assertions, converting PHPUnit to Pest, adding datasets, and TDD workflows. Always activate when the user asks how to write something in Pest, mentions test files or directories (tests/Feature, tests/Unit, tests/Browser), or needs browser testing, smoke testing multiple pages for JS errors, or architecture tests. Covers: test()/it()/expect() syntax, datasets, mocking, browser testing (visit/click/fill), smoke testing, arch(), Livewire component tests, RefreshDatabase, and all Pest 4 features. Do not use for factories, seeders, migrations, controllers, models, or non-test PHP code."
license: MIT
metadata:
  author: laravel
---

# Pest Testing 4

## Documentation

Use `search-docs` for detailed Pest 4 patterns and documentation.

## Basic Usage

### Creating Tests

All tests must be written using Pest. Use `php artisan make:test --pest {name}`.

### Test Organization

- Unit/Feature tests: `tests/Feature` and `tests/Unit` directories.
- Browser tests: `tests/Browser/` directory.
- Do NOT remove tests without approval - these are core application code.

### Basic Test Structure

Pest supports both `test()` and `it()` functions. Before writing new tests, check existing test files in the same directory to match the project's convention. Use `test()` if existing tests use `test()`, or `it()` if they use `it()`.

<!-- Basic Pest Test Example -->
```php
it('is true', function () {
    expect(true)->toBeTrue();
});
```

### Running Tests

- Run minimal tests with filter before finalizing: `php artisan test --compact --filter=testName`.
- Run all tests: `php artisan test --compact`.
- Run file: `php artisan test --compact tests/Feature/ExampleTest.php`.

## Assertions

Use specific assertions (`assertSuccessful()`, `assertNotFound()`) instead of `assertStatus()`:

<!-- Pest Response Assertion -->
```php
it('returns all', function () {
    $this->postJson('/api/docs', [])->assertSuccessful();
});
```

| Use | Instead of |
|-----|------------|
| `assertSuccessful()` | `assertStatus(200)` |
| `assertNotFound()` | `assertStatus(404)` |
| `assertForbidden()` | `assertStatus(403)` |

## Mocking

Import mock function before use: `use function Pest\Laravel\mock;`

## Datasets

Use datasets for repetitive tests (validation rules, etc.):

<!-- Pest Dataset Example -->
```php
it('has emails', function (string $email) {
    expect($email)->not->toBeEmpty();
})->with([
    'james' => 'james@laravel.com',
    'taylor' => 'taylor@laravel.com',
]);
```

## Pest 4 Features

| Feature | Purpose |
|---------|---------|
| Browser Testing | Full integration tests in real browsers |
| Smoke Testing | Validate multiple pages quickly |
| Visual Regression | Compare screenshots for visual changes |
| Test Sharding | Parallel CI runs |
| Architecture Testing | Enforce code conventions |

### Browser Test Example

Browser tests run in real browsers for full integration testing:

- Browser tests live in `tests/Browser/`.
- Use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories.
- Use `RefreshDatabase` for clean state per test.
- Interact with page: click, type, scroll, select, submit, drag-and-drop, touch gestures.
- Test on multiple browsers (Chrome, Firefox, Safari) if requested.
- Test on different devices/viewports (iPhone 14 Pro, tablets) if requested.
- Switch color schemes (light/dark mode) when appropriate.
- Take screenshots or pause tests for debugging.

<!-- Pest Browser Test Example -->
```php
it('may reset the password', function () {
    Notification::fake();

    $this->actingAs(User::factory()->create());

    $page = visit('/sign-in');

    $page->assertSee('Sign In')
        ->assertNoJavaScriptErrors()
        ->click('Forgot Password?')
        ->fill('email', 'nuno@laravel.com')
        ->click('Send Reset Link')
        ->assertSee('We have emailed your password reset link!');

    Notification::assertSent(ResetPassword::class);
});
```

### Smoke Testing

Quickly validate multiple pages have no JavaScript errors:

<!-- Pest Smoke Testing Example -->
```php
$pages = visit(['/', '/about', '/contact']);

$pages->assertNoJavaScriptErrors()->assertNoConsoleLogs();
```

### Visual Regression Testing

Capture and compare screenshots to detect visual changes.

### Test Sharding

Split tests across parallel processes for faster CI runs.

### Architecture Testing

Pest 4 includes architecture testing (from Pest 3):

<!-- Architecture Test Example -->
```php
arch('controllers')
    ->expect('App\Http\Controllers')
    ->toExtendNothing()
    ->toHaveSuffix('Controller');
```

## Common Pitfalls

- Not importing `use function Pest\Laravel\mock;` before using mock
- Using `assertStatus(200)` instead of `assertSuccessful()`
- Forgetting datasets for repetitive validation tests
- Deleting tests without approval
- Forgetting `assertNoJavaScriptErrors()` in browser tests


packages: laravel/framework livewire/livewire livewire/flux pestphp/pest laravel/fortify

queries: browser testing authenticated user form fill click

queries: livewire validation form submit flux error

queries: customer guard logout route invalidate session


server: laravel-boost

tool: search-docs

type: text

text:
# Search Results

## Authentication Logging Out Invalidating Sessions on Other Devices
Authentication | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/authentication.md

### Invalidating Sessions on Other Devices

Laravel also provides a mechanism for invalidating and "logging out" a user's sessions that are active on other devices without invalidating the session on their current device. This feature is typically utilized when a user is changing or updating their password and you would like to invalidate sessions on other devices while keeping the current device authenticated.

Before getting started, you should make sure that the `Illuminate\Session\Middleware\AuthenticateSession` middleware is included on the routes that should receive session authentication. Typically, you should place this middleware on a route group definition so that it can be applied to the majority of your application's routes. By default, the `AuthenticateSession` middleware may be attached to a route using the `auth.session` [middleware alias](/docs/{{version}}/middleware#middleware-aliases):

```php
Route::middleware(['auth', 'auth.session'])->group(function () {
    Route::get('/', function () {
        // ...
    });
});
```

Then, you may use the `logoutOtherDevices` method provided by the `Auth` facade. This method requires the user to confirm their current password, which your application should accept through an input form:

```php
use Illuminate\Support\Facades\Auth;

Auth::logoutOtherDevices($currentPassword);
```

When the `logoutOtherDevices` method is invoked, the user's other sessions will be invalidated entirely, meaning they will be "logged out" of all guards they were previously authenticated by.

---

## Authentication Authentication Quickstart Protecting Routes Specifying a Guard
Authentication | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/authentication.md

#### Specifying a Guard

When attaching the `auth` middleware to a route, you may also specify which "guard" should be used to authenticate the user. The guard specified should correspond to one of the keys in the `guards` array of your `auth.php` configuration file:

```php
Route::get('/flights', function () {
    // Only authenticated users may access this route...
})->middleware('auth:admin');
```

---

## Browser Testing
Browser Testing | pestphp/pest@4.x | Source: https://github.com/pestphp/docs/blob/4.x/browser-testing.md

---
title: Browser Testing
description:
---

# Browser Testing

Browser testing is an essential part of modern web development, allowing you to ensure that your application works correctly across different browsers and devices. Pest provides a simple and elegant way to write browser tests. Here is an example of how to write a browser test using Pest:

```php
it('may welcome the user', function () {
    $page = visit('/');

    $page->assertSee('Welcome');
});
```

This is a basic example of a browser test that checks if the homepage contains the text "Welcome". However, Pest's browser testing capabilities go beyond this simple example. You can use various methods to interact with the page, such as clicking buttons, filling out forms, and navigating between pages.

Here is an example of a more complex browser test, on Laravel, that checks if a user can sign in:

```php
it('may sign in the user', function () {
    Event::fake();

    User::factory()->create([ // assumes RefreshDatabase trait is used on Pest.php...
        'email' => 'nuno@laravel.com',
        'password' => 'password',
    ]);

    $page = visit('/')->on()->mobile()->firefox();

    $page->click('Sign In')
         ->assertUrlIs('/login')
         ->assertSee('Sign In to Your Account')
         ->fill('email', 'nuno@laravel.com')
         ->fill('password', 'password')
         ->click('Submit')
         ->assertSee('Dashboard');

    $this->assertAuthenticated();

    Event::assertDispatched(UserLoggedIn::class);
});
```

Note that, you are leveraging the full power of Laravel's testing capabilities, such as refresh database, event faking, and authentication assertions, while also actually doing browser testing.

## Getting Started

To get started with browser testing in Pest, you need to install the Pest Browser plugin. You can do this by running the following command:

```bash
composer require pestphp/pest-plugin-browser --dev

npm install playwright@latest
npx playwright install
```

Finally, add `tests/Browser/Screenshots` to your `.gitignore` file to avoid committing screenshots taken during browser tests.

### Running Browser Tests

Running browser tests is similar to running regular Pest tests:

```bash
./vendor/bin/pest
```

We recommend running tests in parallel using the `--parallel` option to speed up the execution:

```bash
./vendor/bin/pest --parallel
```

For debugging purposes, you can run the tests in a headed mode and pause the execution at the end of the failed test run:

```bash
./vendor/bin/pest --debug
```

### Navigation

The `visit()` method is used to navigate to a specific URL in your browser test. It provides various methods to interact with the page:

```php
test('example', function () {
    $page = visit('/');

    $page->assertSee('Welcome');
});
```

### Using Other Browsers

By default, the `visit()` method uses Chrome as the browser. However, if you want to use a different browser, you can specify it using the `--browser` option when running the tests:

```bash
./vendor/bin/pest --browser firefox
./vendor/bin/pest --browser safari
```

If you wish to use a different browser by default without specifying it in the command line, you can set it in your `Pest.php` configuration file:

```php
pest()->browser()->inFirefox();
pest()->browser()->inSafari();
```

### Using Other Devices

The `visit()` method uses a desktop viewport. However, you can specify a mobile viewport using the `onMobile()` method. For example:

```php
$page = visit('/')->on()->mobile();
```

If you wish to use a specific device, you can use the `on()` method and chain it with the `macbook14`, `iPhone14Pro`, etc:

```php
$page = visit('/')->on()->iPhone14Pro();
```

### Using Dark Mode

Pest enforces a light color scheme by default. However, you can specify a dark color scheme using the `inDarkMode()` method:

```php
$page = visit('/')->inDarkMode();
```

### Visiting Multiple Pages

You can visit multiple pages simultaneously by passing an array of URLs to the `visit()` method. This is useful for testing scenarios where you need to interact with multiple pages at once:

```php
$pages = visit(['/', '/about']);

$pages->assertNoSmoke()
    ->assertNoAccessibilityIssues()
    ->assertNoConsoleLogs()
    ->assertNoJavaScriptErrors();

[$homePage, $aboutPage] = $pages;

$homePage->assertSee('Welcome to our website');
$aboutPage->assertSee('About Us');
```

### Navigation

After visiting a page, you can navigate to other pages using the `navigate()` method. This method allows you to navigate to a different URL while keeping the current browser context:

```php
$page = visit('/');

$page->navigate('/about')
     ->assertSee('About Us');
```

### Locating Elements

You can locate elements in the DOM using text or CSS selectors. Pest provides a simple syntax for locating elements:

```php
// Clicks the first link with the text "Login"
$page->click('Login');

// Clicks the first element with the class "btn-primary"
$page->click('.btn-primary');

// Clicks the element with the data-test attribute "login"
$page->click('@login');

// Clicks the element with the ID "submit-button"
$page->click('#submit-button');

// etc...
```

### Configuring Timeouts

Sometimes, elements may take time to appear on the page. By default, Pest waits for `5` seconds before timing out. You can configure the default timeout for browser tests in your `Pest.php` configuration file:

```php
pest()->browser()->timeout(10000);
```

### Configuring User Agent

By default, the User Agent will default to the Browser you're running for tests such as: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/133.0.6943.16 Safari/537.36`

You may wish to override the User Agent of the browser for all of your tests, you can configure this in the `Pest.php` configuration file:

```php
pest()->browser()->userAgent('CustomUserAgent');
```

### Configuring Host

By default, the server will bind to `127.0.0.1` for all browser tests.

You may wish to override the host for subdomain applications. You can configure this in the `Pest.php` configuration file:

```php
pest()->browser()->withHost('some-subdomain.localhost');
```

### Geolocation

Sometimes, you need to define where the browser believes it is physically on the earth.  This method takes a latitude and longitude and will set the `geolocation` permission in the browser and then make the coordinates available via Javascript's getCurrentPosition API:

```php
$page = visit('/')
     ->geolocation(39.399872, -8.224454);
```

### Configuring Locale

You can set the locale for your test requests using the `withLocale` method. This is particularly useful for testing multilingual applications.

```php
$page = visit('/')->withLocale('fr-FR');

$page->assertSee('Bienvenue');
```
### Configuring Timezone

You can set the timezone for your test requests using the `withTimezone` method. This is useful for testing date and time displays in different time zones.

```php
$page = visit('/')->withTimezone('America/New_York');

$page->assertSee('EST');
```

### Configuring UserAgent

You can set the User-Agent header for your test requests using the `withUserAgent` method. This is useful for testing how your application responds to different types of clients, such as mobile browsers or bots.

```php
$page = visit('/')->withUserAgent('Googlebot');

$page->assertSee('Welcome, bot!');
```

### Configuring Host

You can set the host for your test server using the `withHost` method. This is useful for testing subdomains or where different hosts serve different content.

```php
$page = visit('/dashboard')->withHost('some-subdomain.localhost');

$page->assertSee('Welcome to Some Subdomain');
```

## Table of Contents

### Available Assertions

[assertTitle](#assert-title)
[assertTitleContains](#assert-title-contains)
[assertSee](#assert-see)
[assertDontSee](#assert-dont-see)
[assertSeeIn](#assert-see-in)
[assertDontSeeIn](#assert-dont-see-in)
[assertSeeAnythingIn](#assert-see-anything-in)
[assertSeeNothingIn](#assert-see-nothing-in)
[assertCount](#assert-count)
[assertScript](#assert-script)
[assertSourceHas](#assert-source-has)
[assertSourceMissing](#assert-source-missing)
[assertSeeLink](#assert-see-link)
[assertDontSeeLink](#assert-dont-see-link)
[assertChecked](#assert-checked)
[assertNotChecked](#assert-not-checked)
[assertIndeterminate](#assert-indeterminate)
[assertRadioSelected](#assert-radio-selected)
[assertRadioNotSelected](#assert-radio-not-selected)
[assertSelected](#assert-selected)
[assertNotSelected](#assert-not-selected)
[assertValue](#assert-value)
[assertValueIsNot](#assert-value-is-not)
[assertAttribute](#assert-attribute)
[assertAttributeMissing](#assert-attribute-missing)
[assertAttributeContains](#assert-attribute-contains)
[assertAttributeDoesntContain](#assert-attribute-doesnt-contain)
[assertAriaAttribute](#assert-aria-attribute)
[assertDataAttribute](#assert-data-attribute)
[assertVisible](#assert-visible)
[assertPresent](#assert-present)
[assertNotPresent](#assert-not-present)
[assertMissing](#assert-missing)
[assertEnabled](#assert-enabled)
[assertDisabled](#assert-disabled)
[assertButtonEnabled](#assert-button-enabled)
[assertButtonDisabled](#assert-button-disabled)
[assertUrlIs](#assert-url-is)
[assertSchemeIs](#assert-scheme-is)
[assertSchemeIsNot](#assert-scheme-is-not)
[assertHostIs](#assert-host-is)
[assertHostIsNot](#assert-host-is-not)
[assertPortIs](#assert-port-is)
[assertPortIsNot](#assert-port-is-not)
[assertPathBeginsWith](#assert-path-begins-with)
[assertPathEndsWith](#assert-path-ends-with)
[assertPathContains](#assert-path-contains)
[assertPathIs](#assert-path-is)
[assertPathIsNot](#assert-path-is-not)
[assertQueryStringHas](#assert-query-string-has)
[assertQueryStringMissing](#assert-query-string-missing)
[assertFragmentIs](#assert-fragment-is)
[assertFragmentBeginsWith](#assert-fragment-begins-with)
[assertFragmentIsNot](#assert-fragment-is-not)
[assertNoSmoke](#assert-no-smoke)
[assertNoConsoleLogs](#assert-no-console-logs)
[assertNoJavaScriptErrors](#assert-no-javascript-errors)
[assertNoAccessibilityIssues](#assert-no-accessibility-issues)
[assertScreenshotMatches](#assert-screenshot-matches)

### Element Interactions

[click](#click)
[text](#text)
[attribute](#attribute)
[keys](#keys)
[withKeyDown](#withKeyDown)
[type](#type)
[typeSlowly](#type-slowly)
[select](#select)
[append](#append)
[clear](#clear)
[radio](#radio)
[check](#check)
[uncheck](#uncheck)
[attach](#attach)
[press](#press)
[pressAndWaitFor](#press-and-wait-for)
[drag](#drag)
[hover](#hover)
[submit](#submit)
[value](#value)
[withinIframe](#within-iframe)
[resize](#resize)
[script](#script)
[content](#content)
[url](#url)
[wait](#wait)
[waitForKey](#wait-for-key)

### Debugging tests

[debug](#debug)
[screenshot](#screenshot)
[screenshotElement](#screenshot-element)
[tinker](#tinker)
[headed](#headed)

## Element Assertions

---

## Http Tests Validation Assertions assertInvalid
Http Tests | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/http-tests.md

#### assertInvalid

Assert that the response has validation errors for the given keys. This method may be used for asserting against responses where the validation errors are returned as a JSON structure or where the validation errors have been flashed to the session:

```php
$response->assertInvalid(['name', 'email']);
```

You may also assert that a given key has a particular validation error message. When doing so, you may provide the entire message or only a small portion of the message:

```php
$response->assertInvalid([
    'name' => 'The name field is required.',
    'email' => 'valid email address',
]);
```

---

## Validation See also
Validation | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/validation

## See also

- **[Forms](/docs/4.x/forms)** — Validate form inputs with real-time feedback
- **[Properties](/docs/4.x/properties)** — Validate property values before persisting
- **[Validate Attribute](/docs/4.x/attribute-validate)** — Use #[Validate] for property validation
- **[Actions](/docs/4.x/actions)** — Validate data in action methods

---

## Wire Transition Browser support
Wire Transition | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/wire-transition

## Browser support

View Transitions are supported in Chrome 111+, Edge 111+, and Safari 18+. In browsers that don't support View Transitions, elements will appear and disappear without animation—the functionality still works, just without the visual transition.

> [!warning] Firefox has limited support
> Firefox 144+ supports basic view transitions, but does not support transition types.

[View browser support on caniuse.com →](https://caniuse.com/view-transitions)

---

## Wire Transition Customizing animations with CSS
Wire Transition | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/wire-transition

## Customizing animations with CSS

View Transitions are controlled entirely through CSS. You can customize the animation by targeting the view-transition pseudo-elements:

```css
/* Customize the transition for a specific element */
::view-transition-old(sidebar) {
    animation: 300ms ease-out both slide-out;
}

::view-transition-new(sidebar) {
    animation: 300ms ease-in both slide-in;
}

@keyframes slide-out {
    to { transform: translateX(-100%); }
}

@keyframes slide-in {
    from { transform: translateX(100%); }
}
```

The View Transitions API provides three pseudo-elements you can style:
- `::view-transition-old(name)` — The outgoing element's snapshot
- `::view-transition-new(name)` — The incoming element's snapshot
- `::view-transition-group(name)` — Container for both snapshots

---

## Passport Protecting Routes Via Middleware
Passport | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passport.md

### Via Middleware

Passport includes an [authentication guard](/docs/{{version}}/authentication#adding-custom-guards) that will validate access tokens on incoming requests. Once you have configured the `api` guard to use the `passport` driver, you only need to specify the `auth:api` middleware on any routes that should require a valid access token:

```php
Route::get('/user', function () {
    // Only API authenticated users may access this route...
})->middleware('auth:api');
```

> [!WARNING]
> If you are using the [client credentials grant](#client-credentials-grant), you should use [the `Laravel\Passport\Http\Middleware\EnsureClientIsResourceOwner` middleware](#client-credentials-grant) to protect your routes instead of the `auth:api` middleware.

---

## Dusk Browser Basics Authentication
Dusk | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/dusk.md

### Authentication

Often, you will be testing pages that require authentication. You can use Dusk's `loginAs` method in order to avoid interacting with your application's login screen during every test. The `loginAs` method accepts a primary key associated with your authenticatable model or an authenticatable model instance:

```php
use App\Models\User;
use Laravel\Dusk\Browser;

$this->browse(function (Browser $browser) {
    $browser->loginAs(User::find(1))
        ->visit('/home');
});
```

> [!WARNING]
> After using the `loginAs` method, the user session will be maintained for all tests within the file.

---

## Validation Form Request Validation
Validation | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/validation.md

## Form Request Validation

---

## Testing Browser testing
Testing | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/testing

## Browser testing

Pest v4 includes first-party browser testing support powered by Playwright. This allows you to test your Livewire components in a real browser, interacting with them just like a user would.

### Installing browser testing

First, install the Pest browser plugin:

```shell
composer require pestphp/pest-plugin-browser --dev
```

Next, install Playwright via npm:

```shell
npm install playwright@latest
npx playwright install
```

For complete browser testing documentation, see the [Pest browser testing guide](https://pestphp.com/docs/browser-testing).

### Writing browser tests

Instead of using `Livewire::test()`, you can use `Livewire::visit()` to test your component in a real browser:

```php
it('can create a new post', function () {
    Livewire::visit('post.create')
        ->type('[wire\:model="title"]', 'My first post')
        ->type('[wire\:model="content"]', 'This is the content')
        ->press('Save')
        ->assertSee('Post created successfully');
});
```

Browser tests are slower than unit tests but provide end-to-end confidence that your components work as expected in a real browser environment.

For a complete list of available browser testing assertions, see the [Pest browser testing assertions](https://pestphp.com/docs/browser-testing#content-available-assertions).

> [!info] When to use browser tests
> Use browser tests for critical user flows and complex interactions. For most component testing, the standard `Livewire::test()` approach is faster and sufficient.

---

## Redirecting Redirect to Route
Redirecting | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/redirecting

## Redirect to Route

In case you want to redirect to a page using its route name you can use the `redirectRoute`.

For example, if you have a page with the route named `'profile'` like this:

```php
    Route::get('/user/profile', function () {
        // ...
    })->name('profile');
```

You can use `redirectRoute` to redirect to that page using the name of the route like so:

```php
    $this->redirectRoute('profile');
```

In case you need to pass parameters to the route you may use the second argument of the method `redirectRoute` like so:

```php
    $this->redirectRoute('profile', ['id' => 1]);
```

---

## Wire Model Customizing update timing
Wire Model | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/wire-model

## Customizing update timing

By default, Livewire will only send a network request when an action is performed (like `wire:click` or `wire:submit`), NOT when a `wire:model` input is updated.

This drastically improves the performance of Livewire by reducing network requests and provides a smoother experience for your users.

However, there are occasions where you may want to update the server more frequently for things like real-time validation.

### Live updating

To send property updates to the server as a user types into an input-field, you can append the `.live` modifier to `wire:model`:

```html
<input type="text" wire:model.live="title">
```

#### Customizing the debounce

By default, when using `wire:model.live`, Livewire adds a 150 millisecond debounce to server updates. This means if a user is continually typing, Livewire will wait until the user stops typing for 150 milliseconds before sending a request.

You can customize this timing by appending `.debounce.Xms` after `.live`. Here is an example of changing the debounce to 250 milliseconds:

```html
<input type="text" wire:model.live.debounce.250ms="title">
```

### Updating on "blur" event

The `.blur` modifier delays syncing until the user clicks away from the input:

```html
<input type="text" wire:model.blur="title">
```

To also send a network request on blur, add `.live`:

```html
<input type="text" wire:model.blur.live="title">
```

### Updating on "change" event

The `.change` modifier triggers on the change event, which is useful for select elements:

```html
<select wire:model.change="state">...</select>

<!-- With network request -->
<select wire:model.change.live="state">...</select>
```

### Updating on "enter" key

The `.enter` modifier syncs when the user presses the Enter key:

```html
<input type="text" wire:model.enter="search">

<!-- With network request -->
<input type="text" wire:model.enter.live="search">
```

---

## Validation Deprecated `[#Rule]` attribute
Validation | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/validation

## Deprecated `[#Rule]` attribute

When Livewire v3 first launched, it used the term "Rule" instead of "Validate" for it's validation attributes (`#[Rule]`).

Because of naming conflicts with Laravel rule objects, this has since been changed to `#[Validate]`. Both are supported in Livewire v3, however it is recommended that you change all occurrences of `#[Rule]` with `#[Validate]` to stay current.

---

## Browser Testing submit
Browser Testing | pestphp/pest@4.x | Source: https://github.com/pestphp/docs/blob/4.x/browser-testing.md

### submit

The `submit` method submits the first form found on the page:

```php
$page->submit();
```

---

## Styles Browser support
Styles | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/styles

## Browser support

Scoped styles use [CSS nesting](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting), which is supported in all modern browsers (Chrome 120+, Firefox 117+, Safari 17.2+). For older browser support, consider using a CSS preprocessor or the `@assets` directive with pre-compiled stylesheets.

_[Truncated]_


output:
Wall time: 4.0909 seconds
Output:
[{"type":"text","text":"# Search Results\n\n## Authentication Logging Out Invalidating Sessions on Other Devices\nAuthentication | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/authentication.md\n\n\n### Invalidating Sessions on Other Devices\n\nLaravel also provides a mechanism for invalidating and \"logging out\" a user's sessions that are active on other devices without invalidating the session on their current device. This feature is typically utilized when a user is changing or updating their password and you would like to invalidate sessions on other devices while keeping the current device authenticated.\n\nBefore getting started, you should make sure that the `Illuminate\\Session\\Middleware\\AuthenticateSession` middleware is included on the routes that should receive session authentication. Typically, you should place this middleware on a route group definition so that it can be applied to the majority of your application's routes. By default, the `AuthenticateSession` middleware may be attached to a route using the `auth.session` [middleware alias](/docs/{{version}}/middleware#middleware-aliases):\n\n```php\nRoute::middleware(['auth', 'auth.session'])->group(function () {\n    Route::get('/', function () {\n        // ...\n    });\n});\n```\n\nThen, you may use the `logoutOtherDevices` method provided by the `Auth` facade. This method requires the user to confirm their current password, which your application should accept through an input form:\n\n```php\nuse Illuminate\\Support\\Facades\\Auth;\n\nAuth::logoutOtherDevices($currentPassword);\n```\n\nWhen the `logoutOtherDevices` method is invoked, the user's other sessions will be invalidated entirely, meaning they will be \"logged out\" of all guards they were previously authenticated by.\n\n---\n\n## Authentication Authentication Quickstart Protecting Routes Specifying a Guard\nAuthentication | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/authentication.md\n\n\n#### Specifying a Guard\n\nWhen attaching the `auth` middleware to a route, you may also specify which \"guard\" should be used to authenticate the user. The guard specified should correspond to one of the keys in the `guards` array of your `auth.php` configuration file:\n\n```php\nRoute::get('/flights', function () {\n    // Only authenticated users may access this route...\n})->middleware('auth:admin');\n```\n\n---\n\n## Browser Testing\nBrowser Testing | pestphp/pest@4.x | Source: https://github.com/pestphp/docs/blob/4.x/browser-testing.md\n\n---\ntitle: Browser Testing\ndescription:\n---\n\n# Browser Testing\n\nBrowser testing is an essential part of modern web development, allowing you to ensure that your application works correctly across different browsers and devices. Pest provides a simple and elegant way to write browser tests. Here is an example of how to write a browser test using Pest:\n\n```php\nit('may welcome the user', function () {\n    $page = visit('/');\n\n    $page->assertSee('Welcome');\n});\n```\n\nThis is a basic example of a browser test that checks if the homepage contains the text \"Welcome\". However, Pest's browser testing capabilities go beyond this simple example. You can use various methods to interact with the page, such as clicking buttons, filling out forms, and navigating between pages.\n\nHere is an example of a more complex browser test, on Laravel, that checks if a user can sign in:\n\n```php\nit('may sign in the user', function () {\n    Event::fake();\n\n    User::factory()->create([ // assumes RefreshDatabase trait is used on Pest.php...\n        'email' => 'nuno@laravel.com',\n        'password' => 'password',\n    ]);\n\n    $page = visit('/')->on()->mobile()->firefox();\n\n    $page->click('Sign In')\n         ->assertUrlIs('/login')\n         ->assertSee('Sign In to Your Account')\n         ->fill('email', 'nuno@laravel.com')\n         ->fill('password', 'password')\n         ->click('Submit')\n         ->assertSee('Dashboard');\n\n    $this->assertAuthenticated();\n\n    Event::assertDispatched(UserLoggedIn::class);\n});\n```\n\nNote that, you are leveraging the full power of Laravel's testing capabilities, such as refresh database, event faking, and authentication assertions, while also actually doing browser testing.\n\n## Getting Started\n\nTo get started with browser testing in Pest, you need to install the Pest Browser plugin. You can do this by running the following command:\n\n```bash\ncomposer require pestphp/pest-plugin-browser --dev\n\nnpm install playwright@latest\nnpx playwright install\n```\n\nFinally, add `tests/Browser/Screenshots` to your `.gitignore` file to avoid committing screenshots taken during browser tests.\n\n### Running Browser Tests\n\nRunning browser tests is similar to running regular Pest tests:\n\n```bash\n./vendor/bin/pest\n```\n\nWe recommend running tests in parallel using the `--parallel` option to speed up the execution:\n\n```bash\n./vendor/bin/pest --parallel\n```\n\nFor debugging purposes, you can run the tests in a headed mode and pause the execution at the end of the failed test run:\n\n```bash\n./vendor/bin/pest --debug\n```\n\n### Navigation\n\nThe `visit()` method is used to navigate to a specific URL in your browser test. It provides various methods to interact with the page:\n\n```php\ntest('example', function () {\n    $page = visit('/');\n\n    $page->assertSee('Welcome');\n});\n```\n\n### Using Other Browsers\n\nBy default, the `visit()` method uses Chrome as the browser. However, if you want to use a different browser, you can specify it using the `--browser` option when running the tests:\n\n```bash\n./vendor/bin/pest --browser firefox\n./vendor/bin/pest --browser safari\n```\n\nIf you wish to use a different browser by default without specifying it in the command line, you can set it in your `Pest.php` configuration file:\n\n```php\npest()->browser()->inFirefox();\npest()->browser()->inSafari();\n```\n\n### Using Other Devices\n\nThe `visit()` method uses a desktop viewport. However, you can specify a mobile viewport using the `onMobile()` method. For example:\n\n```php\n$page = visit('/')->on()->mobile();\n```\n\nIf you wish to use a specific device, you can use the `on()` method and chain it with the `macbook14`, `iPhone14Pro`, etc:\n\n```php\n$page = visit('/')->on()->iPhone14Pro();\n```\n\n### Using Dark Mode\n\nPest enforces a light color scheme by default. However, you can specify a dark color scheme using the `inDarkMode()` method:\n\n```php\n$page = visit('/')->inDarkMode();\n```\n\n### Visiting Multiple Pages\n\nYou can visit multiple pages simultaneously by passing an array of URLs to the `visit()` method. This is useful for testing scenarios where you need to interact with multiple pages at once:\n\n```php\n$pages = visit(['/', '/about']);\n\n$pages->assertNoSmoke()\n    ->assertNoAccessibilityIssues()\n    ->assertNoConsoleLogs()\n    ->assertNoJavaScriptErrors();\n\n[$homePage, $aboutPage] = $pages;\n\n$homePage->assertSee('Welcome to our website');\n$aboutPage->assertSee('About Us');\n```\n\n### Navigation\n\nAfter visiting a page, you can navigate to other pages using the `navigate()` method. This method allows you to navigate to a different URL while keeping the current browser context:\n\n```php\n$page = visit('/');\n\n$page->navigate('/about')\n     ->assertSee('About Us');\n```\n\n### Locating Elements\n\nYou can locate elements in the DOM using text or CSS selectors. Pest provides a simple syntax for locating elements:\n\n```php\n// Clicks the first link with the text \"Login\"\n$page->click('Login');\n\n// Clicks the first element with the class \"btn-primary\"\n$page->click('.btn-primary');\n\n// Clicks the element with the data-test attribute \"login\"\n$page->click('@login');\n\n// Clicks the element with the ID \"submit-button\"\n$page->click('#submit-button');\n\n// etc...\n```\n\n### Configuring Timeouts\n\nSometimes, elements may take time to appear on the page. By default, Pest waits for `5` seconds before timing out. You can configure the default timeout for browser tests in your `Pest.php` configuration file:\n\n```php\npest()->browser()->timeout(10000);\n```\n\n### Configuring User Agent\n\nBy default, the User Agent will default to the Browser you're running for tests such as: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/133.0.6943.16 Safari/537.36` \n\nYou may wish to override the User Agent of the browser for all of your tests, you can configure this in the `Pest.php` configuration file:\n\n```php\npest()->browser()->userAgent('CustomUserAgent');\n```\n\n### Configuring Host\n\nBy default, the server will bind to `127.0.0.1` for all browser tests.\n\nYou may wish to override the host for subdomain applications. You can configure this in the `Pest.php` configuration file:\n\n```php\npest()->browser()->withHost('some-subdomain.localhost');\n```\n\n### Geolocation\n\nSometimes, you need to define where the browser believes it is physically on the earth.  This method takes a latitude and longitude and will set the `geolocation` permission in the browser and then make the coordinates available via Javascript's getCurrentPosition API:\n\n```php\n$page = visit('/')\n     ->geolocation(39.399872, -8.224454);\n```\n\n### Configuring Locale\n\nYou can set the locale for your test requests using the `withLocale` method. This is particularly useful for testing multilingual applications.\n\n```php\n$page = visit('/')->withLocale('fr-FR');\n\n$page->assertSee('Bienvenue');\n```\n### Configuring Timezone\n\nYou can set the timezone for your test requests using the `withTimezone` method. This is useful for testing date and time displays in different time zones.\n\n```php\n$page = visit('/')->withTimezone('America/New_York');\n\n$page->assertSee('EST');\n```\n\n### Configuring UserAgent\n\nYou can set the User-Agent header for your test requests using the `withUserAgent` method. This is useful for testing how your application responds to different types of clients, such as mobile browsers or bots.\n\n```php\n$page = visit('/')->withUserAgent('Googlebot');\n\n$page->assertSee('Welcome, bot!');\n```\n\n### Configuring Host\n\nYou can set the host for your test server using the `withHost` method. This is useful for testing subdomains or where different hosts serve different content.\n\n```php\n$page = visit('/dashboard')->withHost('some-subdomain.localhost');\n\n$page->assertSee('Welcome to Some Subdomain');\n```\n\n## Table of Contents\n\n### Available Assertions\n\n
\n\n[assertTitle](#assert-title)\n[assertTitleContains](#assert-title-contains)\n[assertSee](#assert-see)\n[assertDontSee](#assert-dont-see)\n[assertSeeIn](#assert-see-in)\n[assertDontSeeIn](#assert-dont-see-in)\n[assertSeeAnythingIn](#assert-see-anything-in)\n[assertSeeNothingIn](#assert-see-nothing-in)\n[assertCount](#assert-count)\n[assertScript](#assert-script)\n[assertSourceHas](#assert-source-has)\n[assertSourceMissing](#assert-source-missing)\n[assertSeeLink](#assert-see-link)\n[assertDontSeeLink](#assert-dont-see-link)\n[assertChecked](#assert-checked)\n[assertNotChecked](#assert-not-checked)\n[assertIndeterminate](#assert-indeterminate)\n[assertRadioSelected](#assert-radio-selected)\n[assertRadioNotSelected](#assert-radio-not-selected)\n[assertSelected](#assert-selected)\n[assertNotSelected](#assert-not-selected)\n[assertValue](#assert-value)\n[assertValueIsNot](#assert-value-is-not)\n[assertAttribute](#assert-attribute)\n[assertAttributeMissing](#assert-attribute-missing)\n[assertAttributeContains](#assert-attribute-contains)\n[assertAttributeDoesntContain](#assert-attribute-doesnt-contain)\n[assertAriaAttribute](#assert-aria-attribute)\n[assertDataAttribute](#assert-data-attribute)\n[assertVisible](#assert-visible)\n[assertPresent](#assert-present)\n[assertNotPresent](#assert-not-present)\n[assertMissing](#assert-missing)\n[assertEnabled](#assert-enabled)\n[assertDisabled](#assert-disabled)\n[assertButtonEnabled](#assert-button-enabled)\n[assertButtonDisabled](#assert-button-disabled)\n[assertUrlIs](#assert-url-is)\n[assertSchemeIs](#assert-scheme-is)\n[assertSchemeIsNot](#assert-scheme-is-not)\n[assertHostIs](#assert-host-is)\n[assertHostIsNot](#assert-host-is-not)\n[assertPortIs](#assert-port-is)\n[assertPortIsNot](#assert-port-is-not)\n[assertPathBeginsWith](#assert-path-begins-with)\n[assertPathEndsWith](#assert-path-ends-with)\n[assertPathContains](#assert-path-contains)\n[assertPathIs](#assert-path-is)\n[assertPathIsNot](#assert-path-is-not)\n[assertQueryStringHas](#assert-query-string-has)\n[assertQueryStringMissing](#assert-query-string-missing)\n[assertFragmentIs](#assert-fragment-is)\n[assertFragmentBeginsWith](#assert-fragment-begins-with)\n[assertFragmentIsNot](#assert-fragment-is-not)\n[assertNoSmoke](#assert-no-smoke)\n[assertNoConsoleLogs](#assert-no-console-logs)\n[assertNoJavaScriptErrors](#assert-no-javascript-errors)\n[assertNoAccessibilityIssues](#assert-no-accessibility-issues)\n[assertScreenshotMatches](#assert-screenshot-matches)\n\n
\n\n### Element Interactions\n\n
\n\n[click](#click)\n[text](#text)\n[attribute](#attribute)\n[keys](#keys)\n[withKeyDown](#withKeyDown)\n[type](#type)\n[typeSlowly](#type-slowly)\n[select](#select)\n[append](#append)\n[clear](#clear)\n[radio](#radio)\n[check](#check)\n[uncheck](#uncheck)\n[attach](#attach)\n[press](#press)\n[pressAndWaitFor](#press-and-wait-for)\n[drag](#drag)\n[hover](#hover)\n[submit](#submit)\n[value](#value)\n[withinIframe](#within-iframe)\n[resize](#resize)\n[script](#script)\n[content](#content)\n[url](#url)\n[wait](#wait)\n[waitForKey](#wait-for-key)\n\n
\n\n### Debugging tests\n\n
\n\n[debug](#debug)\n[screenshot](#screenshot)\n[screenshotElement](#screenshot-element)\n[tinker](#tinker)\n[headed](#headed)\n\n
\n\n## Element Assertions\n\n---\n\n## Http Tests Validation Assertions assertInvalid\nHttp Tests | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/http-tests.md\n\n\n#### assertInvalid\n\nAssert that the response has validation errors for the given keys. This method may be used for asserting against responses where the validation errors are returned as a JSON structure or where the validation errors have been flashed to the session:\n\n```php\n$response->assertInvalid(['name', 'email']);\n```\n\nYou may also assert that a given key has a particular validation error message. When doing so, you may provide the entire message or only a small portion of the message:\n\n```php\n$response->assertInvalid([\n    'name' => 'The name field is required.',\n    'email' => 'valid email address',\n]);\n```\n\n---\n\n## Validation See also\nValidation | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/validation\n\n## See also\n\n- **[Forms](/docs/4.x/forms)** — Validate form inputs with real-time feedback\n- **[Properties](/docs/4.x/properties)** — Validate property values before persisting\n- **[Validate Attribute](/docs/4.x/attribute-validate)** — Use #[Validate] for property validation\n- **[Actions](/docs/4.x/actions)** — Validate data in action methods\n\n---\n\n## Wire Transition Browser support\nWire Transition | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/wire-transition\n\n## Browser support\n\nView Transitions are supported in Chrome 111+, Edge 111+, and Safari 18+. In browsers that don't support View Transitions, elements will appear and disappear without animation—the functionality still works, just without the visual transition.\n\n> [!warning] Firefox has limited support\n> Firefox 144+ supports basic view transitions, but does not support transition types.\n\n[View browser support on caniuse.com →](https://caniuse.com/view-transitions)\n\n---\n\n## Wire Transition Customizing animations with CSS\nWire Transition | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/wire-transition\n\n## Customizing animations with CSS\n\nView Transitions are controlled entirely through CSS. You can customize the animation by targeting the view-transition pseudo-elements:\n\n```css\n/* Customize the transition for a specific element */\n::view-transition-old(sidebar) {\n    animation: 300ms ease-out both slide-out;\n}\n\n::view-transition-new(sidebar) {\n    animation: 300ms ease-in both slide-in;\n}\n\n@keyframes slide-out {\n    to { transform: translateX(-100%); }\n}\n\n@keyframes slide-in {\n    from { transform: translateX(100%); }\n}\n```\n\nThe View Transitions API provides three pseudo-elements you can style:\n- `::view-transition-old(name)` — The outgoing element's snapshot\n- `::view-transition-new(name)` — The incoming element's snapshot\n- `::view-transition-group(name)` — Container for both snapshots\n\n---\n\n## Passport Protecting Routes Via Middleware\nPassport | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passport.md\n\n\n### Via Middleware\n\nPassport includes an [authentication guard](/docs/{{version}}/authentication#adding-custom-guards) that will validate access tokens on incoming requests. Once you have configured the `api` guard to use the `passport` driver, you only need to specify the `auth:api` middleware on any routes that should require a valid access token:\n\n```php\nRoute::get('/user', function () {\n    // Only API authenticated users may access this route...\n})->middleware('auth:api');\n```\n\n> [!WARNING]\n> If you are using the [client credentials grant](#client-credentials-grant), you should use [the `Laravel\\Passport\\Http\\Middleware\\EnsureClientIsResourceOwner` middleware](#client-credentials-grant) to protect your routes instead of the `auth:api` middleware.\n\n---\n\n## Dusk Browser Basics Authentication\nDusk | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/dusk.md\n\n\n### Authentication\n\nOften, you will be testing pages that require authentication. You can use Dusk's `loginAs` method in order to avoid interacting with your application's login screen during every test. The `loginAs` method accepts a primary key associated with your authenticatable model or an authenticatable model instance:\n\n```php\nuse App\\Models\\User;\nuse Laravel\\Dusk\\Browser;\n\n$this->browse(function (Browser $browser) {\n    $browser->loginAs(User::find(1))\n        ->visit('/home');\n});\n```\n\n> [!WARNING]\n> After using the `loginAs` method, the user session will be maintained for all tests within the file.\n\n---\n\n## Validation Form Request Validation\nValidation | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/validation.md\n\n\n## Form Request Validation\n\n---\n\n## Testing Browser testing\nTesting | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/testing\n\n## Browser testing\n\nPest v4 includes first-party browser testing support powered by Playwright. This allows you to test your Livewire components in a real browser, interacting with them just like a user would.\n\n### Installing browser testing\n\nFirst, install the Pest browser plugin:\n\n```shell\ncomposer require pestphp/pest-plugin-browser --dev\n```\n\nNext, install Playwright via npm:\n\n```shell\nnpm install playwright@latest\nnpx playwright install\n```\n\nFor complete browser testing documentation, see the [Pest browser testing guide](https://pestphp.com/docs/browser-testing).\n\n### Writing browser tests\n\nInstead of using `Livewire::test()`, you can use `Livewire::visit()` to test your component in a real browser:\n\n```php\nit('can create a new post', function () {\n    Livewire::visit('post.create')\n        ->type('[wire\\:model=\"title\"]', 'My first post')\n        ->type('[wire\\:model=\"content\"]', 'This is the content')\n        ->press('Save')\n        ->assertSee('Post created successfully');\n});\n```\n\nBrowser tests are slower than unit tests but provide end-to-end confidence that your components work as expected in a real browser environment.\n\nFor a complete list of available browser testing assertions, see the [Pest browser testing assertions](https://pestphp.com/docs/browser-testing#content-available-assertions).\n\n> [!info] When to use browser tests\n> Use browser tests for critical user flows and complex interactions. For most component testing, the standard `Livewire::test()` approach is faster and sufficient.\n\n---\n\n## Redirecting Redirect to Route\nRedirecting | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/redirecting\n\n## Redirect to Route\n\nIn case you want to redirect to a page using its route name you can use the `redirectRoute`.\n\nFor example, if you have a page with the route named `'profile'` like this:\n\n```php\n    Route::get('/user/profile', function () {\n        // ...\n    })->name('profile');\n```\n\nYou can use `redirectRoute` to redirect to that page using the name of the route like so:\n\n```php\n    $this->redirectRoute('profile');\n```\n\nIn case you need to pass parameters to the route you may use the second argument of the method `redirectRoute` like so:\n\n```php\n    $this->redirectRoute('profile', ['id' => 1]);\n```\n\n---\n\n## Wire Model Customizing update timing\nWire Model | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/wire-model\n\n## Customizing update timing\n\nBy default, Livewire will only send a network request when an action is performed (like `wire:click` or `wire:submit`), NOT when a `wire:model` input is updated.\n\nThis drastically improves the performance of Livewire by reducing network requests and provides a smoother experience for your users.\n\nHowever, there are occasions where you may want to update the server more frequently for things like real-time validation.\n\n### Live updating\n\nTo send property updates to the server as a user types into an input-field, you can append the `.live` modifier to `wire:model`:\n\n```html\n<input type=\"text\" wire:model.live=\"title\">\n```\n\n#### Customizing the debounce\n\nBy default, when using `wire:model.live`, Livewire adds a 150 millisecond debounce to server updates. This means if a user is continually typing, Livewire will wait until the user stops typing for 150 milliseconds before sending a request.\n\nYou can customize this timing by appending `.debounce.Xms` after `.live`. Here is an example of changing the debounce to 250 milliseconds:\n\n```html\n<input type=\"text\" wire:model.live.debounce.250ms=\"title\">\n```\n\n### Updating on \"blur\" event\n\nThe `.blur` modifier delays syncing until the user clicks away from the input:\n\n```html\n<input type=\"text\" wire:model.blur=\"title\">\n```\n\nTo also send a network request on blur, add `.live`:\n\n```html\n<input type=\"text\" wire:model.blur.live=\"title\">\n```\n\n### Updating on \"change\" event\n\nThe `.change` modifier triggers on the change event, which is useful for select elements:\n\n```html\n<select wire:model.change=\"state\">...</select>\n\n<!-- With network request -->\n<select wire:model.change.live=\"state\">...</select>\n```\n\n### Updating on \"enter\" key\n\nThe `.enter` modifier syncs when the user presses the Enter key:\n\n```html\n<input type=\"text\" wire:model.enter=\"search\">\n\n<!-- With network request -->\n<input type=\"text\" wire:model.enter.live=\"search\">\n```\n\n---\n\n## Validation Deprecated `[#Rule]` attribute\nValidation | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/validation\n\n## Deprecated `[#Rule]` attribute\n\nWhen Livewire v3 first launched, it used the term \"Rule\" instead of \"Validate\" for it's validation attributes (`#[Rule]`).\n\nBecause of naming conflicts with Laravel rule objects, this has since been changed to `#[Validate]`. Both are supported in Livewire v3, however it is recommended that you change all occurrences of `#[Rule]` with `#[Validate]` to stay current.\n\n---\n\n## Browser Testing submit\nBrowser Testing | pestphp/pest@4.x | Source: https://github.com/pestphp/docs/blob/4.x/browser-testing.md\n\n\n### submit\n\nThe `submit` method submits the first form found on the page:\n\n```php\n$page->submit();\n```\n\n---\n\n## Styles Browser support\nStyles | livewire/livewire@4.x | Source: https://livewire.laravel.com/docs/4.x/styles\n\n## Browser support\n\nScoped styles use [CSS nesting](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting), which is supported in all modern browsers (Chrome 120+, Firefox 117+, Safari 17.2+). For older browser support, consider using a CSS preprocessor or the `@assets` directive with pre-compiled stylesheets.\n\n_[Truncated]_"}]


message: The docs confirm the important bits for this slice: guarded routes can target `auth:customer`, logout should explicitly clear the guard/session, and Pest browser tests can drive the Livewire forms directly. I’m reading the existing account implementation now so the new addresses page matches it instead of introducing a parallel style.

phase: commentary


type: message

role: assistant

text: The docs confirm the important bits for this slice: guarded routes can target `auth:customer`, logout should explicitly clear the guard/session, and Pest browser tests can drive the Livewire forms directly. I’m reading the existing account implementation now so the new addresses page matches it instead of introducing a parallel style.


cmd: sed -n '1,240p' app/Livewire/Storefront/Account/Orders/Index.php


cmd: sed -n '1,260p' app/Livewire/Storefront/Account/Orders/Show.php


cmd: sed -n '1,260p' resources/views/livewire/storefront/account/orders/index.blade.php


cmd: sed -n '1,280p' resources/views/livewire/storefront/account/orders/show.blade.php


command: sed -n '1,260p' app/Livewire/Storefront/Account/Orders/Show.php

Show.php

type: read

aggregated_output:
<?php

namespace App\Livewire\Storefront\Account\Orders;

use App\Models\Customer;
use App\Models\Order;
use App\Models\Store;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Locked;
use Livewire\Component;

class Show extends Component
{
    #[Locked]
    public int $storeId;

    #[Locked]
    public int $orderId;

    public function mount(Order $order): void
    {
        $store = app('current_store');
        $customer = Auth::guard('customer')->user();

        abort_unless($store instanceof Store && $customer instanceof Customer, 404);

        $order = Order::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->where('customer_id', $customer->getKey())
            ->whereKey($order->getKey())
            ->first();

        abort_unless($order instanceof Order, 404);

        $this->storeId = $store->getKey();
        $this->orderId = $order->getKey();
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.orders.show', [
            'order' => $this->order(),
        ])->layout('layouts.storefront', [
            'title' => 'Order details',
        ]);
    }

    private function order(): Order
    {
        return Order::withoutGlobalScopes()
            ->with(['lines', 'payments', 'refunds', 'fulfillments.lines'])
            ->where('store_id', $this->storeId)
            ->where('customer_id', Auth::guard('customer')->id())
            ->findOrFail($this->orderId);
    }
}

status: completed


command:
/bin/zsh
-lc
sed -n '1,260p' routes/web.php

web.php

cmd: sed -n '1,260p' routes/web.php

aggregated_output:
<?php

use App\Http\Controllers\Api\OAuthController;
use App\Http\Controllers\Storefront\Account\Auth\CustomerPasswordResetController;
use App\Http\Middleware\EnsureUserEmailIsVerified;
use App\Livewire\Admin\Analytics\Index as AdminAnalyticsIndex;
use App\Livewire\Admin\Apps\Index as AdminAppsIndex;
use App\Livewire\Admin\Apps\Show as AdminAppShow;
use App\Livewire\Admin\Auth\Login as AdminLogin;
use App\Livewire\Admin\Collections\Form as AdminCollectionForm;
use App\Livewire\Admin\Collections\Index as AdminCollectionsIndex;
use App\Livewire\Admin\Customers\Index as AdminCustomersIndex;
use App\Livewire\Admin\Customers\Show as AdminCustomerShow;
use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Livewire\Admin\Developers\Index as AdminDevelopersIndex;
use App\Livewire\Admin\Discounts\Form as AdminDiscountForm;
use App\Livewire\Admin\Discounts\Index as AdminDiscountsIndex;
use App\Livewire\Admin\Inventory\Index as AdminInventoryIndex;
use App\Livewire\Admin\Navigation\Index as AdminNavigationIndex;
use App\Livewire\Admin\Orders\Index as AdminOrdersIndex;
use App\Livewire\Admin\Orders\Show as AdminOrderShow;
use App\Livewire\Admin\Pages\Form as AdminPageForm;
use App\Livewire\Admin\Pages\Index as AdminPagesIndex;
use App\Livewire\Admin\Products\Form as AdminProductForm;
use App\Livewire\Admin\Products\Index as AdminProductsIndex;
use App\Livewire\Admin\Search\Settings as AdminSearchSettings;
use App\Livewire\Admin\Settings\Checkout as AdminSettingsCheckout;
use App\Livewire\Admin\Settings\Index as AdminSettingsIndex;
use App\Livewire\Admin\Settings\Notifications as AdminSettingsNotifications;
use App\Livewire\Admin\Settings\Shipping as AdminSettingsShipping;
use App\Livewire\Admin\Settings\Taxes as AdminSettingsTaxes;
use App\Livewire\Admin\Themes\Editor as AdminThemeEditor;
use App\Livewire\Admin\Themes\Index as AdminThemesIndex;
use App\Livewire\Storefront\Account\Auth\ForgotPassword as CustomerForgotPassword;
use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Account\Auth\Register as CustomerRegister;
use App\Livewire\Storefront\Account\Auth\ResetPassword as CustomerResetPassword;
use App\Livewire\Storefront\Account\Orders\Index as CustomerOrdersIndex;
use App\Livewire\Storefront\Account\Orders\Show as CustomerOrderShow;
use App\Livewire\Storefront\Cart\Show as StorefrontCartShow;
use App\Livewire\Storefront\Checkout\Confirmation as StorefrontCheckoutConfirmation;
use App\Livewire\Storefront\Checkout\Show as StorefrontCheckoutShow;
use App\Livewire\Storefront\Collections\Index as StorefrontCollectionsIndex;
use App\Livewire\Storefront\Collections\Show as StorefrontCollectionShow;
use App\Livewire\Storefront\Home as StorefrontHome;
use App\Livewire\Storefront\Pages\Show as StorefrontPageShow;
use App\Livewire\Storefront\Products\Show as StorefrontProductShow;
use App\Livewire\Storefront\Search\Index as StorefrontSearchIndex;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Http\Controllers\NewPasswordController as FortifyNewPasswordController;
use Laravel\Fortify\Http\Controllers\PasswordResetLinkController as FortifyPasswordResetLinkController;

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('/', StorefrontHome::class)->name('home');
    Route::livewire('collections', StorefrontCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/{handle}', StorefrontCollectionShow::class)->name('collections.show');
    Route::livewire('products/{handle}', StorefrontProductShow::class)->name('products.show');
    Route::livewire('cart', StorefrontCartShow::class)->name('cart.show');
    Route::livewire('checkout', StorefrontCheckoutShow::class)->name('checkout.show');
    Route::livewire('checkout/confirmation/{order}', StorefrontCheckoutConfirmation::class)->name('checkout.confirmation');
    Route::livewire('search', StorefrontSearchIndex::class)->name('search.index');
    Route::livewire('pages/{handle}', StorefrontPageShow::class)->name('pages.show');

    Route::livewire('forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.request');

    Route::post('forgot-password', [CustomerPasswordResetController::class, 'send'])
        ->middleware('guest:customer')
        ->name('customer.password.email');

    Route::livewire('reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.reset');

    Route::post('reset-password', [CustomerPasswordResetController::class, 'update'])
        ->middleware('guest:customer')
        ->name('customer.password.update');
});

Route::livewire('admin/login', AdminLogin::class)
    ->middleware('guest')
    ->name('admin.login');

Route::get('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.request');

Route::post('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.email');

Route::get('admin/reset-password/{token}', [FortifyNewPasswordController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.reset');

Route::post('admin/reset-password', [FortifyNewPasswordController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.update');

Route::post('admin/logout', function () {
    Auth::guard('web')->logout();

    request()->session()->invalidate();
    request()->session()->regenerateToken();

    return redirect()->route('admin.login');
})->middleware('auth')->name('admin.logout');

Route::get('oauth/authorize', [OAuthController::class, 'authorize'])
    ->middleware('auth')
    ->name('oauth.authorize');

Route::post('oauth/token', [OAuthController::class, 'token'])
    ->name('oauth.token');

Route::middleware(['auth', EnsureUserEmailIsVerified::class, 'admin'])->prefix('admin')->name('admin.')->group(function (): void {
    Route::livewire('/', AdminDashboard::class)->name('dashboard');
    Route::livewire('analytics', AdminAnalyticsIndex::class)->name('analytics.index');
    Route::livewire('apps', AdminAppsIndex::class)->name('apps.index');
    Route::livewire('apps/{installation}', AdminAppShow::class)->name('apps.show');
    Route::livewire('developers', AdminDevelopersIndex::class)->name('developers.index');
    Route::livewire('products', AdminProductsIndex::class)->name('products.index');
    Route::livewire('products/create', AdminProductForm::class)->name('products.create');
    Route::livewire('products/{product}/edit', AdminProductForm::class)->name('products.edit');
    Route::livewire('inventory', AdminInventoryIndex::class)->name('inventory.index');
    Route::livewire('orders', AdminOrdersIndex::class)->name('orders.index');
    Route::livewire('orders/{order}', AdminOrderShow::class)->name('orders.show');
    Route::livewire('customers', AdminCustomersIndex::class)->name('customers.index');
    Route::livewire('customers/{customer}', AdminCustomerShow::class)->name('customers.show');
    Route::livewire('discounts', AdminDiscountsIndex::class)->name('discounts.index');
    Route::livewire('discounts/create', AdminDiscountForm::class)->name('discounts.create');
    Route::livewire('discounts/{discount}/edit', AdminDiscountForm::class)->name('discounts.edit');
    Route::livewire('pages', AdminPagesIndex::class)->name('pages.index');
    Route::livewire('pages/create', AdminPageForm::class)->name('pages.create');
    Route::livewire('pages/{page}/edit', AdminPageForm::class)->name('pages.edit');
    Route::livewire('navigation', AdminNavigationIndex::class)->name('navigation.index');
    Route::livewire('themes', AdminThemesIndex::class)->name('themes.index');
    Route::livewire('themes/{theme}/editor', AdminThemeEditor::class)->name('themes.editor');
    Route::livewire('settings', AdminSettingsIndex::class)->name('settings.index');
    Route::livewire('settings/shipping', AdminSettingsShipping::class)->name('settings.shipping');
    Route::livewire('settings/taxes', AdminSettingsTaxes::class)->name('settings.taxes');
    Route::livewire('settings/checkout', AdminSettingsCheckout::class)->name('settings.checkout');
    Route::livewire('settings/notifications', AdminSettingsNotifications::class)->name('settings.notifications');
    Route::livewire('search/settings', AdminSearchSettings::class)->name('search.settings');
    Route::livewire('collections', AdminCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/create', AdminCollectionForm::class)->name('collections.create');
    Route::livewire('collections/{collection}/edit', AdminCollectionForm::class)->name('collections.edit');
});

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('account/login', CustomerLogin::class)
        ->middleware('guest:customer')
        ->name('account.login');

    Route::livewire('account/register', CustomerRegister::class)
        ->middleware('guest:customer')
        ->name('account.register');

    Route::livewire('account/forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.request');

    Route::livewire('account/reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.reset');

    Route::livewire('account', CustomerOrdersIndex::class)
        ->middleware('auth:customer')
        ->name('account.dashboard');

    Route::livewire('account/orders/{order}', CustomerOrderShow::class)
        ->middleware('auth:customer')
        ->name('account.orders.show');
});

Route::redirect('dashboard', 'admin')
    ->middleware(['auth', 'verified'])
    ->name('dashboard');

require __DIR__.'/settings.php';


command: sed -n '1,240p' app/Livewire/Storefront/Account/Orders/Index.php

aggregated_output:
<?php

namespace App\Livewire\Storefront\Account\Orders;

use App\Models\Customer;
use App\Models\Order;
use App\Models\Store;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Locked;
use Livewire\Component;

class Index extends Component
{
    #[Locked]
    public int $storeId;

    public function mount(): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $this->storeId = $store->getKey();
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.orders.index', [
            'orders' => $this->orders(),
        ])->layout('layouts.storefront', [
            'title' => 'Account',
        ]);
    }

    /**
     * @return Collection<int, Order>
     */
    private function orders(): Collection
    {
        $customer = Auth::guard('customer')->user();

        abort_unless($customer instanceof Customer, 403);

        return Order::withoutGlobalScopes()
            ->where('store_id', $this->storeId)
            ->where('customer_id', $customer->getKey())
            ->latest('placed_at')
            ->limit(20)
            ->get();
    }
}


command: sed -n '1,260p' resources/views/livewire/storefront/account/orders/index.blade.php

aggregated_output:
    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account'],
    ]" />

Orders

            @forelse ($orders as $order)

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                        <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                        <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" class="justify-start sm:justify-end" />

            @empty

                    <flux:icon name="shopping-bag" class="mx-auto size-10 text-zinc-400 dark:text-zinc-600" />

No orders yet

                    <flux:button :href="route('collections.index')" wire:navigate variant="primary" class="mt-6">
                        Browse products
                    </flux:button>

            @endforelse


output:
Chunk ID: a1d471
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2477
Output:
<?php

use App\Http\Controllers\Api\OAuthController;
use App\Http\Controllers\Storefront\Account\Auth\CustomerPasswordResetController;
use App\Http\Middleware\EnsureUserEmailIsVerified;
use App\Livewire\Admin\Analytics\Index as AdminAnalyticsIndex;
use App\Livewire\Admin\Apps\Index as AdminAppsIndex;
use App\Livewire\Admin\Apps\Show as AdminAppShow;
use App\Livewire\Admin\Auth\Login as AdminLogin;
use App\Livewire\Admin\Collections\Form as AdminCollectionForm;
use App\Livewire\Admin\Collections\Index as AdminCollectionsIndex;
use App\Livewire\Admin\Customers\Index as AdminCustomersIndex;
use App\Livewire\Admin\Customers\Show as AdminCustomerShow;
use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Livewire\Admin\Developers\Index as AdminDevelopersIndex;
use App\Livewire\Admin\Discounts\Form as AdminDiscountForm;
use App\Livewire\Admin\Discounts\Index as AdminDiscountsIndex;
use App\Livewire\Admin\Inventory\Index as AdminInventoryIndex;
use App\Livewire\Admin\Navigation\Index as AdminNavigationIndex;
use App\Livewire\Admin\Orders\Index as AdminOrdersIndex;
use App\Livewire\Admin\Orders\Show as AdminOrderShow;
use App\Livewire\Admin\Pages\Form as AdminPageForm;
use App\Livewire\Admin\Pages\Index as AdminPagesIndex;
use App\Livewire\Admin\Products\Form as AdminProductForm;
use App\Livewire\Admin\Products\Index as AdminProductsIndex;
use App\Livewire\Admin\Search\Settings as AdminSearchSettings;
use App\Livewire\Admin\Settings\Checkout as AdminSettingsCheckout;
use App\Livewire\Admin\Settings\Index as AdminSettingsIndex;
use App\Livewire\Admin\Settings\Notifications as AdminSettingsNotifications;
use App\Livewire\Admin\Settings\Shipping as AdminSettingsShipping;
use App\Livewire\Admin\Settings\Taxes as AdminSettingsTaxes;
use App\Livewire\Admin\Themes\Editor as AdminThemeEditor;
use App\Livewire\Admin\Themes\Index as AdminThemesIndex;
use App\Livewire\Storefront\Account\Auth\ForgotPassword as CustomerForgotPassword;
use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Account\Auth\Register as CustomerRegister;
use App\Livewire\Storefront\Account\Auth\ResetPassword as CustomerResetPassword;
use App\Livewire\Storefront\Account\Orders\Index as CustomerOrdersIndex;
use App\Livewire\Storefront\Account\Orders\Show as CustomerOrderShow;
use App\Livewire\Storefront\Cart\Show as StorefrontCartShow;
use App\Livewire\Storefront\Checkout\Confirmation as StorefrontCheckoutConfirmation;
use App\Livewire\Storefront\Checkout\Show as StorefrontCheckoutShow;
use App\Livewire\Storefront\Collections\Index as StorefrontCollectionsIndex;
use App\Livewire\Storefront\Collections\Show as StorefrontCollectionShow;
use App\Livewire\Storefront\Home as StorefrontHome;
use App\Livewire\Storefront\Pages\Show as StorefrontPageShow;
use App\Livewire\Storefront\Products\Show as StorefrontProductShow;
use App\Livewire\Storefront\Search\Index as StorefrontSearchIndex;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Http\Controllers\NewPasswordController as FortifyNewPasswordController;
use Laravel\Fortify\Http\Controllers\PasswordResetLinkController as FortifyPasswordResetLinkController;

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('/', StorefrontHome::class)->name('home');
    Route::livewire('collections', StorefrontCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/{handle}', StorefrontCollectionShow::class)->name('collections.show');
    Route::livewire('products/{handle}', StorefrontProductShow::class)->name('products.show');
    Route::livewire('cart', StorefrontCartShow::class)->name('cart.show');
    Route::livewire('checkout', StorefrontCheckoutShow::class)->name('checkout.show');
    Route::livewire('checkout/confirmation/{order}', StorefrontCheckoutConfirmation::class)->name('checkout.confirmation');
    Route::livewire('search', StorefrontSearchIndex::class)->name('search.index');
    Route::livewire('pages/{handle}', StorefrontPageShow::class)->name('pages.show');

    Route::livewire('forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.request');

    Route::post('forgot-password', [CustomerPasswordResetController::class, 'send'])
        ->middleware('guest:customer')
        ->name('customer.password.email');

    Route::livewire('reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.reset');

    Route::post('reset-password', [CustomerPasswordResetController::class, 'update'])
        ->middleware('guest:customer')
        ->name('customer.password.update');
});

Route::livewire('admin/login', AdminLogin::class)
    ->middleware('guest')
    ->name('admin.login');

Route::get('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.request');

Route::post('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.email');

Route::get('admin/reset-password/{token}', [FortifyNewPasswordController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.reset');

Route::post('admin/reset-password', [FortifyNewPasswordController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.update');

Route::post('admin/logout', function () {
    Auth::guard('web')->logout();

    request()->session()->invalidate();
    request()->session()->regenerateToken();

    return redirect()->route('admin.login');
})->middleware('auth')->name('admin.logout');

Route::get('oauth/authorize', [OAuthController::class, 'authorize'])
    ->middleware('auth')
    ->name('oauth.authorize');

Route::post('oauth/token', [OAuthController::class, 'token'])
    ->name('oauth.token');

Route::middleware(['auth', EnsureUserEmailIsVerified::class, 'admin'])->prefix('admin')->name('admin.')->group(function (): void {
    Route::livewire('/', AdminDashboard::class)->name('dashboard');
    Route::livewire('analytics', AdminAnalyticsIndex::class)->name('analytics.index');
    Route::livewire('apps', AdminAppsIndex::class)->name('apps.index');
    Route::livewire('apps/{installation}', AdminAppShow::class)->name('apps.show');
    Route::livewire('developers', AdminDevelopersIndex::class)->name('developers.index');
    Route::livewire('products', AdminProductsIndex::class)->name('products.index');
    Route::livewire('products/create', AdminProductForm::class)->name('products.create');
    Route::livewire('products/{product}/edit', AdminProductForm::class)->name('products.edit');
    Route::livewire('inventory', AdminInventoryIndex::class)->name('inventory.index');
    Route::livewire('orders', AdminOrdersIndex::class)->name('orders.index');
    Route::livewire('orders/{order}', AdminOrderShow::class)->name('orders.show');
    Route::livewire('customers', AdminCustomersIndex::class)->name('customers.index');
    Route::livewire('customers/{customer}', AdminCustomerShow::class)->name('customers.show');
    Route::livewire('discounts', AdminDiscountsIndex::class)->name('discounts.index');
    Route::livewire('discounts/create', AdminDiscountForm::class)->name('discounts.create');
    Route::livewire('discounts/{discount}/edit', AdminDiscountForm::class)->name('discounts.edit');
    Route::livewire('pages', AdminPagesIndex::class)->name('pages.index');
    Route::livewire('pages/create', AdminPageForm::class)->name('pages.create');
    Route::livewire('pages/{page}/edit', AdminPageForm::class)->name('pages.edit');
    Route::livewire('navigation', AdminNavigationIndex::class)->name('navigation.index');
    Route::livewire('themes', AdminThemesIndex::class)->name('themes.index');
    Route::livewire('themes/{theme}/editor', AdminThemeEditor::class)->name('themes.editor');
    Route::livewire('settings', AdminSettingsIndex::class)->name('settings.index');
    Route::livewire('settings/shipping', AdminSettingsShipping::class)->name('settings.shipping');
    Route::livewire('settings/taxes', AdminSettingsTaxes::class)->name('settings.taxes');
    Route::livewire('settings/checkout', AdminSettingsCheckout::class)->name('settings.checkout');
    Route::livewire('settings/notifications', AdminSettingsNotifications::class)->name('settings.notifications');
    Route::livewire('search/settings', AdminSearchSettings::class)->name('search.settings');
    Route::livewire('collections', AdminCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/create', AdminCollectionForm::class)->name('collections.create');
    Route::livewire('collections/{collection}/edit', AdminCollectionForm::class)->name('collections.edit');
});

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('account/login', CustomerLogin::class)
        ->middleware('guest:customer')
        ->name('account.login');

    Route::livewire('account/register', CustomerRegister::class)
        ->middleware('guest:customer')
        ->name('account.register');

    Route::livewire('account/forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.request');

    Route::livewire('account/reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.reset');

    Route::livewire('account', CustomerOrdersIndex::class)
        ->middleware('auth:customer')
        ->name('account.dashboard');

    Route::livewire('account/orders/{order}', CustomerOrderShow::class)
        ->middleware('auth:customer')
        ->name('account.orders.show');
});

Route::redirect('dashboard', 'admin')
    ->middleware(['auth', 'verified'])
    ->name('dashboard');

require __DIR__.'/settings.php';


output:
Chunk ID: 4d61bc
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 302
Output:
<?php

namespace App\Livewire\Storefront\Account\Orders;

use App\Models\Customer;
use App\Models\Order;
use App\Models\Store;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Locked;
use Livewire\Component;

class Index extends Component
{
    #[Locked]
    public int $storeId;

    public function mount(): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $this->storeId = $store->getKey();
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.orders.index', [
            'orders' => $this->orders(),
        ])->layout('layouts.storefront', [
            'title' => 'Account',
        ]);
    }

    /**
     * @return Collection<int, Order>
     */
    private function orders(): Collection
    {
        $customer = Auth::guard('customer')->user();

        abort_unless($customer instanceof Customer, 403);

        return Order::withoutGlobalScopes()
            ->where('store_id', $this->storeId)
            ->where('customer_id', $customer->getKey())
            ->latest('placed_at')
            ->limit(20)
            ->get();
    }
}


output:
Chunk ID: d2cbca
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 375
Output:
<?php

namespace App\Livewire\Storefront\Account\Orders;

use App\Models\Customer;
use App\Models\Order;
use App\Models\Store;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Locked;
use Livewire\Component;

class Show extends Component
{
    #[Locked]
    public int $storeId;

    #[Locked]
    public int $orderId;

    public function mount(Order $order): void
    {
        $store = app('current_store');
        $customer = Auth::guard('customer')->user();

        abort_unless($store instanceof Store && $customer instanceof Customer, 404);

        $order = Order::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->where('customer_id', $customer->getKey())
            ->whereKey($order->getKey())
            ->first();

        abort_unless($order instanceof Order, 404);

        $this->storeId = $store->getKey();
        $this->orderId = $order->getKey();
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.orders.show', [
            'order' => $this->order(),
        ])->layout('layouts.storefront', [
            'title' => 'Order details',
        ]);
    }

    private function order(): Order
    {
        return Order::withoutGlobalScopes()
            ->with(['lines', 'payments', 'refunds', 'fulfillments.lines'])
            ->where('store_id', $this->storeId)
            ->where('customer_id', Auth::guard('customer')->id())
            ->findOrFail($this->orderId);
    }
}


output:
Chunk ID: d66163
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 484
Output:

    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account'],
    ]" />

Orders

            @forelse ($orders as $order)

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                        <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                        <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" class="justify-start sm:justify-end" />

            @empty

                    <flux:icon name="shopping-bag" class="mx-auto size-10 text-zinc-400 dark:text-zinc-600" />

No orders yet

                    <flux:button :href="route('collections.index')" wire:navigate variant="primary" class="mt-6">
                        Browse products
                    </flux:button>

            @endforelse


command: sed -n '1,280p' resources/views/livewire/storefront/account/orders/show.blade.php

aggregated_output:
    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account', 'url' => route('account.dashboard')],
        ['label' => $order->order_number],
    ]" />

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                <flux:heading size="lg">Items</flux:heading>

                    @foreach ($order->lines as $line)

getKey() }}">

{{ $line->title_snapshot }}

Qty {{ $line->quantity }}

                            <x-storefront.price :amount="$line->total_amount" :currency="$order->currency" />

                    @endforeach

            @if ($order->fulfillments->isNotEmpty())

                    <flux:heading size="lg">Fulfillment</flux:heading>

                        @foreach ($order->fulfillments as $fulfillment)

getKey() }}">

                                    {{ $fulfillment->status->value }}
                                    @if ($fulfillment->tracking_number)
                                        {{ $fulfillment->tracking_number }}
                                    @endif

                        @endforeach

            @endif

Summary

                <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    Subtotal
                    <x-storefront.price :amount="$order->subtotal_amount" :currency="$order->currency" />

                    Discount
                    -{{ \App\Support\Money::format($order->discount_amount, $order->currency) }}

                    Shipping
                    <x-storefront.price :amount="$order->shipping_amount" :currency="$order->currency" />

                    Tax
                    <x-storefront.price :amount="$order->tax_amount" :currency="$order->currency" />

                    Total
                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" />


output:
Chunk ID: 5f5b4f
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1189
Output:

    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account', 'url' => route('account.dashboard')],
        ['label' => $order->order_number],
    ]" />

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                <flux:heading size="lg">Items</flux:heading>

                    @foreach ($order->lines as $line)

getKey() }}">

{{ $line->title_snapshot }}

Qty {{ $line->quantity }}

                            <x-storefront.price :amount="$line->total_amount" :currency="$order->currency" />

                    @endforeach

            @if ($order->fulfillments->isNotEmpty())

                    <flux:heading size="lg">Fulfillment</flux:heading>

                        @foreach ($order->fulfillments as $fulfillment)

getKey() }}">

                                    {{ $fulfillment->status->value }}
                                    @if ($fulfillment->tracking_number)
                                        {{ $fulfillment->tracking_number }}
                                    @endif

                        @endforeach

            @endif

Summary

                <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    Subtotal
                    <x-storefront.price :amount="$order->subtotal_amount" :currency="$order->currency" />

                    Discount
                    -{{ \App\Support\Money::format($order->discount_amount, $order->currency) }}

                    Shipping
                    <x-storefront.price :amount="$order->shipping_amount" :currency="$order->currency" />

                    Tax
                    <x-storefront.price :amount="$order->tax_amount" :currency="$order->currency" />

                    Total
                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" />


cmd: sed -n '1,260p' app/Livewire/Storefront/Account/Auth/Login.php


cmd: sed -n '1,300p' app/Livewire/Storefront/Account/Auth/Register.php


cmd: sed -n '1,260p' resources/views/livewire/storefront/account/auth/login.blade.php


cmd: sed -n '1,300p' resources/views/livewire/storefront/account/auth/register.blade.php


cmd: sed -n '1,260p' tests/Feature/Foundation/CustomerAuthTest.php


command: sed -n '1,260p' resources/views/livewire/storefront/account/auth/login.blade.php

aggregated_output:
    <x-auth-header :title="__('Log in')" :description="__('Access your orders and saved addresses')" />

    <form wire:submit="login" class="flex flex-col gap-6">
        <flux:input
            wire:model="email"
            :label="__('Email address')"
            type="email"
            required
            autofocus
            autocomplete="email"
            placeholder="customer@acme.test"
        />

        <flux:input
            wire:model="password"
            :label="__('Password')"
            type="password"
            required
            autocomplete="current-password"
            :placeholder="__('Password')"
            viewable
        />

            <flux:link :href="route('customer.password.request')" wire:navigate>{{ __('Forgot your password?') }}</flux:link>

        <flux:checkbox wire:model="remember" :label="__('Remember me')" />

        <flux:button variant="primary" type="submit" class="w-full" data-test="customer-login-button">
            {{ __('Log in') }}
        </flux:button>
    </form>

        {{ __('New customer?') }}
        <flux:link :href="route('account.register')" wire:navigate>{{ __('Create an account') }}</flux:link>


command: sed -n '1,260p' app/Livewire/Storefront/Account/Auth/Login.php

aggregated_output:
<?php

namespace App\Livewire\Storefront\Account\Auth;

use App\Models\Customer;
use App\Models\Store;
use App\Services\CartService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Validation\ValidationException;
use Livewire\Component;

class Login extends Component
{
    public int $storeId;

    public string $email = '';

    public string $password = '';

    public bool $remember = false;

    public function mount(): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $this->storeId = $store->getKey();
    }

    public function login(): void
    {
        $this->validate([
            'email' => ['required', 'email'],
            'password' => ['required', 'string'],
            'remember' => ['boolean'],
        ]);

        $key = 'customer-login:'.request()->ip();

        if (RateLimiter::tooManyAttempts($key, 5)) {
            throw ValidationException::withMessages([
                'email' => __('Too many attempts. Try again in :seconds seconds.', [
                    'seconds' => RateLimiter::availableIn($key),
                ]),
            ]);
        }

        app()->instance('current_store', Store::query()->findOrFail($this->storeId));

        if (! Auth::guard('customer')->attempt([
            'email' => $this->email,
            'password' => $this->password,
        ], $this->remember)) {
            RateLimiter::hit($key, 60);

            throw ValidationException::withMessages([
                'email' => __('Invalid credentials'),
            ]);
        }

        RateLimiter::clear($key);

        if (request()->hasSession()) {
            request()->session()->regenerate();
        }

        $customer = Auth::guard('customer')->user();

        if ($customer instanceof Customer && session()->has('cart_id')) {
            app(CartService::class)->getOrCreateForSession(Store::query()->findOrFail($this->storeId), $customer);
        }

        $this->redirectRoute('account.dashboard', navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.login')
            ->layout('layouts.auth');
    }
}


output:
Chunk ID: 631d26
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 559
Output:
<?php

namespace App\Livewire\Storefront\Account\Auth;

use App\Models\Customer;
use App\Models\Store;
use App\Services\CartService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Validation\ValidationException;
use Livewire\Component;

class Login extends Component
{
    public int $storeId;

    public string $email = '';

    public string $password = '';

    public bool $remember = false;

    public function mount(): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $this->storeId = $store->getKey();
    }

    public function login(): void
    {
        $this->validate([
            'email' => ['required', 'email'],
            'password' => ['required', 'string'],
            'remember' => ['boolean'],
        ]);

        $key = 'customer-login:'.request()->ip();

        if (RateLimiter::tooManyAttempts($key, 5)) {
            throw ValidationException::withMessages([
                'email' => __('Too many attempts. Try again in :seconds seconds.', [
                    'seconds' => RateLimiter::availableIn($key),
                ]),
            ]);
        }

        app()->instance('current_store', Store::query()->findOrFail($this->storeId));

        if (! Auth::guard('customer')->attempt([
            'email' => $this->email,
            'password' => $this->password,
        ], $this->remember)) {
            RateLimiter::hit($key, 60);

            throw ValidationException::withMessages([
                'email' => __('Invalid credentials'),
            ]);
        }

        RateLimiter::clear($key);

        if (request()->hasSession()) {
            request()->session()->regenerate();
        }

        $customer = Auth::guard('customer')->user();

        if ($customer instanceof Customer && session()->has('cart_id')) {
            app(CartService::class)->getOrCreateForSession(Store::query()->findOrFail($this->storeId), $customer);
        }

        $this->redirectRoute('account.dashboard', navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.login')
            ->layout('layouts.auth');
    }
}