├── .env.example ├── .gitattributes ├── .gitignore ├── README.md ├── SETUP.md ├── app ├── Helpers │ └── sdk_helper.php ├── Http │ └── Controllers │ │ ├── ApiController.php │ │ ├── Controller.php │ │ ├── IndexController.php │ │ ├── LoginController.php │ │ ├── ProfileController.php │ │ ├── SignupController.php │ │ └── UserAreaController.php ├── Models │ └── User.php └── Providers │ └── AppServiceProvider.php ├── artisan ├── bootstrap ├── app.php ├── cache │ └── .gitignore └── providers.php ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── cache.php ├── database.php ├── filesystems.php ├── logging.php ├── mail.php ├── queue.php ├── services.php └── session.php ├── database ├── .gitignore ├── factories │ └── UserFactory.php ├── migrations │ ├── 2024_10_25_155409_create_user_table.php │ └── 2024_10_25_160858_create_sessions_table.php └── seeders │ └── DatabaseSeeder.php ├── package-lock.json ├── package.json ├── phpunit.xml ├── public ├── .htaccess ├── documents-icon.svg ├── favicon.ico ├── github-icon.svg ├── index.php ├── logo.svg ├── main.css └── robots.txt ├── resources └── views │ ├── index_authenticated.blade.php │ ├── index_guest.blade.php │ ├── layout.blade.php │ ├── login.blade.php │ ├── profile.blade.php │ ├── signup.blade.php │ ├── signup_onboarding.blade.php │ ├── userarea_authenticated.blade.php │ └── userarea_guest.blade.php ├── routes ├── console.php └── web.php ├── tests ├── Feature │ └── ExampleTest.php ├── TestCase.php └── Unit │ └── ExampleTest.php └── vite.config.js /.env.example: -------------------------------------------------------------------------------- 1 | SERVER_HOST=localhost 2 | SERVER_PORT=3000 3 | 4 | APP_NAME=Laravel 5 | APP_ENV=local 6 | APP_KEY= 7 | APP_DEBUG=true 8 | APP_TIMEZONE=UTC 9 | APP_URL=http://localhost 10 | 11 | APP_LOCALE=en 12 | APP_FALLBACK_LOCALE=en 13 | APP_FAKER_LOCALE=en_US 14 | 15 | APP_MAINTENANCE_DRIVER=file 16 | # APP_MAINTENANCE_STORE=database 17 | 18 | PHP_CLI_SERVER_WORKERS=4 19 | 20 | BCRYPT_ROUNDS=12 21 | 22 | LOG_CHANNEL=stack 23 | LOG_STACK=single 24 | LOG_DEPRECATIONS_CHANNEL=null 25 | LOG_LEVEL=debug 26 | 27 | DB_CONNECTION=sqlite 28 | # DB_HOST=127.0.0.1 29 | # DB_PORT=3306 30 | # DB_DATABASE=laravel 31 | # DB_USERNAME=root 32 | # DB_PASSWORD= 33 | 34 | SESSION_DRIVER=database 35 | SESSION_LIFETIME=120 36 | SESSION_ENCRYPT=false 37 | SESSION_PATH=/ 38 | SESSION_DOMAIN=null 39 | 40 | BROADCAST_CONNECTION=log 41 | FILESYSTEM_DISK=local 42 | QUEUE_CONNECTION=database 43 | 44 | CACHE_STORE=database 45 | CACHE_PREFIX= 46 | 47 | MEMCACHED_HOST=127.0.0.1 48 | 49 | REDIS_CLIENT=phpredis 50 | REDIS_HOST=127.0.0.1 51 | REDIS_PASSWORD=null 52 | REDIS_PORT=6379 53 | 54 | MAIL_MAILER=log 55 | MAIL_HOST=127.0.0.1 56 | MAIL_PORT=2525 57 | MAIL_USERNAME=null 58 | MAIL_PASSWORD=null 59 | MAIL_ENCRYPTION=null 60 | MAIL_FROM_ADDRESS="hello@example.com" 61 | MAIL_FROM_NAME="${APP_NAME}" 62 | 63 | AWS_ACCESS_KEY_ID= 64 | AWS_SECRET_ACCESS_KEY= 65 | AWS_DEFAULT_REGION=us-east-1 66 | AWS_BUCKET= 67 | AWS_USE_PATH_STYLE_ENDPOINT=false 68 | 69 | VITE_APP_NAME="${APP_NAME}" 70 | CORBADO_PROJECT_ID= 71 | CORBADO_API_SECRET= 72 | CORBADO_FRONTEND_API= 73 | CORBADO_BACKEND_API= 74 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.blade.php diff=html 4 | *.css diff=css 5 | *.html diff=html 6 | *.md diff=markdown 7 | *.php diff=php 8 | 9 | /.github export-ignore 10 | CHANGELOG.md export-ignore 11 | .styleci.yml export-ignore 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /node_modules 3 | /public/build 4 | /public/hot 5 | /public/storage 6 | /storage/*.key 7 | /storage/pail 8 | /vendor 9 | .env 10 | .env.backup 11 | .env.production 12 | .env.test 13 | .phpactor.json 14 | .phpunit.result.cache 15 | Homestead.json 16 | Homestead.yaml 17 | auth.json 18 | npm-debug.log 19 | yarn-error.log 20 | /.fleet 21 | /.idea 22 | /.vscode 23 | /.zed -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GitHub Repo Cover 2 | 3 | # PHP Laravel Passkeys Example Application 4 | 5 | This is a sample implementation of the [Corbado passkeys-first authentication solution](https://www.corbado.com) using 6 | PHP Laravel. The following packages are being used: 7 | 8 | - [Corbado web-js](https://github.com/corbado/javascript/tree/develop/packages/web-js) 9 | - [Corbado PHP SDK](https://github.com/corbado/corbado-php) 10 | 11 | [![integration-guides](https://github.com/user-attachments/assets/7859201b-a345-4b68-b336-6e2edcc6577b)](https://app.corbado.com/integration-guides/php-laravel) 12 | 13 | ## File structure 14 | 15 | - `app/Http/Controllers`: contains the controllers for handling HTTP requests 16 | - `config`: contains the configuration files 17 | - `database/migrations`: contains the database migration files, including our custom user table 18 | - `public`: contains the publicly accessible files, such as assets 19 | - `resources/views`: contains the Blade templates 20 | - `routes/web.php`: contains the route definitions 21 | - `.env`: environment variables configuration file 22 | 23 | ## Setup 24 | 25 | ### Prerequisites 26 | 27 | Please follow the steps in [Getting started](https://docs.corbado.com/overview/getting-started) to create and configure 28 | a project in the [Corbado developer panel](https://app.corbado.com/). 29 | 30 | You need to have [PHP](https://www.php.net/downloads) and [Composer](https://getcomposer.org/download/) installed to run it. 31 | 32 | ### Configure environment variables 33 | 34 | Use the values you obtained in [Prerequisites](#prerequisites) to configure the following variables inside a `.env` 35 | file you create in the root folder of this project: 36 | 37 | ```sh 38 | CORBADO_PROJECT_ID=pro-XXX 39 | CORBADO_API_SECRET=corbado1_XXX 40 | CORBADO_FRONTEND_API=https://${CORBADO_PROJECT_ID}.frontendapi.cloud.corbado.io 41 | CORBADO_BACKEND_API=https://backendapi.cloud.corbado.io 42 | ``` 43 | 44 | ## Usage 45 | 46 | ### Run the project locally 47 | 48 | Run 49 | 50 | ```sh 51 | composer install 52 | ``` 53 | 54 | to install all dependencies. 55 | 56 | Finally, you can run the project locally with 57 | 58 | ```sh 59 | php artisan serve 60 | ``` 61 | 62 | ## Passkeys support 63 | 64 | - Community for Developer Support: https://bit.ly/passkeys-community 65 | - Passkeys Debugger: https://www.passkeys-debugger.io/ 66 | - Passkey Subreddit: https://www.reddit.com/r/passkey/ 67 | 68 | ## Telemetry 69 | 70 | This example application uses telemetry. By gathering telemetry data, we gain a more comprehensive understanding of how our SDKs, components, and example applications are utilized across various scenarios. This information is crucial in helping us prioritize features that are beneficial and impactful for the majority of our users. Read our [official documentation](https://docs.corbado.com/corbado-complete/other/telemetry) for more details. 71 | 72 | To disable telemetry, add the following line to your `.env` file: 73 | 74 | ```sh 75 | CORBADO_TELEMETRY_DISABLED=true 76 | ``` -------------------------------------------------------------------------------- /SETUP.md: -------------------------------------------------------------------------------- 1 | # Setup instructions (later needed for the integration guide) 2 | 3 | - Install PHP and composer 4 | - Run composer create-project laravel/laravel example-app 5 | - Run Corbado Getting Started to create new Corbado project 6 | - Set Corbado config in .env 7 | - Add SERVER_HOST=localhost SERVER_PORT=3000 to top of .env 8 | - composer require corbado/php-sdk 9 | - composer require symfony/cache 10 | - Explain storage/logs/laravel.log (session-token validation errors are logged there with info level) 11 | - Run php artisan migrate 12 | - Run php artisan serve 13 | -------------------------------------------------------------------------------- /app/Helpers/sdk_helper.php: -------------------------------------------------------------------------------- 1 | setJwksCachePool(new FilesystemAdapter()); 20 | $sdk = new SDK($config); 21 | } 22 | 23 | return $sdk; 24 | } 25 | } -------------------------------------------------------------------------------- /app/Http/Controllers/ApiController.php: -------------------------------------------------------------------------------- 1 | getAuthenticatedUserFromAuthorizationHeader($request); 13 | if ($corbadoUser !== null) { 14 | return response()->json([ 15 | 'secret' => 'Passkeys are cool!', 16 | ]); 17 | } 18 | 19 | return response()->json([ 20 | 'error' => 'Not authenticated' 21 | ], status: 401); 22 | } 23 | } -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | sdk = getSdk(); 26 | } 27 | 28 | protected function getAuthenticatedUserFromCookie(): ?UserEntity 29 | { 30 | // Must use $_COOKIE here because cookie has not been created by Laravel 31 | // itself (Laravel encrypts cookies by default). 32 | $sessionToken = $_COOKIE['cbo_session_token'] ?? null; 33 | if (empty($sessionToken)) { 34 | return null; 35 | } 36 | 37 | try { 38 | return $this->sdk->sessions()->validateToken($sessionToken); 39 | } catch (\Corbado\Exceptions\ValidationException $e) { 40 | Log::info($e->getMessage()); 41 | } 42 | 43 | return null; 44 | } 45 | 46 | /** 47 | * @throws ConfigException 48 | * @throws AssertException 49 | */ 50 | protected function getUserIdentifiers(string $userId): IdentifierList 51 | { 52 | return $this->sdk->identifiers()->listByUserID($userId); 53 | } 54 | 55 | protected function getAuthenticatedUserFromAuthorizationHeader(Request $request): ?UserEntity 56 | { 57 | $sessionToken = $request->bearerToken(); 58 | if (empty($sessionToken)) { 59 | return null; 60 | } 61 | 62 | try { 63 | return $this->sdk->sessions()->validateToken($sessionToken); 64 | } catch (\Corbado\Exceptions\ValidationException $e) { 65 | Log::info($e->getMessage()); 66 | } 67 | 68 | return null; 69 | } 70 | } -------------------------------------------------------------------------------- /app/Http/Controllers/IndexController.php: -------------------------------------------------------------------------------- 1 | getAuthenticatedUserFromCookie(); 14 | if ($corbadoUser !== null) { 15 | $user = DB::table('user')->where('corbado_user_id', $corbadoUser->getID())->first(); 16 | return view('index_authenticated', ['corbadoUser' => $corbadoUser, 'user' => $user]); 17 | } 18 | 19 | return view('index_guest', ['corbadoUser' => $corbadoUser]); 20 | } 21 | } -------------------------------------------------------------------------------- /app/Http/Controllers/LoginController.php: -------------------------------------------------------------------------------- 1 | getAuthenticatedUserFromCookie(); 14 | if ($corbadoUser !== null) { 15 | return redirect()->route('profile')->withErrors('You are already logged in!'); 16 | } 17 | 18 | return view('login', ['corbadoUser' => $corbadoUser]); 19 | } 20 | } -------------------------------------------------------------------------------- /app/Http/Controllers/ProfileController.php: -------------------------------------------------------------------------------- 1 | getAuthenticatedUserFromCookie(); 15 | if ($corbadoUser === null) { 16 | return redirect()->route('login')->withErrors('You must be logged in to view your profile!'); 17 | } 18 | $user = DB::table('user')->where('corbado_user_id', $corbadoUser->getID())->first(); 19 | $userIdentifiers = $this->getUserIdentifiers($corbadoUser->getID()); 20 | return view('profile', ['corbadoUser' => $corbadoUser, 'userIdentifiers' => $userIdentifiers->getIdentifiers(), 'user' => $user]); 21 | } 22 | } -------------------------------------------------------------------------------- /app/Http/Controllers/SignupController.php: -------------------------------------------------------------------------------- 1 | getAuthenticatedUserFromCookie(); 15 | if ($corbadoUser !== null) { 16 | return redirect()->route('profile')->withErrors('You are already logged in!'); 17 | } 18 | 19 | return view('signup', ['corbadoUser' => $corbadoUser]); 20 | } 21 | 22 | public function onboarding(Request $request): View|RedirectResponse 23 | { 24 | $corbadoUser = $this->getAuthenticatedUserFromCookie(); 25 | if ($corbadoUser === null) { 26 | return redirect()->route('index'); 27 | } 28 | 29 | $user = DB::selectOne('SELECT * FROM user WHERE corbado_user_id = ?', [$corbadoUser->getID()]); 30 | if ($user === null) { 31 | DB::insert('INSERT INTO user (corbado_user_id, created_at, updated_at) VALUES (?, current_timestamp, current_timestamp)', [$corbadoUser->getID()]); 32 | } else { 33 | return redirect()->route('profile'); 34 | } 35 | 36 | return view('signup_onboarding', ['corbadoUser' => $corbadoUser]); 37 | } 38 | 39 | public function handleOnboarding(Request $request): View|RedirectResponse 40 | { 41 | $data = $request->validate([ 42 | 'city' => 'required|string|min:3|max:100', 43 | ]); 44 | 45 | DB::update('UPDATE user SET city = ?, updated_at = current_timestamp WHERE corbado_user_id = ?', [$data['city'], $this->getAuthenticatedUserFromCookie()->getID()]); 46 | 47 | return redirect()->route('index'); 48 | } 49 | } -------------------------------------------------------------------------------- /app/Http/Controllers/UserAreaController.php: -------------------------------------------------------------------------------- 1 | getAuthenticatedUserFromCookie(); 14 | if ($corbadoUser !== null) { 15 | return view('userarea_authenticated', ['corbadoUser' => $corbadoUser]); 16 | } 17 | 18 | return view('userarea_guest', ['corbadoUser' => $corbadoUser]); 19 | } 20 | } -------------------------------------------------------------------------------- /app/Models/User.php: -------------------------------------------------------------------------------- 1 | */ 13 | use HasFactory, Notifiable; 14 | 15 | /** 16 | * The attributes that are mass assignable. 17 | * 18 | * @var array 19 | */ 20 | protected $fillable = [ 21 | 'name', 22 | 'email', 23 | 'password', 24 | ]; 25 | 26 | /** 27 | * The attributes that should be hidden for serialization. 28 | * 29 | * @var array 30 | */ 31 | protected $hidden = [ 32 | 'password', 33 | 'remember_token', 34 | ]; 35 | 36 | /** 37 | * Get the attributes that should be cast. 38 | * 39 | * @return array 40 | */ 41 | protected function casts(): array 42 | { 43 | return [ 44 | 'email_verified_at' => 'datetime', 45 | 'password' => 'hashed', 46 | ]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | handleCommand(new ArgvInput); 14 | 15 | exit($status); 16 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | withRouting( 9 | web: __DIR__.'/../routes/web.php', 10 | commands: __DIR__.'/../routes/console.php', 11 | health: '/up', 12 | ) 13 | ->withMiddleware(function (Middleware $middleware) { 14 | // 15 | }) 16 | ->withExceptions(function (Exceptions $exceptions) { 17 | // 18 | })->create(); 19 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /bootstrap/providers.php: -------------------------------------------------------------------------------- 1 | env('APP_NAME', 'Laravel'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Application Environment 21 | |-------------------------------------------------------------------------- 22 | | 23 | | This value determines the "environment" your application is currently 24 | | running in. This may determine how you prefer to configure various 25 | | services the application utilizes. Set this in your ".env" file. 26 | | 27 | */ 28 | 29 | 'env' => env('APP_ENV', 'production'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application Debug Mode 34 | |-------------------------------------------------------------------------- 35 | | 36 | | When your application is in debug mode, detailed error messages with 37 | | stack traces will be shown on every error that occurs within your 38 | | application. If disabled, a simple generic error page is shown. 39 | | 40 | */ 41 | 42 | 'debug' => (bool) env('APP_DEBUG', false), 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Application URL 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This URL is used by the console to properly generate URLs when using 50 | | the Artisan command line tool. You should set this to the root of 51 | | the application so that it's available within Artisan commands. 52 | | 53 | */ 54 | 55 | 'url' => env('APP_URL', 'http://localhost'), 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Application Timezone 60 | |-------------------------------------------------------------------------- 61 | | 62 | | Here you may specify the default timezone for your application, which 63 | | will be used by the PHP date and date-time functions. The timezone 64 | | is set to "UTC" by default as it is suitable for most use cases. 65 | | 66 | */ 67 | 68 | 'timezone' => env('APP_TIMEZONE', 'UTC'), 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Application Locale Configuration 73 | |-------------------------------------------------------------------------- 74 | | 75 | | The application locale determines the default locale that will be used 76 | | by Laravel's translation / localization methods. This option can be 77 | | set to any locale for which you plan to have translation strings. 78 | | 79 | */ 80 | 81 | 'locale' => env('APP_LOCALE', 'en'), 82 | 83 | 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), 84 | 85 | 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | Encryption Key 90 | |-------------------------------------------------------------------------- 91 | | 92 | | This key is utilized by Laravel's encryption services and should be set 93 | | to a random, 32 character string to ensure that all encrypted values 94 | | are secure. You should do this prior to deploying the application. 95 | | 96 | */ 97 | 98 | 'cipher' => 'AES-256-CBC', 99 | 100 | 'key' => env('APP_KEY'), 101 | 102 | 'previous_keys' => [ 103 | ...array_filter( 104 | explode(',', env('APP_PREVIOUS_KEYS', '')) 105 | ), 106 | ], 107 | 108 | /* 109 | |-------------------------------------------------------------------------- 110 | | Maintenance Mode Driver 111 | |-------------------------------------------------------------------------- 112 | | 113 | | These configuration options determine the driver used to determine and 114 | | manage Laravel's "maintenance mode" status. The "cache" driver will 115 | | allow maintenance mode to be controlled across multiple machines. 116 | | 117 | | Supported drivers: "file", "cache" 118 | | 119 | */ 120 | 121 | 'maintenance' => [ 122 | 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), 123 | 'store' => env('APP_MAINTENANCE_STORE', 'database'), 124 | ], 125 | 126 | ]; 127 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => env('AUTH_GUARD', 'web'), 18 | 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | which utilizes session storage plus the Eloquent user provider. 29 | | 30 | | All authentication guards have a user provider, which defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | system used by the application. Typically, Eloquent is utilized. 33 | | 34 | | Supported: "session" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | ], 44 | 45 | /* 46 | |-------------------------------------------------------------------------- 47 | | User Providers 48 | |-------------------------------------------------------------------------- 49 | | 50 | | All authentication guards have a user provider, which defines how the 51 | | users are actually retrieved out of your database or other storage 52 | | system used by the application. Typically, Eloquent is utilized. 53 | | 54 | | If you have multiple user tables or models you may configure multiple 55 | | providers to represent the model / table. These providers may then 56 | | be assigned to any extra authentication guards you have defined. 57 | | 58 | | Supported: "database", "eloquent" 59 | | 60 | */ 61 | 62 | 'providers' => [ 63 | 'users' => [ 64 | 'driver' => 'eloquent', 65 | 'model' => env('AUTH_MODEL', App\Models\User::class), 66 | ], 67 | 68 | // 'users' => [ 69 | // 'driver' => 'database', 70 | // 'table' => 'users', 71 | // ], 72 | ], 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Resetting Passwords 77 | |-------------------------------------------------------------------------- 78 | | 79 | | These configuration options specify the behavior of Laravel's password 80 | | reset functionality, including the table utilized for token storage 81 | | and the user provider that is invoked to actually retrieve users. 82 | | 83 | | The expiry time is the number of minutes that each reset token will be 84 | | considered valid. This security feature keeps tokens short-lived so 85 | | they have less time to be guessed. You may change this as needed. 86 | | 87 | | The throttle setting is the number of seconds a user must wait before 88 | | generating more password reset tokens. This prevents the user from 89 | | quickly generating a very large amount of password reset tokens. 90 | | 91 | */ 92 | 93 | 'passwords' => [ 94 | 'users' => [ 95 | 'provider' => 'users', 96 | 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), 97 | 'expire' => 60, 98 | 'throttle' => 60, 99 | ], 100 | ], 101 | 102 | /* 103 | |-------------------------------------------------------------------------- 104 | | Password Confirmation Timeout 105 | |-------------------------------------------------------------------------- 106 | | 107 | | Here you may define the amount of seconds before a password confirmation 108 | | window expires and users are asked to re-enter their password via the 109 | | confirmation screen. By default, the timeout lasts for three hours. 110 | | 111 | */ 112 | 113 | 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), 114 | 115 | ]; 116 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_STORE', 'database'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Cache Stores 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the cache "stores" for your application as 26 | | well as their drivers. You may even define multiple stores for the 27 | | same cache driver to group types of items stored in your caches. 28 | | 29 | | Supported drivers: "array", "database", "file", "memcached", 30 | | "redis", "dynamodb", "octane", "null" 31 | | 32 | */ 33 | 34 | 'stores' => [ 35 | 36 | 'array' => [ 37 | 'driver' => 'array', 38 | 'serialize' => false, 39 | ], 40 | 41 | 'database' => [ 42 | 'driver' => 'database', 43 | 'connection' => env('DB_CACHE_CONNECTION'), 44 | 'table' => env('DB_CACHE_TABLE', 'cache'), 45 | 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), 46 | 'lock_table' => env('DB_CACHE_LOCK_TABLE'), 47 | ], 48 | 49 | 'file' => [ 50 | 'driver' => 'file', 51 | 'path' => storage_path('framework/cache/data'), 52 | 'lock_path' => storage_path('framework/cache/data'), 53 | ], 54 | 55 | 'memcached' => [ 56 | 'driver' => 'memcached', 57 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 58 | 'sasl' => [ 59 | env('MEMCACHED_USERNAME'), 60 | env('MEMCACHED_PASSWORD'), 61 | ], 62 | 'options' => [ 63 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 64 | ], 65 | 'servers' => [ 66 | [ 67 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 68 | 'port' => env('MEMCACHED_PORT', 11211), 69 | 'weight' => 100, 70 | ], 71 | ], 72 | ], 73 | 74 | 'redis' => [ 75 | 'driver' => 'redis', 76 | 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), 77 | 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), 78 | ], 79 | 80 | 'dynamodb' => [ 81 | 'driver' => 'dynamodb', 82 | 'key' => env('AWS_ACCESS_KEY_ID'), 83 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 84 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 85 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), 86 | 'endpoint' => env('DYNAMODB_ENDPOINT'), 87 | ], 88 | 89 | 'octane' => [ 90 | 'driver' => 'octane', 91 | ], 92 | 93 | ], 94 | 95 | /* 96 | |-------------------------------------------------------------------------- 97 | | Cache Key Prefix 98 | |-------------------------------------------------------------------------- 99 | | 100 | | When utilizing the APC, database, memcached, Redis, and DynamoDB cache 101 | | stores, there might be other applications using the same cache. For 102 | | that reason, you may prefix every cache key to avoid collisions. 103 | | 104 | */ 105 | 106 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), 107 | 108 | ]; 109 | -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | env('DB_CONNECTION', 'sqlite'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Database Connections 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Below are all of the database connections defined for your application. 27 | | An example configuration is provided for each database system which 28 | | is supported by Laravel. You're free to add / remove connections. 29 | | 30 | */ 31 | 32 | 'connections' => [ 33 | 34 | 'sqlite' => [ 35 | 'driver' => 'sqlite', 36 | 'url' => env('DB_URL'), 37 | 'database' => env('DB_DATABASE', database_path('database.sqlite')), 38 | 'prefix' => '', 39 | 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), 40 | 'busy_timeout' => null, 41 | 'journal_mode' => null, 42 | 'synchronous' => null, 43 | ], 44 | 45 | 'mysql' => [ 46 | 'driver' => 'mysql', 47 | 'url' => env('DB_URL'), 48 | 'host' => env('DB_HOST', '127.0.0.1'), 49 | 'port' => env('DB_PORT', '3306'), 50 | 'database' => env('DB_DATABASE', 'laravel'), 51 | 'username' => env('DB_USERNAME', 'root'), 52 | 'password' => env('DB_PASSWORD', ''), 53 | 'unix_socket' => env('DB_SOCKET', ''), 54 | 'charset' => env('DB_CHARSET', 'utf8mb4'), 55 | 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), 56 | 'prefix' => '', 57 | 'prefix_indexes' => true, 58 | 'strict' => true, 59 | 'engine' => null, 60 | 'options' => extension_loaded('pdo_mysql') ? array_filter([ 61 | PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), 62 | ]) : [], 63 | ], 64 | 65 | 'mariadb' => [ 66 | 'driver' => 'mariadb', 67 | 'url' => env('DB_URL'), 68 | 'host' => env('DB_HOST', '127.0.0.1'), 69 | 'port' => env('DB_PORT', '3306'), 70 | 'database' => env('DB_DATABASE', 'laravel'), 71 | 'username' => env('DB_USERNAME', 'root'), 72 | 'password' => env('DB_PASSWORD', ''), 73 | 'unix_socket' => env('DB_SOCKET', ''), 74 | 'charset' => env('DB_CHARSET', 'utf8mb4'), 75 | 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), 76 | 'prefix' => '', 77 | 'prefix_indexes' => true, 78 | 'strict' => true, 79 | 'engine' => null, 80 | 'options' => extension_loaded('pdo_mysql') ? array_filter([ 81 | PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), 82 | ]) : [], 83 | ], 84 | 85 | 'pgsql' => [ 86 | 'driver' => 'pgsql', 87 | 'url' => env('DB_URL'), 88 | 'host' => env('DB_HOST', '127.0.0.1'), 89 | 'port' => env('DB_PORT', '5432'), 90 | 'database' => env('DB_DATABASE', 'laravel'), 91 | 'username' => env('DB_USERNAME', 'root'), 92 | 'password' => env('DB_PASSWORD', ''), 93 | 'charset' => env('DB_CHARSET', 'utf8'), 94 | 'prefix' => '', 95 | 'prefix_indexes' => true, 96 | 'search_path' => 'public', 97 | 'sslmode' => 'prefer', 98 | ], 99 | 100 | 'sqlsrv' => [ 101 | 'driver' => 'sqlsrv', 102 | 'url' => env('DB_URL'), 103 | 'host' => env('DB_HOST', 'localhost'), 104 | 'port' => env('DB_PORT', '1433'), 105 | 'database' => env('DB_DATABASE', 'laravel'), 106 | 'username' => env('DB_USERNAME', 'root'), 107 | 'password' => env('DB_PASSWORD', ''), 108 | 'charset' => env('DB_CHARSET', 'utf8'), 109 | 'prefix' => '', 110 | 'prefix_indexes' => true, 111 | // 'encrypt' => env('DB_ENCRYPT', 'yes'), 112 | // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), 113 | ], 114 | 115 | ], 116 | 117 | /* 118 | |-------------------------------------------------------------------------- 119 | | Migration Repository Table 120 | |-------------------------------------------------------------------------- 121 | | 122 | | This table keeps track of all the migrations that have already run for 123 | | your application. Using this information, we can determine which of 124 | | the migrations on disk haven't actually been run on the database. 125 | | 126 | */ 127 | 128 | 'migrations' => [ 129 | 'table' => 'migrations', 130 | 'update_date_on_publish' => true, 131 | ], 132 | 133 | /* 134 | |-------------------------------------------------------------------------- 135 | | Redis Databases 136 | |-------------------------------------------------------------------------- 137 | | 138 | | Redis is an open source, fast, and advanced key-value store that also 139 | | provides a richer body of commands than a typical key-value system 140 | | such as Memcached. You may define your connection settings here. 141 | | 142 | */ 143 | 144 | 'redis' => [ 145 | 146 | 'client' => env('REDIS_CLIENT', 'phpredis'), 147 | 148 | 'options' => [ 149 | 'cluster' => env('REDIS_CLUSTER', 'redis'), 150 | 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), 151 | ], 152 | 153 | 'default' => [ 154 | 'url' => env('REDIS_URL'), 155 | 'host' => env('REDIS_HOST', '127.0.0.1'), 156 | 'username' => env('REDIS_USERNAME'), 157 | 'password' => env('REDIS_PASSWORD'), 158 | 'port' => env('REDIS_PORT', '6379'), 159 | 'database' => env('REDIS_DB', '0'), 160 | ], 161 | 162 | 'cache' => [ 163 | 'url' => env('REDIS_URL'), 164 | 'host' => env('REDIS_HOST', '127.0.0.1'), 165 | 'username' => env('REDIS_USERNAME'), 166 | 'password' => env('REDIS_PASSWORD'), 167 | 'port' => env('REDIS_PORT', '6379'), 168 | 'database' => env('REDIS_CACHE_DB', '1'), 169 | ], 170 | 171 | ], 172 | 173 | ]; 174 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DISK', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Filesystem Disks 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Below you may configure as many filesystem disks as necessary, and you 24 | | may even configure multiple disks for the same driver. Examples for 25 | | most supported storage drivers are configured here for reference. 26 | | 27 | | Supported drivers: "local", "ftp", "sftp", "s3" 28 | | 29 | */ 30 | 31 | 'disks' => [ 32 | 33 | 'local' => [ 34 | 'driver' => 'local', 35 | 'root' => storage_path('app/private'), 36 | 'serve' => true, 37 | 'throw' => false, 38 | ], 39 | 40 | 'public' => [ 41 | 'driver' => 'local', 42 | 'root' => storage_path('app/public'), 43 | 'url' => env('APP_URL').'/storage', 44 | 'visibility' => 'public', 45 | 'throw' => false, 46 | ], 47 | 48 | 's3' => [ 49 | 'driver' => 's3', 50 | 'key' => env('AWS_ACCESS_KEY_ID'), 51 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 52 | 'region' => env('AWS_DEFAULT_REGION'), 53 | 'bucket' => env('AWS_BUCKET'), 54 | 'url' => env('AWS_URL'), 55 | 'endpoint' => env('AWS_ENDPOINT'), 56 | 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 57 | 'throw' => false, 58 | ], 59 | 60 | ], 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Symbolic Links 65 | |-------------------------------------------------------------------------- 66 | | 67 | | Here you may configure the symbolic links that will be created when the 68 | | `storage:link` Artisan command is executed. The array keys should be 69 | | the locations of the links and the values should be their targets. 70 | | 71 | */ 72 | 73 | 'links' => [ 74 | public_path('storage') => storage_path('app/public'), 75 | ], 76 | 77 | ]; 78 | -------------------------------------------------------------------------------- /config/logging.php: -------------------------------------------------------------------------------- 1 | env('LOG_CHANNEL', 'stack'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Deprecations Log Channel 26 | |-------------------------------------------------------------------------- 27 | | 28 | | This option controls the log channel that should be used to log warnings 29 | | regarding deprecated PHP and library features. This allows you to get 30 | | your application ready for upcoming major versions of dependencies. 31 | | 32 | */ 33 | 34 | 'deprecations' => [ 35 | 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 36 | 'trace' => env('LOG_DEPRECATIONS_TRACE', false), 37 | ], 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Log Channels 42 | |-------------------------------------------------------------------------- 43 | | 44 | | Here you may configure the log channels for your application. Laravel 45 | | utilizes the Monolog PHP logging library, which includes a variety 46 | | of powerful log handlers and formatters that you're free to use. 47 | | 48 | | Available drivers: "single", "daily", "slack", "syslog", 49 | | "errorlog", "monolog", "custom", "stack" 50 | | 51 | */ 52 | 53 | 'channels' => [ 54 | 55 | 'stack' => [ 56 | 'driver' => 'stack', 57 | 'channels' => explode(',', env('LOG_STACK', 'single')), 58 | 'ignore_exceptions' => false, 59 | ], 60 | 61 | 'single' => [ 62 | 'driver' => 'single', 63 | 'path' => storage_path('logs/laravel.log'), 64 | 'level' => env('LOG_LEVEL', 'debug'), 65 | 'replace_placeholders' => true, 66 | ], 67 | 68 | 'daily' => [ 69 | 'driver' => 'daily', 70 | 'path' => storage_path('logs/laravel.log'), 71 | 'level' => env('LOG_LEVEL', 'debug'), 72 | 'days' => env('LOG_DAILY_DAYS', 14), 73 | 'replace_placeholders' => true, 74 | ], 75 | 76 | 'slack' => [ 77 | 'driver' => 'slack', 78 | 'url' => env('LOG_SLACK_WEBHOOK_URL'), 79 | 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), 80 | 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), 81 | 'level' => env('LOG_LEVEL', 'critical'), 82 | 'replace_placeholders' => true, 83 | ], 84 | 85 | 'papertrail' => [ 86 | 'driver' => 'monolog', 87 | 'level' => env('LOG_LEVEL', 'debug'), 88 | 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), 89 | 'handler_with' => [ 90 | 'host' => env('PAPERTRAIL_URL'), 91 | 'port' => env('PAPERTRAIL_PORT'), 92 | 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), 93 | ], 94 | 'processors' => [PsrLogMessageProcessor::class], 95 | ], 96 | 97 | 'stderr' => [ 98 | 'driver' => 'monolog', 99 | 'level' => env('LOG_LEVEL', 'debug'), 100 | 'handler' => StreamHandler::class, 101 | 'formatter' => env('LOG_STDERR_FORMATTER'), 102 | 'with' => [ 103 | 'stream' => 'php://stderr', 104 | ], 105 | 'processors' => [PsrLogMessageProcessor::class], 106 | ], 107 | 108 | 'syslog' => [ 109 | 'driver' => 'syslog', 110 | 'level' => env('LOG_LEVEL', 'debug'), 111 | 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), 112 | 'replace_placeholders' => true, 113 | ], 114 | 115 | 'errorlog' => [ 116 | 'driver' => 'errorlog', 117 | 'level' => env('LOG_LEVEL', 'debug'), 118 | 'replace_placeholders' => true, 119 | ], 120 | 121 | 'null' => [ 122 | 'driver' => 'monolog', 123 | 'handler' => NullHandler::class, 124 | ], 125 | 126 | 'emergency' => [ 127 | 'path' => storage_path('logs/laravel.log'), 128 | ], 129 | 130 | ], 131 | 132 | ]; 133 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_MAILER', 'log'), 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Mailer Configurations 22 | |-------------------------------------------------------------------------- 23 | | 24 | | Here you may configure all of the mailers used by your application plus 25 | | their respective settings. Several examples have been configured for 26 | | you and you are free to add your own as your application requires. 27 | | 28 | | Laravel supports a variety of mail "transport" drivers that can be used 29 | | when delivering an email. You may specify which one you're using for 30 | | your mailers below. You may also add additional mailers if needed. 31 | | 32 | | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", 33 | | "postmark", "resend", "log", "array", 34 | | "failover", "roundrobin" 35 | | 36 | */ 37 | 38 | 'mailers' => [ 39 | 40 | 'smtp' => [ 41 | 'transport' => 'smtp', 42 | 'url' => env('MAIL_URL'), 43 | 'host' => env('MAIL_HOST', '127.0.0.1'), 44 | 'port' => env('MAIL_PORT', 2525), 45 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 46 | 'username' => env('MAIL_USERNAME'), 47 | 'password' => env('MAIL_PASSWORD'), 48 | 'timeout' => null, 49 | 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), 50 | ], 51 | 52 | 'ses' => [ 53 | 'transport' => 'ses', 54 | ], 55 | 56 | 'postmark' => [ 57 | 'transport' => 'postmark', 58 | // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), 59 | // 'client' => [ 60 | // 'timeout' => 5, 61 | // ], 62 | ], 63 | 64 | 'resend' => [ 65 | 'transport' => 'resend', 66 | ], 67 | 68 | 'sendmail' => [ 69 | 'transport' => 'sendmail', 70 | 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), 71 | ], 72 | 73 | 'log' => [ 74 | 'transport' => 'log', 75 | 'channel' => env('MAIL_LOG_CHANNEL'), 76 | ], 77 | 78 | 'array' => [ 79 | 'transport' => 'array', 80 | ], 81 | 82 | 'failover' => [ 83 | 'transport' => 'failover', 84 | 'mailers' => [ 85 | 'smtp', 86 | 'log', 87 | ], 88 | ], 89 | 90 | 'roundrobin' => [ 91 | 'transport' => 'roundrobin', 92 | 'mailers' => [ 93 | 'ses', 94 | 'postmark', 95 | ], 96 | ], 97 | 98 | ], 99 | 100 | /* 101 | |-------------------------------------------------------------------------- 102 | | Global "From" Address 103 | |-------------------------------------------------------------------------- 104 | | 105 | | You may wish for all emails sent by your application to be sent from 106 | | the same address. Here you may specify a name and address that is 107 | | used globally for all emails that are sent by your application. 108 | | 109 | */ 110 | 111 | 'from' => [ 112 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 113 | 'name' => env('MAIL_FROM_NAME', 'Example'), 114 | ], 115 | 116 | ]; 117 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'database'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Queue Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure the connection options for every queue backend 24 | | used by your application. An example configuration is provided for 25 | | each backend supported by Laravel. You're also free to add more. 26 | | 27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'connection' => env('DB_QUEUE_CONNECTION'), 40 | 'table' => env('DB_QUEUE_TABLE', 'jobs'), 41 | 'queue' => env('DB_QUEUE', 'default'), 42 | 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), 43 | 'after_commit' => false, 44 | ], 45 | 46 | 'beanstalkd' => [ 47 | 'driver' => 'beanstalkd', 48 | 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), 49 | 'queue' => env('BEANSTALKD_QUEUE', 'default'), 50 | 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), 51 | 'block_for' => 0, 52 | 'after_commit' => false, 53 | ], 54 | 55 | 'sqs' => [ 56 | 'driver' => 'sqs', 57 | 'key' => env('AWS_ACCESS_KEY_ID'), 58 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 59 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 60 | 'queue' => env('SQS_QUEUE', 'default'), 61 | 'suffix' => env('SQS_SUFFIX'), 62 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 63 | 'after_commit' => false, 64 | ], 65 | 66 | 'redis' => [ 67 | 'driver' => 'redis', 68 | 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), 69 | 'queue' => env('REDIS_QUEUE', 'default'), 70 | 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), 71 | 'block_for' => null, 72 | 'after_commit' => false, 73 | ], 74 | 75 | ], 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Job Batching 80 | |-------------------------------------------------------------------------- 81 | | 82 | | The following options configure the database and table that store job 83 | | batching information. These options can be updated to any database 84 | | connection and table which has been defined by your application. 85 | | 86 | */ 87 | 88 | 'batching' => [ 89 | 'database' => env('DB_CONNECTION', 'sqlite'), 90 | 'table' => 'job_batches', 91 | ], 92 | 93 | /* 94 | |-------------------------------------------------------------------------- 95 | | Failed Queue Jobs 96 | |-------------------------------------------------------------------------- 97 | | 98 | | These options configure the behavior of failed queue job logging so you 99 | | can control how and where failed jobs are stored. Laravel ships with 100 | | support for storing failed jobs in a simple file or in a database. 101 | | 102 | | Supported drivers: "database-uuids", "dynamodb", "file", "null" 103 | | 104 | */ 105 | 106 | 'failed' => [ 107 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), 108 | 'database' => env('DB_CONNECTION', 'sqlite'), 109 | 'table' => 'failed_jobs', 110 | ], 111 | 112 | ]; 113 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'token' => env('POSTMARK_TOKEN'), 19 | ], 20 | 21 | 'ses' => [ 22 | 'key' => env('AWS_ACCESS_KEY_ID'), 23 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 24 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 25 | ], 26 | 27 | 'resend' => [ 28 | 'key' => env('RESEND_KEY'), 29 | ], 30 | 31 | 'slack' => [ 32 | 'notifications' => [ 33 | 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), 34 | 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), 35 | ], 36 | ], 37 | 38 | ]; 39 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | env('SESSION_DRIVER', 'database'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Session Lifetime 26 | |-------------------------------------------------------------------------- 27 | | 28 | | Here you may specify the number of minutes that you wish the session 29 | | to be allowed to remain idle before it expires. If you want them 30 | | to expire immediately when the browser is closed then you may 31 | | indicate that via the expire_on_close configuration option. 32 | | 33 | */ 34 | 35 | 'lifetime' => env('SESSION_LIFETIME', 120), 36 | 37 | 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Session Encryption 42 | |-------------------------------------------------------------------------- 43 | | 44 | | This option allows you to easily specify that all of your session data 45 | | should be encrypted before it's stored. All encryption is performed 46 | | automatically by Laravel and you may use the session like normal. 47 | | 48 | */ 49 | 50 | 'encrypt' => env('SESSION_ENCRYPT', false), 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | Session File Location 55 | |-------------------------------------------------------------------------- 56 | | 57 | | When utilizing the "file" session driver, the session files are placed 58 | | on disk. The default storage location is defined here; however, you 59 | | are free to provide another location where they should be stored. 60 | | 61 | */ 62 | 63 | 'files' => storage_path('framework/sessions'), 64 | 65 | /* 66 | |-------------------------------------------------------------------------- 67 | | Session Database Connection 68 | |-------------------------------------------------------------------------- 69 | | 70 | | When using the "database" or "redis" session drivers, you may specify a 71 | | connection that should be used to manage these sessions. This should 72 | | correspond to a connection in your database configuration options. 73 | | 74 | */ 75 | 76 | 'connection' => env('SESSION_CONNECTION'), 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | Session Database Table 81 | |-------------------------------------------------------------------------- 82 | | 83 | | When using the "database" session driver, you may specify the table to 84 | | be used to store sessions. Of course, a sensible default is defined 85 | | for you; however, you're welcome to change this to another table. 86 | | 87 | */ 88 | 89 | 'table' => env('SESSION_TABLE', 'sessions'), 90 | 91 | /* 92 | |-------------------------------------------------------------------------- 93 | | Session Cache Store 94 | |-------------------------------------------------------------------------- 95 | | 96 | | When using one of the framework's cache driven session backends, you may 97 | | define the cache store which should be used to store the session data 98 | | between requests. This must match one of your defined cache stores. 99 | | 100 | | Affects: "apc", "dynamodb", "memcached", "redis" 101 | | 102 | */ 103 | 104 | 'store' => env('SESSION_STORE'), 105 | 106 | /* 107 | |-------------------------------------------------------------------------- 108 | | Session Sweeping Lottery 109 | |-------------------------------------------------------------------------- 110 | | 111 | | Some session drivers must manually sweep their storage location to get 112 | | rid of old sessions from storage. Here are the chances that it will 113 | | happen on a given request. By default, the odds are 2 out of 100. 114 | | 115 | */ 116 | 117 | 'lottery' => [2, 100], 118 | 119 | /* 120 | |-------------------------------------------------------------------------- 121 | | Session Cookie Name 122 | |-------------------------------------------------------------------------- 123 | | 124 | | Here you may change the name of the session cookie that is created by 125 | | the framework. Typically, you should not need to change this value 126 | | since doing so does not grant a meaningful security improvement. 127 | | 128 | */ 129 | 130 | 'cookie' => env( 131 | 'SESSION_COOKIE', 132 | Str::slug(env('APP_NAME', 'laravel'), '_').'_session' 133 | ), 134 | 135 | /* 136 | |-------------------------------------------------------------------------- 137 | | Session Cookie Path 138 | |-------------------------------------------------------------------------- 139 | | 140 | | The session cookie path determines the path for which the cookie will 141 | | be regarded as available. Typically, this will be the root path of 142 | | your application, but you're free to change this when necessary. 143 | | 144 | */ 145 | 146 | 'path' => env('SESSION_PATH', '/'), 147 | 148 | /* 149 | |-------------------------------------------------------------------------- 150 | | Session Cookie Domain 151 | |-------------------------------------------------------------------------- 152 | | 153 | | This value determines the domain and subdomains the session cookie is 154 | | available to. By default, the cookie will be available to the root 155 | | domain and all subdomains. Typically, this shouldn't be changed. 156 | | 157 | */ 158 | 159 | 'domain' => env('SESSION_DOMAIN'), 160 | 161 | /* 162 | |-------------------------------------------------------------------------- 163 | | HTTPS Only Cookies 164 | |-------------------------------------------------------------------------- 165 | | 166 | | By setting this option to true, session cookies will only be sent back 167 | | to the server if the browser has a HTTPS connection. This will keep 168 | | the cookie from being sent to you when it can't be done securely. 169 | | 170 | */ 171 | 172 | 'secure' => env('SESSION_SECURE_COOKIE'), 173 | 174 | /* 175 | |-------------------------------------------------------------------------- 176 | | HTTP Access Only 177 | |-------------------------------------------------------------------------- 178 | | 179 | | Setting this value to true will prevent JavaScript from accessing the 180 | | value of the cookie and the cookie will only be accessible through 181 | | the HTTP protocol. It's unlikely you should disable this option. 182 | | 183 | */ 184 | 185 | 'http_only' => env('SESSION_HTTP_ONLY', true), 186 | 187 | /* 188 | |-------------------------------------------------------------------------- 189 | | Same-Site Cookies 190 | |-------------------------------------------------------------------------- 191 | | 192 | | This option determines how your cookies behave when cross-site requests 193 | | take place, and can be used to mitigate CSRF attacks. By default, we 194 | | will set this value to "lax" to permit secure cross-site requests. 195 | | 196 | | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value 197 | | 198 | | Supported: "lax", "strict", "none", null 199 | | 200 | */ 201 | 202 | 'same_site' => env('SESSION_SAME_SITE', 'lax'), 203 | 204 | /* 205 | |-------------------------------------------------------------------------- 206 | | Partitioned Cookies 207 | |-------------------------------------------------------------------------- 208 | | 209 | | Setting this value to true will tie the cookie to the top-level site for 210 | | a cross-site context. Partitioned cookies are accepted by the browser 211 | | when flagged "secure" and the Same-Site attribute is set to "none". 212 | | 213 | */ 214 | 215 | 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), 216 | 217 | ]; 218 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class UserFactory extends Factory 13 | { 14 | /** 15 | * The current password being used by the factory. 16 | */ 17 | protected static ?string $password; 18 | 19 | /** 20 | * Define the model's default state. 21 | * 22 | * @return array 23 | */ 24 | public function definition(): array 25 | { 26 | return [ 27 | 'name' => fake()->name(), 28 | 'email' => fake()->unique()->safeEmail(), 29 | 'email_verified_at' => now(), 30 | 'password' => static::$password ??= Hash::make('password'), 31 | 'remember_token' => Str::random(10), 32 | ]; 33 | } 34 | 35 | /** 36 | * Indicate that the model's email address should be unverified. 37 | */ 38 | public function unverified(): static 39 | { 40 | return $this->state(fn (array $attributes) => [ 41 | 'email_verified_at' => null, 42 | ]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /database/migrations/2024_10_25_155409_create_user_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('corbado_user_id', 30)->index(); 17 | $table->string('city', 100)->nullable(); 18 | $table->timestamps(); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | */ 25 | public function down(): void 26 | { 27 | Schema::dropIfExists('user'); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /database/migrations/2024_10_25_160858_create_sessions_table.php: -------------------------------------------------------------------------------- 1 | string('id')->primary(); 16 | $table->foreignId('user_id')->nullable()->index(); 17 | $table->string('ip_address', 45)->nullable(); 18 | $table->text('user_agent')->nullable(); 19 | $table->longText('payload'); 20 | $table->integer('last_activity')->index(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | */ 27 | public function down(): void 28 | { 29 | Schema::dropIfExists('sessions'); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | 19 | User::factory()->create([ 20 | 'name' => 'Test User', 21 | 'email' => 'test@example.com', 22 | ]); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-vanillajs-php-laravel", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "autoprefixer": "^10.4.20", 9 | "axios": "^1.7.4", 10 | "concurrently": "^9.0.1", 11 | "laravel-vite-plugin": "^1.0", 12 | "vite": "^6.3.5" 13 | } 14 | }, 15 | "node_modules/@esbuild/aix-ppc64": { 16 | "version": "0.25.5", 17 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", 18 | "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", 19 | "cpu": [ 20 | "ppc64" 21 | ], 22 | "dev": true, 23 | "license": "MIT", 24 | "optional": true, 25 | "os": [ 26 | "aix" 27 | ], 28 | "engines": { 29 | "node": ">=18" 30 | } 31 | }, 32 | "node_modules/@esbuild/android-arm": { 33 | "version": "0.25.5", 34 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", 35 | "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", 36 | "cpu": [ 37 | "arm" 38 | ], 39 | "dev": true, 40 | "license": "MIT", 41 | "optional": true, 42 | "os": [ 43 | "android" 44 | ], 45 | "engines": { 46 | "node": ">=18" 47 | } 48 | }, 49 | "node_modules/@esbuild/android-arm64": { 50 | "version": "0.25.5", 51 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", 52 | "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", 53 | "cpu": [ 54 | "arm64" 55 | ], 56 | "dev": true, 57 | "license": "MIT", 58 | "optional": true, 59 | "os": [ 60 | "android" 61 | ], 62 | "engines": { 63 | "node": ">=18" 64 | } 65 | }, 66 | "node_modules/@esbuild/android-x64": { 67 | "version": "0.25.5", 68 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", 69 | "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", 70 | "cpu": [ 71 | "x64" 72 | ], 73 | "dev": true, 74 | "license": "MIT", 75 | "optional": true, 76 | "os": [ 77 | "android" 78 | ], 79 | "engines": { 80 | "node": ">=18" 81 | } 82 | }, 83 | "node_modules/@esbuild/darwin-arm64": { 84 | "version": "0.25.5", 85 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", 86 | "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", 87 | "cpu": [ 88 | "arm64" 89 | ], 90 | "dev": true, 91 | "license": "MIT", 92 | "optional": true, 93 | "os": [ 94 | "darwin" 95 | ], 96 | "engines": { 97 | "node": ">=18" 98 | } 99 | }, 100 | "node_modules/@esbuild/darwin-x64": { 101 | "version": "0.25.5", 102 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", 103 | "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", 104 | "cpu": [ 105 | "x64" 106 | ], 107 | "dev": true, 108 | "license": "MIT", 109 | "optional": true, 110 | "os": [ 111 | "darwin" 112 | ], 113 | "engines": { 114 | "node": ">=18" 115 | } 116 | }, 117 | "node_modules/@esbuild/freebsd-arm64": { 118 | "version": "0.25.5", 119 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", 120 | "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", 121 | "cpu": [ 122 | "arm64" 123 | ], 124 | "dev": true, 125 | "license": "MIT", 126 | "optional": true, 127 | "os": [ 128 | "freebsd" 129 | ], 130 | "engines": { 131 | "node": ">=18" 132 | } 133 | }, 134 | "node_modules/@esbuild/freebsd-x64": { 135 | "version": "0.25.5", 136 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", 137 | "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", 138 | "cpu": [ 139 | "x64" 140 | ], 141 | "dev": true, 142 | "license": "MIT", 143 | "optional": true, 144 | "os": [ 145 | "freebsd" 146 | ], 147 | "engines": { 148 | "node": ">=18" 149 | } 150 | }, 151 | "node_modules/@esbuild/linux-arm": { 152 | "version": "0.25.5", 153 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", 154 | "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", 155 | "cpu": [ 156 | "arm" 157 | ], 158 | "dev": true, 159 | "license": "MIT", 160 | "optional": true, 161 | "os": [ 162 | "linux" 163 | ], 164 | "engines": { 165 | "node": ">=18" 166 | } 167 | }, 168 | "node_modules/@esbuild/linux-arm64": { 169 | "version": "0.25.5", 170 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", 171 | "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", 172 | "cpu": [ 173 | "arm64" 174 | ], 175 | "dev": true, 176 | "license": "MIT", 177 | "optional": true, 178 | "os": [ 179 | "linux" 180 | ], 181 | "engines": { 182 | "node": ">=18" 183 | } 184 | }, 185 | "node_modules/@esbuild/linux-ia32": { 186 | "version": "0.25.5", 187 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", 188 | "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", 189 | "cpu": [ 190 | "ia32" 191 | ], 192 | "dev": true, 193 | "license": "MIT", 194 | "optional": true, 195 | "os": [ 196 | "linux" 197 | ], 198 | "engines": { 199 | "node": ">=18" 200 | } 201 | }, 202 | "node_modules/@esbuild/linux-loong64": { 203 | "version": "0.25.5", 204 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", 205 | "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", 206 | "cpu": [ 207 | "loong64" 208 | ], 209 | "dev": true, 210 | "license": "MIT", 211 | "optional": true, 212 | "os": [ 213 | "linux" 214 | ], 215 | "engines": { 216 | "node": ">=18" 217 | } 218 | }, 219 | "node_modules/@esbuild/linux-mips64el": { 220 | "version": "0.25.5", 221 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", 222 | "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", 223 | "cpu": [ 224 | "mips64el" 225 | ], 226 | "dev": true, 227 | "license": "MIT", 228 | "optional": true, 229 | "os": [ 230 | "linux" 231 | ], 232 | "engines": { 233 | "node": ">=18" 234 | } 235 | }, 236 | "node_modules/@esbuild/linux-ppc64": { 237 | "version": "0.25.5", 238 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", 239 | "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", 240 | "cpu": [ 241 | "ppc64" 242 | ], 243 | "dev": true, 244 | "license": "MIT", 245 | "optional": true, 246 | "os": [ 247 | "linux" 248 | ], 249 | "engines": { 250 | "node": ">=18" 251 | } 252 | }, 253 | "node_modules/@esbuild/linux-riscv64": { 254 | "version": "0.25.5", 255 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", 256 | "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", 257 | "cpu": [ 258 | "riscv64" 259 | ], 260 | "dev": true, 261 | "license": "MIT", 262 | "optional": true, 263 | "os": [ 264 | "linux" 265 | ], 266 | "engines": { 267 | "node": ">=18" 268 | } 269 | }, 270 | "node_modules/@esbuild/linux-s390x": { 271 | "version": "0.25.5", 272 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", 273 | "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", 274 | "cpu": [ 275 | "s390x" 276 | ], 277 | "dev": true, 278 | "license": "MIT", 279 | "optional": true, 280 | "os": [ 281 | "linux" 282 | ], 283 | "engines": { 284 | "node": ">=18" 285 | } 286 | }, 287 | "node_modules/@esbuild/linux-x64": { 288 | "version": "0.25.5", 289 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", 290 | "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", 291 | "cpu": [ 292 | "x64" 293 | ], 294 | "dev": true, 295 | "license": "MIT", 296 | "optional": true, 297 | "os": [ 298 | "linux" 299 | ], 300 | "engines": { 301 | "node": ">=18" 302 | } 303 | }, 304 | "node_modules/@esbuild/netbsd-arm64": { 305 | "version": "0.25.5", 306 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", 307 | "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", 308 | "cpu": [ 309 | "arm64" 310 | ], 311 | "dev": true, 312 | "license": "MIT", 313 | "optional": true, 314 | "os": [ 315 | "netbsd" 316 | ], 317 | "engines": { 318 | "node": ">=18" 319 | } 320 | }, 321 | "node_modules/@esbuild/netbsd-x64": { 322 | "version": "0.25.5", 323 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", 324 | "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", 325 | "cpu": [ 326 | "x64" 327 | ], 328 | "dev": true, 329 | "license": "MIT", 330 | "optional": true, 331 | "os": [ 332 | "netbsd" 333 | ], 334 | "engines": { 335 | "node": ">=18" 336 | } 337 | }, 338 | "node_modules/@esbuild/openbsd-arm64": { 339 | "version": "0.25.5", 340 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", 341 | "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", 342 | "cpu": [ 343 | "arm64" 344 | ], 345 | "dev": true, 346 | "license": "MIT", 347 | "optional": true, 348 | "os": [ 349 | "openbsd" 350 | ], 351 | "engines": { 352 | "node": ">=18" 353 | } 354 | }, 355 | "node_modules/@esbuild/openbsd-x64": { 356 | "version": "0.25.5", 357 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", 358 | "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", 359 | "cpu": [ 360 | "x64" 361 | ], 362 | "dev": true, 363 | "license": "MIT", 364 | "optional": true, 365 | "os": [ 366 | "openbsd" 367 | ], 368 | "engines": { 369 | "node": ">=18" 370 | } 371 | }, 372 | "node_modules/@esbuild/sunos-x64": { 373 | "version": "0.25.5", 374 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", 375 | "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", 376 | "cpu": [ 377 | "x64" 378 | ], 379 | "dev": true, 380 | "license": "MIT", 381 | "optional": true, 382 | "os": [ 383 | "sunos" 384 | ], 385 | "engines": { 386 | "node": ">=18" 387 | } 388 | }, 389 | "node_modules/@esbuild/win32-arm64": { 390 | "version": "0.25.5", 391 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", 392 | "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", 393 | "cpu": [ 394 | "arm64" 395 | ], 396 | "dev": true, 397 | "license": "MIT", 398 | "optional": true, 399 | "os": [ 400 | "win32" 401 | ], 402 | "engines": { 403 | "node": ">=18" 404 | } 405 | }, 406 | "node_modules/@esbuild/win32-ia32": { 407 | "version": "0.25.5", 408 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", 409 | "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", 410 | "cpu": [ 411 | "ia32" 412 | ], 413 | "dev": true, 414 | "license": "MIT", 415 | "optional": true, 416 | "os": [ 417 | "win32" 418 | ], 419 | "engines": { 420 | "node": ">=18" 421 | } 422 | }, 423 | "node_modules/@esbuild/win32-x64": { 424 | "version": "0.25.5", 425 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", 426 | "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", 427 | "cpu": [ 428 | "x64" 429 | ], 430 | "dev": true, 431 | "license": "MIT", 432 | "optional": true, 433 | "os": [ 434 | "win32" 435 | ], 436 | "engines": { 437 | "node": ">=18" 438 | } 439 | }, 440 | "node_modules/@rollup/rollup-android-arm-eabi": { 441 | "version": "4.41.1", 442 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", 443 | "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", 444 | "cpu": [ 445 | "arm" 446 | ], 447 | "dev": true, 448 | "license": "MIT", 449 | "optional": true, 450 | "os": [ 451 | "android" 452 | ] 453 | }, 454 | "node_modules/@rollup/rollup-android-arm64": { 455 | "version": "4.41.1", 456 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", 457 | "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", 458 | "cpu": [ 459 | "arm64" 460 | ], 461 | "dev": true, 462 | "license": "MIT", 463 | "optional": true, 464 | "os": [ 465 | "android" 466 | ] 467 | }, 468 | "node_modules/@rollup/rollup-darwin-arm64": { 469 | "version": "4.41.1", 470 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", 471 | "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", 472 | "cpu": [ 473 | "arm64" 474 | ], 475 | "dev": true, 476 | "license": "MIT", 477 | "optional": true, 478 | "os": [ 479 | "darwin" 480 | ] 481 | }, 482 | "node_modules/@rollup/rollup-darwin-x64": { 483 | "version": "4.41.1", 484 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", 485 | "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", 486 | "cpu": [ 487 | "x64" 488 | ], 489 | "dev": true, 490 | "license": "MIT", 491 | "optional": true, 492 | "os": [ 493 | "darwin" 494 | ] 495 | }, 496 | "node_modules/@rollup/rollup-freebsd-arm64": { 497 | "version": "4.41.1", 498 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", 499 | "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", 500 | "cpu": [ 501 | "arm64" 502 | ], 503 | "dev": true, 504 | "license": "MIT", 505 | "optional": true, 506 | "os": [ 507 | "freebsd" 508 | ] 509 | }, 510 | "node_modules/@rollup/rollup-freebsd-x64": { 511 | "version": "4.41.1", 512 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", 513 | "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", 514 | "cpu": [ 515 | "x64" 516 | ], 517 | "dev": true, 518 | "license": "MIT", 519 | "optional": true, 520 | "os": [ 521 | "freebsd" 522 | ] 523 | }, 524 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 525 | "version": "4.41.1", 526 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", 527 | "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", 528 | "cpu": [ 529 | "arm" 530 | ], 531 | "dev": true, 532 | "license": "MIT", 533 | "optional": true, 534 | "os": [ 535 | "linux" 536 | ] 537 | }, 538 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 539 | "version": "4.41.1", 540 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", 541 | "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", 542 | "cpu": [ 543 | "arm" 544 | ], 545 | "dev": true, 546 | "license": "MIT", 547 | "optional": true, 548 | "os": [ 549 | "linux" 550 | ] 551 | }, 552 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 553 | "version": "4.41.1", 554 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", 555 | "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", 556 | "cpu": [ 557 | "arm64" 558 | ], 559 | "dev": true, 560 | "license": "MIT", 561 | "optional": true, 562 | "os": [ 563 | "linux" 564 | ] 565 | }, 566 | "node_modules/@rollup/rollup-linux-arm64-musl": { 567 | "version": "4.41.1", 568 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", 569 | "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", 570 | "cpu": [ 571 | "arm64" 572 | ], 573 | "dev": true, 574 | "license": "MIT", 575 | "optional": true, 576 | "os": [ 577 | "linux" 578 | ] 579 | }, 580 | "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 581 | "version": "4.41.1", 582 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", 583 | "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", 584 | "cpu": [ 585 | "loong64" 586 | ], 587 | "dev": true, 588 | "license": "MIT", 589 | "optional": true, 590 | "os": [ 591 | "linux" 592 | ] 593 | }, 594 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 595 | "version": "4.41.1", 596 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", 597 | "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", 598 | "cpu": [ 599 | "ppc64" 600 | ], 601 | "dev": true, 602 | "license": "MIT", 603 | "optional": true, 604 | "os": [ 605 | "linux" 606 | ] 607 | }, 608 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 609 | "version": "4.41.1", 610 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", 611 | "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", 612 | "cpu": [ 613 | "riscv64" 614 | ], 615 | "dev": true, 616 | "license": "MIT", 617 | "optional": true, 618 | "os": [ 619 | "linux" 620 | ] 621 | }, 622 | "node_modules/@rollup/rollup-linux-riscv64-musl": { 623 | "version": "4.41.1", 624 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", 625 | "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", 626 | "cpu": [ 627 | "riscv64" 628 | ], 629 | "dev": true, 630 | "license": "MIT", 631 | "optional": true, 632 | "os": [ 633 | "linux" 634 | ] 635 | }, 636 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 637 | "version": "4.41.1", 638 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", 639 | "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", 640 | "cpu": [ 641 | "s390x" 642 | ], 643 | "dev": true, 644 | "license": "MIT", 645 | "optional": true, 646 | "os": [ 647 | "linux" 648 | ] 649 | }, 650 | "node_modules/@rollup/rollup-linux-x64-gnu": { 651 | "version": "4.41.1", 652 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", 653 | "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", 654 | "cpu": [ 655 | "x64" 656 | ], 657 | "dev": true, 658 | "license": "MIT", 659 | "optional": true, 660 | "os": [ 661 | "linux" 662 | ] 663 | }, 664 | "node_modules/@rollup/rollup-linux-x64-musl": { 665 | "version": "4.41.1", 666 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", 667 | "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", 668 | "cpu": [ 669 | "x64" 670 | ], 671 | "dev": true, 672 | "license": "MIT", 673 | "optional": true, 674 | "os": [ 675 | "linux" 676 | ] 677 | }, 678 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 679 | "version": "4.41.1", 680 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", 681 | "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", 682 | "cpu": [ 683 | "arm64" 684 | ], 685 | "dev": true, 686 | "license": "MIT", 687 | "optional": true, 688 | "os": [ 689 | "win32" 690 | ] 691 | }, 692 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 693 | "version": "4.41.1", 694 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", 695 | "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", 696 | "cpu": [ 697 | "ia32" 698 | ], 699 | "dev": true, 700 | "license": "MIT", 701 | "optional": true, 702 | "os": [ 703 | "win32" 704 | ] 705 | }, 706 | "node_modules/@rollup/rollup-win32-x64-msvc": { 707 | "version": "4.41.1", 708 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", 709 | "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", 710 | "cpu": [ 711 | "x64" 712 | ], 713 | "dev": true, 714 | "license": "MIT", 715 | "optional": true, 716 | "os": [ 717 | "win32" 718 | ] 719 | }, 720 | "node_modules/@types/estree": { 721 | "version": "1.0.7", 722 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", 723 | "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", 724 | "dev": true, 725 | "license": "MIT" 726 | }, 727 | "node_modules/ansi-regex": { 728 | "version": "5.0.1", 729 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 730 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 731 | "dev": true, 732 | "license": "MIT", 733 | "engines": { 734 | "node": ">=8" 735 | } 736 | }, 737 | "node_modules/ansi-styles": { 738 | "version": "4.3.0", 739 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 740 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 741 | "dev": true, 742 | "license": "MIT", 743 | "dependencies": { 744 | "color-convert": "^2.0.1" 745 | }, 746 | "engines": { 747 | "node": ">=8" 748 | }, 749 | "funding": { 750 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 751 | } 752 | }, 753 | "node_modules/asynckit": { 754 | "version": "0.4.0", 755 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 756 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 757 | "dev": true, 758 | "license": "MIT" 759 | }, 760 | "node_modules/autoprefixer": { 761 | "version": "10.4.20", 762 | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", 763 | "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", 764 | "dev": true, 765 | "funding": [ 766 | { 767 | "type": "opencollective", 768 | "url": "https://opencollective.com/postcss/" 769 | }, 770 | { 771 | "type": "tidelift", 772 | "url": "https://tidelift.com/funding/github/npm/autoprefixer" 773 | }, 774 | { 775 | "type": "github", 776 | "url": "https://github.com/sponsors/ai" 777 | } 778 | ], 779 | "license": "MIT", 780 | "dependencies": { 781 | "browserslist": "^4.23.3", 782 | "caniuse-lite": "^1.0.30001646", 783 | "fraction.js": "^4.3.7", 784 | "normalize-range": "^0.1.2", 785 | "picocolors": "^1.0.1", 786 | "postcss-value-parser": "^4.2.0" 787 | }, 788 | "bin": { 789 | "autoprefixer": "bin/autoprefixer" 790 | }, 791 | "engines": { 792 | "node": "^10 || ^12 || >=14" 793 | }, 794 | "peerDependencies": { 795 | "postcss": "^8.1.0" 796 | } 797 | }, 798 | "node_modules/axios": { 799 | "version": "1.9.0", 800 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", 801 | "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", 802 | "dev": true, 803 | "license": "MIT", 804 | "dependencies": { 805 | "follow-redirects": "^1.15.6", 806 | "form-data": "^4.0.0", 807 | "proxy-from-env": "^1.1.0" 808 | } 809 | }, 810 | "node_modules/browserslist": { 811 | "version": "4.24.3", 812 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", 813 | "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", 814 | "dev": true, 815 | "funding": [ 816 | { 817 | "type": "opencollective", 818 | "url": "https://opencollective.com/browserslist" 819 | }, 820 | { 821 | "type": "tidelift", 822 | "url": "https://tidelift.com/funding/github/npm/browserslist" 823 | }, 824 | { 825 | "type": "github", 826 | "url": "https://github.com/sponsors/ai" 827 | } 828 | ], 829 | "license": "MIT", 830 | "dependencies": { 831 | "caniuse-lite": "^1.0.30001688", 832 | "electron-to-chromium": "^1.5.73", 833 | "node-releases": "^2.0.19", 834 | "update-browserslist-db": "^1.1.1" 835 | }, 836 | "bin": { 837 | "browserslist": "cli.js" 838 | }, 839 | "engines": { 840 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 841 | } 842 | }, 843 | "node_modules/caniuse-lite": { 844 | "version": "1.0.30001690", 845 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", 846 | "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", 847 | "dev": true, 848 | "funding": [ 849 | { 850 | "type": "opencollective", 851 | "url": "https://opencollective.com/browserslist" 852 | }, 853 | { 854 | "type": "tidelift", 855 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 856 | }, 857 | { 858 | "type": "github", 859 | "url": "https://github.com/sponsors/ai" 860 | } 861 | ], 862 | "license": "CC-BY-4.0" 863 | }, 864 | "node_modules/chalk": { 865 | "version": "4.1.2", 866 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 867 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 868 | "dev": true, 869 | "license": "MIT", 870 | "dependencies": { 871 | "ansi-styles": "^4.1.0", 872 | "supports-color": "^7.1.0" 873 | }, 874 | "engines": { 875 | "node": ">=10" 876 | }, 877 | "funding": { 878 | "url": "https://github.com/chalk/chalk?sponsor=1" 879 | } 880 | }, 881 | "node_modules/chalk/node_modules/supports-color": { 882 | "version": "7.2.0", 883 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 884 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 885 | "dev": true, 886 | "license": "MIT", 887 | "dependencies": { 888 | "has-flag": "^4.0.0" 889 | }, 890 | "engines": { 891 | "node": ">=8" 892 | } 893 | }, 894 | "node_modules/cliui": { 895 | "version": "8.0.1", 896 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 897 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 898 | "dev": true, 899 | "license": "ISC", 900 | "dependencies": { 901 | "string-width": "^4.2.0", 902 | "strip-ansi": "^6.0.1", 903 | "wrap-ansi": "^7.0.0" 904 | }, 905 | "engines": { 906 | "node": ">=12" 907 | } 908 | }, 909 | "node_modules/color-convert": { 910 | "version": "2.0.1", 911 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 912 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 913 | "dev": true, 914 | "license": "MIT", 915 | "dependencies": { 916 | "color-name": "~1.1.4" 917 | }, 918 | "engines": { 919 | "node": ">=7.0.0" 920 | } 921 | }, 922 | "node_modules/color-name": { 923 | "version": "1.1.4", 924 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 925 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 926 | "dev": true, 927 | "license": "MIT" 928 | }, 929 | "node_modules/combined-stream": { 930 | "version": "1.0.8", 931 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 932 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 933 | "dev": true, 934 | "license": "MIT", 935 | "dependencies": { 936 | "delayed-stream": "~1.0.0" 937 | }, 938 | "engines": { 939 | "node": ">= 0.8" 940 | } 941 | }, 942 | "node_modules/concurrently": { 943 | "version": "9.1.1", 944 | "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.1.tgz", 945 | "integrity": "sha512-6VX8lrBIycgZKTwBsWS+bLrmkGRkDmvtGsYylRN9b93CygN6CbK46HmnQ3rdSOR8HRjdahDrxb5MqD9cEFOg5Q==", 946 | "dev": true, 947 | "license": "MIT", 948 | "dependencies": { 949 | "chalk": "^4.1.2", 950 | "lodash": "^4.17.21", 951 | "rxjs": "^7.8.1", 952 | "shell-quote": "^1.8.1", 953 | "supports-color": "^8.1.1", 954 | "tree-kill": "^1.2.2", 955 | "yargs": "^17.7.2" 956 | }, 957 | "bin": { 958 | "conc": "dist/bin/concurrently.js", 959 | "concurrently": "dist/bin/concurrently.js" 960 | }, 961 | "engines": { 962 | "node": ">=18" 963 | }, 964 | "funding": { 965 | "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" 966 | } 967 | }, 968 | "node_modules/delayed-stream": { 969 | "version": "1.0.0", 970 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 971 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 972 | "dev": true, 973 | "license": "MIT", 974 | "engines": { 975 | "node": ">=0.4.0" 976 | } 977 | }, 978 | "node_modules/electron-to-chromium": { 979 | "version": "1.5.76", 980 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", 981 | "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", 982 | "dev": true, 983 | "license": "ISC" 984 | }, 985 | "node_modules/emoji-regex": { 986 | "version": "8.0.0", 987 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 988 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 989 | "dev": true, 990 | "license": "MIT" 991 | }, 992 | "node_modules/esbuild": { 993 | "version": "0.25.5", 994 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", 995 | "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", 996 | "dev": true, 997 | "hasInstallScript": true, 998 | "license": "MIT", 999 | "bin": { 1000 | "esbuild": "bin/esbuild" 1001 | }, 1002 | "engines": { 1003 | "node": ">=18" 1004 | }, 1005 | "optionalDependencies": { 1006 | "@esbuild/aix-ppc64": "0.25.5", 1007 | "@esbuild/android-arm": "0.25.5", 1008 | "@esbuild/android-arm64": "0.25.5", 1009 | "@esbuild/android-x64": "0.25.5", 1010 | "@esbuild/darwin-arm64": "0.25.5", 1011 | "@esbuild/darwin-x64": "0.25.5", 1012 | "@esbuild/freebsd-arm64": "0.25.5", 1013 | "@esbuild/freebsd-x64": "0.25.5", 1014 | "@esbuild/linux-arm": "0.25.5", 1015 | "@esbuild/linux-arm64": "0.25.5", 1016 | "@esbuild/linux-ia32": "0.25.5", 1017 | "@esbuild/linux-loong64": "0.25.5", 1018 | "@esbuild/linux-mips64el": "0.25.5", 1019 | "@esbuild/linux-ppc64": "0.25.5", 1020 | "@esbuild/linux-riscv64": "0.25.5", 1021 | "@esbuild/linux-s390x": "0.25.5", 1022 | "@esbuild/linux-x64": "0.25.5", 1023 | "@esbuild/netbsd-arm64": "0.25.5", 1024 | "@esbuild/netbsd-x64": "0.25.5", 1025 | "@esbuild/openbsd-arm64": "0.25.5", 1026 | "@esbuild/openbsd-x64": "0.25.5", 1027 | "@esbuild/sunos-x64": "0.25.5", 1028 | "@esbuild/win32-arm64": "0.25.5", 1029 | "@esbuild/win32-ia32": "0.25.5", 1030 | "@esbuild/win32-x64": "0.25.5" 1031 | } 1032 | }, 1033 | "node_modules/escalade": { 1034 | "version": "3.2.0", 1035 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1036 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1037 | "dev": true, 1038 | "license": "MIT", 1039 | "engines": { 1040 | "node": ">=6" 1041 | } 1042 | }, 1043 | "node_modules/follow-redirects": { 1044 | "version": "1.15.9", 1045 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", 1046 | "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", 1047 | "dev": true, 1048 | "funding": [ 1049 | { 1050 | "type": "individual", 1051 | "url": "https://github.com/sponsors/RubenVerborgh" 1052 | } 1053 | ], 1054 | "license": "MIT", 1055 | "engines": { 1056 | "node": ">=4.0" 1057 | }, 1058 | "peerDependenciesMeta": { 1059 | "debug": { 1060 | "optional": true 1061 | } 1062 | } 1063 | }, 1064 | "node_modules/form-data": { 1065 | "version": "4.0.1", 1066 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", 1067 | "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", 1068 | "dev": true, 1069 | "license": "MIT", 1070 | "dependencies": { 1071 | "asynckit": "^0.4.0", 1072 | "combined-stream": "^1.0.8", 1073 | "mime-types": "^2.1.12" 1074 | }, 1075 | "engines": { 1076 | "node": ">= 6" 1077 | } 1078 | }, 1079 | "node_modules/fraction.js": { 1080 | "version": "4.3.7", 1081 | "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", 1082 | "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", 1083 | "dev": true, 1084 | "license": "MIT", 1085 | "engines": { 1086 | "node": "*" 1087 | }, 1088 | "funding": { 1089 | "type": "patreon", 1090 | "url": "https://github.com/sponsors/rawify" 1091 | } 1092 | }, 1093 | "node_modules/fsevents": { 1094 | "version": "2.3.3", 1095 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1096 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1097 | "dev": true, 1098 | "hasInstallScript": true, 1099 | "license": "MIT", 1100 | "optional": true, 1101 | "os": [ 1102 | "darwin" 1103 | ], 1104 | "engines": { 1105 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1106 | } 1107 | }, 1108 | "node_modules/get-caller-file": { 1109 | "version": "2.0.5", 1110 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1111 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1112 | "dev": true, 1113 | "license": "ISC", 1114 | "engines": { 1115 | "node": "6.* || 8.* || >= 10.*" 1116 | } 1117 | }, 1118 | "node_modules/has-flag": { 1119 | "version": "4.0.0", 1120 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1121 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1122 | "dev": true, 1123 | "license": "MIT", 1124 | "engines": { 1125 | "node": ">=8" 1126 | } 1127 | }, 1128 | "node_modules/is-fullwidth-code-point": { 1129 | "version": "3.0.0", 1130 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1131 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1132 | "dev": true, 1133 | "license": "MIT", 1134 | "engines": { 1135 | "node": ">=8" 1136 | } 1137 | }, 1138 | "node_modules/laravel-vite-plugin": { 1139 | "version": "1.1.1", 1140 | "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.1.1.tgz", 1141 | "integrity": "sha512-HMZXpoSs1OR+7Lw1+g4Iy/s3HF3Ldl8KxxYT2Ot8pEB4XB/QRuZeWgDYJdu552UN03YRSRNK84CLC9NzYRtncA==", 1142 | "dev": true, 1143 | "license": "MIT", 1144 | "dependencies": { 1145 | "picocolors": "^1.0.0", 1146 | "vite-plugin-full-reload": "^1.1.0" 1147 | }, 1148 | "bin": { 1149 | "clean-orphaned-assets": "bin/clean.js" 1150 | }, 1151 | "engines": { 1152 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 1153 | }, 1154 | "peerDependencies": { 1155 | "vite": "^5.0.0 || ^6.0.0" 1156 | } 1157 | }, 1158 | "node_modules/lodash": { 1159 | "version": "4.17.21", 1160 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1161 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1162 | "dev": true, 1163 | "license": "MIT" 1164 | }, 1165 | "node_modules/mime-db": { 1166 | "version": "1.52.0", 1167 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1168 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1169 | "dev": true, 1170 | "license": "MIT", 1171 | "engines": { 1172 | "node": ">= 0.6" 1173 | } 1174 | }, 1175 | "node_modules/mime-types": { 1176 | "version": "2.1.35", 1177 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1178 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1179 | "dev": true, 1180 | "license": "MIT", 1181 | "dependencies": { 1182 | "mime-db": "1.52.0" 1183 | }, 1184 | "engines": { 1185 | "node": ">= 0.6" 1186 | } 1187 | }, 1188 | "node_modules/nanoid": { 1189 | "version": "3.3.11", 1190 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", 1191 | "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 1192 | "dev": true, 1193 | "funding": [ 1194 | { 1195 | "type": "github", 1196 | "url": "https://github.com/sponsors/ai" 1197 | } 1198 | ], 1199 | "license": "MIT", 1200 | "bin": { 1201 | "nanoid": "bin/nanoid.cjs" 1202 | }, 1203 | "engines": { 1204 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1205 | } 1206 | }, 1207 | "node_modules/node-releases": { 1208 | "version": "2.0.19", 1209 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", 1210 | "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", 1211 | "dev": true, 1212 | "license": "MIT" 1213 | }, 1214 | "node_modules/normalize-range": { 1215 | "version": "0.1.2", 1216 | "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", 1217 | "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", 1218 | "dev": true, 1219 | "license": "MIT", 1220 | "engines": { 1221 | "node": ">=0.10.0" 1222 | } 1223 | }, 1224 | "node_modules/picocolors": { 1225 | "version": "1.1.1", 1226 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1227 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1228 | "dev": true, 1229 | "license": "ISC" 1230 | }, 1231 | "node_modules/picomatch": { 1232 | "version": "2.3.1", 1233 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1234 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1235 | "dev": true, 1236 | "license": "MIT", 1237 | "engines": { 1238 | "node": ">=8.6" 1239 | }, 1240 | "funding": { 1241 | "url": "https://github.com/sponsors/jonschlinkert" 1242 | } 1243 | }, 1244 | "node_modules/postcss": { 1245 | "version": "8.5.4", 1246 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", 1247 | "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", 1248 | "dev": true, 1249 | "funding": [ 1250 | { 1251 | "type": "opencollective", 1252 | "url": "https://opencollective.com/postcss/" 1253 | }, 1254 | { 1255 | "type": "tidelift", 1256 | "url": "https://tidelift.com/funding/github/npm/postcss" 1257 | }, 1258 | { 1259 | "type": "github", 1260 | "url": "https://github.com/sponsors/ai" 1261 | } 1262 | ], 1263 | "license": "MIT", 1264 | "dependencies": { 1265 | "nanoid": "^3.3.11", 1266 | "picocolors": "^1.1.1", 1267 | "source-map-js": "^1.2.1" 1268 | }, 1269 | "engines": { 1270 | "node": "^10 || ^12 || >=14" 1271 | } 1272 | }, 1273 | "node_modules/postcss-value-parser": { 1274 | "version": "4.2.0", 1275 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 1276 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 1277 | "dev": true, 1278 | "license": "MIT" 1279 | }, 1280 | "node_modules/proxy-from-env": { 1281 | "version": "1.1.0", 1282 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 1283 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", 1284 | "dev": true, 1285 | "license": "MIT" 1286 | }, 1287 | "node_modules/require-directory": { 1288 | "version": "2.1.1", 1289 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1290 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1291 | "dev": true, 1292 | "license": "MIT", 1293 | "engines": { 1294 | "node": ">=0.10.0" 1295 | } 1296 | }, 1297 | "node_modules/rollup": { 1298 | "version": "4.41.1", 1299 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", 1300 | "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", 1301 | "dev": true, 1302 | "license": "MIT", 1303 | "dependencies": { 1304 | "@types/estree": "1.0.7" 1305 | }, 1306 | "bin": { 1307 | "rollup": "dist/bin/rollup" 1308 | }, 1309 | "engines": { 1310 | "node": ">=18.0.0", 1311 | "npm": ">=8.0.0" 1312 | }, 1313 | "optionalDependencies": { 1314 | "@rollup/rollup-android-arm-eabi": "4.41.1", 1315 | "@rollup/rollup-android-arm64": "4.41.1", 1316 | "@rollup/rollup-darwin-arm64": "4.41.1", 1317 | "@rollup/rollup-darwin-x64": "4.41.1", 1318 | "@rollup/rollup-freebsd-arm64": "4.41.1", 1319 | "@rollup/rollup-freebsd-x64": "4.41.1", 1320 | "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", 1321 | "@rollup/rollup-linux-arm-musleabihf": "4.41.1", 1322 | "@rollup/rollup-linux-arm64-gnu": "4.41.1", 1323 | "@rollup/rollup-linux-arm64-musl": "4.41.1", 1324 | "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", 1325 | "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", 1326 | "@rollup/rollup-linux-riscv64-gnu": "4.41.1", 1327 | "@rollup/rollup-linux-riscv64-musl": "4.41.1", 1328 | "@rollup/rollup-linux-s390x-gnu": "4.41.1", 1329 | "@rollup/rollup-linux-x64-gnu": "4.41.1", 1330 | "@rollup/rollup-linux-x64-musl": "4.41.1", 1331 | "@rollup/rollup-win32-arm64-msvc": "4.41.1", 1332 | "@rollup/rollup-win32-ia32-msvc": "4.41.1", 1333 | "@rollup/rollup-win32-x64-msvc": "4.41.1", 1334 | "fsevents": "~2.3.2" 1335 | } 1336 | }, 1337 | "node_modules/rxjs": { 1338 | "version": "7.8.1", 1339 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", 1340 | "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", 1341 | "dev": true, 1342 | "license": "Apache-2.0", 1343 | "dependencies": { 1344 | "tslib": "^2.1.0" 1345 | } 1346 | }, 1347 | "node_modules/shell-quote": { 1348 | "version": "1.8.2", 1349 | "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", 1350 | "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", 1351 | "dev": true, 1352 | "license": "MIT", 1353 | "engines": { 1354 | "node": ">= 0.4" 1355 | }, 1356 | "funding": { 1357 | "url": "https://github.com/sponsors/ljharb" 1358 | } 1359 | }, 1360 | "node_modules/source-map-js": { 1361 | "version": "1.2.1", 1362 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 1363 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 1364 | "dev": true, 1365 | "license": "BSD-3-Clause", 1366 | "engines": { 1367 | "node": ">=0.10.0" 1368 | } 1369 | }, 1370 | "node_modules/string-width": { 1371 | "version": "4.2.3", 1372 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1373 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1374 | "dev": true, 1375 | "license": "MIT", 1376 | "dependencies": { 1377 | "emoji-regex": "^8.0.0", 1378 | "is-fullwidth-code-point": "^3.0.0", 1379 | "strip-ansi": "^6.0.1" 1380 | }, 1381 | "engines": { 1382 | "node": ">=8" 1383 | } 1384 | }, 1385 | "node_modules/strip-ansi": { 1386 | "version": "6.0.1", 1387 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1388 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1389 | "dev": true, 1390 | "license": "MIT", 1391 | "dependencies": { 1392 | "ansi-regex": "^5.0.1" 1393 | }, 1394 | "engines": { 1395 | "node": ">=8" 1396 | } 1397 | }, 1398 | "node_modules/supports-color": { 1399 | "version": "8.1.1", 1400 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1401 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1402 | "dev": true, 1403 | "license": "MIT", 1404 | "dependencies": { 1405 | "has-flag": "^4.0.0" 1406 | }, 1407 | "engines": { 1408 | "node": ">=10" 1409 | }, 1410 | "funding": { 1411 | "url": "https://github.com/chalk/supports-color?sponsor=1" 1412 | } 1413 | }, 1414 | "node_modules/tinyglobby": { 1415 | "version": "0.2.14", 1416 | "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", 1417 | "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", 1418 | "dev": true, 1419 | "license": "MIT", 1420 | "dependencies": { 1421 | "fdir": "^6.4.4", 1422 | "picomatch": "^4.0.2" 1423 | }, 1424 | "engines": { 1425 | "node": ">=12.0.0" 1426 | }, 1427 | "funding": { 1428 | "url": "https://github.com/sponsors/SuperchupuDev" 1429 | } 1430 | }, 1431 | "node_modules/tinyglobby/node_modules/fdir": { 1432 | "version": "6.4.5", 1433 | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", 1434 | "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", 1435 | "dev": true, 1436 | "license": "MIT", 1437 | "peerDependencies": { 1438 | "picomatch": "^3 || ^4" 1439 | }, 1440 | "peerDependenciesMeta": { 1441 | "picomatch": { 1442 | "optional": true 1443 | } 1444 | } 1445 | }, 1446 | "node_modules/tinyglobby/node_modules/picomatch": { 1447 | "version": "4.0.2", 1448 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 1449 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 1450 | "dev": true, 1451 | "license": "MIT", 1452 | "engines": { 1453 | "node": ">=12" 1454 | }, 1455 | "funding": { 1456 | "url": "https://github.com/sponsors/jonschlinkert" 1457 | } 1458 | }, 1459 | "node_modules/tree-kill": { 1460 | "version": "1.2.2", 1461 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", 1462 | "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", 1463 | "dev": true, 1464 | "license": "MIT", 1465 | "bin": { 1466 | "tree-kill": "cli.js" 1467 | } 1468 | }, 1469 | "node_modules/tslib": { 1470 | "version": "2.8.1", 1471 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 1472 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 1473 | "dev": true, 1474 | "license": "0BSD" 1475 | }, 1476 | "node_modules/update-browserslist-db": { 1477 | "version": "1.1.1", 1478 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", 1479 | "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", 1480 | "dev": true, 1481 | "funding": [ 1482 | { 1483 | "type": "opencollective", 1484 | "url": "https://opencollective.com/browserslist" 1485 | }, 1486 | { 1487 | "type": "tidelift", 1488 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1489 | }, 1490 | { 1491 | "type": "github", 1492 | "url": "https://github.com/sponsors/ai" 1493 | } 1494 | ], 1495 | "license": "MIT", 1496 | "dependencies": { 1497 | "escalade": "^3.2.0", 1498 | "picocolors": "^1.1.0" 1499 | }, 1500 | "bin": { 1501 | "update-browserslist-db": "cli.js" 1502 | }, 1503 | "peerDependencies": { 1504 | "browserslist": ">= 4.21.0" 1505 | } 1506 | }, 1507 | "node_modules/vite": { 1508 | "version": "6.3.5", 1509 | "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", 1510 | "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", 1511 | "dev": true, 1512 | "license": "MIT", 1513 | "dependencies": { 1514 | "esbuild": "^0.25.0", 1515 | "fdir": "^6.4.4", 1516 | "picomatch": "^4.0.2", 1517 | "postcss": "^8.5.3", 1518 | "rollup": "^4.34.9", 1519 | "tinyglobby": "^0.2.13" 1520 | }, 1521 | "bin": { 1522 | "vite": "bin/vite.js" 1523 | }, 1524 | "engines": { 1525 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 1526 | }, 1527 | "funding": { 1528 | "url": "https://github.com/vitejs/vite?sponsor=1" 1529 | }, 1530 | "optionalDependencies": { 1531 | "fsevents": "~2.3.3" 1532 | }, 1533 | "peerDependencies": { 1534 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 1535 | "jiti": ">=1.21.0", 1536 | "less": "*", 1537 | "lightningcss": "^1.21.0", 1538 | "sass": "*", 1539 | "sass-embedded": "*", 1540 | "stylus": "*", 1541 | "sugarss": "*", 1542 | "terser": "^5.16.0", 1543 | "tsx": "^4.8.1", 1544 | "yaml": "^2.4.2" 1545 | }, 1546 | "peerDependenciesMeta": { 1547 | "@types/node": { 1548 | "optional": true 1549 | }, 1550 | "jiti": { 1551 | "optional": true 1552 | }, 1553 | "less": { 1554 | "optional": true 1555 | }, 1556 | "lightningcss": { 1557 | "optional": true 1558 | }, 1559 | "sass": { 1560 | "optional": true 1561 | }, 1562 | "sass-embedded": { 1563 | "optional": true 1564 | }, 1565 | "stylus": { 1566 | "optional": true 1567 | }, 1568 | "sugarss": { 1569 | "optional": true 1570 | }, 1571 | "terser": { 1572 | "optional": true 1573 | }, 1574 | "tsx": { 1575 | "optional": true 1576 | }, 1577 | "yaml": { 1578 | "optional": true 1579 | } 1580 | } 1581 | }, 1582 | "node_modules/vite-plugin-full-reload": { 1583 | "version": "1.2.0", 1584 | "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", 1585 | "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", 1586 | "dev": true, 1587 | "license": "MIT", 1588 | "dependencies": { 1589 | "picocolors": "^1.0.0", 1590 | "picomatch": "^2.3.1" 1591 | } 1592 | }, 1593 | "node_modules/vite/node_modules/fdir": { 1594 | "version": "6.4.5", 1595 | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", 1596 | "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", 1597 | "dev": true, 1598 | "license": "MIT", 1599 | "peerDependencies": { 1600 | "picomatch": "^3 || ^4" 1601 | }, 1602 | "peerDependenciesMeta": { 1603 | "picomatch": { 1604 | "optional": true 1605 | } 1606 | } 1607 | }, 1608 | "node_modules/vite/node_modules/picomatch": { 1609 | "version": "4.0.2", 1610 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 1611 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 1612 | "dev": true, 1613 | "license": "MIT", 1614 | "engines": { 1615 | "node": ">=12" 1616 | }, 1617 | "funding": { 1618 | "url": "https://github.com/sponsors/jonschlinkert" 1619 | } 1620 | }, 1621 | "node_modules/wrap-ansi": { 1622 | "version": "7.0.0", 1623 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1624 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1625 | "dev": true, 1626 | "license": "MIT", 1627 | "dependencies": { 1628 | "ansi-styles": "^4.0.0", 1629 | "string-width": "^4.1.0", 1630 | "strip-ansi": "^6.0.0" 1631 | }, 1632 | "engines": { 1633 | "node": ">=10" 1634 | }, 1635 | "funding": { 1636 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1637 | } 1638 | }, 1639 | "node_modules/y18n": { 1640 | "version": "5.0.8", 1641 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1642 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1643 | "dev": true, 1644 | "license": "ISC", 1645 | "engines": { 1646 | "node": ">=10" 1647 | } 1648 | }, 1649 | "node_modules/yargs": { 1650 | "version": "17.7.2", 1651 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 1652 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 1653 | "dev": true, 1654 | "license": "MIT", 1655 | "dependencies": { 1656 | "cliui": "^8.0.1", 1657 | "escalade": "^3.1.1", 1658 | "get-caller-file": "^2.0.5", 1659 | "require-directory": "^2.1.1", 1660 | "string-width": "^4.2.3", 1661 | "y18n": "^5.0.5", 1662 | "yargs-parser": "^21.1.1" 1663 | }, 1664 | "engines": { 1665 | "node": ">=12" 1666 | } 1667 | }, 1668 | "node_modules/yargs-parser": { 1669 | "version": "21.1.1", 1670 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 1671 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 1672 | "dev": true, 1673 | "license": "ISC", 1674 | "engines": { 1675 | "node": ">=12" 1676 | } 1677 | } 1678 | } 1679 | } 1680 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "type": "module", 4 | "scripts": { 5 | "build": "vite build", 6 | "dev": "vite" 7 | }, 8 | "devDependencies": { 9 | "autoprefixer": "^10.4.20", 10 | "axios": "^1.7.4", 11 | "concurrently": "^9.0.1", 12 | "laravel-vite-plugin": "^1.0", 13 | "vite": "^6.3.5" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | tests/Unit 10 | 11 | 12 | tests/Feature 13 | 14 | 15 | 16 | 17 | app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/documents-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/github-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | github [#142] 6 | Created with Sketch. 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | handleRequest(Request::capture()); 18 | -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /public/main.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Inter:opsz@14..32&family=Space+Grotesk:wght@300..700&display=swap"); 2 | /* CSS reset */ 3 | *, 4 | *::before, 5 | *::after { 6 | box-sizing: border-box; 7 | } 8 | 9 | * { 10 | margin: 0; 11 | } 12 | 13 | body { 14 | line-height: 1.5; 15 | -webkit-font-smoothing: antialiased; 16 | } 17 | 18 | img, 19 | picture, 20 | video, 21 | canvas, 22 | svg { 23 | display: block; 24 | max-width: 100%; 25 | } 26 | 27 | input, 28 | button, 29 | textarea, 30 | select { 31 | font: inherit; 32 | } 33 | 34 | p, 35 | h1, 36 | h2, 37 | h3, 38 | h4, 39 | h5, 40 | h6 { 41 | overflow-wrap: break-word; 42 | } 43 | 44 | li { 45 | list-style-type: none; 46 | } 47 | 48 | a { 49 | text-decoration: none; 50 | } 51 | 52 | button { 53 | border: none; 54 | cursor: pointer; 55 | } 56 | 57 | ul { 58 | padding: 0; 59 | } 60 | 61 | span { 62 | color: inherit; 63 | font-family: inherit; 64 | font-size: inherit; 65 | } 66 | 67 | /* CSS reset end */ 68 | 69 | /* General Theming */ 70 | :root { 71 | --font-space-grotesk: "Space Grotesk", serif; 72 | --font-inter: "Inter", sans-serif; 73 | --text-slate: #94a3b8; 74 | --primary: #2c56f6; 75 | --secondary: #59acfe; 76 | --bg-light: #2c334b; 77 | --bg-medium: #171b29ff; 78 | } 79 | 80 | body { 81 | background-color: var(--bg-medium); 82 | margin: 0 auto; 83 | } 84 | 85 | main { 86 | max-width: 700px; 87 | margin: 0 auto; 88 | padding: 3rem 1rem; 89 | overflow: auto; 90 | } 91 | 92 | h1, 93 | h2, 94 | h3, 95 | h4, 96 | h5, 97 | h6 { 98 | font-family: var(--font-space-grotesk); 99 | color: white; 100 | font-weight: bold; 101 | } 102 | 103 | p, 104 | li, 105 | a { 106 | font-family: var(--font-inter); 107 | } 108 | 109 | button { 110 | font-family: var(--font-space-grotesk); 111 | font-weight: bold; 112 | } 113 | 114 | p, 115 | li, 116 | a { 117 | color: var(--text-slate); 118 | } 119 | 120 | a { 121 | transition: color 0.3s; 122 | } 123 | 124 | a:hover { 125 | color: white; 126 | } 127 | 128 | .loader { 129 | border: 5px solid var(--text-slate); 130 | border-bottom-color: transparent; 131 | border-radius: 50%; 132 | margin: 0 auto; 133 | animation: rotation 1s linear infinite; 134 | width: 2rem; 135 | height: 2rem; 136 | } 137 | 138 | @keyframes rotation { 139 | 0% { 140 | transform: rotate(0deg); 141 | } 142 | 100% { 143 | transform: rotate(360deg); 144 | } 145 | } 146 | 147 | div:has(> nav) { 148 | background-color: var(--bg-light); 149 | } 150 | 151 | /* Navigation */ 152 | nav { 153 | padding: 0.5rem 1rem; 154 | display: grid; 155 | gap: 0.5rem; 156 | grid-template-columns: repeat(1, minmax(0, 1fr)); 157 | align-items: center; 158 | max-width: 1400px; 159 | margin: 0 auto; 160 | } 161 | 162 | nav p { 163 | color: white; 164 | } 165 | 166 | nav ul { 167 | justify-self: center; 168 | display: flex; 169 | justify-content: center; 170 | align-items: center; 171 | background-color: #727a95; 172 | border-radius: 8px; 173 | width: fit-content; 174 | /*max-width: 500px;*/ 175 | padding: 0.3rem; 176 | gap: 0.2rem; 177 | } 178 | 179 | nav ul li { 180 | border-radius: 8px; 181 | transition: background-color 0.3s; 182 | } 183 | 184 | nav ul li:has(a[data-selected="true"]) { 185 | background-color: var(--bg-light); 186 | } 187 | 188 | nav ul li:not(:has(a[data-selected="true"])):hover { 189 | background-color: #61677c; 190 | } 191 | 192 | nav ul li a { 193 | font-family: var(--font-space-grotesk); 194 | color: white; 195 | padding: 0.5rem 1rem; 196 | display: inline-block; 197 | } 198 | 199 | nav > a:first-child { 200 | justify-self: center; 201 | display: flex; 202 | align-items: center; 203 | gap: 0.5rem; 204 | font-family: var(--font-space-grotesk); 205 | font-weight: bold; 206 | font-size: 20px; 207 | } 208 | 209 | nav > button:last-child { 210 | font-family: var(--font-space-grotesk); 211 | background-color: var(--primary); 212 | color: white; 213 | justify-self: center; 214 | transition: background-color 0.3s; 215 | border-radius: 8px; 216 | font-weight: bold; 217 | padding: 0.5rem 1rem; 218 | } 219 | 220 | /* Main */ 221 | 222 | main section { 223 | padding: 1rem; 224 | background-color: #0c0c1f; 225 | box-shadow: 0 0 14px 0 rgba(44, 86, 246, 0.5); 226 | border-radius: 8px; 227 | text-align: center; 228 | } 229 | 230 | main h1 { 231 | color: var(--secondary); 232 | margin: 0 auto; 233 | padding-bottom: 1rem; 234 | } 235 | 236 | main p { 237 | padding-top: 4px; 238 | padding-bottom: 4px; 239 | } 240 | 241 | main .button, 242 | main button { 243 | display: inline-block; 244 | font-family: var(--font-space-grotesk); 245 | font-weight: bold; 246 | background-color: var(--primary); 247 | color: white; 248 | padding: 0.5rem 1rem; 249 | border-radius: 8px; 250 | transition: background-color 0.3s; 251 | margin: 0.4rem 0.2rem; 252 | } 253 | 254 | main .button:disabled, 255 | main button:disabled { 256 | background-color: #1b3494; 257 | cursor: not-allowed; 258 | } 259 | 260 | main .button:hover:not([disabled]), 261 | button:hover:not([type="button"]):not([title]):not(.cb-primary-button):not( 262 | [disabled] 263 | ) { 264 | background-color: var(--secondary); 265 | } 266 | 267 | main ul { 268 | display: flex; 269 | justify-content: center; 270 | align-items: center; 271 | gap: 1rem; 272 | flex-wrap: wrap; 273 | padding: 0.2rem 0; 274 | } 275 | 276 | main ul li { 277 | color: white; 278 | font-family: var(--font-space-grotesk); 279 | } 280 | 281 | main ul li::before { 282 | content: ""; 283 | display: inline-block; 284 | width: 24px; 285 | height: 24px; 286 | margin-right: 2px; 287 | background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIiBmaWxsPSJub25lIj4KPGcgZmlsdGVyPSJ1cmwoI2ZpbHRlcjBfZl8zNl83MTUpIj4KPGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iNiIgZmlsbD0iIzIxOEVEMiIvPgo8Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSI2IiBmaWxsPSIjMjE4RUQyIi8+CjwvZz4KPGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iNiIgZmlsbD0iIzIxOEVEMiIvPgo8Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSI2IiBmaWxsPSIjMjE4RUQyIi8+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2ZfMzZfNzE1IiB4PSIwIiB5PSIwIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iNSIgcmVzdWx0PSJlZmZlY3QxX2ZvcmVncm91bmRCbHVyXzM2XzcxNSIvPgo8L2ZpbHRlcj4KPC9kZWZzPgo8L3N2Zz4="); 288 | background-size: cover; 289 | vertical-align: middle; 290 | } 291 | 292 | #secret-box { 293 | border: 2px solid var(--text-slate); 294 | background: var(--bg-light); 295 | margin-top: 1rem; 296 | justify-self: center; 297 | padding: 0.3rem; 298 | } 299 | 300 | #secret-box h3 { 301 | display: inline; 302 | color: var(--secondary); 303 | } 304 | 305 | #secret-box p { 306 | display: inline; 307 | color: white; 308 | } 309 | 310 | #city-form { 311 | display: flex; 312 | flex-direction: column; 313 | align-items: center; 314 | gap: 0.5rem; 315 | margin-top: 1rem; 316 | } 317 | 318 | #city-form > input { 319 | font-family: var(--font-inter); 320 | background-color: var(--bg-light); 321 | border: white 2px solid; 322 | border-radius: 8px; 323 | color: white; 324 | padding: 0.2rem 0.5rem; 325 | } 326 | 327 | #identifier-list { 328 | display: flex; 329 | flex-direction: column; 330 | padding: 0.5rem; 331 | border: 1px solid var(--text-slate); 332 | border-radius: 8px; 333 | margin-bottom: 0.5rem; 334 | } 335 | 336 | #identifier-list > div { 337 | display: grid; 338 | grid-template-columns: repeat(1, minmax(0, 1fr)); 339 | justify-items: start; 340 | } 341 | 342 | #identifier-list > div:not(:last-child) { 343 | border-bottom: 1px solid var(--text-slate); 344 | } 345 | 346 | /* Footer */ 347 | footer { 348 | margin: 0 auto; 349 | display: flex; 350 | align-items: center; 351 | justify-content: center; 352 | gap: 0.5rem; 353 | padding-top: 3rem; 354 | } 355 | 356 | footer > a { 357 | display: flex; 358 | gap: 0.5rem; 359 | transition: background-color 0.3s; 360 | padding: 0.5rem 1rem; 361 | border-radius: 8px; 362 | } 363 | 364 | footer > a:hover { 365 | background-color: var(--bg-light); 366 | color: var(--text-slate); 367 | } 368 | 369 | footer > svg:hover { 370 | fill: white; 371 | } 372 | 373 | /* Custom Corbado styles */ 374 | 375 | .cbo-custom-styles { 376 | .cb-passkey-list-title { 377 | display: none; 378 | } 379 | 380 | .cb-passkey-list-primary-button { 381 | margin-left: auto; 382 | margin-right: auto; 383 | } 384 | 385 | .cb-passkey-list-primary-button:hover { 386 | background-color: var(--secondary); 387 | } 388 | 389 | .cb-passkey-list-card, 390 | .cb-container { 391 | background-color: var(--bg-light); 392 | } 393 | 394 | .cb-input, 395 | .cb-icon-button-with-icon-only, 396 | .cb-last-identifier { 397 | background-color: var(--bg-medium); 398 | } 399 | } 400 | 401 | @media (min-width: 540px) { 402 | nav ul li a { 403 | padding: 0.5rem 2rem; 404 | } 405 | 406 | #identifier-list > div { 407 | grid-template-columns: repeat(2, minmax(0, 1fr)); 408 | } 409 | } 410 | 411 | @media (min-width: 1150px) { 412 | nav { 413 | grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr); 414 | } 415 | 416 | nav > a:first-child { 417 | justify-self: start; 418 | } 419 | 420 | nav > button:last-child { 421 | justify-self: end; 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /resources/views/index_authenticated.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |
5 |

6 | Welcome 7 | from {{ !empty($user->city) ? $user->city : 'unknown'}}! 8 |

9 |

You now have access to everything and can visit the user area:

10 | User area 11 |
12 | 18 | @endsection -------------------------------------------------------------------------------- /resources/views/index_guest.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |
5 |

Welcome Guest!

6 |

This example demonstrates Corbado's passkey-first authentication solution.

7 |

It covers all relevant aspects like -

8 |
    9 |
  • Sign-up
  • 10 |
  • Login
  • 11 |
  • Protecting Routes
  • 12 |
13 |

It can be used as a starting point for your own application or to learn.

14 | Sign up 15 | Login 16 |
17 | @endsection -------------------------------------------------------------------------------- /resources/views/layout.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Corbado Example 7 | 8 | 9 | 10 | 11 | 12 | 51 | 52 | @if(env('CORBADO_TELEMETRY_DISABLED') !== true) 53 | 64 | @endif 65 | 66 | 67 |
68 | 112 |
113 | 114 | @if ($errors->any()) 115 |
116 |
    117 | @foreach ($errors->all() as $error) 118 |
  • {{ $error }}
  • 119 | @endforeach 120 |
121 |
122 | @endif 123 | 124 |
125 |
126 | @yield('content') 127 |
128 | 148 |
149 | 156 | 157 | -------------------------------------------------------------------------------- /resources/views/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |

Login

5 |
6 | 17 | @endsection -------------------------------------------------------------------------------- /resources/views/profile.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |

Profile

5 |

Example userID: {{$user->id}}

6 |

Corbado userID: {{$user->corbado_user_id}}

7 |

Your Identifiers

8 | < 9 |
10 | @foreach ($userIdentifiers as $identifier) 11 |
12 |

13 | Type: {{ $identifier->getType() }} 14 |

15 |

16 | Value: {{ $identifier->getValue() }} 17 |

18 |
19 | @endforeach 20 |
21 |

Manage your Passkeys

22 |
23 | 27 | @endsection -------------------------------------------------------------------------------- /resources/views/signup.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |

Signup

5 |
6 | 17 | @endsection -------------------------------------------------------------------------------- /resources/views/signup_onboarding.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |

Onboarding

5 |

Choose your city

6 |
7 | @csrf 8 | 9 | 10 |
11 | @endsection -------------------------------------------------------------------------------- /resources/views/userarea_authenticated.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |

User area!

5 |

Since you are logged-in, we can tell you a secret:

6 | 7 |
8 | 39 | @endsection -------------------------------------------------------------------------------- /resources/views/userarea_guest.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('content') 4 |
5 |

User area!

6 |

This page is for logged-in users only. Please login:

7 | Login 8 |
9 | @endsection -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 8 | })->purpose('Display an inspiring quote')->hourly(); 9 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | name('index'); 12 | Route::get('/userarea', [UserAreaController::class, 'userArea'])->name('userArea'); 13 | Route::get('/signup', [SignupController::class, 'signup'])->name('signup'); 14 | Route::get('/login', [LoginController::class, 'login'])->name('login'); 15 | Route::get('/signup/onboarding', [SignupController::class, 'onboarding'])->name('onboarding'); 16 | Route::post('/signup/onboarding', [SignupController::class, 'handleOnboarding'])->name('handleOnboarding'); 17 | Route::get('/profile', [ProfileController::class, 'profile'])->name('profile'); 18 | Route::get('/api/secret', [ApiController::class, 'secret'])->name('secret'); -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 16 | 17 | $response->assertStatus(200); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import laravel from "laravel-vite-plugin"; 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | laravel({ 7 | input: ["resources/css/app.css", "resources/js/app.js"], 8 | refresh: true, 9 | }), 10 | ], 11 | }); 12 | --------------------------------------------------------------------------------