From 3988941f3f1f0270d9d6b2fa29eca3ef17d28635 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 22 Sep 2026 22:05:33 +0930 Subject: [PATCH 1/5] chore: upgrade laravel/pulse ^1.3 -> ^1.8 (1.8.1) --- composer.json | 2 +- composer.lock | 211 ++++++++++++++++++++++++++------------------------ 2 files changed, 111 insertions(+), 102 deletions(-) diff --git a/composer.json b/composer.json index 5845eea85..ba7484b92 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "laravel/framework": "^13.0", "laravel/horizon": "^5.0", "laravel/passport": "^13.4.4", - "laravel/pulse": "^1.3", + "laravel/pulse": "^1.8", "laravel/sanctum": "^4.3", "laravel/tinker": "^3.0", "laravel/ui": "^4.2", diff --git a/composer.lock b/composer.lock index 33d15823e..d19278648 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "03d710d525be0612fac492c42e960daa", + "content-hash": "af40964f6e2cbfc1eb1aadef670e4c5c", "packages": [ { "name": "aws/aws-crt-php", @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.394.5", + "version": "3.395.7", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "12c80170a12c9e9e5d9057bff4d197979631624f" + "reference": "575425a1c7c1dabb808badc7995e67874cba102a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/12c80170a12c9e9e5d9057bff4d197979631624f", - "reference": "12c80170a12c9e9e5d9057bff4d197979631624f", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/575425a1c7c1dabb808badc7995e67874cba102a", + "reference": "575425a1c7c1dabb808badc7995e67874cba102a", "shasum": "" }, "require": { @@ -153,9 +153,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.394.5" + "source": "https://github.com/aws/aws-sdk-php/tree/3.395.7" }, - "time": "2026-08-31T22:10:11+00:00" + "time": "2026-09-21T18:22:34+00:00" }, { "name": "bacon/bacon-qr-code", @@ -938,16 +938,16 @@ }, { "name": "ezyang/htmlpurifier", - "version": "v4.19.0", + "version": "v4.19.1", "source": { "type": "git", "url": "https://github.com/ezyang/htmlpurifier.git", - "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf" + "reference": "5e0539132d934f936fbae2c88b55d58f9438623f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf", - "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/5e0539132d934f936fbae2c88b55d58f9438623f", + "reference": "5e0539132d934f936fbae2c88b55d58f9438623f", "shasum": "" }, "require": { @@ -993,32 +993,32 @@ ], "support": { "issues": "https://github.com/ezyang/htmlpurifier/issues", - "source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0" + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.1" }, - "time": "2025-10-17T16:34:55+00:00" + "time": "2026-09-15T15:42:51+00:00" }, { "name": "firebase/php-jwt", - "version": "v7.1.0", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/googleapis/php-jwt.git", - "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0" + "reference": "f502cdbf279cd7532060b041f7c22a05208c0b93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/b374a5d1a4f1f67fadc2165cdb284645945e2fc0", - "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0", + "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/f502cdbf279cd7532060b041f7c22a05208c0b93", + "reference": "f502cdbf279cd7532060b041f7c22a05208c0b93", "shasum": "" }, "require": { "php": "^8.0" }, "require-dev": { - "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/guzzle": "^7.4||^8.0", "phpfastcache/phpfastcache": "^9.2", "phpseclib/phpseclib": "~3.0", - "phpspec/prophecy-phpunit": "^2.0", + "phpspec/prophecy-phpunit": "^2.2", "phpunit/phpunit": "^9.5", "psr/cache": "^2.0||^3.0", "psr/http-client": "^1.0", @@ -1030,6 +1030,14 @@ "phpseclib/phpseclib": "Support PS256 (RSASSA-PSS) signatures" }, "type": "library", + "extra": { + "component": { + "id": "jwt", + "path": "Jwt", + "entry": "README.md", + "target": "googleapis/php-jwt.git" + } + }, "autoload": { "psr-4": { "Firebase\\JWT\\": "src" @@ -1059,9 +1067,9 @@ ], "support": { "issues": "https://github.com/googleapis/php-jwt/issues", - "source": "https://github.com/googleapis/php-jwt/tree/v7.1.0" + "source": "https://github.com/googleapis/php-jwt/tree/v7.2.0" }, - "time": "2026-06-11T17:54:14+00:00" + "time": "2026-09-21T19:29:58+00:00" }, { "name": "fruitcake/php-cors", @@ -3031,16 +3039,16 @@ }, { "name": "league/commonmark", - "version": "2.10.1", + "version": "2.10.3", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "9d489ab67a02960fd8ffe624d93f751daf95439e" + "reference": "6efbd9c472b91db0a3350fcd601c8332c2382e1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/9d489ab67a02960fd8ffe624d93f751daf95439e", - "reference": "9d489ab67a02960fd8ffe624d93f751daf95439e", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6efbd9c472b91db0a3350fcd601c8332c2382e1f", + "reference": "6efbd9c472b91db0a3350fcd601c8332c2382e1f", "shasum": "" }, "require": { @@ -3134,7 +3142,7 @@ "type": "tidelift" } ], - "time": "2026-09-07T13:44:26+00:00" + "time": "2026-09-21T13:07:34+00:00" }, { "name": "league/config", @@ -3934,16 +3942,16 @@ }, { "name": "livewire/livewire", - "version": "v4.4.3", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "92f1427022714b34024459167aa6a85d4fb4af44" + "reference": "c6b7db7a92103ac2738e8fdc926cecc93eb67853" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/92f1427022714b34024459167aa6a85d4fb4af44", - "reference": "92f1427022714b34024459167aa6a85d4fb4af44", + "url": "https://api.github.com/repos/livewire/livewire/zipball/c6b7db7a92103ac2738e8fdc926cecc93eb67853", + "reference": "c6b7db7a92103ac2738e8fdc926cecc93eb67853", "shasum": "" }, "require": { @@ -3998,7 +4006,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v4.4.3" + "source": "https://github.com/livewire/livewire/tree/v4.4.6" }, "funding": [ { @@ -4006,7 +4014,7 @@ "type": "github" } ], - "time": "2026-08-31T15:40:58+00:00" + "time": "2026-09-21T18:51:23+00:00" }, { "name": "matomo/device-detector", @@ -4646,16 +4654,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.8.0", + "version": "v5.9.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f" + "reference": "9e33da9553fe7786f0962b35f4e4ecf01be89def" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f", - "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9e33da9553fe7786f0962b35f4e4ecf01be89def", + "reference": "9e33da9553fe7786f0962b35f4e4ecf01be89def", "shasum": "" }, "require": { @@ -4697,9 +4705,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.8.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.9.0" }, - "time": "2026-07-04T14:30:18+00:00" + "time": "2026-09-13T18:51:52+00:00" }, { "name": "nunomaduro/termwind", @@ -7300,20 +7308,20 @@ }, { "name": "spomky-labs/pki-framework", - "version": "1.6.2", + "version": "1.6.3", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/pki-framework.git", - "reference": "8f333bebe104ea24f1a160a6fb69e2dead4f1882" + "reference": "792e909d4e387adffe3c4f404451c7d57a3d2022" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/8f333bebe104ea24f1a160a6fb69e2dead4f1882", - "reference": "8f333bebe104ea24f1a160a6fb69e2dead4f1882", + "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/792e909d4e387adffe3c4f404451c7d57a3d2022", + "reference": "792e909d4e387adffe3c4f404451c7d57a3d2022", "shasum": "" }, "require": { - "brick/math": "^0.10|^0.11|^0.12|^0.13|^0.14|^0.15|^0.16|^0.17|^0.18|^0.19|^0.20", + "brick/math": "^0.10|^0.11|^0.12|^0.13|^0.14|^0.15|^0.16|^0.17|^0.18|^0.19|^0.20|^1.0", "ext-mbstring": "*", "php": ">=8.1" }, @@ -7394,7 +7402,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/pki-framework/issues", - "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.6.2" + "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.6.3" }, "funding": [ { @@ -7406,7 +7414,7 @@ "type": "patreon" } ], - "time": "2026-09-08T07:15:08+00:00" + "time": "2026-09-12T19:02:49+00:00" }, { "name": "stevebauman/purify", @@ -7476,16 +7484,16 @@ }, { "name": "symfony/cache", - "version": "v7.4.18", + "version": "v7.4.19", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "6c521e19a99e8ae57e22aa85b9271534513ee850" + "reference": "e037fd41e9f8ec9ac270e2a4c76a1992d18d808c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/6c521e19a99e8ae57e22aa85b9271534513ee850", - "reference": "6c521e19a99e8ae57e22aa85b9271534513ee850", + "url": "https://api.github.com/repos/symfony/cache/zipball/e037fd41e9f8ec9ac270e2a4c76a1992d18d808c", + "reference": "e037fd41e9f8ec9ac270e2a4c76a1992d18d808c", "shasum": "" }, "require": { @@ -7555,7 +7563,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.4.18" + "source": "https://github.com/symfony/cache/tree/v7.4.19" }, "funding": [ { @@ -7575,7 +7583,7 @@ "type": "tidelift" } ], - "time": "2026-08-30T20:10:52+00:00" + "time": "2026-09-08T13:28:43+00:00" }, { "name": "symfony/cache-contracts", @@ -8360,16 +8368,16 @@ }, { "name": "symfony/http-client", - "version": "v7.4.18", + "version": "v7.4.19", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "68d81f78d127984ff2e741f0e0d9cb1078f8f3ea" + "reference": "3a523f38dc399337ec45b2ab9628e8c37ceb23c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/68d81f78d127984ff2e741f0e0d9cb1078f8f3ea", - "reference": "68d81f78d127984ff2e741f0e0d9cb1078f8f3ea", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3a523f38dc399337ec45b2ab9628e8c37ceb23c7", + "reference": "3a523f38dc399337ec45b2ab9628e8c37ceb23c7", "shasum": "" }, "require": { @@ -8437,7 +8445,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.4.18" + "source": "https://github.com/symfony/http-client/tree/v7.4.19" }, "funding": [ { @@ -8457,7 +8465,7 @@ "type": "tidelift" } ], - "time": "2026-08-30T13:49:59+00:00" + "time": "2026-09-08T13:28:43+00:00" }, { "name": "symfony/http-client-contracts", @@ -10956,20 +10964,20 @@ }, { "name": "web-token/jwt-library", - "version": "4.2.2", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/web-token/jwt-library.git", - "reference": "ae642340ee2ca91ca0c37edd72a9d06302651ca9" + "reference": "db962c3ad8bc91c531a49dd373f0a641fc507bfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-library/zipball/ae642340ee2ca91ca0c37edd72a9d06302651ca9", - "reference": "ae642340ee2ca91ca0c37edd72a9d06302651ca9", + "url": "https://api.github.com/repos/web-token/jwt-library/zipball/db962c3ad8bc91c531a49dd373f0a641fc507bfd", + "reference": "db962c3ad8bc91c531a49dd373f0a641fc507bfd", "shasum": "" }, "require": { - "brick/math": "^0.12|^0.13|^0.14|^0.15|^0.16|^0.17|^0.18|^0.19|^0.20", + "brick/math": "^0.12|^0.13|^0.14|^0.15|^0.16|^0.17|^0.18|^0.19|^0.20|^1.0", "php": ">=8.2", "psr/clock": "^1.0", "spomky-labs/pki-framework": "^1.2.1", @@ -11030,7 +11038,7 @@ ], "support": { "issues": "https://github.com/web-token/jwt-library/issues", - "source": "https://github.com/web-token/jwt-library/tree/4.2.2" + "source": "https://github.com/web-token/jwt-library/tree/4.2.3" }, "funding": [ { @@ -11042,7 +11050,7 @@ "type": "patreon" } ], - "time": "2026-08-30T13:53:36+00:00" + "time": "2026-09-12T18:50:35+00:00" } ], "packages-dev": [ @@ -11671,16 +11679,16 @@ }, { "name": "filp/whoops", - "version": "2.18.4", + "version": "2.18.5", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + "reference": "baec851ad6ae00db8bd0fdd30d208afc1b71c56e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "url": "https://api.github.com/repos/filp/whoops/zipball/baec851ad6ae00db8bd0fdd30d208afc1b71c56e", + "reference": "baec851ad6ae00db8bd0fdd30d208afc1b71c56e", "shasum": "" }, "require": { @@ -11689,8 +11697,8 @@ }, "require-dev": { "mockery/mockery": "^1.0", - "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", - "symfony/var-dumper": "^4.0 || ^5.0" + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3 || ^10.5.58", + "symfony/var-dumper": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0" }, "suggest": { "symfony/var-dumper": "Pretty print complex values better with var-dumper available", @@ -11730,7 +11738,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.4" + "source": "https://github.com/filp/whoops/tree/2.18.5" }, "funding": [ { @@ -11738,7 +11746,7 @@ "type": "github" } ], - "time": "2025-08-08T12:00:00+00:00" + "time": "2026-09-18T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -11898,16 +11906,16 @@ }, { "name": "larastan/larastan", - "version": "v3.12.1", + "version": "v3.12.2", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "168fd3b955e723c51dbf81709849b0c3ac4ac5f6" + "reference": "c328727e6103c1147d1c64cc96b3aedfda26bc20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/168fd3b955e723c51dbf81709849b0c3ac4ac5f6", - "reference": "168fd3b955e723c51dbf81709849b0c3ac4ac5f6", + "url": "https://api.github.com/repos/larastan/larastan/zipball/c328727e6103c1147d1c64cc96b3aedfda26bc20", + "reference": "c328727e6103c1147d1c64cc96b3aedfda26bc20", "shasum": "" }, "require": { @@ -11975,7 +11983,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v3.12.1" + "source": "https://github.com/larastan/larastan/tree/v3.12.2" }, "funding": [ { @@ -11983,7 +11991,7 @@ "type": "github" } ], - "time": "2026-09-13T15:17:35+00:00" + "time": "2026-09-19T10:46:58+00:00" }, { "name": "laravel/pint", @@ -12924,16 +12932,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.7", + "version": "6.0.3", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "31a105931bc8ffa3a123383829772e832fd8d903" + "reference": "7bae67520aa9f5ecc506d646810bd40d9da54582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/31a105931bc8ffa3a123383829772e832fd8d903", - "reference": "31a105931bc8ffa3a123383829772e832fd8d903", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/7bae67520aa9f5ecc506d646810bd40d9da54582", + "reference": "7bae67520aa9f5ecc506d646810bd40d9da54582", "shasum": "" }, "require": { @@ -12941,8 +12949,8 @@ "ext-filter": "*", "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7|^2.0", + "phpdocumentor/type-resolver": "^2.0", + "phpstan/phpdoc-parser": "^2.0", "webmozart/assert": "^1.9.1 || ^2" }, "require-dev": { @@ -12952,7 +12960,8 @@ "phpstan/phpstan-mockery": "^1.1", "phpstan/phpstan-webmozart-assert": "^1.2", "phpunit/phpunit": "^9.5", - "psalm/phar": "^5.26" + "psalm/phar": "^5.26", + "shipmonk/dead-code-detector": "^0.5.1" }, "type": "library", "extra": { @@ -12982,44 +12991,44 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.7" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.3" }, - "time": "2026-03-18T20:47:46+00:00" + "time": "2026-03-18T20:49:53+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.12.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195" + "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195", - "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9", + "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.18|^2.0" + "phpstan/phpdoc-parser": "^2.0" }, "require-dev": { "ext-tokenizer": "*", "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" + "psalm/phar": "^4" }, "type": "library", "extra": { "branch-alias": { - "dev-1.x": "1.x-dev" + "dev-1.x": "1.x-dev", + "dev-2.x": "2.x-dev" } }, "autoload": { @@ -13040,9 +13049,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0" }, - "time": "2025-11-21T15:09:14+00:00" + "time": "2026-01-06T21:53:42+00:00" }, { "name": "phpstan/phpdoc-parser", From 139b29733e24f4c6fb3ff59ab80f00a9a1c35869 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 22 Sep 2026 22:32:37 +0930 Subject: [PATCH 2/5] fix: serve Pulse and Horizon dashboards under admin/ to avoid username route collisions - Pulse: set PULSE_PATH default to admin/pulse; Pulse::ignoreRoutes() in AppServiceProvider and register the dashboard explicitly in routes/web-admin.php so it is matched before the {username} profile catch-all. - Horizon: set horizon.path to admin/horizon (all Horizon routes follow); add an explicit base-path GET mirroring Horizon's own HomeController@index for clarity. - Remove now-unneeded 'horizon' reservation from RestrictedNames. - Add PULSE_ENABLED-gated Pulse links to admin sidenav and topnav. - Replace HorizonRedirectTest with HorizonDashboardTest (base path now renders the dashboard directly instead of redirecting). --- app/Providers/AppServiceProvider.php | 1 + app/Util/Lexer/RestrictedNames.php | 3 - config/horizon.php | 2 +- config/pulse.php | 2 +- .../views/admin/partial/sidenav.blade.php | 11 +++- .../views/admin/partial/topnav.blade.php | 5 +- routes/web-admin.php | 28 +++++++++ routes/web.php | 4 -- tests/Feature/Admin/HorizonDashboardTest.php | 53 +++++++++++++++++ tests/Feature/Admin/HorizonRedirectTest.php | 57 ------------------- 10 files changed, 98 insertions(+), 68 deletions(-) create mode 100644 tests/Feature/Admin/HorizonDashboardTest.php delete mode 100644 tests/Feature/Admin/HorizonRedirectTest.php diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 861a07541..d8a563a3b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -230,6 +230,7 @@ class AppServiceProvider extends ServiceProvider public function register() { Passport::ignoreRoutes(); + Pulse::ignoreRoutes(); $this->app->bind(UserOidcService::class, function () { return UserOidcService::build(); diff --git a/app/Util/Lexer/RestrictedNames.php b/app/Util/Lexer/RestrictedNames.php index 21295554e..c2a32aac2 100644 --- a/app/Util/Lexer/RestrictedNames.php +++ b/app/Util/Lexer/RestrictedNames.php @@ -99,9 +99,6 @@ class RestrictedNames 'mix-manifest.json', 'robots.txt', - // Laravel Horizon - 'horizon', - // Reserved routes 'a', 'app', diff --git a/config/horizon.php b/config/horizon.php index ea330b81a..9cee4194e 100644 --- a/config/horizon.php +++ b/config/horizon.php @@ -26,7 +26,7 @@ return [ | */ - 'path' => 'horizon', + 'path' => env('HORIZON_PATH', 'admin/horizon'), /* |-------------------------------------------------------------------------- diff --git a/config/pulse.php b/config/pulse.php index 7341ca7f0..2d993143f 100644 --- a/config/pulse.php +++ b/config/pulse.php @@ -30,7 +30,7 @@ return [ | */ - 'path' => env('PULSE_PATH', 'pulse'), + 'path' => env('PULSE_PATH', 'admin/pulse'), /* |-------------------------------------------------------------------------- diff --git a/resources/views/admin/partial/sidenav.blade.php b/resources/views/admin/partial/sidenav.blade.php index ce9ef0471..70e20a58e 100644 --- a/resources/views/admin/partial/sidenav.blade.php +++ b/resources/views/admin/partial/sidenav.blade.php @@ -146,12 +146,21 @@ + @if(config('pulse.enabled')) + + @endif + diff --git a/routes/web-admin.php b/routes/web-admin.php index cb508f696..b6e75d7fb 100644 --- a/routes/web-admin.php +++ b/routes/web-admin.php @@ -5,6 +5,34 @@ use App\Http\Controllers\AdminController; use App\Http\Controllers\AdminCuratedRegisterController; use App\Http\Controllers\AdminShadowFilterController; use App\Http\Controllers\PageController; +use Illuminate\Contracts\View\Factory; +use Laravel\Horizon\Http\Controllers\HomeController as HorizonHomeController; +use Laravel\Pulse\Pulse; + +// Laravel Pulse + Horizon dashboards, kept under `admin/*` so their routes can +// never collide with the `{username}` profile catch-all in routes/web.php +// (a username cannot contain a slash). This file loads before routes/web.php and +// before Horizon's provider routes (see bootstrap/app.php), so these definitions +// win on route-match order. +// +// Pulse: registered explicitly (with Pulse::ignoreRoutes() set in AppServiceProvider +// so the package does not self-register at its default path). +// +// Horizon: the explicit base-path GET below is deliberately identical to Horizon's +// own optional `{view?}` catch-all (same HomeController@index action, same 'horizon' +// middleware group) which would otherwise serve this path. It is not required for +// correctness; it exists only to make admin/horizon visible in Pixelfed's own route +// files. All other Horizon subpaths (admin/horizon/dashboard, /api/*, assets) are +// still served by Horizon itself. +Route::domain(config('pixelfed.domain.app'))->middleware(['localization'])->group(function () { + Route::get(config('pulse.path', 'admin/pulse'), function (Pulse $pulse, Factory $view) { + return $view->make('pulse::dashboard'); + })->middleware('pulse')->name('pulse'); + + Route::get(config('horizon.path'), [HorizonHomeController::class, 'index']) + ->middleware('horizon') + ->name('horizon.base'); +}); Route::domain(config('pixelfed.domain.admin'))->prefix('i/admin')->middleware(['localization'])->group(function () { Route::redirect('/', '/dashboard'); diff --git a/routes/web.php b/routes/web.php index b1970f0b8..d4188fe96 100644 --- a/routes/web.php +++ b/routes/web.php @@ -500,10 +500,6 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['localization'])->grou Route::get('auth/invite/a/{code}', [AdminInviteController::class, 'index']); Route::post('api/v1.1/auth/invite/admin/re', [AdminInviteController::class, 'apiRegister'])->middleware('throttle:5,1440'); - // Laravel 13's Horizon no longer redirects the base path to its dashboard, - // so /horizon 404s by default. Redirect admins from /horizon to /horizon/dashboard. - Route::redirect('horizon', '/horizon/dashboard')->middleware('admin'); - Route::redirect('groups/', '/groups/home'); Route::redirect('groups/home', '/groups/feed'); diff --git a/tests/Feature/Admin/HorizonDashboardTest.php b/tests/Feature/Admin/HorizonDashboardTest.php new file mode 100644 index 000000000..d33dc79ca --- /dev/null +++ b/tests/Feature/Admin/HorizonDashboardTest.php @@ -0,0 +1,53 @@ +admin()->create(); + $admin->refresh(); + + // The base path is handled by Horizon (not a redirect) and renders the SPA. + $this->actingAs($admin) + ->get('/'.$path) + ->assertOk() + ->assertSee('Horizon', false); +}); + +it('serves the Horizon dashboard at the /dashboard subpath for an admin', function () { + $path = config('horizon.path'); + + $admin = User::factory()->admin()->create(); + $admin->refresh(); + + $this->actingAs($admin) + ->get('/'.$path.'/dashboard') + ->assertOk(); +}); + +it('does not allow a non-admin to access the Horizon dashboard', function () { + $user = User::factory()->create(['is_admin' => false]); + $user->refresh(); + + // Horizon's authorization gate (viewHorizon) forbids non-admins. + $this->actingAs($user) + ->get('/'.config('horizon.path')) + ->assertForbidden(); +}); diff --git a/tests/Feature/Admin/HorizonRedirectTest.php b/tests/Feature/Admin/HorizonRedirectTest.php deleted file mode 100644 index 416fcb108..000000000 --- a/tests/Feature/Admin/HorizonRedirectTest.php +++ /dev/null @@ -1,57 +0,0 @@ -admin()->create(); - $admin->refresh(); - - $response = $this->actingAs($admin)->get('/horizon'); - - $response->assertRedirect('/horizon/dashboard'); - - // The Location header must be absolute so a trailing-slash request cannot - // resolve it into a doubled /horizon/horizon/dashboard path. - expect($response->headers->get('Location'))->toEndWith('/horizon/dashboard'); - expect(parse_url($response->headers->get('Location'), PHP_URL_PATH)) - ->toBe('/horizon/dashboard'); -}); - -it('redirects with an absolute Location for a trailing-slash /horizon/ request', function () { - $admin = User::factory()->admin()->create(); - $admin->refresh(); - - $response = $this->actingAs($admin)->get('/horizon/'); - - // Regardless of the trailing slash, the redirect path is the absolute - // dashboard path, never a relative reference that would double up. - expect(parse_url($response->headers->get('Location'), PHP_URL_PATH)) - ->toBe('/horizon/dashboard'); -}); - -it('does not allow a non-admin to use the /horizon redirect', function () { - $user = User::factory()->create(['is_admin' => false]); - $user->refresh(); - - // The admin middleware bounces non-admins to the app root, not the dashboard. - $this->actingAs($user) - ->get('/horizon') - ->assertRedirect(config('app.url')); -}); From 5654ab6c270c4687a32abc87646bcf7c91209db7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 22 Sep 2026 22:41:00 +0930 Subject: [PATCH 3/5] fix: viewPulse gate denies admins due to strict === on boolean is_admin is_admin is cast to bool on the User model, so $user->is_admin === 1 is always false and the gate 403s every user, admins included. Use a boolean check, consistent with the viewHorizon gate. --- app/Providers/AppServiceProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index d8a563a3b..a98826628 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -112,7 +112,9 @@ class AppServiceProvider extends ServiceProvider Event::listen(Failed::class, LogFailedLogin::class); Gate::define('viewPulse', function (User $user) { - return $user->is_admin === 1; + // is_admin is cast to bool on the User model, so a strict `=== 1` + // never matches. Use a boolean check, consistent with viewHorizon. + return (bool) $user->is_admin === true; }); if (config('pulse.enabled', false)) { From b06e810375a75ef252b89e6bf865352520a14172 Mon Sep 17 00:00:00 2001 From: Shlee Date: Tue, 22 Sep 2026 22:44:18 +0930 Subject: [PATCH 4/5] Update web-admin.php --- routes/web-admin.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/routes/web-admin.php b/routes/web-admin.php index b6e75d7fb..d97d552a1 100644 --- a/routes/web-admin.php +++ b/routes/web-admin.php @@ -11,19 +11,6 @@ use Laravel\Pulse\Pulse; // Laravel Pulse + Horizon dashboards, kept under `admin/*` so their routes can // never collide with the `{username}` profile catch-all in routes/web.php -// (a username cannot contain a slash). This file loads before routes/web.php and -// before Horizon's provider routes (see bootstrap/app.php), so these definitions -// win on route-match order. -// -// Pulse: registered explicitly (with Pulse::ignoreRoutes() set in AppServiceProvider -// so the package does not self-register at its default path). -// -// Horizon: the explicit base-path GET below is deliberately identical to Horizon's -// own optional `{view?}` catch-all (same HomeController@index action, same 'horizon' -// middleware group) which would otherwise serve this path. It is not required for -// correctness; it exists only to make admin/horizon visible in Pixelfed's own route -// files. All other Horizon subpaths (admin/horizon/dashboard, /api/*, assets) are -// still served by Horizon itself. Route::domain(config('pixelfed.domain.app'))->middleware(['localization'])->group(function () { Route::get(config('pulse.path', 'admin/pulse'), function (Pulse $pulse, Factory $view) { return $view->make('pulse::dashboard'); From 662b7bdee8d73d87972baca23734022117aacf5c Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 22 Sep 2026 22:47:39 +0930 Subject: [PATCH 5/5] fix(larastan): resolve octane-compatibility error in CaptchaServiceProvider The singleton closure injected the boot-time $app and constructed new CaptchaManager($app), which larastan's checkOctaneCompatibility flags as holding a stale container across requests. Resolve the current container via Container::getInstance() instead. --- app/Providers/CaptchaServiceProvider.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Providers/CaptchaServiceProvider.php b/app/Providers/CaptchaServiceProvider.php index 56d98b423..29cc0aadd 100644 --- a/app/Providers/CaptchaServiceProvider.php +++ b/app/Providers/CaptchaServiceProvider.php @@ -3,6 +3,7 @@ namespace App\Providers; use App\Services\Captcha\CaptchaManager; +use Illuminate\Container\Container; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Validator; use Illuminate\Support\ServiceProvider; @@ -11,7 +12,12 @@ class CaptchaServiceProvider extends ServiceProvider { public function register(): void { - $this->app->singleton('captcha.manager', fn ($app): CaptchaManager => new CaptchaManager($app)); + // Resolve the current container via Container::getInstance() rather than + // capturing the $app injected at boot time, so the manager never holds a + // stale container instance across requests under Octane. + $this->app->singleton('captcha.manager', function (): CaptchaManager { + return new CaptchaManager(Container::getInstance()); + }); $this->app->alias('captcha.manager', CaptchaManager::class); }