text:
Script completed
Wall time 0.1 seconds
Output:

text:
<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->prepend(App\Http\Middleware\ResolveStore::class);

        $middleware->group('storefront', [
            'store.resolve:storefront',
        ]);

        $middleware->group('admin', [
            'store.resolve:admin',
        ]);

        $middleware->alias([
            'store.resolve' => App\Http\Middleware\ResolveStore::class,
            'role.check' => App\Http\Middleware\EnsureStoreRole::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();
<?php

namespace App\Http\Middleware;

use App\Enums\StoreDomainType;
use App\Enums\StoreStatus;
use App\Models\Store;
use App\Models\StoreDomain;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class ResolveStore
{
    public function handle(Request $request, Closure $next, string $context = 'storefront'): Response
    {
        if (! Schema::hasTable('stores')) {
            return $next($request);
        }

        if ($this->isPublicAdminAuthRequest($request)) {
            return $next($request);
        }
        $context = $context === 'storefront' && $this->isAdminRequest($request)
            ? 'admin'
            : $context;

        $store = $context === 'admin'
            ? $this->resolveAdminStore($request)
            : $this->resolveStorefrontStore($request);

        abort_unless($store instanceof Store, $context === 'admin' ? 403 : 404);

        if ($store->status === StoreStatus::Suspended) {
            if ($context === 'storefront') {
                abort(503, 'This store is currently unavailable.');
            }

            if (! in_array($request->method(), ['GET', 'HEAD', 'OPTIONS'], true)) {
                abort(403);
            }
        }

        $binding = (string) config('tenancy.binding', 'current_store');
        app()->instance($binding, $store);
        View::share((string) config('tenancy.view_share', 'currentStore'), $store);

        return $next($request);
    }

    private function resolveStorefrontStore(Request $request): ?Store
    {
        $hostname = Str::lower(rtrim(trim($request->getHost()), '.'));
        $cacheKey = config('tenancy.cache_prefix', 'store-domains').':'.$hostname;

        $storeId = Cache::remember(
            $cacheKey,
            (int) config('tenancy.store_cache_ttl', 300),
            fn (): ?int => StoreDomain::query()
                ->where('hostname', $hostname)
                ->where('type', config('tenancy.storefront_domain_type', StoreDomainType::Storefront->value))
                ->value('store_id'),
        );

        return $storeId === null ? null : Store::query()->find($storeId);
    }

    private function resolveAdminStore(Request $request): ?Store
    {
        $storeId = $request->session()->get(config('tenancy.admin_session_key', 'current_store_id'));
        $user = $request->user('web') ?? $request->user();

        if ($storeId === null || $user === null) {
            return null;
        }

        return $user->stores()->whereKey($storeId)->first();
    }

    private function isAdminRequest(Request $request): bool
    {
        $prefix = trim((string) config('tenancy.admin_path_prefix', 'admin'), '/');

        if ($request->is($prefix, $prefix.'/*') || $request->routeIs($prefix.'.*')) {
            return true;
        }

        return $request->is('livewire/update') && str_contains((string) $request->headers->get('referer'), '/admin');
    }

    private function isPublicAdminAuthRequest(Request $request): bool
    {
        return $request->is('admin/login', 'admin/forgot-password', 'admin/reset-password/*');
    }
}
<?php

use App\Livewire\Admin\Auth\ForgotPassword as AdminForgotPassword;
use App\Livewire\Admin\Auth\Login as AdminLogin;
use App\Livewire\Admin\Auth\ResetPassword as AdminResetPassword;
use App\Livewire\Admin\Customers\Index as AdminCustomersIndex;
use App\Livewire\Admin\Customers\Show as AdminCustomersShow;
use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Livewire\Admin\Discounts\Form as AdminDiscountForm;
use App\Livewire\Admin\Discounts\Index as AdminDiscountsIndex;
use App\Livewire\Admin\Orders\Index as AdminOrdersIndex;
use App\Livewire\Admin\Orders\Show as AdminOrdersShow;
use App\Livewire\Admin\Products\Form as AdminProductForm;
use App\Livewire\Admin\Products\Index as AdminProductsIndex;
use App\Livewire\Admin\Section as AdminSection;
use App\Livewire\Admin\Settings\General as AdminSettingsGeneral;
use App\Livewire\Admin\Settings\Shipping as AdminSettingsShipping;
use App\Livewire\Admin\Settings\Taxes as AdminSettingsTaxes;
use App\Livewire\Storefront\Account\Addresses\Index as AccountAddresses;
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\Dashboard as AccountDashboard;
use App\Livewire\Storefront\Account\Orders\Index as AccountOrders;
use App\Livewire\Storefront\Account\Orders\Show as AccountOrderShow;
use App\Livewire\Storefront\Cart\Show as CartShow;
use App\Livewire\Storefront\Checkout\Confirmation as CheckoutConfirmation;
use App\Livewire\Storefront\Checkout\Show as CheckoutShow;
use App\Livewire\Storefront\Collections\Index as CollectionsIndex;
use App\Livewire\Storefront\Collections\Show as CollectionShow;
use App\Livewire\Storefront\Home;
use App\Livewire\Storefront\Pages\Show as PageShow;
use App\Livewire\Storefront\Products\Show as ProductShow;
use App\Livewire\Storefront\Search\Index as SearchIndex;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;

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

require __DIR__.'/settings.php';

Route::get('/favicon.ico', fn (): \Symfony\Component\HttpFoundation\Response => response('', 204))->name('favicon');

Route::middleware('store.resolve')->group(function (): void {
    Route::livewire('/', Home::class)->name('home');
    Route::livewire('/collections', CollectionsIndex::class)->name('collections.index');
    Route::livewire('/collections/{handle}', CollectionShow::class)->name('collection.show');
    Route::livewire('/products/{handle}', ProductShow::class)->name('product.show');
    Route::livewire('/cart', CartShow::class)->name('cart.show');
    Route::livewire('/search', SearchIndex::class)->name('search');
    Route::livewire('/pages/{handle}', PageShow::class)->name('page.show');
    Route::livewire('/checkout/{checkoutId}', CheckoutShow::class)->name('checkout.show');
    Route::livewire('/checkout/{checkoutId}/confirmation', CheckoutConfirmation::class)->name('checkout.confirmation');
    Route::livewire('/account/login', CustomerLogin::class)->middleware('throttle:login')->name('account.login');
    Route::livewire('/account/register', CustomerRegister::class)->name('account.register');
    Route::livewire('/forgot-password', CustomerForgotPassword::class)->name('password.request');
    Route::livewire('/reset-password/{token}', CustomerResetPassword::class)->name('password.reset');
    Route::post('/account/logout', function (): \Illuminate\Http\RedirectResponse {
        Auth::guard('customer')->logout();
        request()->session()->invalidate();
        request()->session()->regenerateToken();

        return redirect()->route('home');
    })->name('account.logout');

    Route::middleware('auth:customer')->group(function (): void {
        Route::livewire('/account', AccountDashboard::class)->name('account.dashboard');
        Route::livewire('/account/orders', AccountOrders::class)->name('account.orders');
        Route::livewire('/account/orders/{orderNumber}', AccountOrderShow::class)->name('account.order.show');
        Route::livewire('/account/addresses', AccountAddresses::class)->name('account.addresses');
    });
});

Route::livewire('/admin/login', AdminLogin::class)->middleware('throttle:login')->name('admin.login');
Route::livewire('/admin/forgot-password', AdminForgotPassword::class)->middleware('throttle:login')->name('admin.password.request');
Route::livewire('/admin/reset-password/{token}', AdminResetPassword::class)->name('admin.password.reset');
Route::post('/admin/logout', function (): \Illuminate\Http\RedirectResponse {
    Auth::guard('web')->logout();
    request()->session()->invalidate();
    request()->session()->regenerateToken();

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

Route::prefix('admin')->middleware(['auth', 'verified', 'store.resolve', 'role.check:owner,admin,staff,support'])->group(function (): void {
    Route::livewire('/', AdminDashboard::class)->name('admin.dashboard');
    Route::livewire('/products', AdminProductsIndex::class)->name('admin.products.index');
    Route::livewire('/products/create', AdminProductForm::class)->middleware('role.check:owner,admin,staff')->name('admin.products.create');
    Route::livewire('/products/{product}/edit', AdminProductForm::class)->middleware('role.check:owner,admin,staff')->name('admin.products.edit');
    Route::livewire('/orders', AdminOrdersIndex::class)->name('admin.orders.index');
    Route::livewire('/orders/{order}', AdminOrdersShow::class)->name('admin.orders.show');
    Route::livewire('/customers', AdminCustomersIndex::class)->name('admin.customers.index');
    Route::livewire('/customers/{customer}', AdminCustomersShow::class)->name('admin.customers.show');
    Route::livewire('/discounts', AdminDiscountsIndex::class)->name('admin.discounts.index');
    Route::livewire('/discounts/create', AdminDiscountForm::class)->middleware('role.check:owner,admin,staff')->name('admin.discounts.create');
    Route::livewire('/discounts/{discount}/edit', AdminDiscountForm::class)->middleware('role.check:owner,admin,staff')->name('admin.discounts.edit');
    Route::livewire('/settings', AdminSettingsGeneral::class)->middleware('role.check:owner,admin')->name('admin.settings');
    Route::livewire('/settings/shipping', AdminSettingsShipping::class)->middleware('role.check:owner,admin')->name('admin.settings.shipping');
    Route::livewire('/settings/taxes', AdminSettingsTaxes::class)->middleware('role.check:owner,admin')->name('admin.settings.taxes');
    Route::livewire('/inventory', AdminSection::class)->name('admin.inventory');
    Route::livewire('/collections', AdminSection::class)->name('admin.collections');
    Route::livewire('/collections/create', AdminSection::class)->middleware('role.check:owner,admin,staff')->name('admin.collections.create');
    Route::livewire('/collections/{collection}/edit', AdminSection::class)->middleware('role.check:owner,admin,staff')->name('admin.collections.edit');
    Route::livewire('/themes', AdminSection::class)->name('admin.themes');
    Route::livewire('/themes/{theme}/editor', AdminSection::class)->name('admin.themes.editor');
    Route::livewire('/pages', AdminSection::class)->name('admin.pages');
    Route::livewire('/pages/create', AdminSection::class)->middleware('role.check:owner,admin')->name('admin.pages.create');
    Route::livewire('/pages/{page}/edit', AdminSection::class)->middleware('role.check:owner,admin')->name('admin.pages.edit');
    Route::livewire('/navigation', AdminSection::class)->name('admin.navigation');
    Route::livewire('/apps', AdminSection::class)->name('admin.apps');
    Route::livewire('/apps/{installation}', AdminSection::class)->name('admin.apps.show');
    Route::livewire('/developers', AdminSection::class)->name('admin.developers');
    Route::livewire('/analytics', AdminSection::class)->name('admin.analytics');
    Route::livewire('/search/settings', AdminSection::class)->name('admin.search.settings');
});
<?php

use App\Enums\StoreDomainType;
use App\Enums\StoreStatus;
use App\Enums\StoreUserRole;
use App\Models\Store;
use App\Models\StoreDomain;
use App\Models\User;
use Illuminate\Support\Facades\Route;

uses(\Illuminate\Foundation\Testing\LazilyRefreshDatabase::class);

beforeEach(function (): void {
    config(['cache.default' => 'array']);

    Route::middleware(['web', 'storefront'])->get('/tenant-resolution-test', function () {
        return response()->json([
            'store_id' => app('current_store')->getKey(),
            'view_store_id' => view()->shared('currentStore')->getKey(),
        ]);
    });

    Route::middleware(['web', 'admin'])->get('/admin/tenant-resolution-test', function () {
        return response()->json(['store_id' => app('current_store')->getKey()]);
    });
});

afterEach(function (): void {
    app()->forgetInstance('current_store');
});

test('a storefront request resolves and shares the store by hostname', function () {
    $store = Store::factory()->create();

    StoreDomain::factory()->create([
        'store_id' => $store->getKey(),
        'hostname' => 'fashion.example.test',
        'type' => StoreDomainType::Storefront,
    ]);

    $this->get('http://fashion.example.test/tenant-resolution-test')
        ->assertSuccessful()
        ->assertJson([
            'store_id' => $store->getKey(),
            'view_store_id' => $store->getKey(),
        ]);
});

test('a storefront hostname is cached as a store id', function () {
    $store = Store::factory()->create();

    $domain = StoreDomain::factory()->create([
        'store_id' => $store->getKey(),
        'hostname' => 'cached.example.test',
    ]);

    $this->get('http://cached.example.test/tenant-resolution-test')->assertSuccessful();

    $domain->delete();

    $this->get('http://cached.example.test/tenant-resolution-test')
        ->assertSuccessful()
        ->assertJson(['store_id' => $store->getKey()]);
});

test('unknown storefront hosts return not found', function () {
    $this->get('http://missing.example.test/tenant-resolution-test')->assertNotFound();
});

test('suspended storefronts return service unavailable', function () {
    $store = Store::factory()->create(['status' => StoreStatus::Suspended]);

    StoreDomain::factory()->create([
        'store_id' => $store->getKey(),
        'hostname' => 'suspended.example.test',
    ]);

    $this->get('http://suspended.example.test/tenant-resolution-test')
        ->assertServiceUnavailable();
});

test('admin requests resolve only the session store the user belongs to', function () {
    $store = Store::factory()->create();
    $user = User::factory()->create();

    $store->users()->attach($user, ['role' => StoreUserRole::Owner]);

    $this->actingAs($user)
        ->withSession(['current_store_id' => $store->getKey()])
        ->get('/admin/tenant-resolution-test')
        ->assertSuccessful()
        ->assertJson(['store_id' => $store->getKey()]);
});

test('admin requests reject a session store without membership', function () {
    $store = Store::factory()->create();
    $user = User::factory()->create();

    $this->actingAs($user)
        ->withSession(['current_store_id' => $store->getKey()])
        ->get('/admin/tenant-resolution-test')
        ->assertForbidden();
});


exec

status: completed

input:
const r = await tools.exec_command({cmd:"rg -n \"setUpdateRoute|updateRoute\" vendor/livewire/livewire app bootstrap | head -60 && sed -n '1,260p' app/Providers/AppServiceProvider.php && sed -n '1,200p' app/Providers/FortifyServiceProvider.php 2>/dev/null || true && sed -n '1,220p' routes/settings.php","workdir":"/Users/wesner/Herd/shop","yield_time_ms":10000,"max_output_tokens":18000});
text(r.output);


type: CommandExecution

command: rg -n "setUpdateRoute|updateRoute" vendor/livewire/livewire app bootstrap | head -60 && sed -n '1,260p' app/Providers/AppServiceProvider.php && sed -n '1,200p' app/Providers/FortifyServiceProvider.php 2>/dev/null || true && sed -n '1,220p' routes/settings.php

type: unknown

status: completed

stdout:
vendor/livewire/livewire/src/Livewire.php:17: * @method static void setUpdateRoute($callback)
vendor/livewire/livewire/src/LivewireManager.php:158:    function setUpdateRoute($callback)
vendor/livewire/livewire/src/LivewireManager.php:160:        return app(HandleRequests::class)->setUpdateRoute($callback);
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:18:    protected $updateRoute;
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:24:        if (! $this->updateRoute && ! $this->updateRouteExists()) {
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:25:            app($this::class)->setUpdateRoute(function ($handle) {
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:35:    protected function updateRouteExists()
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:47:        // When routes are cached, $this->updateRoute may be null because
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:48:        // setUpdateRoute() was never called (the route already existed).
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:50:        $route = $this->updateRoute ?? $this->findUpdateRoute();
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:90:    function setUpdateRoute($callback)
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:99:        $this->updateRoute = $route;
vendor/livewire/livewire/dist/livewire.min.js.map:4:  "sourcesContent": ["/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress\n * @license MIT */\n\n;(function(root, factory) {\n\n  if (typeof define === 'function' && define.amd) {\n    define(factory);\n  } else if (typeof exports === 'object') {\n    module.exports = factory();\n  } else {\n    root.NProgress = factory();\n  }\n\n})(this, function() {\n  var NProgress = {};\n\n  NProgress.version = '0.2.0';\n\n  var Settings = NProgress.settings = {\n    minimum: 0.08,\n    easing: 'ease',\n    positionUsing: '',\n    speed: 200,\n    trickle: true,\n    trickleRate: 0.02,\n    trickleSpeed: 800,\n    showSpinner: true,\n    barSelector: '[role=\"bar\"]',\n    spinnerSelector: '[role=\"spinner\"]',\n    parent: 'body',\n    template: '

'\n  };\n\n  /**\n   * Updates configuration.\n   *\n   *     NProgress.configure({\n   *       minimum: 0.1\n   *     });\n   */\n  NProgress.configure = function(options) {\n    var key, value;\n    for (key in options) {\n      value = options[key];\n      if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;\n    }\n\n    return this;\n  };\n\n  /**\n   * Last number.\n   */\n\n  NProgress.status = null;\n\n  /**\n   * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.\n   *\n   *     NProgress.set(0.4);\n   *     NProgress.set(1.0);\n   */\n\n  NProgress.set = function(n) {\n    var started = NProgress.isStarted();\n\n    n = clamp(n, Settings.minimum, 1);\n    NProgress.status = (n === 1 ? null : n);\n\n    var progress = NProgress.render(!started),\n        bar      = progress.querySelector(Settings.barSelector),\n        speed    = Settings.speed,\n        ease     = Settings.easing;\n\n    progress.offsetWidth; /* Repaint */\n\n    queue(function(next) {\n      // Set positionUsing if it hasn't already been set\n      if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();\n\n      // Add transition\n      css(bar, barPositionCSS(n, speed, ease));\n\n      if (n === 1) {\n        // Fade out\n        css(progress, { \n          transition: 'none', \n          opacity: 1 \n        });\n        progress.offsetWidth; /* Repaint */\n\n        setTimeout(function() {\n          css(progress, { \n            transition: 'all ' + speed + 'ms linear', \n            opacity: 0 \n          });\n          setTimeout(function() {\n            NProgress.remove();\n            next();\n          }, speed);\n        }, speed);\n      } else {\n        setTimeout(next, speed);\n      }\n    });\n\n    return this;\n  };\n\n  NProgress.isStarted = function() {\n    return typeof NProgress.status === 'number';\n  };\n\n  /**\n   * Shows the progress bar.\n   * This is the same as setting the status to 0%, except that it doesn't go backwards.\n   *\n   *     NProgress.start();\n   *\n   */\n  NProgress.start = function() {\n    if (!NProgress.status) NProgress.set(0);\n\n    var work = function() {\n      setTimeout(function() {\n        if (!NProgress.status) return;\n        NProgress.trickle();\n        work();\n      }, Settings.trickleSpeed);\n    };\n\n    if (Settings.trickle) work();\n\n    return this;\n  };\n\n  /**\n   * Hides the progress bar.\n   * This is the *sort of* the same as setting the status to 100%, with the\n   * difference being `done()` makes some placebo effect of some realistic motion.\n   *\n   *     NProgress.done();\n   *\n   * If `true` is passed, it will show the progress bar even if its hidden.\n   *\n   *     NProgress.done(true);\n   */\n\n  NProgress.done = function(force) {\n    if (!force && !NProgress.status) return this;\n\n    return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);\n  };\n\n  /**\n   * Increments by a random amount.\n   */\n\n  NProgress.inc = function(amount) {\n    var n = NProgress.status;\n\n    if (!n) {\n      return NProgress.start();\n    } else {\n      if (typeof amount !== 'number') {\n        amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);\n      }\n\n      n = clamp(n + amount, 0, 0.994);\n      return NProgress.set(n);\n    }\n  };\n\n  NProgress.trickle = function() {\n    return NProgress.inc(Math.random() * Settings.trickleRate);\n  };\n\n  /**\n   * Waits for all supplied jQuery promises and\n   * increases the progress as the promises resolve.\n   *\n   * @param $promise jQUery Promise\n   */\n  (function() {\n    var initial = 0, current = 0;\n\n    NProgress.promise = function($promise) {\n      if (!$promise || $promise.state() === \"resolved\") {\n        return this;\n      }\n\n      if (current === 0) {\n        NProgress.start();\n      }\n\n      initial++;\n      current++;\n\n      $promise.always(function() {\n        current--;\n        if (current === 0) {\n            initial = 0;\n            NProgress.done();\n        } else {\n            NProgress.set((initial - current) / initial);\n        }\n      });\n\n      return this;\n    };\n\n  })();\n\n  /**\n   * (Internal) renders the progress bar markup based on the `template`\n   * setting.\n   */\n\n  NProgress.render = function(fromStart) {\n    if (NProgress.isRendered()) return document.getElementById('nprogress');\n\n    addClass(document.documentElement, 'nprogress-busy');\n    \n    var progress = document.createElement('div');\n    progress.id = 'nprogress';\n    progress.innerHTML = Settings.template;\n\n    var bar      = progress.querySelector(Settings.barSelector),\n        perc     = fromStart ? '-100' : toBarPerc(NProgress.status || 0),\n        parent   = document.querySelector(Settings.parent),\n        spinner;\n    \n    css(bar, {\n      transition: 'all 0 linear',\n      transform: 'translate3d(' + perc + '%,0,0)'\n    });\n\n    if (!Settings.showSpinner) {\n      spinner = progress.querySelector(Settings.spinnerSelector);\n      spinner && removeElement(spinner);\n    }\n\n    if (parent != document.body) {\n      addClass(parent, 'nprogress-custom-parent');\n    }\n\n    parent.appendChild(progress);\n    return progress;\n  };\n\n  /**\n   * Removes the element. Opposite of render().\n   */\n\n  NProgress.remove = function() {\n    removeClass(document.documentElement, 'nprogress-busy');\n    removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');\n    var progress = document.getElementById('nprogress');\n    progress && removeElement(progress);\n  };\n\n  /**\n   * Checks if the progress bar is rendered.\n   */\n\n  NProgress.isRendered = function() {\n    return !!document.getElementById('nprogress');\n  };\n\n  /**\n   * Determine which positioning CSS rule to use.\n   */\n\n  NProgress.getPositioningCSS = function() {\n    // Sniff on document.body.style\n    var bodyStyle = document.body.style;\n\n    // Sniff prefixes\n    var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :\n                       ('MozTransform' in bodyStyle) ? 'Moz' :\n                       ('msTransform' in bodyStyle) ? 'ms' :\n                       ('OTransform' in bodyStyle) ? 'O' : '';\n\n    if (vendorPrefix + 'Perspective' in bodyStyle) {\n      // Modern browsers with 3D support, e.g. Webkit, IE10\n      return 'translate3d';\n    } else if (vendorPrefix + 'Transform' in bodyStyle) {\n      // Browsers without 3D support, e.g. IE9\n      return 'translate';\n    } else {\n      // Browsers without translate() support, e.g. IE7-8\n      return 'margin';\n    }\n  };\n\n  /**\n   * Helpers\n   */\n\n  function clamp(n, min, max) {\n    if (n < min) return min;\n    if (n > max) return max;\n    return n;\n  }\n\n  /**\n   * (Internal) converts a percentage (`0..1`) to a bar translateX\n   * percentage (`-100%..0%`).\n   */\n\n  function toBarPerc(n) {\n    return (-1 + n) * 100;\n  }\n\n\n  /**\n   * (Internal) returns the correct CSS for changing the bar's\n   * position given an n percentage, and speed and ease from Settings\n   */\n\n  function barPositionCSS(n, speed, ease) {\n    var barCSS;\n\n    if (Settings.positionUsing === 'translate3d') {\n      barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };\n    } else if (Settings.positionUsing === 'translate') {\n      barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };\n    } else {\n      barCSS = { 'margin-left': toBarPerc(n)+'%' };\n    }\n\n    barCSS.transition = 'all '+speed+'ms '+ease;\n\n    return barCSS;\n  }\n\n  /**\n   * (Internal) Queues a function to be executed.\n   */\n\n  var queue = (function() {\n    var pending = [];\n    \n    function next() {\n      var fn = pending.shift();\n      if (fn) {\n        fn(next);\n      }\n    }\n\n    return function(fn) {\n      pending.push(fn);\n      if (pending.length == 1) next();\n    };\n  })();\n\n  /**\n   * (Internal) Applies css properties to an element, similar to the jQuery \n   * css method.\n   *\n   * While this helper does assist with vendor prefixed property names, it \n   * does not perform any manipulation of values prior to setting styles.\n   */\n\n  var css = (function() {\n    var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],\n        cssProps    = {};\n\n    function camelCase(string) {\n      return string.replace(/^-ms-/, 'ms-').replace(/-([\\da-z])/gi, function(match, letter) {\n        return letter.toUpperCase();\n      });\n    }\n\n    function getVendorProp(name) {\n      var style = document.body.style;\n      if (name in style) return name;\n\n      var i = cssPrefixes.length,\n          capName = name.charAt(0).toUpperCase() + name.slice(1),\n          vendorName;\n      while (i--) {\n        vendorName = cssPrefixes[i] + capName;\n        if (vendorName in style) return vendorName;\n      }\n\n      return name;\n    }\n\n    function getStyleProp(name) {\n      name = camelCase(name);\n      return cssProps[name] || (cssProps[name] = getVendorProp(name));\n    }\n\n    function applyCss(element, prop, value) {\n      prop = getStyleProp(prop);\n      element.style[prop] = value;\n    }\n\n    return function(element, properties) {\n      var args = arguments,\n          prop, \n          value;\n\n      if (args.length == 2) {\n        for (prop in properties) {\n          value = properties[prop];\n          if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);\n        }\n      } else {\n        applyCss(element, args[1], args[2]);\n      }\n    }\n  })();\n\n  /**\n   * (Internal) Determines if an element or space separated list of class names contains a class name.\n   */\n\n  function hasClass(element, name) {\n    var list = typeof element == 'string' ? element : classList(element);\n    return list.indexOf(' ' + name + ' ') >= 0;\n  }\n\n  /**\n   * (Internal) Adds a class to an element.\n   */\n\n  function addClass(element, name) {\n    var oldList = classList(element),\n        newList = oldList + name;\n\n    if (hasClass(oldList, name)) return; \n\n    // Trim the opening space.\n    element.className = newList.substring(1);\n  }\n\n  /**\n   * (Internal) Removes a class from an element.\n   */\n\n  function removeClass(element, name) {\n    var oldList = classList(element),\n        newList;\n\n    if (!hasClass(element, name)) return;\n\n    // Replace the class name.\n    newList = oldList.replace(' ' + name + ' ', ' ');\n\n    // Trim the opening and closing spaces.\n    element.className = newList.substring(1, newList.length - 1);\n  }\n\n  /**\n   * (Internal) Gets a space separated list of the class names on the element. \n   * The list is wrapped with a single space on each end to facilitate finding \n   * matches within the list.\n   */\n\n  function classList(element) {\n    return (' ' + (element.className || '') + ' ').replace(/\\s+/gi, ' ');\n  }\n\n  /**\n   * (Internal) Removes an element from the DOM.\n   */\n\n  function removeElement(element) {\n    element && element.parentNode && element.parentNode.removeChild(element);\n  }\n\n  return NProgress;\n});\n\n", "\nexport class Bag {\n    constructor() { this.arrays = {} }\n\n    add(key, value) {\n        if (! this.arrays[key]) this.arrays[key] = []\n        this.arrays[key].push(value)\n    }\n\n    remove(key) {\n        if (this.arrays[key]) delete this.arrays[key]\n    }\n\n    get(key) { return this.arrays[key] || [] }\n\n    each(key, callback) { return this.get(key).forEach(callback) }\n}\n\nexport class WeakBag {\n    constructor() { this.arrays = new WeakMap }\n\n    add(key, value) {\n        if (! this.arrays.has(key)) this.arrays.set(key, [])\n        this.arrays.get(key).push(value)\n    }\n\n    remove(key) {\n        if (this.arrays.has(key)) this.arrays.delete(key, [])\n    }\n\n    get(key) { return this.arrays.has(key) ? this.arrays.get(key) : [] }\n\n    each(key, callback) { return this.get(key).forEach(callback) }\n}\n\nexport function dispatch(target, name, detail = {}, bubbles = true) {\n    target.dispatchEvent(\n        new CustomEvent(name, {\n            detail,\n            bubbles,\n            // Allows events to pass the shadow DOM barrier.\n            composed: true,\n            cancelable: true,\n        })\n    )\n}\n\nexport function listen(target, name, handler) {\n    target.addEventListener(name, handler)\n\n    return () => target.removeEventListener(name, handler)\n}\n\n/**\n * Type-checking in JS is weird and annoying, these are better.\n */\nexport function isObjecty(subject) { return (typeof subject === 'object' && subject !== null) }\nexport function isObject(subject) { return (isObjecty(subject) && ! isArray(subject)) }\nexport function isArray(subject) { return Array.isArray(subject) }\nexport function isFunction(subject) { return typeof subject === 'function' }\nexport function isPrimitive(subject) { return typeof subject !== 'object' || subject === null }\n\n/**\n * Clone an object deeply to wipe out any shared references.\n */\nexport function deepClone(obj) { return JSON.parse(JSON.stringify(obj)) }\n\n/**\n * Determine if two objects take the exact same shape.\n */\nexport function deeplyEqual(a, b) { return JSON.stringify(a) === JSON.stringify(b) }\n\n/**\n * An easy way to loop through arrays and objects.\n */\nexport function each(subject, callback) {\n    Object.entries(subject).forEach(([key, value]) => callback(key, value))\n}\n\n/**\n * Parse a path string into segments, supporting dot and bracket notation.\n * e.g. \"foo.bar\", \"foo[0].bar\", \"foo['hey'].baz\"\n */\nfunction parsePathSegments(path) {\n    if (path === '') return []\n\n    return path\n        .replace(/\\[(['\"]?)(.+?)\\1\\]/g, '.$2')  // Convert brackets to dots: foo['bar'] \u2192 foo.bar, foo[0] \u2192 foo.0\n        .replace(/^\\./, '')                      // Remove leading dot if present\n        .split('.')\n}\n\n/**\n * Get a property from an object with support for dot-notation and bracket-notation.\n */\nexport function dataGet(object, key) {\n    if (key === '') return object\n\n    return parsePathSegments(key).reduce((carry, i) => {\n        return carry?.[i]\n    }, object)\n}\n\n/**\n * Set a property on an object with support for dot-notation and bracket-notation.\n */\nexport function dataSet(object, key, value) {\n    let segments = parsePathSegments(key)\n\n    if (segments.length === 1) {\n        return object[segments[0]] = value\n    }\n\n    let firstSegment = segments.shift()\n    let restOfSegments = segments.join('.')\n    let nextSegment = segments[0]\n\n    if (object[firstSegment] === undefined) {\n        object[firstSegment] = {}\n    }\n\n    // If we're about to set a numeric key that would create null gaps, convert to object.\n    // This prevents JavaScript from filling intermediate indices with nulls\n    // (e.g., arr[1000] = true creates 1000 null entries in a JS array).\n    // We only convert when the key would create gaps (key > length), not when appending.\n    if (isArray(object[firstSegment]) && isNumeric(nextSegment) && parseInt(nextSegment) > object[firstSegment].length) {\n        object[firstSegment] = { ...object[firstSegment] }\n    }\n\n    dataSet(object[firstSegment], restOfSegments, value)\n}\n\nfunction isNumeric(subject) {\n    return ! isNaN(parseInt(subject))\n}\n\n/**\n * Delete a property from an object with support for dot-notation and bracket-notation.\n */\nexport function dataDelete(object, key) {\n    let segments = parsePathSegments(key)\n\n    if (segments.length === 1) {\n        if (Array.isArray(object)) {\n            object.splice(segments[0], 1)\n        } else {\n            delete object[segments[0]]\n        }\n        return\n    }\n\n    let firstSegment = segments.shift()\n    let restOfSegments = segments.join('.')\n\n    if (object[firstSegment] !== undefined) {\n        dataDelete(object[firstSegment], restOfSegments)\n    }\n}\n\n/**\n * Create a flat, dot-notated diff of two objects.\n * @deprecated Use diffAndConsolidate instead for smarter update consolidation\n */\nexport function diff(left, right, diffs = {}, path = '') {\n    // Are they the same?\n    if (left === right) return diffs\n\n    // Are they COMPLETELY different?\n    if (typeof left !== typeof right || (isObject(left) && isArray(right)) || (isArray(left) && isObject(right))) {\n        diffs[path] = right;\n        return diffs\n    }\n\n    // Is the right or left side a primitive value (a leaf node)?\n    if (isPrimitive(left) || isPrimitive(right)) {\n        diffs[path] = right\n        return diffs\n    }\n\n    // We now know both are objects...\n    let leftKeys = Object.keys(left)\n\n    // Recursively diff the object's properties...\n    Object.entries(right).forEach(([key, value]) => {\n        diffs = {...diffs, ...diff(left[key], right[key], diffs, path === '' ? key : `${path}.${key}`)}\n        leftKeys = leftKeys.filter(i => i !== key)\n    })\n\n    // Mark any items for removal...\n    leftKeys.forEach(key => {\n        diffs[`${path}.${key}`] = '__rm__'\n    })\n\n    return diffs\n}\n\n/**\n * Create a flat, dot-notated diff of two objects with automatic consolidation.\n * When multiple items in an array/object change or the size changes,\n * the diff is consolidated to the parent level instead of individual items.\n */\nexport function diffAndConsolidate(left, right) {\n    let diffs = {}\n\n    diffRecursive(left, right, '', diffs, left, right)\n\n    return diffs\n}\n\nfunction diffRecursive(left, right, path, diffs, rootLeft, rootRight) {\n    // Are they the same?\n    if (left === right) return { changed: false, consolidated: false }\n\n    // Track if we're doing a type conversion from empty array/null/undefined to object\n    // In this case, we want granular diffs, not consolidation\n    let convertedToObject = false\n\n    // Helper to check if an array has non-numeric (string) keys\n    // Arrays with string keys need granular diffs because JSON.stringify ignores them\n    let hasNonNumericKeys = (arr) => {\n        return isArray(arr) && Object.keys(arr).some(k => isNaN(parseInt(k)))\n    }\n\n    // Are they COMPLETELY different types?\n    if (typeof left !== typeof right || (isObject(left) && isArray(right)) || (isArray(left) && isObject(right))) {\n        // Special case: if left is an empty array and right is an object,\n        // treat the empty array as an empty object so we get granular diffs.\n        // This handles the case where wire:model.live=\"tableFilters.filter_1.value\"\n        // updates tableFilters from [] to { filter_1: { value: 'foo' } }\n        if (isArray(left) && left.length === 0 && isObject(right)) {\n            left = {}\n            convertedToObject = true\n            // Fall through to continue with object comparison below\n        }\n        // Special case: if left is undefined/null and right is an object,\n        // treat left as an empty object to get granular diffs for new properties\n        else if ((left === undefined || left === null) && isObject(right)) {\n            left = {}\n            convertedToObject = true\n            // Fall through to continue with object comparison below\n        } else {\n            diffs[path] = right\n            return { changed: true, consolidated: false }\n        }\n    }\n\n    // Special case: if both are arrays but right has non-numeric keys,\n    // we need granular diffs because JSON.stringify ignores string keys on arrays.\n    // Treat both as objects to properly diff the string keys.\n    if (isArray(left) && isArray(right) && hasNonNumericKeys(right)) {\n        // Treat the arrays as objects for comparison\n        // If left was empty, mark as converted to object to prevent consolidation\n        if (Object.keys(left).length === 0) {\n            convertedToObject = true\n        }\n    }\n\n    // Is either side a primitive value (a leaf node)?\n    if (isPrimitive(left) || isPrimitive(right)) {\n        diffs[path] = right\n        return { changed: true, consolidated: false }\n    }\n\n    // Both are objects/arrays - check if we should consolidate at this level\n    let leftKeys = Object.keys(left)\n    let rightKeys = Object.keys(right)\n\n    // If the size changed, consolidate at this level\n    // BUT if we converted to object, don't consolidate - we're adding new items\n    // and should produce granular diffs for query string handling\n    if (leftKeys.length !== rightKeys.length && !convertedToObject) {\n        // For root level, we can't consolidate to a single key, so diff each root property\n        if (path === '') {\n            Object.keys(right).forEach(key => {\n                if (!deeplyEqual(left[key], right[key])) {\n                    diffs[key] = right[key]\n                }\n            })\n            return { changed: true, consolidated: true }\n        }\n        diffs[path] = dataGet(rootRight, path)\n        return { changed: true, consolidated: true }\n    }\n\n    // Check if all keys are the same (no additions/removals)\n    let keysMatch = leftKeys.every(k => rightKeys.includes(k))\n\n    if (!keysMatch && !convertedToObject) {\n        // Keys differ (some added, some removed) - consolidate\n        if (path !== '') {\n            diffs[path] = dataGet(rootRight, path)\n            return { changed: true, consolidated: true }\n        }\n    }\n\n    // Recursively diff children\n    let childDiffs = {}\n    let changedCount = 0\n    let consolidatedCount = 0\n    let totalChildren = rightKeys.length\n\n    rightKeys.forEach(key => {\n        let childPath = path === '' ? key : `${path}.${key}`\n        let result = diffRecursive(left[key], right[key], childPath, childDiffs, rootLeft, rootRight)\n        if (result.changed) changedCount++\n        if (result.consolidated) consolidatedCount++\n    })\n\n    // If all children changed AND none of them were already consolidated, consolidate to this level\n    // (unless we're at root). This prevents double-consolidation up the tree.\n    // ALSO skip consolidation if we converted to object - we're adding new items, not replacing\n    // Only consolidate if there are MULTIPLE children - single property changes should remain granular\n    // for wire:target to work correctly (e.g., wire:target=\"form.text\" needs \"form.text\" not \"form\")\n    if (path !== '' && totalChildren > 1 && changedCount === totalChildren && consolidatedCount === 0 && !convertedToObject) {\n        diffs[path] = dataGet(rootRight, path)\n        return { changed: true, consolidated: true }\n    }\n\n    // Otherwise, add individual child diffs\n    Object.assign(diffs, childDiffs)\n\n    // If any child was consolidated, bubble that up to prevent further consolidation\n    return { changed: changedCount > 0, consolidated: consolidatedCount > 0 }\n}\n\n/**\n * The data that's passed between the browser and server is in the form of\n * nested tuples consisting of the schema: [rawValue, metadata]. In this\n * method we're extracting the plain JS object of only the raw values.\n */\nexport function extractData(payload) {\n    let value = isSynthetic(payload) ? payload[0] : payload\n    let meta = isSynthetic(payload) ? payload[1] : undefined\n\n    if (isObjecty(value)) {\n        Object.entries(value).forEach(([key, iValue]) => {\n            value[key] = extractData(iValue)\n        })\n    }\n\n    return value\n}\n\n/**\n * Determine if the variable passed in is a node in a nested metadata\n * tuple tree. (Meaning it takes the form of: [rawData, metadata])\n */\nexport function isSynthetic(subject) {\n    return Array.isArray(subject)\n        && subject.length === 2\n        && typeof subject[1] === 'object'\n        && Object.keys(subject[1]).includes('s')\n}\n\n/**\n * Post requests in Laravel require a csrf token to be passed\n * along with the payload. Here, we'll try and locate one.\n */\nexport function getCsrfToken() {\n    // Purposely not caching. Fetching it fresh every time ensures we're\n    // not depending on a stale session's CSRF token...\n\n    if (document.querySelector('meta[name=\"csrf-token\"]')) {\n        return document.querySelector('meta[name=\"csrf-token\"]').getAttribute('content')\n    }\n\n    if (document.querySelector('[data-csrf]')) {\n        return document.querySelector('[data-csrf]').getAttribute('data-csrf')\n    }\n\n    if (window.livewireScriptConfig['csrf'] ?? false) {\n        return window.livewireScriptConfig['csrf']\n    }\n\n    throw 'Livewire: No CSRF token detected'\n}\n\nlet nonce;\n\nexport function getNonce() {\n    if (nonce) return nonce\n\n\n    if (window.livewireScriptConfig && (window.livewireScriptConfig['nonce'] ?? false)) {\n        nonce = window.livewireScriptConfig['nonce']\n\n        return nonce\n    }\n\n    let elWithNonce = document.querySelector('style[data-livewire-style][nonce]')\n\n    if (elWithNonce) {\n        nonce = elWithNonce.nonce\n\n        return nonce\n    }\n\n    return null\n}\n\n/**\n * Livewire's base URL for loading JS/CSS modules.\n * Returns a full URL including origin, generated by PHP's url() helper.\n */\nexport function getModuleUrl() {\n    return document.querySelector('[data-module-url]')?.getAttribute('data-module-url') ?? window.livewireScriptConfig['moduleUrl'] ?? null\n}\n\n/**\n * Livewire's update URI. This is configurable via Livewire::setUpdateRoute(...)\n */\nexport function getUpdateUri() {\n    return document.querySelector('[data-update-uri]')?.getAttribute('data-update-uri') ?? window.livewireScriptConfig['uri'] ?? null\n}\n\nexport function contentIsFromDump(content) {\n    return !! content.match(/

formatted_output:
Warning: truncated output (original token count: 262152)
Total output lines: 183

vendor/livewire/livewire/src/Livewire.php:17: * @method static void setUpdateRoute($callback)
vendor/livewire/livewire/src/LivewireManager.php:158:    function setUpdateRoute($callback)
vendor/livewire/livewire/src/LivewireManager.php:160:        return app(HandleRequests::class)->setUpdateRoute($callback);
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:18:    protected $updateRoute;
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:24:        if (! $this->updateRoute && ! $this->updateRouteExists()) {
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:25:            app($this::class)->setUpdateRoute(function ($handle) {
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:35:    protected function updateRouteExists()
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:47:        // When routes are cached, $this->updateRoute may be null because
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:48:        // setUpdateRoute() was never called (the route already existed).
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:50:        $route = $this->updateRoute ?? $this->findUpdateRoute();
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:90:    function setUpdateRoute($callback)
vendor/livewire/livewire/src/Mechanisms/HandleRequests/HandleRequests.php:99:        $this->updateRoute = $route;
vendor/livewire/livewire/dist/livewire.min.js.map:4:  "sourcesContent": ["/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress\n * @license MIT */\n\n;(function(root, factory) {\n\n  if (typeof define === 'function' && define.amd) {\n    define(factory);\n  } else if (typeof exports === 'object') {\n    module.exports = factory();\n  } else {\n    root.NProgress = factory();\n  }\n\n})(this, function() {\n  var NProgress = {};\n\n  NProgress.version = '0.2.0';\n\n  var Settings = NProgress.settings = {\n    minimum: 0.08,\n    easing: 'ease',\n    positionUsing: '',\n    speed: 200,\n    trickle: true,\n    trickleRate: 0.02,\n    trickleSpeed: 800,\n    showSpinner: true,\n    barSelector: '[role=\"bar\"]',\n    spinnerSelector: '[role=\"spinner\"]',\n    parent: 'body',\n    template: '

'\n  };\n\n  /**\n   * Updates configuration.\n   *\n   *     NProgress.configure({\n   *       minimum: 0.1\n   *     });\n   */\n  NProgress.configure = function(options) {\n    var key, value;\n    for (key in options) {\n      value = options[key];\n      if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;\n    }\n\n    return this;\n  };\n\n  /**\n   * Last number.\n   */\n\n  NProgress.status = null;\n\n  /**\n   * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.\n   *\n   *     NProgress.set(0.4);\n   *     NProgress.set(1.0);\n   */\n\n  NProgress.set = function(n) {\n    var started = NProgress.isStarted();\n\n    n = clamp(n, Settings.minimum, 1);\n    NProgress.status = (n === 1 ? null : n);\n\n    var progress = NProgress.render(!started),\n        bar      = progress.querySelector(Settings.barSelector),\n        speed    = Settings.speed,\n        ease     = Settings.easing;\n\n    progress.offsetWidth; /* Repaint */\n\n    queue(function(next) {\n      // Set positionUsing if it hasn't already been set\n      if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();\n\n      // Add transition\n      css(bar, barPositionCSS(n, speed, ease));\n\n      if (n === 1) {\n        // Fade out\n        css(progress, { \n          transition: 'none', \n          opacity: 1 \n        });\n        progress.offsetWidth; /* Repaint */\n\n        setTimeout(function() {\n          css(progress, { \n            transition: 'all ' + speed + 'ms linear', \n            opacity: 0 \n          });\n          setTimeout(function() {\n            NProgress.remove();\n            next();\n          }, speed);\n        }, speed);\n      } else {\n        setTimeout(next, speed);\n      }\n    });\n\n    return this;\n  };\n\n  NProgress.isStarted = function() {\n    return typeof NProgress.status === 'number';\n  };\n\n  /**\n   * Shows the progress bar.\n   * This is the same as setting the status to 0%, except that it doesn't go backwards.\n   *\n   *     NProgress.start();\n   *\n   */\n  NProgress.start = function() {\n    if (!NProgress.status) NProgress.set(0);\n\n    var work = function() {\n      setTimeout(function() {\n        if (!NProgress.status) return;\n        NProgress.trickle();\n        work();\n      }, Settings.trickleSpeed);\n    };\n\n    if (Settings.trickle) work();\n\n    return this;\n  };\n\n  /**\n   * Hides the progress bar.\n   * This is the *sort of* the same as setting the status to 100%, with the\n   * difference being `done()` makes some placebo effect of some realistic motion.\n   *\n   *     NProgress.done();\n   *\n   * If `true` is passed, it will show the progress bar even if its hidden.\n   *\n   *     NProgress.done(true);\n   */\n\n  NProgress.done = function(force) {\n    if (!force && !NProgress.status) return this;\n\n    return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);\n  };\n\n  /**\n   * Increments by a random amount.\n   */\n\n  NProgress.inc = function(amount) {\n    var n = NProgress.status;\n\n    if (!n) {\n      return NProgress.start();\n    } else {\n      if (typeof amount !== 'number') {\n        amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);\n      }\n\n      n = clamp(n + amount, 0, 0.994);\n      return NProgress.set(n);\n    }\n  };\n\n  NProgress.trickle = function() {\n    return NProgress.inc(Math.random() * Settings.trickleRate);\n  };\n\n  /**\n   * Waits for all supplied jQuery promises and\n   * increases the progress as the promises resolve.\n   *\n   * @param $promise jQUery Promise\n   */\n  (function() {\n    var initial = 0, current = 0;\n\n    NProgress.promise = function($promise) {\n      if (!$promise || $promise.state() === \"resolved\") {\n        return this;\n      }\n\n      if (current === 0) {\n        NProgress.start();\n      }\n\n      initial++;\n      current++;\n\n      $promise.always(function() {\n        current--;\n        if (current === 0) {\n            initial = 0;\n            NProgress.done();\n        } else {\n            NProgress.set((initial - current) / initial);\n        }\n      });\n\n      return this;\n    };\n\n  })();\n\n  /**\n   * (Internal) renders the progress bar markup based on the `template`\n   * setting.\n   */\n\n  NProgress.render = function(fromStart) {\n    if (NProgress.isRendered()) return document.getElementById('nprogress');\n\n    addClass(document.documentElement, 'nprogress-busy');\n    \n    var progress = document.createElement('div');\n    progress.id = 'nprogress';\n    progress.innerHTML = Settings.template;\n\n    var bar      = progress.querySelector(Settings.barSelector),\n        perc     = fromStart ? '-100' : toBarPerc(NProgress.status || 0),\n        parent   = document.querySelector(Settings.parent),\n        spinner;\n    \n    css(bar, {\n      transition: 'all 0 linear',\n      transform: 'translate3d(' + perc + '%,0,0)'\n    });\n\n    if (!Settings.showSpinner) {\n      spinner = progress.querySelector(Settings.spinnerSelector);\n      spinner && removeElement(spinner);\n    }\n\n    if (parent != document.body) {\n      addClass(parent, 'nprogress-custom-parent');\n    }\n\n    parent.appendChild(progress);\n    return progress;\n  };\n\n  /**\n   * Removes the element. Opposite of render().\n   */\n\n  NProgress.remove = function() {\n    removeClass(document.documentElement, 'nprogress-busy');\n    removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');\n    var progress = document.getElementById('nprogress');\n    progress && removeElement(progress);\n  };\n\n  /**\n   * Checks if the progress bar is rendered.\n   */\n\n  NProgress.isRendered = function() {\n    return !!document.getElementById('nprogress');\n  };\n\n  /**\n   * Determine which positioning CSS rule to use.\n   */\n\n  NProgress.getPositioningCSS = function() {\n    // Sniff on document.body.style\n    var bodyStyle = document.body.style;\n\n    // Sniff prefixes\n    var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :\n                       ('MozTransform' in bodyStyle) ? 'Moz' :\n                       ('msTransform' in bodyStyle) ? 'ms' :\n                       ('OTransform' in bodyStyle) ? 'O' : '';\n\n    if (vendorPrefix + 'Perspective' in bodyStyle) {\n      // Modern browsers with 3D support, e.g. Webkit, IE10\n      return 'translate3d';\n    } else if (vendorPrefix + 'Transform' in bodyStyle) {\n      // Browsers without 3D support, e.g. IE9\n      return 'translate';\n    } else {\n      // Browsers without translate() support, e.g. IE7-8\n      return 'margin';\n    }\n  };\n\n  /**\n   * Helpers\n   */\n\n  function clamp(n, min, max) {\n    if (n < min) return min;\n    if (n > max) return max;\n    return n;\n  }\n\n  /**\n   * (Internal) converts a percentage (`0..1`) to a bar translateX\n   * percentage (`-100%..0%`).\n   */\n\n  function toBarPerc(n) {\n    return (-1 + n) * 100;\n  }\n\n\n  /**\n   * (Internal) returns the correct CSS for changing the bar's\n   * position given an n percentage, and speed and ease from Settings\n   */\n\n  function barPositionCSS(n, speed, ease) {\n    var barCSS;\n\n    if (Settings.positionUsing === 'translate3d') {\n      barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };\n    } else if (Settings.positionUsing === 'translate') {\n      barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };\n    } else {\n      barCSS = { 'margin-left': toBarPerc(n)+'%' };\n    }\n\n    barCSS.transition = 'all '+speed+'ms '+ease;\n\n    return barCSS;\n  }\n\n  /**\n   * (Internal) Queues a function to be executed.\n   */\n\n  var queue = (function() {\n    var pending = [];\n    \n    function next() {\n      var fn = pending.shift();\n      if (fn) {\n        fn(next);\n      }\n    }\n\n    return function(fn) {\n      pending.push(fn);\n      if (pending.length == 1) next();\n    };\n  })();\n\n  /**\n   * (Internal) Applies css properties to an element, similar to the jQuery \n   * css method.\n   *\n   * While this helper does assist with vendor prefixed property names, it \n   * does not perform any manipulation of values prior to setting styles.\n   */\n\n  var css = (function() {\n    var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],\n        cssProps    = {};\n\n    function camelCase(string) {\n      return string.replace(/^-ms-/, 'ms-').replace(/-([\\da-z])/gi, function(match, letter) {\n        return letter.toUpperCase();\n      });\n    }\n\n    function getVendorProp(name) {\n      var style = document.body.style;\n      if (name in style) return name;\n\n      var i = cssPrefixes.length,\n          capName = name.charAt(0).toUpperCase() + name.slice(1),\n          vendorName;\n      while (i--) {\n        vendorName = cssPrefixes[i] + capName;\n        if (vendorName in style) return vendorName;\n      }\n\n      return name;\n    }\n\n    function getStyleProp(name) {\n      name = camelCase(name);\n      return cssProps[name] || (cssProps[name] = getVendorProp(name));\n    }\n\n    function applyCss(element, prop, value) {\n      prop = getStyleProp(prop);\n      element.style[prop] = value;\n    }\n\n    return function(element, properties) {\n      var args = arguments,\n          prop, \n          value;\n\n      if (args.length == 2) {\n        for (prop in properties) {\n          value = properties[prop];\n          if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);\n        }\n      } else {\n        applyCss(element, args[1], args[2]);\n      }\n    }\n  })();\n\n  /**\n   * (Internal) Determines if an element or space separated list of class names contains a class name.\n   */\n\n  function hasClass(element, name) {\n    var list = typeof element == 'string' ? element : classList(element);\n    return list.indexOf(' ' + name + ' ') >= 0;\n  }\n\n  /**\n   * (Internal) Adds a class to an element.\n   */\n\n  function addClass(element, name) {\n    var oldList = classList(element),\n        newList = oldList + name;\n\n    if (hasClass(oldList, name)) return; \n\n    // Trim the opening space.\n    element.className = newList.substring(1);\n  }\n\n  /**\n   * (Internal) Removes a class from an element.\n   */\n\n  function removeClass(element, name) {\n    var oldList = classList(element),\n        newList;\n\n    if (!hasClass(element, name)) return;\n\n    // Replace the class name.\n    newList = oldList.replace(' ' + name + ' ', ' ');\n\n    // Trim the opening and closing spaces.\n    element.className = newList.substring(1, newList.length - 1);\n  }\n\n  /**\n   * (Internal) Gets a space separated list of the class names on the element. \n   * The list is wrapped with a single space on each end to facilitate finding \n   * matches within the list.\n   */\n\n  function classList(element) {\n    return (' ' + (element.className || '') + ' ').replace(/\\s+/gi, ' ');\n  }\n\n  /**\n   * (Internal) Removes an element from the DOM.\n   */\n\n  function removeElement(element) {\n    element && element.parentNode && element.parentNode.removeChild(element);\n  }\n\n  return NProgress;\n});\n\n", "\nexport class Bag {\n    constructor() { this.arrays = {} }\n\n    add(key, value) {\n        if (! this.arrays[key]) this.arrays[key] = []\n        this.arrays[key].push(value)\n    }\n\n    remove(key) {\n        if (this.arrays[key]) delete this.arrays[key]\n    }\n\n    get(key) { return this.arrays[key] || [] }\n\n    each(key, callback) { return this.get(key).forEach(callback) }\n}\n\nexport class WeakBag {\n    constructor() { this.arrays = new WeakMap }\n\n    add(key, value) {\n        if (! this.arrays.has(key)) this.arrays.set(key, [])\n        this.arrays.get(key).push(value)\n    }\n\n    remove(key) {\n        if (this.arrays.has(key)) this.arrays.delete(key, [])\n    }\n\n    get(key) { return this.arrays.has(key) ? this.arrays.get(key) : [] }\n\n    each(key, callback) { return this.get(key).forEach(callback) }\n}\n\nexport function dispatch(target, name, detail = {}, bubbles = true) {\n    target.dispatchEvent(\n        new CustomEvent(name, {\n            detail,\n            bubbles,\n            // Allows events to pass the shadow DOM barrier.\n            composed: true,\n            cancelable: true,\n        })\n    )\n}\n\nexport function listen(target, name, handler) {\n    target.addEventListener(name, handler)\n\n    return () => target.removeEventListener(name, handler)\n}\n\n/**\n * Type-checking in JS is weird and annoying, these are better.\n */\nexport function isObjecty(subject) { return (typeof subject === 'object' && subject !== null) }\nexport function isObject(subject) { return (isObjecty(subject) && ! isArray(subject)) }\nexport function isArray(subject) { return Array.isArray(subject) }\nexport function isFunction(subject) { return typeof subject === 'function' }\nexport function isPrimitive(subject) { return typeof subject !== 'object' || subject === null }\n\n/**\n * Clone an object deeply to wipe out any shared references.\n */\nexport function deepClone(obj) { return JSON.parse(JSON.stringify(obj)) }\n\n/**\n * Determine if two objects take the exact same shape.\n */\nexport function deeplyEqual(a, b) { return JSON.stringify(a) === JSON.stringify(b) }\n\n/**\n * An easy way to loop through arrays and objects.\n */\nexport function each(subject, callback) {\n    Object.entries(subject).forEach(([key, value]) => callback(key, value))\n}\n\n/**\n * Parse a path string into segments, supporting dot and bracket notation.\n * e.g. \"foo.bar\", \"foo[0].bar\", \"foo['hey'].baz\"\n */\nfunction parsePathSegments(path) {\n    if (path === '') return []\n\n    return path\n        .replace(/\\[(['\"]?)(.+?)\\1\\]/g, '.$2')  // Convert brackets to dots: foo['bar'] \u2192 foo.bar, foo[0] \u2192 foo.0\n        .replace(/^\\./, '')                      // Remove leading dot if present\n        .split('.')\n}\n\n/**\n * Get a property from an object with support for dot-notation and bracket-notation.\n */\nexport function dataGet(object, key) {\n    if (key === '') return object\n\n    return parsePathSegments(key).reduce((carry, i) => {\n        return carry?.[i]\n    }, object)\n}\n\n/**\n * Set a property on an object with support for dot-notation and bracket-notation.\n */\nexport function dataSet(object, key, value) {\n    let segments = parsePathSegments(key)\n\n    if (segments.length === 1) {\n        return object[segments[0]] = value\n    }\n\n    let firstSegment = segments.shift()\n    let restOfSegments = segments.join('.')\n    let nextSegment = segments[0]\n\n    if (object[firstSegment] === undefined) {\n        object[firstSegment] = {}\n    }\n\n    // If we're about to set a numeric key that would create null gaps, convert to object.\n    // This prevents JavaScript from filling intermediate indices with nulls\n    // (e.g., arr[1000] = true creates 1000 null entries in a JS array).\n    // We only convert when the key would create gaps (key > length), not when appending.\n    if (isArray(object[firstSegment]) && isNumeric(nextSegment) && parseInt(nextSegment) > object[firstSegment].length) {\n        object[firstSegment] = { ...object[firstSegment] }\n    }\n\n    dataSet(object[firstSegment], restOfSegments, value)\n}\n\nfunction isNumeric(subject) {\n    return ! isNaN(parseInt(subject))\n}\n\n/**\n * Delete a property from an object with support for dot-notation and bracket-notation.\n */\nexport function dataDelete(object, key) {\n    let segments = parsePathSegments(key)\n\n    if (segments.length === 1) {\n        if (Array.isArray(object)) {\n            object.splice(segments[0], 1)\n        } else {\n            delete object[segments[0]]\n        }\n        return\n    }\n\n    let firstSegment = segments.shift()\n    let restOfSegments = segments.join('.')\n\n    if (object[firstSegment] !== undefined) {\n        dataDelete(object[firstSegment], restOfSegments)\n    }\n}\n\n/**\n * Create a flat, dot-notated diff of two objects.\n * @deprecated Use diffAndConsolidate instead for smarter update consolidation\n */\nexport function diff(left, right, diffs = {}, path = '') {\n    // Are they the same?\n    if (left === right) return diffs\n\n    // Are they COMPLETELY different?\n    if (typeof left !== typeof right || (isObject(left) && isArray(right)) || (isArray(left) && isObject(right))) {\n        diffs[path] = right;\n        return diffs\n    }\n\n    // Is the right or left side a primitive value (a leaf node)?\n    if (isPrimitive(left) || isPrimitive(right)) {\n        diffs[path] = right\n        return diffs\n    }\n\n    // We now know both are objects...\n    let leftKeys = Object.keys(left)\n\n    // Recursively diff the object's properties...\n    Object.entries(right).forEach(([key, value]) => {\n        diffs = {...diffs, ...diff(left[key], right[key], diffs, path === '' ? key : `${path}.${key}`)}\n        leftKeys = leftKeys.filter(i => i !== key)\n    })\n\n    // Mark any items for removal...\n    leftKeys.forEach(key => {\n        diffs[`${path}.${key}`] = '__rm__'\n    })\n\n    return diffs\n}\n\n/**\n * Create a flat, dot-notated diff of two objects with automatic consolidation.\n * When multiple items in an array/object change or the size changes,\n * the diff is consolidated to the parent level instead of individual items.\n */\nexport function diffAndConsolidate(left, right) {\n    let diffs = {}\n\n    diffRecursive(left, right, '', diffs, left, right)\n\n    r…252152 tokens truncated… } from '@/request'\nimport Alpine from 'alpinejs'\n\ndirective('model', ({ el, directive, component, cleanup }) => {\n    // @todo: will need to probaby do this further upstream i just don't want to bog down the entire lifecycle right now...\n    // this is to support slots properly...\n    component = findComponentByEl(el)\n\n    let { expression, modifiers } = directive\n\n    if (! expression) {\n        return console.warn('Livewire: [wire:model] is missing a value.', el)\n    }\n\n    if (componentIsMissingProperty(component, expression)) {\n        return console.warn('Livewire: [wire:model=\"'+expression+'\"] property does not exist on component: ['+component.name+']', el)\n    }\n\n    // Handle file uploads differently...\n    if (el.type && el.type.toLowerCase() === 'file') {\n        return handleFileUpload(el, expression, component, cleanup)\n    }\n\n    // Split modifiers at .live boundary\n    // Modifiers BEFORE .live control client-side (x-model) sync timing\n    // Modifiers AFTER .live control network request timing\n    let liveIndex = modifiers.indexOf('live')\n    let isLive = liveIndex !== -1\n\n    // Backwards compatibility: .lazy without .live implies .change.live\n    let hasLazyWithoutLive = modifiers.includes('lazy') && ! isLive\n    let shouldSendNetwork = isLive || hasLazyWithoutLive\n\n    let ephemeralModifiers = isLive && ! hasLazyWithoutLive ? modifiers.slice(0, liveIndex) : modifiers.slice()\n    let networkModifiers = isLive && ! hasLazyWithoutLive ? modifiers.slice(liveIndex + 1) : []\n\n    // For .lazy backwards compat, trigger network on change\n    if (hasLazyWithoutLive) {\n        // Remove 'lazy' from ephemeralModifiers for .lazy backwards compat\n        ephemeralModifiers = ephemeralModifiers.filter(m => m !== 'lazy')\n        networkModifiers.push('change')\n    }\n\n    // Add self/deep modifier for event propagation control\n    if (! (ephemeralModifiers.includes('deep') || networkModifiers.includes('deep'))) {\n        if (! ephemeralModifiers.includes('self')) {\n            ephemeralModifiers.push('self')\n        }\n    }\n\n    // Extract ephemeral trigger modifiers (these control when x-model syncs)\n    let ephemeralOnBlur = ephemeralModifiers.includes('blur')\n    let ephemeralOnChange = ephemeralModifiers.includes('change') || ephemeralModifiers.includes('lazy')\n    let ephemeralOnEnter = ephemeralModifiers.includes('enter')\n    let hasEphemeralTriggers = ephemeralOnBlur || ephemeralOnChange || ephemeralOnEnter\n\n    // Extract network trigger modifiers\n    let networkOnBlur = networkModifiers.includes('blur')\n    let networkOnChange = networkModifiers.includes('change') || networkModifiers.includes('lazy')\n    let networkOnEnter = networkModifiers.includes('enter')\n    let hasNetworkTriggers = networkOnBlur || networkOnChange || networkOnEnter\n    let isDebounced = networkModifiers.includes('debounce')\n    let isThrottled = networkModifiers.includes('throttle')\n\n    // Trigger a network request\n    let update = () => {\n        setNextActionOrigin({ el, directive })\n\n        if (isLive || isDebounced) {\n            setNextActionMetadata({ type: 'model.live' })\n        }\n\n        expression.startsWith('$parent')\n            ? component.$wire.$parent.$commit()\n            : component.$wire.$commit()\n    }\n\n    let debouncedUpdate = update\n\n    // Apply debounce/throttle from network modifiers\n    if ((shouldSendNetwork && ! hasNetworkTriggers && isRealtimeInput(el)) || isDebounced) {\n        debouncedUpdate = debounce(debouncedUpdate, parseModifierDuration(networkModifiers, 'debounce') || 150)\n    }\n\n    if (isThrottled) {\n        debouncedUpdate = throttle(debouncedUpdate, parseModifierDuration(networkModifiers, 'throttle') || 150)\n    }\n\n    // Build the bindings object\n    let bindings = {}\n\n    // Network event listeners (for modifiers after .live, or .lazy backwards compat)\n    if (shouldSendNetwork && networkOnBlur) {\n        bindings['@blur'] = () => update()\n    }\n\n    if (shouldSendNetwork && networkOnChange) {\n        bindings['@change'] = () => update()\n    }\n\n    if (shouldSendNetwork && networkOnEnter) {\n        bindings['@keydown.enter'] = () => update()\n    }\n\n    // Build x-model modifier tail from ephemeral modifiers\n    let xModelTail = getModifierTail(ephemeralModifiers)\n\n    bindings['x-model' + xModelTail] = () => {\n        return {\n            get() {\n                return dataGet(component.$wire, expression)\n            },\n            set(value) {\n                dataSet(component.$wire, expression, value)\n\n                // If .live is present and no specific network triggers, fire on every ephemeral sync\n                if (shouldSendNetwork && ! hasNetworkTriggers) {\n                    debouncedUpdate()\n                }\n            },\n        }\n    }\n\n    Alpine.bind(el, bindings)\n})\n\nfunction getModifierTail(modifiers) {\n    // Filter out Livewire-specific modifiers that shouldn't go to x-model\n    // Keep: blur, change, lazy, enter, self, deep, number, boolean, trim, fill\n    // Remove: defer, live, debounce, throttle (and their durations)\n    modifiers = modifiers.filter(i => ! [\n        'defer', 'live'\n    ].includes(i))\n\n    if (modifiers.includes('debounce')) {\n        let index = modifiers.indexOf('debounce')\n        let hasDuration = parseModifierDuration(modifiers, 'debounce') !== undefined\n\n        // Delete the subsequent modifier if it's a duration...\n        modifiers.splice(index, hasDuration ? 2 : 1)\n    }\n\n    if (modifiers.includes('throttle')) {\n        let index = modifiers.indexOf('throttle')\n        let hasDuration = parseModifierDuration(modifiers, 'throttle') !== undefined\n\n        // Delete the subsequent modifier if it's a duration...\n        modifiers.splice(index, hasDuration ? 2 : 1)\n    }\n\n    if (modifiers.length === 0) return ''\n\n    return '.' + modifiers.join('.')\n}\n\nfunction isRealtimeInput(el) {\n    return (\n        ['INPUT', 'TEXTAREA'].includes(el.tagName.toUpperCase()) &&\n        !['checkbox', 'radio'].includes(el.type)\n    )\n        || el.tagName.toUpperCase() === 'UI-SLIDER' // Flux UI\n        || el.tagName.toUpperCase() === 'UI-COMPOSER' // Flux UI\n}\n\nfunction isDirty(subject, dirty) {\n    // Check for exact match: wire:model=\"bob\" in ['bob']\n    if (dirty.includes(subject)) return true\n\n    // Check case of parent: wire:model=\"bob.1\" in ['bob']\n    return dirty.some(i => subject.startsWith(i))\n}\n\nfunction componentIsMissingProperty(component, property) {\n    if (property.startsWith('$parent')) {\n        let parent = findComponentByEl(component.el.parentElement, false)\n\n        if (! parent) return true\n\n        return componentIsMissingProperty(parent, property.slice(7).replace(/^\\./, ''))\n    }\n\n    // Extract base property, handling both \"foo.bar\" and \"['foo'].bar\"\n    let match = property.match(/^\\[['\"]?([^\\]'\"]+)['\"]?\\]/) || property.match(/^([^.\\[]+)/)\n    let baseProperty = match[1]\n\n    return ! Object.keys(component.canonical).includes(baseProperty)\n}\n\nfunction debounce(func, wait) {\n    var timeout;\n\n    return function() {\n      var context = this, args = arguments;\n\n      var later = function() {\n            timeout = null\n\n            func.apply(context, args)\n      }\n\n      clearTimeout(timeout)\n\n      timeout = setTimeout(later, wait)\n    }\n}\n\nfunction throttle(func, limit) {\n    let inThrottle\n\n    return function() {\n        let context = this, args = arguments\n\n        if (! inThrottle) {\n            func.apply(context, args)\n\n            inThrottle = true\n\n            setTimeout(() => inThrottle = false, limit)\n        }\n    }\n}\n\nfunction parseModifierDuration(modifiers, key) {\n    let index = modifiers.indexOf(key)\n    if (index === -1) return undefined\n\n    let nextModifier = modifiers[modifiers.indexOf(key)+1] || 'invalid-wait'\n    let duration = nextModifier.split('ms')[0]\n\n    return ! isNaN(duration) ? duration : undefined\n}", "import { directive } from \"@/directives\"\nimport { evaluateActionExpression } from '../evaluator'\nimport { setNextActionOrigin } from \"@/request\"\n\ndirective('init', ({ component, el, directive }) => {\n    let fullMethod = directive.expression ? directive.expression : '$refresh'\n\n    setNextActionOrigin({ el, directive })\n\n    evaluateActionExpression(el, fullMethod)\n})\n", "import { directive, getDirectives } from \"@/directives\"\nimport { setNextActionMetadata, setNextActionOrigin } from '@/request'\nimport { evaluateActionExpression } from '../evaluator'\n\ndirective('poll', ({ el, directive, component }) => {\n    let interval = extractDurationFrom(directive.modifiers, 2000)\n\n    let { start, pauseWhile, throttleWhile, stopWhen } = poll(() => {\n        triggerComponentRequest(el, directive, component)\n    }, interval)\n\n    start()\n\n    throttleWhile(() => theTabIsInTheBackground() && theDirectiveIsMissingKeepAlive(directive))\n    pauseWhile(() => theDirectiveHasVisible(directive) && theElementIsNotInTheViewport(el))\n    pauseWhile(() => theDirectiveIsOffTheElement(el))\n    pauseWhile(() => livewireIsOffline())\n    stopWhen(() => theElementIsDisconnected(el))\n})\n\nfunction triggerComponentRequest(el, directive, component) {\n    // Set targetEl to null to prevent data-loading on poll actions\n    setNextActionOrigin({ el, directive, targetEl: null })\n    setNextActionMetadata({ type: 'poll' })\n\n    let fullMethod = directive.expression ? directive.expression : '$refresh'\n\n    evaluateActionExpression(el, fullMethod)\n}\n\nexport function poll(callback, interval = 2000) {\n    let pauseConditions = []\n    let throttleConditions = []\n    let stopConditions = []\n\n    return {\n        start() {\n            let clear = syncronizedInterval(interval, () => {\n                if (stopConditions.some(i => i())) return clear()\n                if (pauseConditions.some(i => i())) return\n                if (throttleConditions.some(i => i()) && Math.random() < .95) return\n\n                callback()\n            })\n        },\n        pauseWhile(condition) {\n            pauseConditions.push(condition)\n        },\n        throttleWhile(condition) {\n            throttleConditions.push(condition)\n        },\n        stopWhen(condition) {\n            stopConditions.push(condition)\n        }\n    }\n}\n\nlet clocks = []\n\nfunction syncronizedInterval(ms, callback) {\n    if (! clocks[ms]) {\n        let clock = {\n            timer: setInterval(() => clock.callbacks.forEach(i => i()), ms),\n            callbacks: new Set,\n        }\n\n        clocks[ms] = clock\n    }\n\n    clocks[ms].callbacks.add(callback)\n\n    return () => {\n        clocks[ms].callbacks.delete(callback)\n\n        if (clocks[ms].callbacks.size === 0) {\n            clearInterval(clocks[ms].timer)\n            delete clocks[ms]\n        }\n    }\n}\n\nlet isOffline = false\n\nwindow.addEventListener('offline', () => isOffline = true)\nwindow.addEventListener('online', () => isOffline = false)\n\nexport function livewireIsOffline() {\n    return isOffline\n}\n\nlet inBackground = false\n\ndocument.addEventListener('visibilitychange', () => { inBackground = document.hidden }, false)\n\nfunction theTabIsInTheBackground() {\n    return inBackground\n}\n\nfunction theDirectiveIsOffTheElement(el) {\n    return ! getDirectives(el).has('poll')\n}\n\nfunction theDirectiveIsMissingKeepAlive(directive) {\n    return ! directive.modifiers.includes('keep-alive')\n}\n\nfunction theDirectiveHasVisible(directive) {\n    return directive.modifiers.includes('visible')\n}\n\nfunction theElementIsNotInTheViewport(el) {\n    let bounding = el.getBoundingClientRect()\n\n    return ! (\n        bounding.top < (window.innerHeight || document.documentElement.clientHeight) &&\n        bounding.left < (window.innerWidth || document.documentElement.clientWidth) &&\n        bounding.bottom > 0 &&\n        bounding.right > 0\n    )\n}\n\nexport function theElementIsDisconnected(el) {\n    return el.isConnected === false\n}\n\nexport function extractDurationFrom(modifiers, defaultDuration) {\n    let durationInMilliSeconds\n    let durationInMilliSecondsString = modifiers.find(mod => mod.match(/([0-9]+)ms/))\n    let durationInSecondsString = modifiers.find(mod => mod.match(/([0-9]+)s/))\n\n    if (durationInMilliSecondsString) {\n        durationInMilliSeconds = Number(durationInMilliSecondsString.replace('ms', ''))\n    } else if (durationInSecondsString) {\n        durationInMilliSeconds = Number(durationInSecondsString.replace('s', '')) * 1000\n    }\n\n    return durationInMilliSeconds || defaultDuration\n}\n", "import { evaluateActionExpression } from '../evaluator'\nimport Alpine from 'alpinejs'\n\nAlpine.interceptInit(el => {\n    for (let i = 0; i < el.attributes.length; i++) {\n        if (el.attributes[i].name.startsWith('wire:show')) {\n            let { name, value } = el.attributes[i]\n\n            let modifierString = name.split('wire:show')[1]\n\n            let expression = value.trim()\n\n            Alpine.bind(el, {\n                ['x-show' + modifierString]() {\n                    return evaluateActionExpression(el, expression)\n                }\n            })\n        }\n    }\n})", "import Alpine from 'alpinejs'\nimport { evaluateActionExpression } from '../evaluator'\n\nAlpine.interceptInit(el => {\n    for (let i = 0; i < el.attributes.length; i++) {\n        if (el.attributes[i].name.startsWith('wire:text')) {\n            let { name, value } = el.attributes[i]\n\n            let modifierString = name.split('wire:text')[1]\n\n            let expression = value.trim()\n\n            Alpine.bind(el, {\n                ['x-text' + modifierString]() {\n                    return evaluateActionExpression(el, expression)\n                }\n            })\n        }\n    }\n})\n", "import Alpine from 'alpinejs'\nimport { evaluateActionExpression } from '../evaluator'\n\nAlpine.interceptInit(el => {\n    for (let i = 0; i < el.attributes.length; i++) {\n        if (el.attributes[i].name.startsWith('wire:bind:')) {\n            let { name, value } = el.attributes[i]\n\n            let remainder = name.split('wire:bind')[1]\n\n            let expression = value.trim()\n\n            Alpine.bind(el, {\n                ['x-bind' + remainder]() {\n                    return evaluateActionExpression(el, expression)\n                }\n            })\n        }\n    }\n})\n"],
<?php

namespace App\Providers;

use App\Auth\CustomerUserProvider;
use App\Contracts\PaymentProvider as PaymentProviderContract;
use App\Models\Product;
use App\Observers\ProductObserver;
use App\Services\MockPaymentProvider;
use Carbon\CarbonImmutable;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Rules\Password;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->app->bind(PaymentProviderContract::class, MockPaymentProvider::class);
        Auth::provider('customer', fn ($app, array $config): CustomerUserProvider => new CustomerUserProvider($app['hash'], $config['model']));
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        $this->configureDefaults();
        Model::preventLazyLoading(! app()->isProduction());
        Product::observe(ProductObserver::class);
        RateLimiter::for('login', fn (Request $request): Limit => Limit::perMinute(5)->by($request->ip()));
        RateLimiter::for('api.storefront', fn (Request $request): Limit => Limit::perMinute(120)->by($request->ip()));
        RateLimiter::for('checkout', fn (Request $request): Limit => Limit::perMinute(10)->by($request->hasSession() ? $request->session()->getId() : $request->ip()));
    }

    /**
     * Configure default behaviors for production-ready applications.
     */
    protected function configureDefaults(): void
    {
        Date::use(CarbonImmutable::class);

        DB::prohibitDestructiveCommands(
            app()->isProduction(),
        );

        Password::defaults(fn (): ?Password => app()->isProduction()
            ? Password::min(12)
                ->mixedCase()
                ->letters()
                ->numbers()
                ->symbols()
                ->uncompromised()
            : null
        );
    }
}
<?php

namespace App\Providers;

use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Laravel\Fortify\Fortify;

class FortifyServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        $this->configureActions();
        $this->configureViews();
        $this->configureRateLimiting();
    }

    /**
     * Configure Fortify actions.
     */
    private function configureActions(): void
    {
        Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
        Fortify::createUsersUsing(CreateNewUser::class);
    }

    /**
     * Configure Fortify views.
     */
    private function configureViews(): void
    {
        Fortify::loginView(fn () => view('livewire.auth.login'));
        Fortify::verifyEmailView(fn () => view('livewire.auth.verify-email'));
        Fortify::twoFactorChallengeView(fn () => view('livewire.auth.two-factor-challenge'));
        Fortify::confirmPasswordView(fn () => view('livewire.auth.confirm-password'));
        Fortify::registerView(fn () => view('livewire.auth.register'));
        Fortify::resetPasswordView(fn () => view('livewire.auth.reset-password'));
        Fortify::requestPasswordResetLinkView(fn () => view('livewire.auth.forgot-password'));
    }

    /**
     * Configure rate limiting.
     */
    private function configureRateLimiting(): void
    {
        RateLimiter::for('two-factor', function (Request $request) {
            return Limit::perMinute(5)->by($request->session()->get('login.id'));
        });

        RateLimiter::for('login', function (Request $request) {
            $throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());

            return Limit::perMinute(5)->by($throttleKey);
        });
    }
}
<?php

use App\Livewire\Settings\Appearance;
use App\Livewire\Settings\Password;
use App\Livewire\Settings\Profile;
use App\Livewire\Settings\TwoFactor;
use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Features;

Route::middleware(['auth'])->group(function () {
    Route::redirect('settings', 'settings/profile');

    Route::livewire('settings/profile', Profile::class)->name('profile.edit');
});

Route::middleware(['auth', 'verified'])->group(function () {
    Route::livewire('settings/password', Password::class)->name('user-password.edit');
    Route::livewire('settings/appearance', Appearance::class)->name('appearance.edit');

    Route::livewire('settings/two-factor', TwoFactor::class)
        ->middleware(
            when(
                Features::canManageTwoFactorAuthentication()
                && Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword'),
                ['password.confirm'],
                [],
            ),
        )
        ->name('two-factor.show');
});