diff --git a/.cursor/rules/laravel-boost.mdc b/.cursor/rules/laravel-boost.mdc index 6e21fa7..9464f06 100644 --- a/.cursor/rules/laravel-boost.mdc +++ b/.cursor/rules/laravel-boost.mdc @@ -11,7 +11,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for ## Foundational Context This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions. -- php - 8.4.12 +- php - 8.3.24 - laravel/framework (LARAVEL) - v12 - laravel/prompts (PROMPTS) - v0 - livewire/flux (FLUXUI_FREE) - v2 @@ -19,7 +19,7 @@ This application is a Laravel application and its main Laravel ecosystems packag - livewire/volt (VOLT) - v1 - larastan/larastan (LARASTAN) - v3 - laravel/pint (PINT) - v1 -- pestphp/pest (PEST) - v4 +- pestphp/pest (PEST) - v3 - tailwindcss (TAILWINDCSS) - v4 @@ -465,53 +465,6 @@ it('has emails', function (string $email) { -=== pest/v4 rules === - -## Pest 4 - -- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage. -- Browser testing is incredibly powerful and useful for this project. -- Browser tests should live in `tests/Browser/`. -- Use the `search-docs` tool for detailed guidance on utilizing these features. - -### Browser Testing -- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test. -- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test. -- If requested, test on multiple browsers (Chrome, Firefox, Safari). -- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints). -- Switch color schemes (light/dark mode) when appropriate. -- Take screenshots or pause tests for debugging when appropriate. - -### Example Tests - - -it('may reset the password', function () { - Notification::fake(); - - $this->actingAs(User::factory()->create()); - - $page = visit('/sign-in'); // Visit on a real browser... - - $page->assertSee('Sign In') - ->assertNoJavascriptErrors() // or ->assertNoConsoleLogs() - ->click('Forgot Password?') - ->fill('email', 'nuno@laravel.com') - ->click('Send Reset Link') - ->assertSee('We have emailed your password reset link!') - - Notification::assertSent(ResetPassword::class); -}); - - - - - -$pages = visit(['/', '/about', '/contact']); - -$pages->assertNoJavascriptErrors()->assertNoConsoleLogs(); - - - === tailwindcss/core rules === ## Tailwind Core diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index be2748d..a331541 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -8,7 +8,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for ## Foundational Context This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions. -- php - 8.4.12 +- php - 8.3.24 - laravel/framework (LARAVEL) - v12 - laravel/prompts (PROMPTS) - v0 - livewire/flux (FLUXUI_FREE) - v2 @@ -16,7 +16,7 @@ This application is a Laravel application and its main Laravel ecosystems packag - livewire/volt (VOLT) - v1 - larastan/larastan (LARASTAN) - v3 - laravel/pint (PINT) - v1 -- pestphp/pest (PEST) - v4 +- pestphp/pest (PEST) - v3 - tailwindcss (TAILWINDCSS) - v4 @@ -462,53 +462,6 @@ it('has emails', function (string $email) { -=== pest/v4 rules === - -## Pest 4 - -- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage. -- Browser testing is incredibly powerful and useful for this project. -- Browser tests should live in `tests/Browser/`. -- Use the `search-docs` tool for detailed guidance on utilizing these features. - -### Browser Testing -- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test. -- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test. -- If requested, test on multiple browsers (Chrome, Firefox, Safari). -- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints). -- Switch color schemes (light/dark mode) when appropriate. -- Take screenshots or pause tests for debugging when appropriate. - -### Example Tests - - -it('may reset the password', function () { - Notification::fake(); - - $this->actingAs(User::factory()->create()); - - $page = visit('/sign-in'); // Visit on a real browser... - - $page->assertSee('Sign In') - ->assertNoJavascriptErrors() // or ->assertNoConsoleLogs() - ->click('Forgot Password?') - ->fill('email', 'nuno@laravel.com') - ->click('Send Reset Link') - ->assertSee('We have emailed your password reset link!') - - Notification::assertSent(ResetPassword::class); -}); - - - - - -$pages = visit(['/', '/about', '/contact']); - -$pages->assertNoJavascriptErrors()->assertNoConsoleLogs(); - - - === tailwindcss/core rules === ## Tailwind Core diff --git a/.junie/guidelines.md b/.junie/guidelines.md index be2748d..a331541 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -8,7 +8,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for ## Foundational Context This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions. -- php - 8.4.12 +- php - 8.3.24 - laravel/framework (LARAVEL) - v12 - laravel/prompts (PROMPTS) - v0 - livewire/flux (FLUXUI_FREE) - v2 @@ -16,7 +16,7 @@ This application is a Laravel application and its main Laravel ecosystems packag - livewire/volt (VOLT) - v1 - larastan/larastan (LARASTAN) - v3 - laravel/pint (PINT) - v1 -- pestphp/pest (PEST) - v4 +- pestphp/pest (PEST) - v3 - tailwindcss (TAILWINDCSS) - v4 @@ -462,53 +462,6 @@ it('has emails', function (string $email) { -=== pest/v4 rules === - -## Pest 4 - -- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage. -- Browser testing is incredibly powerful and useful for this project. -- Browser tests should live in `tests/Browser/`. -- Use the `search-docs` tool for detailed guidance on utilizing these features. - -### Browser Testing -- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test. -- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test. -- If requested, test on multiple browsers (Chrome, Firefox, Safari). -- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints). -- Switch color schemes (light/dark mode) when appropriate. -- Take screenshots or pause tests for debugging when appropriate. - -### Example Tests - - -it('may reset the password', function () { - Notification::fake(); - - $this->actingAs(User::factory()->create()); - - $page = visit('/sign-in'); // Visit on a real browser... - - $page->assertSee('Sign In') - ->assertNoJavascriptErrors() // or ->assertNoConsoleLogs() - ->click('Forgot Password?') - ->fill('email', 'nuno@laravel.com') - ->click('Send Reset Link') - ->assertSee('We have emailed your password reset link!') - - Notification::assertSent(ResetPassword::class); -}); - - - - - -$pages = visit(['/', '/about', '/contact']); - -$pages->assertNoJavascriptErrors()->assertNoConsoleLogs(); - - - === tailwindcss/core rules === ## Tailwind Core diff --git a/CLAUDE.md b/CLAUDE.md index be2748d..a331541 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for ## Foundational Context This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions. -- php - 8.4.12 +- php - 8.3.24 - laravel/framework (LARAVEL) - v12 - laravel/prompts (PROMPTS) - v0 - livewire/flux (FLUXUI_FREE) - v2 @@ -16,7 +16,7 @@ This application is a Laravel application and its main Laravel ecosystems packag - livewire/volt (VOLT) - v1 - larastan/larastan (LARASTAN) - v3 - laravel/pint (PINT) - v1 -- pestphp/pest (PEST) - v4 +- pestphp/pest (PEST) - v3 - tailwindcss (TAILWINDCSS) - v4 @@ -462,53 +462,6 @@ it('has emails', function (string $email) { -=== pest/v4 rules === - -## Pest 4 - -- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage. -- Browser testing is incredibly powerful and useful for this project. -- Browser tests should live in `tests/Browser/`. -- Use the `search-docs` tool for detailed guidance on utilizing these features. - -### Browser Testing -- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test. -- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test. -- If requested, test on multiple browsers (Chrome, Firefox, Safari). -- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints). -- Switch color schemes (light/dark mode) when appropriate. -- Take screenshots or pause tests for debugging when appropriate. - -### Example Tests - - -it('may reset the password', function () { - Notification::fake(); - - $this->actingAs(User::factory()->create()); - - $page = visit('/sign-in'); // Visit on a real browser... - - $page->assertSee('Sign In') - ->assertNoJavascriptErrors() // or ->assertNoConsoleLogs() - ->click('Forgot Password?') - ->fill('email', 'nuno@laravel.com') - ->click('Send Reset Link') - ->assertSee('We have emailed your password reset link!') - - Notification::assertSent(ResetPassword::class); -}); - - - - - -$pages = visit(['/', '/about', '/contact']); - -$pages->assertNoJavascriptErrors()->assertNoConsoleLogs(); - - - === tailwindcss/core rules === ## Tailwind Core diff --git a/app/Models/Plugin.php b/app/Models/Plugin.php index 3079ab7..7290381 100644 --- a/app/Models/Plugin.php +++ b/app/Models/Plugin.php @@ -236,11 +236,11 @@ class Plugin extends Model $template = preg_replace_callback( '/{%\s*for\s+(\w+)\s+in\s+([^|]+)\s*\|\s*([^}]+)%}/', function ($matches) { - $variableName = mb_trim($matches[1]); - $collection = mb_trim($matches[2]); - $filter = mb_trim($matches[3]); - $tempVarName = '_temp_'.uniqid(); - + $variableName = trim($matches[1]); + $collection = trim($matches[2]); + $filter = trim($matches[3]); + $tempVarName = '_temp_' . uniqid(); + return "{% assign {$tempVarName} = {$collection} | {$filter} %}{% for {$variableName} in {$tempVarName} %}"; }, $template diff --git a/app/Services/PluginImportService.php b/app/Services/PluginImportService.php index 29b5688..dbd8ec8 100644 --- a/app/Services/PluginImportService.php +++ b/app/Services/PluginImportService.php @@ -7,7 +7,6 @@ use App\Models\User; use Exception; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\File; -use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Storage; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; @@ -49,130 +48,6 @@ class PluginImportService // Find the required files (settings.yml and full.liquid/full.blade.php) $filePaths = $this->findRequiredFiles($tempDir); - // Validate that we found the required files - if (! $filePaths['settingsYamlPath'] || ! $filePaths['fullLiquidPath']) { - throw new Exception('Invalid ZIP structure. Required files settings.yml and full.liquid are missing.'); // full.blade.php - } - - // Parse settings.yml - $settingsYaml = File::get($filePaths['settingsYamlPath']); - $settings = Yaml::parse($settingsYaml); - - // Read full.liquid content - $fullLiquid = File::get($filePaths['fullLiquidPath']); - - // Prepend shared.liquid content if available - if ($filePaths['sharedLiquidPath'] && File::exists($filePaths['sharedLiquidPath'])) { - $sharedLiquid = File::get($filePaths['sharedLiquidPath']); - $fullLiquid = $sharedLiquid."\n".$fullLiquid; - } - - $fullLiquid = '
'."\n".$fullLiquid."\n".'
'; - - // Check if the file ends with .liquid to set markup language - $markupLanguage = 'blade'; - if (pathinfo($filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') { - $markupLanguage = 'liquid'; - } - - // Ensure custom_fields is properly formatted - if (! isset($settings['custom_fields']) || ! is_array($settings['custom_fields'])) { - $settings['custom_fields'] = []; - } - - // Create configuration template with the custom fields - $configurationTemplate = [ - 'custom_fields' => $settings['custom_fields'], - ]; - - $plugin_updated = isset($settings['id']) - && Plugin::where('user_id', $user->id)->where('trmnlp_id', $settings['id'])->exists(); - // Create a new plugin - $plugin = Plugin::updateOrCreate( - [ - 'user_id' => $user->id, 'trmnlp_id' => $settings['id'] ?? Uuid::v7(), - ], - [ - 'user_id' => $user->id, - 'name' => $settings['name'] ?? 'Imported Plugin', - 'trmnlp_id' => $settings['id'] ?? Uuid::v7(), - 'data_stale_minutes' => $settings['refresh_interval'] ?? 15, - 'data_strategy' => $settings['strategy'] ?? 'static', - 'polling_url' => $settings['polling_url'] ?? null, - 'polling_verb' => $settings['polling_verb'] ?? 'get', - 'polling_header' => isset($settings['polling_headers']) - ? str_replace('=', ':', $settings['polling_headers']) - : null, - 'polling_body' => $settings['polling_body'] ?? null, - 'markup_language' => $markupLanguage, - 'render_markup' => $fullLiquid, - 'configuration_template' => $configurationTemplate, - 'data_payload' => json_decode($settings['static_data'] ?? '{}', true), - ]); - - if (! $plugin_updated) { - // Extract default values from custom_fields and populate configuration - $configuration = []; - foreach ($settings['custom_fields'] as $field) { - if (isset($field['keyname']) && isset($field['default'])) { - $configuration[$field['keyname']] = $field['default']; - } - } - // set only if plugin is new - $plugin->update([ - 'configuration' => $configuration, - ]); - } - $plugin['trmnlp_yaml'] = $settingsYaml; - - return $plugin; - - } finally { - // Clean up temporary directory - Storage::deleteDirectory($tempDirName); - } - } - - /** - * Import a plugin from a ZIP URL - * - * @param string $zipUrl The URL to the ZIP file - * @param User $user The user importing the plugin - * @return Plugin The created plugin instance - * - * @throws Exception If the ZIP file is invalid or required files are missing - */ - public function importFromUrl(string $zipUrl, User $user): Plugin - { - // Download the ZIP file - $response = Http::timeout(60)->get($zipUrl); - - if (! $response->successful()) { - throw new Exception('Could not download the ZIP file from the provided URL.'); - } - - // Create a temporary file - $tempDirName = 'temp/'.uniqid('plugin_import_', true); - Storage::makeDirectory($tempDirName); - $tempDir = Storage::path($tempDirName); - $zipPath = $tempDir.'/plugin.zip'; - - // Save the downloaded content to a temporary file - File::put($zipPath, $response->body()); - - try { - // Extract the ZIP file using ZipArchive - $zip = new ZipArchive(); - if ($zip->open($zipPath) !== true) { - throw new Exception('Could not open the downloaded ZIP file.'); - } - - $zip->extractTo($tempDir); - $zip->close(); - - // Find the required files (settings.yml and full.liquid/full.blade.php) - $filePaths = $this->findRequiredFiles($tempDir); - // Validate that we found the required files if (! $filePaths['settingsYamlPath'] || ! $filePaths['fullLiquidPath']) { throw new Exception('Invalid ZIP structure. Required files settings.yml and full.liquid/full.blade.php are missing.'); diff --git a/composer.lock b/composer.lock index 2ad26ef..79f70e1 100644 --- a/composer.lock +++ b/composer.lock @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.356.8", + "version": "3.356.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "3efa8c62c11fedb17b90f60b2d3a9f815b406e63" + "reference": "5872ccb5100c4afb0dae3db0bd46636f63ae8147" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3efa8c62c11fedb17b90f60b2d3a9f815b406e63", - "reference": "3efa8c62c11fedb17b90f60b2d3a9f815b406e63", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5872ccb5100c4afb0dae3db0bd46636f63ae8147", + "reference": "5872ccb5100c4afb0dae3db0bd46636f63ae8147", "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.356.8" + "source": "https://github.com/aws/aws-sdk-php/tree/3.356.5" }, - "time": "2025-08-29T18:06:18+00:00" + "time": "2025-08-26T18:05:04+00:00" }, { "name": "bnussbau/laravel-trmnl-blade", @@ -1691,16 +1691,16 @@ }, { "name": "laravel/framework", - "version": "v12.26.4", + "version": "v12.26.2", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09" + "reference": "56c5fc46cfb1005d0aaa82c7592d63edb776a787" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/085a367a32ba86fcfa647bfc796098ae6f795b09", - "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09", + "url": "https://api.github.com/repos/laravel/framework/zipball/56c5fc46cfb1005d0aaa82c7592d63edb776a787", + "reference": "56c5fc46cfb1005d0aaa82c7592d63edb776a787", "shasum": "" }, "require": { @@ -1740,8 +1740,8 @@ "symfony/http-kernel": "^7.2.0", "symfony/mailer": "^7.2.0", "symfony/mime": "^7.2.0", - "symfony/polyfill-php83": "^1.33", - "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-php83": "^1.31", + "symfony/polyfill-php84": "^1.31", "symfony/polyfill-php85": "^1.33", "symfony/process": "^7.2.0", "symfony/routing": "^7.2.0", @@ -1810,7 +1810,7 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^10.6.3", + "orchestra/testbench-core": "^10.6.0", "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", @@ -1904,7 +1904,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-08-29T14:15:53+00:00" + "time": "2025-08-26T18:04:56+00:00" }, { "name": "laravel/prompts", @@ -4973,16 +4973,16 @@ }, { "name": "symfony/console", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7" + "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", - "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", + "url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1", + "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1", "shasum": "" }, "require": { @@ -5047,7 +5047,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.3" + "source": "https://github.com/symfony/console/tree/v7.3.2" }, "funding": [ { @@ -5067,7 +5067,7 @@ "type": "tidelift" } ], - "time": "2025-08-25T06:35:40+00:00" + "time": "2025-07-30T17:13:41+00:00" }, { "name": "symfony/css-selector", @@ -5284,16 +5284,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v7.3.3", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", "shasum": "" }, "require": { @@ -5344,7 +5344,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" }, "funding": [ { @@ -5355,16 +5355,12 @@ "url": "https://github.com/fabpot", "type": "github" }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-04-22T09:11:45+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5512,16 +5508,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00" + "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00", - "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6877c122b3a6cc3695849622720054f6e6fa5fa6", + "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6", "shasum": "" }, "require": { @@ -5571,7 +5567,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.3" + "source": "https://github.com/symfony/http-foundation/tree/v7.3.2" }, "funding": [ { @@ -5591,20 +5587,20 @@ "type": "tidelift" } ], - "time": "2025-08-20T08:04:18+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b" + "reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b", - "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6ecc895559ec0097e221ed2fd5eb44d5fede083c", + "reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c", "shasum": "" }, "require": { @@ -5689,7 +5685,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.3" + "source": "https://github.com/symfony/http-kernel/tree/v7.3.2" }, "funding": [ { @@ -5709,20 +5705,20 @@ "type": "tidelift" } ], - "time": "2025-08-29T08:23:45+00:00" + "time": "2025-07-31T10:45:04+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575" + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575", - "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575", + "url": "https://api.github.com/repos/symfony/mailer/zipball/d43e84d9522345f96ad6283d5dfccc8c1cfc299b", + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b", "shasum": "" }, "require": { @@ -5773,7 +5769,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.3" + "source": "https://github.com/symfony/mailer/tree/v7.3.2" }, "funding": [ { @@ -5793,7 +5789,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/mime", @@ -6714,16 +6710,16 @@ }, { "name": "symfony/process", - "version": "v7.3.3", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "32241012d521e2e8a9d713adb0812bb773b907f1" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1", - "reference": "32241012d521e2e8a9d713adb0812bb773b907f1", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { @@ -6755,7 +6751,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.3" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -6766,16 +6762,12 @@ "url": "https://github.com/fabpot", "type": "github" }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-18T09:42:54+00:00" + "time": "2025-04-17T09:11:12+00:00" }, { "name": "symfony/routing", @@ -6947,16 +6939,16 @@ }, { "name": "symfony/string", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c" + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", - "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", + "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", "shasum": "" }, "require": { @@ -7014,7 +7006,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.3" + "source": "https://github.com/symfony/string/tree/v7.3.2" }, "funding": [ { @@ -7034,20 +7026,20 @@ "type": "tidelift" } ], - "time": "2025-08-25T06:35:40+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "symfony/translation", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e0837b4cbcef63c754d89a4806575cada743a38d" + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d", - "reference": "e0837b4cbcef63c754d89a4806575cada743a38d", + "url": "https://api.github.com/repos/symfony/translation/zipball/81b48f4daa96272efcce9c7a6c4b58e629df3c90", + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90", "shasum": "" }, "require": { @@ -7114,7 +7106,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.3" + "source": "https://github.com/symfony/translation/tree/v7.3.2" }, "funding": [ { @@ -7134,7 +7126,7 @@ "type": "tidelift" } ], - "time": "2025-08-01T21:02:37+00:00" + "time": "2025-07-30T17:31:46+00:00" }, { "name": "symfony/translation-contracts", @@ -7290,16 +7282,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f" + "reference": "53205bea27450dc5c65377518b3275e126d45e75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", - "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", + "reference": "53205bea27450dc5c65377518b3275e126d45e75", "shasum": "" }, "require": { @@ -7353,7 +7345,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.2" }, "funding": [ { @@ -7373,20 +7365,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-07-29T20:02:46+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137" + "reference": "05b3e90654c097817325d6abd284f7938b05f467" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/d4dfcd2a822cbedd7612eb6fbd260e46f87b7137", - "reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/05b3e90654c097817325d6abd284f7938b05f467", + "reference": "05b3e90654c097817325d6abd284f7938b05f467", "shasum": "" }, "require": { @@ -7434,7 +7426,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.3.3" + "source": "https://github.com/symfony/var-exporter/tree/v7.3.2" }, "funding": [ { @@ -7454,20 +7446,20 @@ "type": "tidelift" } ], - "time": "2025-08-18T13:10:53+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "symfony/yaml", - "version": "v7.3.3", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "d4f4a66866fe2451f61296924767280ab5732d9d" + "reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/d4f4a66866fe2451f61296924767280ab5732d9d", - "reference": "d4f4a66866fe2451f61296924767280ab5732d9d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/b8d7d868da9eb0919e99c8830431ea087d6aae30", + "reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30", "shasum": "" }, "require": { @@ -7510,7 +7502,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.3" + "source": "https://github.com/symfony/yaml/tree/v7.3.2" }, "funding": [ { @@ -7530,7 +7522,7 @@ "type": "tidelift" } ], - "time": "2025-08-27T11:34:33+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -7893,16 +7885,16 @@ "packages-dev": [ { "name": "brianium/paratest", - "version": "v7.12.0", + "version": "v7.11.2", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "6a34ddb12a3bd5bd07d831ce95f111087f3bcbd8" + "reference": "521aa381c212816d0dc2f04f1532a5831969cb5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/6a34ddb12a3bd5bd07d831ce95f111087f3bcbd8", - "reference": "6a34ddb12a3bd5bd07d831ce95f111087f3bcbd8", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/521aa381c212816d0dc2f04f1532a5831969cb5e", + "reference": "521aa381c212816d0dc2f04f1532a5831969cb5e", "shasum": "" }, "require": { @@ -7912,11 +7904,11 @@ "ext-simplexml": "*", "fidry/cpu-core-counter": "^1.3.0", "jean85/pretty-package-versions": "^2.1.1", - "php": "~8.3.0 || ~8.4.0 || ~8.5.0", + "php": "~8.3.0 || ~8.4.0", "phpunit/php-code-coverage": "^12.3.2", "phpunit/php-file-iterator": "^6", "phpunit/php-timer": "^8", - "phpunit/phpunit": "^12.3.6", + "phpunit/phpunit": "^12.3.5", "sebastian/environment": "^8.0.3", "symfony/console": "^6.4.20 || ^7.3.2", "symfony/process": "^6.4.20 || ^7.3.0" @@ -7971,7 +7963,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.12.0" + "source": "https://github.com/paratestphp/paratest/tree/v7.11.2" }, "funding": [ { @@ -7983,7 +7975,7 @@ "type": "paypal" } ], - "time": "2025-08-29T05:28:31+00:00" + "time": "2025-08-19T09:24:27+00:00" }, { "name": "doctrine/deprecations", @@ -8471,16 +8463,16 @@ }, { "name": "laravel/boost", - "version": "v1.0.20", + "version": "v1.0.18", "source": { "type": "git", "url": "https://github.com/laravel/boost.git", - "reference": "c2ac67ce42c39ffe6c3c073c9202d54a96eaa5b5" + "reference": "df2a62b5864759ea8cce8a4b7575b657e9c7d4ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/boost/zipball/c2ac67ce42c39ffe6c3c073c9202d54a96eaa5b5", - "reference": "c2ac67ce42c39ffe6c3c073c9202d54a96eaa5b5", + "url": "https://api.github.com/repos/laravel/boost/zipball/df2a62b5864759ea8cce8a4b7575b657e9c7d4ab", + "reference": "df2a62b5864759ea8cce8a4b7575b657e9c7d4ab", "shasum": "" }, "require": { @@ -8489,13 +8481,13 @@ "illuminate/contracts": "^10.0|^11.0|^12.0", "illuminate/routing": "^10.0|^11.0|^12.0", "illuminate/support": "^10.0|^11.0|^12.0", - "laravel/mcp": "^0.1.1", + "laravel/mcp": "^0.1.0", "laravel/prompts": "^0.1.9|^0.3", - "laravel/roster": "^0.2.4", - "php": "^8.1" + "laravel/roster": "^0.2", + "php": "^8.1|^8.2" }, "require-dev": { - "laravel/pint": "^1.14", + "laravel/pint": "^1.14|^1.23", "mockery/mockery": "^1.6", "orchestra/testbench": "^8.22.0|^9.0|^10.0", "pestphp/pest": "^2.0|^3.0", @@ -8532,7 +8524,7 @@ "issues": "https://github.com/laravel/boost/issues", "source": "https://github.com/laravel/boost" }, - "time": "2025-08-28T14:46:17+00:00" + "time": "2025-08-16T09:10:03+00:00" }, { "name": "laravel/mcp", @@ -8748,16 +8740,16 @@ }, { "name": "laravel/roster", - "version": "v0.2.5", + "version": "v0.2.3", "source": { "type": "git", "url": "https://github.com/laravel/roster.git", - "reference": "0252fa419733c61b3ebeba8e4e2b9ad2a63f3a17" + "reference": "caeed7609b02c00c3f1efec52812d8d87c5d4096" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/roster/zipball/0252fa419733c61b3ebeba8e4e2b9ad2a63f3a17", - "reference": "0252fa419733c61b3ebeba8e4e2b9ad2a63f3a17", + "url": "https://api.github.com/repos/laravel/roster/zipball/caeed7609b02c00c3f1efec52812d8d87c5d4096", + "reference": "caeed7609b02c00c3f1efec52812d8d87c5d4096", "shasum": "" }, "require": { @@ -8805,20 +8797,20 @@ "issues": "https://github.com/laravel/roster/issues", "source": "https://github.com/laravel/roster" }, - "time": "2025-08-29T07:47:42+00:00" + "time": "2025-08-13T15:00:25+00:00" }, { "name": "laravel/sail", - "version": "v1.45.0", + "version": "v1.44.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "019a2933ff4a9199f098d4259713f9bc266a874e" + "reference": "a09097bd2a8a38e23ac472fa6a6cf5b0d1c1d3fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/019a2933ff4a9199f098d4259713f9bc266a874e", - "reference": "019a2933ff4a9199f098d4259713f9bc266a874e", + "url": "https://api.github.com/repos/laravel/sail/zipball/a09097bd2a8a38e23ac472fa6a6cf5b0d1c1d3fe", + "reference": "a09097bd2a8a38e23ac472fa6a6cf5b0d1c1d3fe", "shasum": "" }, "require": { @@ -8868,7 +8860,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2025-08-25T19:28:31+00:00" + "time": "2025-07-04T16:17:06+00:00" }, { "name": "mockery/mockery", @@ -9114,16 +9106,16 @@ }, { "name": "pestphp/pest", - "version": "v4.0.4", + "version": "v4.0.3", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "47fb1d77631d608022cc7af96cac90ac741c8394" + "reference": "e54e4a0178889209a928f7bee63286149d4eb707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/47fb1d77631d608022cc7af96cac90ac741c8394", - "reference": "47fb1d77631d608022cc7af96cac90ac741c8394", + "url": "https://api.github.com/repos/pestphp/pest/zipball/e54e4a0178889209a928f7bee63286149d4eb707", + "reference": "e54e4a0178889209a928f7bee63286149d4eb707", "shasum": "" }, "require": { @@ -9135,12 +9127,12 @@ "pestphp/pest-plugin-mutate": "^4.0.1", "pestphp/pest-plugin-profanity": "^4.0.1", "php": "^8.3.0", - "phpunit/phpunit": "^12.3.7", + "phpunit/phpunit": "^12.3.6", "symfony/process": "^7.3.0" }, "conflict": { "filp/whoops": "<2.18.3", - "phpunit/phpunit": ">12.3.7", + "phpunit/phpunit": ">12.3.6", "sebastian/exporter": "<7.0.0", "webmozart/assert": "<1.11.0" }, @@ -9214,7 +9206,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v4.0.4" + "source": "https://github.com/pestphp/pest/tree/v4.0.3" }, "funding": [ { @@ -9226,7 +9218,7 @@ "type": "github" } ], - "time": "2025-08-28T18:19:42+00:00" + "time": "2025-08-24T14:17:23+00:00" }, { "name": "pestphp/pest-plugin", @@ -9938,16 +9930,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", "shasum": "" }, "require": { @@ -9979,9 +9971,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0" }, - "time": "2025-08-30T15:50:23+00:00" + "time": "2025-07-13T07:04:09+00:00" }, { "name": "phpstan/phpstan", @@ -10043,34 +10035,34 @@ }, { "name": "phpunit/php-code-coverage", - "version": "12.3.5", + "version": "12.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "96dc0466673e215bf5536301039017f03cd45c6b" + "reference": "086553c5b2e0e1e20293d782d788ab768202b621" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/96dc0466673e215bf5536301039017f03cd45c6b", - "reference": "96dc0466673e215bf5536301039017f03cd45c6b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/086553c5b2e0e1e20293d782d788ab768202b621", + "reference": "086553c5b2e0e1e20293d782d788ab768202b621", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.6.1", + "nikic/php-parser": "^5.4.0", "php": ">=8.3", "phpunit/php-file-iterator": "^6.0", "phpunit/php-text-template": "^5.0", "sebastian/complexity": "^5.0", - "sebastian/environment": "^8.0.3", + "sebastian/environment": "^8.0", "sebastian/lines-of-code": "^4.0", "sebastian/version": "^6.0", "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^12.3.7" + "phpunit/phpunit": "^12.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -10108,7 +10100,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.5" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.2" }, "funding": [ { @@ -10128,7 +10120,7 @@ "type": "tidelift" } ], - "time": "2025-09-01T08:07:42+00:00" + "time": "2025-07-29T06:19:24+00:00" }, { "name": "phpunit/php-file-iterator", @@ -10377,16 +10369,16 @@ }, { "name": "phpunit/phpunit", - "version": "12.3.7", + "version": "12.3.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e" + "reference": "a2cab3224f687150ac2f3cc13d99b64ba1e1d088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b8fa997c49682979ad6bfaa0d7fb25f54954965e", - "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2cab3224f687150ac2f3cc13d99b64ba1e1d088", + "reference": "a2cab3224f687150ac2f3cc13d99b64ba1e1d088", "shasum": "" }, "require": { @@ -10400,7 +10392,7 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.3", - "phpunit/php-code-coverage": "^12.3.3", + "phpunit/php-code-coverage": "^12.3.2", "phpunit/php-file-iterator": "^6.0.0", "phpunit/php-invoker": "^6.0.0", "phpunit/php-text-template": "^5.0.0", @@ -10454,7 +10446,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.7" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.6" }, "funding": [ { @@ -10478,7 +10470,7 @@ "type": "tidelift" } ], - "time": "2025-08-28T05:15:46+00:00" + "time": "2025-08-20T14:43:23+00:00" }, { "name": "sebastian/cli-parser", @@ -10910,16 +10902,16 @@ }, { "name": "sebastian/global-state", - "version": "8.0.2", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "ef1377171613d09edd25b7816f05be8313f9115d" + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", - "reference": "ef1377171613d09edd25b7816f05be8313f9115d", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/570a2aeb26d40f057af686d63c4e99b075fb6cbc", + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc", "shasum": "" }, "require": { @@ -10960,27 +10952,15 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", - "type": "tidelift" } ], - "time": "2025-08-29T11:29:25+00:00" + "time": "2025-02-07T04:56:59+00:00" }, { "name": "sebastian/lines-of-code", diff --git a/config/app.php b/config/app.php index 73bcaaf..98eaee9 100644 --- a/config/app.php +++ b/config/app.php @@ -152,5 +152,4 @@ return [ 'version' => env('APP_VERSION', null), - 'catalog_url' => env('CATALOG_URL', 'https://raw.githubusercontent.com/bnussbau/trmnl-recipe-catalog/refs/heads/main/catalog.yaml'), ]; diff --git a/resources/views/livewire/catalog/index.blade.php b/resources/views/livewire/catalog/index.blade.php deleted file mode 100644 index 4725e68..0000000 --- a/resources/views/livewire/catalog/index.blade.php +++ /dev/null @@ -1,148 +0,0 @@ -loadCatalogPlugins(); - } - - private function loadCatalogPlugins(): void - { - $catalogUrl = config('app.catalog_url'); - - $this->catalogPlugins = Cache::remember('catalog_plugins', 43200, function () use ($catalogUrl) { - try { - $response = Http::get($catalogUrl); - $catalogContent = $response->body(); - $catalog = Yaml::parse($catalogContent); - - return collect($catalog)->map(function ($plugin, $key) { - return [ - 'id' => $key, - 'name' => $plugin['name'] ?? 'Unknown Plugin', - 'description' => $plugin['author_bio']['description'] ?? '', - 'author' => $plugin['author']['name'] ?? 'Unknown Author', - 'github' => $plugin['author']['github'] ?? null, - 'license' => $plugin['license'] ?? null, - 'zip_url' => $plugin['trmnlp']['zip_url'] ?? null, - 'repo_url' => $plugin['trmnlp']['repo'] ?? null, - 'logo_url' => $plugin['logo_url'] ?? null, - 'screenshot_url' => $plugin['screenshot_url'] ?? null, - 'learn_more_url' => $plugin['author_bio']['learn_more_url'] ?? null, - ]; - })->toArray(); - } catch (\Exception $e) { - Log::error('Failed to load catalog from URL: ' . $e->getMessage()); - return []; - } - }); - } - - public function installPlugin(string $pluginId, PluginImportService $pluginImportService): void - { - abort_unless(auth()->user() !== null, 403); - - $plugin = collect($this->catalogPlugins)->firstWhere('id', $pluginId); - - if (!$plugin || !$plugin['zip_url']) { - $this->addError('installation', 'Plugin not found or no download URL available.'); - return; - } - - $this->installingPlugin = $pluginId; - - try { - $importedPlugin = $pluginImportService->importFromUrl($plugin['zip_url'], auth()->user()); - - $this->dispatch('plugin-installed'); - Flux::modal('import-from-catalog')->close(); - - } catch (\Exception $e) { - $this->addError('installation', 'Error installing plugin: ' . $e->getMessage()); - } finally { - $this->installingPlugin = ''; - } - } -}; ?> - -
- @if(empty($catalogPlugins)) -
- - No plugins available - Catalog is empty -
- @else -
- @error('installation') - - @enderror - - @foreach($catalogPlugins as $plugin) -
-
- @if($plugin['logo_url']) - {{ $plugin['name'] }} - @else -
- -
- @endif - -
-
-
-

{{ $plugin['name'] }}

- @if ($plugin['github']) -

by {{ $plugin['github'] }}

- @endif -
-
- @if($plugin['license']) - {{ $plugin['license'] }} - @endif - @if($plugin['repo_url']) - - - - @endif -
-
- - @if($plugin['description']) -

{{ $plugin['description'] }}

- @endif - -
- - Install - - - @if($plugin['learn_more_url']) - - Learn More - - @endif -
-
-
-
- @endforeach -
- @endif -
diff --git a/resources/views/livewire/plugins/index.blade.php b/resources/views/livewire/plugins/index.blade.php index 828e051..9a5dd69 100644 --- a/resources/views/livewire/plugins/index.blade.php +++ b/resources/views/livewire/plugins/index.blade.php @@ -36,7 +36,7 @@ new class extends Component { 'polling_body' => 'nullable|string', ]; - public function refreshPlugins(): void + private function refreshPlugins(): void { $userPlugins = auth()->user()?->plugins?->map(function ($plugin) { return $plugin->toArray(); @@ -96,8 +96,10 @@ new class extends Component { $this->reset(['zipFile']); Flux::modal('import-zip')->close(); + $this->dispatch('notify', ['type' => 'success', 'message' => 'Plugin imported successfully!']); + } catch (\Exception $e) { - $this->addError('zipFile', 'Error installing plugin: ' . $e->getMessage()); + $this->dispatch('notify', ['type' => 'error', 'message' => 'Error importing plugin: ' . $e->getMessage()]); } } @@ -118,10 +120,7 @@ new class extends Component { - Import Recipe Archive - - - Import from Catalog + Import Recipe Seed Example Recipes @@ -168,7 +167,7 @@ new class extends Component {
- .zip Archive + - @error('zipFile') - - @enderror + @error('zipFile') {{ $message }} @enderror
@@ -189,18 +186,6 @@ new class extends Component {
- -
-
- Import from Catalog - Alpha - - Browse and install Recipes from the community. Add yours here. -
- -
-
-
diff --git a/tests/Feature/Livewire/Catalog/IndexTest.php b/tests/Feature/Livewire/Catalog/IndexTest.php deleted file mode 100644 index 7defd78..0000000 --- a/tests/Feature/Livewire/Catalog/IndexTest.php +++ /dev/null @@ -1,102 +0,0 @@ - Http::response('', 200), - ]); - - $component = Volt::test('catalog.index'); - - $component->assertSee('No plugins available'); -}); - -it('loads plugins from catalog URL', function () { - // Clear cache first to ensure fresh data - Cache::forget('catalog_plugins'); - - // Mock the HTTP response for the catalog URL - $catalogData = [ - 'test-plugin' => [ - 'name' => 'Test Plugin', - 'author' => ['name' => 'Test Author', 'github' => 'testuser'], - 'author_bio' => [ - 'description' => 'A test plugin', - 'learn_more_url' => 'https://example.com', - ], - 'license' => 'MIT', - 'trmnlp' => [ - 'zip_url' => 'https://example.com/plugin.zip', - ], - 'logo_url' => 'https://example.com/logo.png', - ], - ]; - - $yamlContent = Yaml::dump($catalogData); - - // Override the default mock with specific data - Http::fake([ - config('app.catalog_url') => Http::response($yamlContent, 200), - ]); - - $component = Volt::test('catalog.index'); - - $component->assertSee('Test Plugin'); - $component->assertSee('testuser'); - $component->assertSee('A test plugin'); - $component->assertSee('MIT'); -}); - -it('shows error when plugin not found', function () { - $user = User::factory()->create(); - - $this->actingAs($user); - - $component = Volt::test('catalog.index'); - - $component->call('installPlugin', 'non-existent-plugin'); - - // The component should dispatch an error notification - $component->assertHasErrors(); -}); - -it('shows error when zip_url is missing', function () { - $user = User::factory()->create(); - - // Mock the HTTP response for the catalog URL without zip_url - $catalogData = [ - 'test-plugin' => [ - 'name' => 'Test Plugin', - 'author' => ['name' => 'Test Author'], - 'author_bio' => ['description' => 'A test plugin'], - 'license' => 'MIT', - 'trmnlp' => [], - ], - ]; - - $yamlContent = Yaml::dump($catalogData); - - Http::fake([ - config('app.catalog_url') => Http::response($yamlContent, 200), - ]); - - $this->actingAs($user); - - $component = Volt::test('catalog.index'); - - $component->call('installPlugin', 'test-plugin'); - - // The component should dispatch an error notification - $component->assertHasErrors(); - -}); diff --git a/tests/Feature/PluginImportTest.php b/tests/Feature/PluginImportTest.php index 25325d2..9aeda6e 100644 --- a/tests/Feature/PluginImportTest.php +++ b/tests/Feature/PluginImportTest.php @@ -94,7 +94,7 @@ it('throws exception for missing required files', function () { $pluginImportService = new PluginImportService(); expect(fn () => $pluginImportService->importFromZip($zipFile, $user)) - ->toThrow(Exception::class, 'Invalid ZIP structure. Required files settings.yml and full.liquid are missing.'); + ->toThrow(Exception::class, 'Invalid ZIP structure. Required files settings.yml and full.liquid/full.blade.php are missing.'); }); it('sets default values when settings are missing', function () { diff --git a/tests/Feature/PluginLiquidWhereFilterTest.php b/tests/Feature/PluginLiquidWhereFilterTest.php index c165109..22a2fa5 100644 --- a/tests/Feature/PluginLiquidWhereFilterTest.php +++ b/tests/Feature/PluginLiquidWhereFilterTest.php @@ -12,6 +12,7 @@ use App\Models\Plugin; * to: * {% assign _temp_xxx = collection | filter: "key", "value" %}{% for item in _temp_xxx %} */ + test('where filter works when assigned to variable first', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid',