From 0abbe69868dd2111da67d8360c50266da636a1ca Mon Sep 17 00:00:00 2001 From: HolgerHatGarKeineNode Date: Sat, 17 Jan 2026 23:26:05 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20Remove=20election-relat?= =?UTF-8?q?ed=20blade=20files=20no=20longer=20in=20use?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .junie/guidelines.md | 375 ++++ .junie/mcp/mcp.json | 11 + .mcp.json | 11 + AGENTS.md | 375 ++++ CLAUDE.md | 375 ++++ app/Livewire/Association/Election/Admin.php | 171 ++ app/Livewire/Association/Election/Index.php | 71 + app/Livewire/Association/Election/Show.php | 186 ++ app/Livewire/Association/Members/Admin.php | 66 + app/Livewire/Association/News/Index.php | 122 ++ app/Livewire/Association/Profile.php | 304 +++ .../ProjectSupport/Form/Create.php | 70 + .../Association/ProjectSupport/Form/Edit.php | 75 + .../Association/ProjectSupport/Index.php | 102 + .../Association/ProjectSupport/Show.php | 109 + app/Livewire/Changelog.php | 28 + app/Livewire/EinundzwanzigFeed/Index.php | 51 + app/Livewire/Meetups/Grid.php | 10 + app/Livewire/Meetups/Mockup.php | 102 + app/Livewire/Meetups/Table.php | 10 + app/Livewire/Meetups/Worldmap.php | 20 + app/Livewire/Welcome.php | 10 + app/Providers/VoltServiceProvider.php | 28 - boost.json | 14 + bootstrap/providers.php | 1 - composer.json | 14 +- composer.lock | 1889 ++++++++++------- config/livewire.php | 282 +++ opencode.json | 14 + resources/views/layouts/app.blade.php | 197 ++ .../association/election/admin.blade.php | 74 + .../association/election/index.blade.php | 33 + .../association/election/show.blade.php} | 312 +-- .../association/members/admin.blade.php | 20 + .../association/news/index.blade.php | 176 +- .../association/profile.blade.php | 370 +--- .../project-support/form/create.blade.php | 123 +- .../project-support/form/edit.blade.php} | 129 +- .../project-support/index.blade.php | 75 + .../project-support/show.blade.php} | 177 +- .../{pages => livewire}/changelog.blade.php | 40 - .../einundzwanzig-feed/index.blade.php | 58 +- .../meetups/grid.blade.php | 29 - .../views/livewire/meetups/mockup.blade.php | 35 + .../views/livewire/meetups/table.blade.php | 5 + .../views/livewire/meetups/worldmap.blade.php | 46 + resources/views/livewire/welcome.blade.php | 5 + .../election/admin/[Election:year].blade.php | 257 --- .../association/election/index.blade.php | 103 - .../pages/association/members/admin.blade.php | 93 - .../project-support/index.blade.php | 187 -- resources/views/pages/index.blade.php | 24 - .../views/pages/meetups/mockup.blade.php | 145 -- resources/views/pages/meetups/table.blade.php | 34 - .../views/pages/meetups/worldmap.blade.php | 76 - routes/web.php | 47 + storage/pail/.gitignore | 2 + 58 files changed, 4839 insertions(+), 2930 deletions(-) create mode 100644 .junie/guidelines.md create mode 100644 .junie/mcp/mcp.json create mode 100644 .mcp.json create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 app/Livewire/Association/Election/Admin.php create mode 100644 app/Livewire/Association/Election/Index.php create mode 100644 app/Livewire/Association/Election/Show.php create mode 100644 app/Livewire/Association/Members/Admin.php create mode 100644 app/Livewire/Association/News/Index.php create mode 100644 app/Livewire/Association/Profile.php create mode 100644 app/Livewire/Association/ProjectSupport/Form/Create.php create mode 100644 app/Livewire/Association/ProjectSupport/Form/Edit.php create mode 100644 app/Livewire/Association/ProjectSupport/Index.php create mode 100644 app/Livewire/Association/ProjectSupport/Show.php create mode 100644 app/Livewire/Changelog.php create mode 100644 app/Livewire/EinundzwanzigFeed/Index.php create mode 100644 app/Livewire/Meetups/Grid.php create mode 100644 app/Livewire/Meetups/Mockup.php create mode 100644 app/Livewire/Meetups/Table.php create mode 100644 app/Livewire/Meetups/Worldmap.php create mode 100644 app/Livewire/Welcome.php delete mode 100644 app/Providers/VoltServiceProvider.php create mode 100644 boost.json create mode 100644 config/livewire.php create mode 100644 opencode.json create mode 100644 resources/views/layouts/app.blade.php create mode 100644 resources/views/livewire/association/election/admin.blade.php create mode 100644 resources/views/livewire/association/election/index.blade.php rename resources/views/{pages/association/election/[Election:year].blade.php => livewire/association/election/show.blade.php} (80%) create mode 100644 resources/views/livewire/association/members/admin.blade.php rename resources/views/{pages => livewire}/association/news/index.blade.php (71%) rename resources/views/{pages => livewire}/association/profile.blade.php (67%) rename resources/views/{pages => livewire}/association/project-support/form/create.blade.php (55%) rename resources/views/{pages/association/project-support/form/[ProjectProposal:slug].blade.php => livewire/association/project-support/form/edit.blade.php} (56%) create mode 100644 resources/views/livewire/association/project-support/index.blade.php rename resources/views/{pages/association/project-support/[ProjectProposal:slug].blade.php => livewire/association/project-support/show.blade.php} (56%) rename resources/views/{pages => livewire}/changelog.blade.php (81%) rename resources/views/{pages => livewire}/einundzwanzig-feed/index.blade.php (72%) rename resources/views/{pages => livewire}/meetups/grid.blade.php (96%) create mode 100644 resources/views/livewire/meetups/mockup.blade.php create mode 100644 resources/views/livewire/meetups/table.blade.php create mode 100644 resources/views/livewire/meetups/worldmap.blade.php create mode 100644 resources/views/livewire/welcome.blade.php delete mode 100644 resources/views/pages/association/election/admin/[Election:year].blade.php delete mode 100644 resources/views/pages/association/election/index.blade.php delete mode 100644 resources/views/pages/association/members/admin.blade.php delete mode 100644 resources/views/pages/association/project-support/index.blade.php delete mode 100644 resources/views/pages/index.blade.php delete mode 100644 resources/views/pages/meetups/mockup.blade.php delete mode 100644 resources/views/pages/meetups/table.blade.php delete mode 100644 resources/views/pages/meetups/worldmap.blade.php create mode 100644 storage/pail/.gitignore diff --git a/.gitignore b/.gitignore index 862902c..ebc6cb3 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ yarn-error.log /.idea /.vscode /relay +/storage/media-library diff --git a/.junie/guidelines.md b/.junie/guidelines.md new file mode 100644 index 0000000..f367dec --- /dev/null +++ b/.junie/guidelines.md @@ -0,0 +1,375 @@ + +=== foundation rules === + +# Laravel Boost Guidelines + +The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications. + +## 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.3.29 +- laravel/folio (FOLIO) - v1 +- laravel/framework (LARAVEL) - v11 +- laravel/prompts (PROMPTS) - v0 +- laravel/pulse (PULSE) - v1 +- laravel/reverb (REVERB) - v1 +- laravel/sail (SAIL) - v1 +- laravel/sanctum (SANCTUM) - v4 +- livewire/livewire (LIVEWIRE) - v4 +- laravel/mcp (MCP) - v0 +- laravel/pint (PINT) - v1 +- pestphp/pest (PEST) - v2 +- phpunit/phpunit (PHPUNIT) - v10 +- laravel-echo (ECHO) - v1 +- tailwindcss (TAILWINDCSS) - v3 + +## Conventions +- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming. +- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`. +- Check for existing components to reuse before writing a new one. + +## Verification Scripts +- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important. + +## Application Structure & Architecture +- Stick to existing directory structure; don't create new base folders without approval. +- Do not change the application's dependencies without approval. + +## Frontend Bundling +- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail yarn run build`, `vendor/bin/sail yarn run dev`, or `vendor/bin/sail composer run dev`. Ask them. + +## Replies +- Be concise in your explanations - focus on what's important rather than explaining obvious details. + +## Documentation Files +- You must only create documentation files if explicitly requested by the user. + +=== boost rules === + +## Laravel Boost +- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them. + +## Artisan +- Use the `list-artisan-commands` tool when you need to call an Artisan command to double-check the available parameters. + +## URLs +- Whenever you share a project URL with the user, you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain/IP, and port. + +## Tinker / Debugging +- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly. +- Use the `database-query` tool when you only need to read from the database. + +## Reading Browser Logs With the `browser-logs` Tool +- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost. +- Only recent browser logs will be useful - ignore old logs. + +## Searching Documentation (Critically Important) +- Boost comes with a powerful `search-docs` tool you should use before any other approaches when dealing with Laravel or Laravel ecosystem packages. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages. +- The `search-docs` tool is perfect for all Laravel-related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc. +- You must use this tool to search for Laravel ecosystem documentation before falling back to other approaches. +- Search the documentation before making code changes to ensure we are taking the correct approach. +- Use multiple, broad, simple, topic-based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`. +- Do not add package names to queries; package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`. + +### Available Search Syntax +- You can and should pass multiple queries at once. The most relevant results will be returned first. + +1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'. +2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit". +3. Quoted Phrases (Exact Position) - query="infinite scroll" - words must be adjacent and in that order. +4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit". +5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms. + +=== php rules === + +## PHP + +- Always use curly braces for control structures, even if it has one line. + +### Constructors +- Use PHP 8 constructor property promotion in `__construct()`. + - public function __construct(public GitHub $github) { } +- Do not allow empty `__construct()` methods with zero parameters unless the constructor is private. + +### Type Declarations +- Always use explicit return type declarations for methods and functions. +- Use appropriate PHP type hints for method parameters. + + +protected function isAccessible(User $user, ?string $path = null): bool +{ + ... +} + + +## Comments +- Prefer PHPDoc blocks over inline comments. Never use comments within the code itself unless there is something very complex going on. + +## PHPDoc Blocks +- Add useful array shape type definitions for arrays when appropriate. + +## Enums +- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`. + +=== sail rules === + +## Laravel Sail + +- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail. +- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`. +- Open the application in the browser by running `vendor/bin/sail open`. +- Always prefix PHP, Artisan, Composer, and Node commands with `vendor/bin/sail`. Examples: + - Run Artisan Commands: `vendor/bin/sail artisan migrate` + - Install Composer packages: `vendor/bin/sail composer install` + - Execute Node commands: `vendor/bin/sail yarn run dev` + - Execute PHP scripts: `vendor/bin/sail php [script]` +- View all available Sail commands by running `vendor/bin/sail` without arguments. + +=== folio/core rules === + +## Laravel Folio + +- Laravel Folio is a file-based router. With Laravel Folio, a new route is created for every Blade file within the configured Folio directory. For example, pages are usually in `resources/views/pages/` and the file structure determines routes: + - `pages/index.blade.php` → `/` + - `pages/profile/index.blade.php` → `/profile` + - `pages/auth/login.blade.php` → `/auth/login` +- You may list available Folio routes using `vendor/bin/sail artisan folio:list` or using the `list-routes` tool. + +### New Pages & Routes +- Always create new `folio` pages and routes using `vendor/bin/sail artisan folio:page [name]` following existing naming conventions. + + + // Creates: resources/views/pages/products.blade.php → /products + vendor/bin/sail artisan folio:page "products" + + // Creates: resources/views/pages/products/[id].blade.php → /products/{id} + vendor/bin/sail artisan folio:page "products/[id]" + + +- Add a 'name' to each new Folio page at the very top of the file so it has a named route available for other parts of the codebase to use. + + +use function Laravel\Folio\name; + +name('products.index'); + + +### Support & Documentation +- Folio supports: middleware, serving pages from multiple paths, subdomain routing, named routes, nested routes, index routes, route parameters, and route model binding. +- If available, use the `search-docs` tool to use Folio to its full potential and help the user effectively. + + +use function Laravel\Folio\{name, middleware}; + +name('admin.products'); +middleware(['auth', 'verified', 'can:manage-products']); +?> + + +=== laravel/core rules === + +## Do Things the Laravel Way + +- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool. +- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`. +- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior. + +### Database +- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins. +- Use Eloquent models and relationships before suggesting raw database queries. +- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them. +- Generate code that prevents N+1 query problems by using eager loading. +- Use Laravel's query builder for very complex database operations. + +### Model Creation +- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `vendor/bin/sail artisan make:model`. + +### APIs & Eloquent Resources +- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention. + +### Controllers & Validation +- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages. +- Check sibling Form Requests to see if the application uses array or string based validation rules. + +### Queues +- Use queued jobs for time-consuming operations with the `ShouldQueue` interface. + +### Authentication & Authorization +- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.). + +### URL Generation +- When generating links to other pages, prefer named routes and the `route()` function. + +### Configuration +- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`. + +### Testing +- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model. +- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`. +- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests. + +### Vite Error +- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `vendor/bin/sail yarn run build` or ask the user to run `vendor/bin/sail yarn run dev` or `vendor/bin/sail composer run dev`. + +=== laravel/v11 rules === + +## Laravel 11 + +- Use the `search-docs` tool to get version-specific documentation. +- Laravel 11 brought a new streamlined file structure which this project now uses. + +### Laravel 11 Structure +- In Laravel 11, middleware are no longer registered in `app/Http/Kernel.php`. +- Middleware are configured declaratively in `bootstrap/app.php` using `Application::configure()->withMiddleware()`. +- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files. +- `bootstrap/providers.php` contains application specific service providers. +- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration. +- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration. + +### Database +- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost. +- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`. + +### Models +- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models. + +### New Artisan Commands +- List Artisan commands using Boost's MCP tool, if available. New commands available in Laravel 11: + - `vendor/bin/sail artisan make:enum` + - `vendor/bin/sail artisan make:class` + - `vendor/bin/sail artisan make:interface` + +=== livewire/core rules === + +## Livewire + +- Use the `search-docs` tool to find exact version-specific documentation for how to write Livewire and Livewire tests. +- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` Artisan command to create new components. +- State should live on the server, with the UI reflecting it. +- All Livewire requests hit the Laravel backend; they're like regular HTTP requests. Always validate form data and run authorization checks in Livewire actions. + +## Livewire Best Practices +- Livewire components require a single root element. +- Use `wire:loading` and `wire:dirty` for delightful loading states. +- Add `wire:key` in loops: + + ```blade + @foreach ($items as $item) +
+ {{ $item->name }} +
+ @endforeach + ``` + +- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects: + + + public function mount(User $user) { $this->user = $user; } + public function updatedSearch() { $this->resetPage(); } + + +## Testing Livewire + + + Livewire::test(Counter::class) + ->assertSet('count', 0) + ->call('increment') + ->assertSet('count', 1) + ->assertSee(1) + ->assertStatus(200); + + + + $this->get('/posts/create') + ->assertSeeLivewire(CreatePost::class); + + +=== pint/core rules === + +## Laravel Pint Code Formatter + +- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style. +- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues. + +=== pest/core rules === + +## Pest +### Testing +- If you need to verify a feature is working, write or update a Unit / Feature test. + +### Pest Tests +- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`. +- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application. +- Tests should test all of the happy paths, failure paths, and weird paths. +- Tests live in the `tests/Feature` and `tests/Unit` directories. +- Pest tests look and behave like this: + +it('is true', function () { + expect(true)->toBeTrue(); +}); + + +### Running Tests +- Run the minimal number of tests using an appropriate filter before finalizing code edits. +- To run all tests: `vendor/bin/sail artisan test --compact`. +- To run all tests in a file: `vendor/bin/sail artisan test --compact tests/Feature/ExampleTest.php`. +- To filter on a particular test name: `vendor/bin/sail artisan test --compact --filter=testName` (recommended after making a change to a related file). +- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing. + +### Pest Assertions +- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.: + +it('returns all', function () { + $response = $this->postJson('/api/docs', []); + + $response->assertSuccessful(); +}); + + +### Mocking +- Mocking can be very helpful when appropriate. +- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do. +- You can also create partial mocks using the same import or self method. + +### Datasets +- Use datasets in Pest to simplify tests that have a lot of duplicated data. This is often the case when testing validation rules, so consider this solution when writing tests for validation rules. + + +it('has emails', function (string $email) { + expect($email)->not->toBeEmpty(); +})->with([ + 'james' => 'james@laravel.com', + 'taylor' => 'taylor@laravel.com', +]); + + +=== tailwindcss/core rules === + +## Tailwind CSS + +- Use Tailwind CSS classes to style HTML; check and use existing Tailwind conventions within the project before writing your own. +- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc.). +- Think through class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child carefully to limit repetition, and group elements logically. +- You can use the `search-docs` tool to get exact examples from the official documentation when needed. + +### Spacing +- When listing items, use gap utilities for spacing; don't use margins. + + +
+
Superior
+
Michigan
+
Erie
+
+
+ +### Dark Mode +- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`. + +=== tailwindcss/v3 rules === + +## Tailwind CSS 3 + +- Always use Tailwind CSS v3; verify you're using only classes supported by this version. +
diff --git a/.junie/mcp/mcp.json b/.junie/mcp/mcp.json new file mode 100644 index 0000000..04eba29 --- /dev/null +++ b/.junie/mcp/mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "laravel-boost": { + "command": "vendor/bin/sail", + "args": [ + "artisan", + "boost:mcp" + ] + } + } +} \ No newline at end of file diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..04eba29 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "laravel-boost": { + "command": "vendor/bin/sail", + "args": [ + "artisan", + "boost:mcp" + ] + } + } +} \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f367dec --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,375 @@ + +=== foundation rules === + +# Laravel Boost Guidelines + +The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications. + +## 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.3.29 +- laravel/folio (FOLIO) - v1 +- laravel/framework (LARAVEL) - v11 +- laravel/prompts (PROMPTS) - v0 +- laravel/pulse (PULSE) - v1 +- laravel/reverb (REVERB) - v1 +- laravel/sail (SAIL) - v1 +- laravel/sanctum (SANCTUM) - v4 +- livewire/livewire (LIVEWIRE) - v4 +- laravel/mcp (MCP) - v0 +- laravel/pint (PINT) - v1 +- pestphp/pest (PEST) - v2 +- phpunit/phpunit (PHPUNIT) - v10 +- laravel-echo (ECHO) - v1 +- tailwindcss (TAILWINDCSS) - v3 + +## Conventions +- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming. +- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`. +- Check for existing components to reuse before writing a new one. + +## Verification Scripts +- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important. + +## Application Structure & Architecture +- Stick to existing directory structure; don't create new base folders without approval. +- Do not change the application's dependencies without approval. + +## Frontend Bundling +- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail yarn run build`, `vendor/bin/sail yarn run dev`, or `vendor/bin/sail composer run dev`. Ask them. + +## Replies +- Be concise in your explanations - focus on what's important rather than explaining obvious details. + +## Documentation Files +- You must only create documentation files if explicitly requested by the user. + +=== boost rules === + +## Laravel Boost +- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them. + +## Artisan +- Use the `list-artisan-commands` tool when you need to call an Artisan command to double-check the available parameters. + +## URLs +- Whenever you share a project URL with the user, you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain/IP, and port. + +## Tinker / Debugging +- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly. +- Use the `database-query` tool when you only need to read from the database. + +## Reading Browser Logs With the `browser-logs` Tool +- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost. +- Only recent browser logs will be useful - ignore old logs. + +## Searching Documentation (Critically Important) +- Boost comes with a powerful `search-docs` tool you should use before any other approaches when dealing with Laravel or Laravel ecosystem packages. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages. +- The `search-docs` tool is perfect for all Laravel-related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc. +- You must use this tool to search for Laravel ecosystem documentation before falling back to other approaches. +- Search the documentation before making code changes to ensure we are taking the correct approach. +- Use multiple, broad, simple, topic-based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`. +- Do not add package names to queries; package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`. + +### Available Search Syntax +- You can and should pass multiple queries at once. The most relevant results will be returned first. + +1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'. +2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit". +3. Quoted Phrases (Exact Position) - query="infinite scroll" - words must be adjacent and in that order. +4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit". +5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms. + +=== php rules === + +## PHP + +- Always use curly braces for control structures, even if it has one line. + +### Constructors +- Use PHP 8 constructor property promotion in `__construct()`. + - public function __construct(public GitHub $github) { } +- Do not allow empty `__construct()` methods with zero parameters unless the constructor is private. + +### Type Declarations +- Always use explicit return type declarations for methods and functions. +- Use appropriate PHP type hints for method parameters. + + +protected function isAccessible(User $user, ?string $path = null): bool +{ + ... +} + + +## Comments +- Prefer PHPDoc blocks over inline comments. Never use comments within the code itself unless there is something very complex going on. + +## PHPDoc Blocks +- Add useful array shape type definitions for arrays when appropriate. + +## Enums +- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`. + +=== sail rules === + +## Laravel Sail + +- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail. +- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`. +- Open the application in the browser by running `vendor/bin/sail open`. +- Always prefix PHP, Artisan, Composer, and Node commands with `vendor/bin/sail`. Examples: + - Run Artisan Commands: `vendor/bin/sail artisan migrate` + - Install Composer packages: `vendor/bin/sail composer install` + - Execute Node commands: `vendor/bin/sail yarn run dev` + - Execute PHP scripts: `vendor/bin/sail php [script]` +- View all available Sail commands by running `vendor/bin/sail` without arguments. + +=== folio/core rules === + +## Laravel Folio + +- Laravel Folio is a file-based router. With Laravel Folio, a new route is created for every Blade file within the configured Folio directory. For example, pages are usually in `resources/views/pages/` and the file structure determines routes: + - `pages/index.blade.php` → `/` + - `pages/profile/index.blade.php` → `/profile` + - `pages/auth/login.blade.php` → `/auth/login` +- You may list available Folio routes using `vendor/bin/sail artisan folio:list` or using the `list-routes` tool. + +### New Pages & Routes +- Always create new `folio` pages and routes using `vendor/bin/sail artisan folio:page [name]` following existing naming conventions. + + + // Creates: resources/views/pages/products.blade.php → /products + vendor/bin/sail artisan folio:page "products" + + // Creates: resources/views/pages/products/[id].blade.php → /products/{id} + vendor/bin/sail artisan folio:page "products/[id]" + + +- Add a 'name' to each new Folio page at the very top of the file so it has a named route available for other parts of the codebase to use. + + +use function Laravel\Folio\name; + +name('products.index'); + + +### Support & Documentation +- Folio supports: middleware, serving pages from multiple paths, subdomain routing, named routes, nested routes, index routes, route parameters, and route model binding. +- If available, use the `search-docs` tool to use Folio to its full potential and help the user effectively. + + +use function Laravel\Folio\{name, middleware}; + +name('admin.products'); +middleware(['auth', 'verified', 'can:manage-products']); +?> + + +=== laravel/core rules === + +## Do Things the Laravel Way + +- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool. +- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`. +- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior. + +### Database +- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins. +- Use Eloquent models and relationships before suggesting raw database queries. +- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them. +- Generate code that prevents N+1 query problems by using eager loading. +- Use Laravel's query builder for very complex database operations. + +### Model Creation +- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `vendor/bin/sail artisan make:model`. + +### APIs & Eloquent Resources +- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention. + +### Controllers & Validation +- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages. +- Check sibling Form Requests to see if the application uses array or string based validation rules. + +### Queues +- Use queued jobs for time-consuming operations with the `ShouldQueue` interface. + +### Authentication & Authorization +- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.). + +### URL Generation +- When generating links to other pages, prefer named routes and the `route()` function. + +### Configuration +- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`. + +### Testing +- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model. +- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`. +- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests. + +### Vite Error +- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `vendor/bin/sail yarn run build` or ask the user to run `vendor/bin/sail yarn run dev` or `vendor/bin/sail composer run dev`. + +=== laravel/v11 rules === + +## Laravel 11 + +- Use the `search-docs` tool to get version-specific documentation. +- Laravel 11 brought a new streamlined file structure which this project now uses. + +### Laravel 11 Structure +- In Laravel 11, middleware are no longer registered in `app/Http/Kernel.php`. +- Middleware are configured declaratively in `bootstrap/app.php` using `Application::configure()->withMiddleware()`. +- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files. +- `bootstrap/providers.php` contains application specific service providers. +- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration. +- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration. + +### Database +- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost. +- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`. + +### Models +- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models. + +### New Artisan Commands +- List Artisan commands using Boost's MCP tool, if available. New commands available in Laravel 11: + - `vendor/bin/sail artisan make:enum` + - `vendor/bin/sail artisan make:class` + - `vendor/bin/sail artisan make:interface` + +=== livewire/core rules === + +## Livewire + +- Use the `search-docs` tool to find exact version-specific documentation for how to write Livewire and Livewire tests. +- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` Artisan command to create new components. +- State should live on the server, with the UI reflecting it. +- All Livewire requests hit the Laravel backend; they're like regular HTTP requests. Always validate form data and run authorization checks in Livewire actions. + +## Livewire Best Practices +- Livewire components require a single root element. +- Use `wire:loading` and `wire:dirty` for delightful loading states. +- Add `wire:key` in loops: + + ```blade + @foreach ($items as $item) +
+ {{ $item->name }} +
+ @endforeach + ``` + +- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects: + + + public function mount(User $user) { $this->user = $user; } + public function updatedSearch() { $this->resetPage(); } + + +## Testing Livewire + + + Livewire::test(Counter::class) + ->assertSet('count', 0) + ->call('increment') + ->assertSet('count', 1) + ->assertSee(1) + ->assertStatus(200); + + + + $this->get('/posts/create') + ->assertSeeLivewire(CreatePost::class); + + +=== pint/core rules === + +## Laravel Pint Code Formatter + +- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style. +- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues. + +=== pest/core rules === + +## Pest +### Testing +- If you need to verify a feature is working, write or update a Unit / Feature test. + +### Pest Tests +- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`. +- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application. +- Tests should test all of the happy paths, failure paths, and weird paths. +- Tests live in the `tests/Feature` and `tests/Unit` directories. +- Pest tests look and behave like this: + +it('is true', function () { + expect(true)->toBeTrue(); +}); + + +### Running Tests +- Run the minimal number of tests using an appropriate filter before finalizing code edits. +- To run all tests: `vendor/bin/sail artisan test --compact`. +- To run all tests in a file: `vendor/bin/sail artisan test --compact tests/Feature/ExampleTest.php`. +- To filter on a particular test name: `vendor/bin/sail artisan test --compact --filter=testName` (recommended after making a change to a related file). +- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing. + +### Pest Assertions +- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.: + +it('returns all', function () { + $response = $this->postJson('/api/docs', []); + + $response->assertSuccessful(); +}); + + +### Mocking +- Mocking can be very helpful when appropriate. +- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do. +- You can also create partial mocks using the same import or self method. + +### Datasets +- Use datasets in Pest to simplify tests that have a lot of duplicated data. This is often the case when testing validation rules, so consider this solution when writing tests for validation rules. + + +it('has emails', function (string $email) { + expect($email)->not->toBeEmpty(); +})->with([ + 'james' => 'james@laravel.com', + 'taylor' => 'taylor@laravel.com', +]); + + +=== tailwindcss/core rules === + +## Tailwind CSS + +- Use Tailwind CSS classes to style HTML; check and use existing Tailwind conventions within the project before writing your own. +- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc.). +- Think through class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child carefully to limit repetition, and group elements logically. +- You can use the `search-docs` tool to get exact examples from the official documentation when needed. + +### Spacing +- When listing items, use gap utilities for spacing; don't use margins. + + +
+
Superior
+
Michigan
+
Erie
+
+
+ +### Dark Mode +- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`. + +=== tailwindcss/v3 rules === + +## Tailwind CSS 3 + +- Always use Tailwind CSS v3; verify you're using only classes supported by this version. +
diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f367dec --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,375 @@ + +=== foundation rules === + +# Laravel Boost Guidelines + +The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications. + +## 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.3.29 +- laravel/folio (FOLIO) - v1 +- laravel/framework (LARAVEL) - v11 +- laravel/prompts (PROMPTS) - v0 +- laravel/pulse (PULSE) - v1 +- laravel/reverb (REVERB) - v1 +- laravel/sail (SAIL) - v1 +- laravel/sanctum (SANCTUM) - v4 +- livewire/livewire (LIVEWIRE) - v4 +- laravel/mcp (MCP) - v0 +- laravel/pint (PINT) - v1 +- pestphp/pest (PEST) - v2 +- phpunit/phpunit (PHPUNIT) - v10 +- laravel-echo (ECHO) - v1 +- tailwindcss (TAILWINDCSS) - v3 + +## Conventions +- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming. +- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`. +- Check for existing components to reuse before writing a new one. + +## Verification Scripts +- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important. + +## Application Structure & Architecture +- Stick to existing directory structure; don't create new base folders without approval. +- Do not change the application's dependencies without approval. + +## Frontend Bundling +- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail yarn run build`, `vendor/bin/sail yarn run dev`, or `vendor/bin/sail composer run dev`. Ask them. + +## Replies +- Be concise in your explanations - focus on what's important rather than explaining obvious details. + +## Documentation Files +- You must only create documentation files if explicitly requested by the user. + +=== boost rules === + +## Laravel Boost +- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them. + +## Artisan +- Use the `list-artisan-commands` tool when you need to call an Artisan command to double-check the available parameters. + +## URLs +- Whenever you share a project URL with the user, you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain/IP, and port. + +## Tinker / Debugging +- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly. +- Use the `database-query` tool when you only need to read from the database. + +## Reading Browser Logs With the `browser-logs` Tool +- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost. +- Only recent browser logs will be useful - ignore old logs. + +## Searching Documentation (Critically Important) +- Boost comes with a powerful `search-docs` tool you should use before any other approaches when dealing with Laravel or Laravel ecosystem packages. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages. +- The `search-docs` tool is perfect for all Laravel-related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc. +- You must use this tool to search for Laravel ecosystem documentation before falling back to other approaches. +- Search the documentation before making code changes to ensure we are taking the correct approach. +- Use multiple, broad, simple, topic-based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`. +- Do not add package names to queries; package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`. + +### Available Search Syntax +- You can and should pass multiple queries at once. The most relevant results will be returned first. + +1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'. +2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit". +3. Quoted Phrases (Exact Position) - query="infinite scroll" - words must be adjacent and in that order. +4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit". +5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms. + +=== php rules === + +## PHP + +- Always use curly braces for control structures, even if it has one line. + +### Constructors +- Use PHP 8 constructor property promotion in `__construct()`. + - public function __construct(public GitHub $github) { } +- Do not allow empty `__construct()` methods with zero parameters unless the constructor is private. + +### Type Declarations +- Always use explicit return type declarations for methods and functions. +- Use appropriate PHP type hints for method parameters. + + +protected function isAccessible(User $user, ?string $path = null): bool +{ + ... +} + + +## Comments +- Prefer PHPDoc blocks over inline comments. Never use comments within the code itself unless there is something very complex going on. + +## PHPDoc Blocks +- Add useful array shape type definitions for arrays when appropriate. + +## Enums +- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`. + +=== sail rules === + +## Laravel Sail + +- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail. +- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`. +- Open the application in the browser by running `vendor/bin/sail open`. +- Always prefix PHP, Artisan, Composer, and Node commands with `vendor/bin/sail`. Examples: + - Run Artisan Commands: `vendor/bin/sail artisan migrate` + - Install Composer packages: `vendor/bin/sail composer install` + - Execute Node commands: `vendor/bin/sail yarn run dev` + - Execute PHP scripts: `vendor/bin/sail php [script]` +- View all available Sail commands by running `vendor/bin/sail` without arguments. + +=== folio/core rules === + +## Laravel Folio + +- Laravel Folio is a file-based router. With Laravel Folio, a new route is created for every Blade file within the configured Folio directory. For example, pages are usually in `resources/views/pages/` and the file structure determines routes: + - `pages/index.blade.php` → `/` + - `pages/profile/index.blade.php` → `/profile` + - `pages/auth/login.blade.php` → `/auth/login` +- You may list available Folio routes using `vendor/bin/sail artisan folio:list` or using the `list-routes` tool. + +### New Pages & Routes +- Always create new `folio` pages and routes using `vendor/bin/sail artisan folio:page [name]` following existing naming conventions. + + + // Creates: resources/views/pages/products.blade.php → /products + vendor/bin/sail artisan folio:page "products" + + // Creates: resources/views/pages/products/[id].blade.php → /products/{id} + vendor/bin/sail artisan folio:page "products/[id]" + + +- Add a 'name' to each new Folio page at the very top of the file so it has a named route available for other parts of the codebase to use. + + +use function Laravel\Folio\name; + +name('products.index'); + + +### Support & Documentation +- Folio supports: middleware, serving pages from multiple paths, subdomain routing, named routes, nested routes, index routes, route parameters, and route model binding. +- If available, use the `search-docs` tool to use Folio to its full potential and help the user effectively. + + +use function Laravel\Folio\{name, middleware}; + +name('admin.products'); +middleware(['auth', 'verified', 'can:manage-products']); +?> + + +=== laravel/core rules === + +## Do Things the Laravel Way + +- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool. +- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`. +- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior. + +### Database +- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins. +- Use Eloquent models and relationships before suggesting raw database queries. +- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them. +- Generate code that prevents N+1 query problems by using eager loading. +- Use Laravel's query builder for very complex database operations. + +### Model Creation +- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `vendor/bin/sail artisan make:model`. + +### APIs & Eloquent Resources +- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention. + +### Controllers & Validation +- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages. +- Check sibling Form Requests to see if the application uses array or string based validation rules. + +### Queues +- Use queued jobs for time-consuming operations with the `ShouldQueue` interface. + +### Authentication & Authorization +- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.). + +### URL Generation +- When generating links to other pages, prefer named routes and the `route()` function. + +### Configuration +- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`. + +### Testing +- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model. +- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`. +- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests. + +### Vite Error +- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `vendor/bin/sail yarn run build` or ask the user to run `vendor/bin/sail yarn run dev` or `vendor/bin/sail composer run dev`. + +=== laravel/v11 rules === + +## Laravel 11 + +- Use the `search-docs` tool to get version-specific documentation. +- Laravel 11 brought a new streamlined file structure which this project now uses. + +### Laravel 11 Structure +- In Laravel 11, middleware are no longer registered in `app/Http/Kernel.php`. +- Middleware are configured declaratively in `bootstrap/app.php` using `Application::configure()->withMiddleware()`. +- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files. +- `bootstrap/providers.php` contains application specific service providers. +- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration. +- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration. + +### Database +- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost. +- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`. + +### Models +- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models. + +### New Artisan Commands +- List Artisan commands using Boost's MCP tool, if available. New commands available in Laravel 11: + - `vendor/bin/sail artisan make:enum` + - `vendor/bin/sail artisan make:class` + - `vendor/bin/sail artisan make:interface` + +=== livewire/core rules === + +## Livewire + +- Use the `search-docs` tool to find exact version-specific documentation for how to write Livewire and Livewire tests. +- Use the `vendor/bin/sail artisan make:livewire [Posts\CreatePost]` Artisan command to create new components. +- State should live on the server, with the UI reflecting it. +- All Livewire requests hit the Laravel backend; they're like regular HTTP requests. Always validate form data and run authorization checks in Livewire actions. + +## Livewire Best Practices +- Livewire components require a single root element. +- Use `wire:loading` and `wire:dirty` for delightful loading states. +- Add `wire:key` in loops: + + ```blade + @foreach ($items as $item) +
+ {{ $item->name }} +
+ @endforeach + ``` + +- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects: + + + public function mount(User $user) { $this->user = $user; } + public function updatedSearch() { $this->resetPage(); } + + +## Testing Livewire + + + Livewire::test(Counter::class) + ->assertSet('count', 0) + ->call('increment') + ->assertSet('count', 1) + ->assertSee(1) + ->assertStatus(200); + + + + $this->get('/posts/create') + ->assertSeeLivewire(CreatePost::class); + + +=== pint/core rules === + +## Laravel Pint Code Formatter + +- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style. +- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues. + +=== pest/core rules === + +## Pest +### Testing +- If you need to verify a feature is working, write or update a Unit / Feature test. + +### Pest Tests +- All tests must be written using Pest. Use `vendor/bin/sail artisan make:test --pest {name}`. +- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application. +- Tests should test all of the happy paths, failure paths, and weird paths. +- Tests live in the `tests/Feature` and `tests/Unit` directories. +- Pest tests look and behave like this: + +it('is true', function () { + expect(true)->toBeTrue(); +}); + + +### Running Tests +- Run the minimal number of tests using an appropriate filter before finalizing code edits. +- To run all tests: `vendor/bin/sail artisan test --compact`. +- To run all tests in a file: `vendor/bin/sail artisan test --compact tests/Feature/ExampleTest.php`. +- To filter on a particular test name: `vendor/bin/sail artisan test --compact --filter=testName` (recommended after making a change to a related file). +- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing. + +### Pest Assertions +- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.: + +it('returns all', function () { + $response = $this->postJson('/api/docs', []); + + $response->assertSuccessful(); +}); + + +### Mocking +- Mocking can be very helpful when appropriate. +- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do. +- You can also create partial mocks using the same import or self method. + +### Datasets +- Use datasets in Pest to simplify tests that have a lot of duplicated data. This is often the case when testing validation rules, so consider this solution when writing tests for validation rules. + + +it('has emails', function (string $email) { + expect($email)->not->toBeEmpty(); +})->with([ + 'james' => 'james@laravel.com', + 'taylor' => 'taylor@laravel.com', +]); + + +=== tailwindcss/core rules === + +## Tailwind CSS + +- Use Tailwind CSS classes to style HTML; check and use existing Tailwind conventions within the project before writing your own. +- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc.). +- Think through class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child carefully to limit repetition, and group elements logically. +- You can use the `search-docs` tool to get exact examples from the official documentation when needed. + +### Spacing +- When listing items, use gap utilities for spacing; don't use margins. + + +
+
Superior
+
Michigan
+
Erie
+
+
+ +### Dark Mode +- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`. + +=== tailwindcss/v3 rules === + +## Tailwind CSS 3 + +- Always use Tailwind CSS v3; verify you're using only classes supported by this version. +
diff --git a/app/Livewire/Association/Election/Admin.php b/app/Livewire/Association/Election/Admin.php new file mode 100644 index 0000000..35e93b8 --- /dev/null +++ b/app/Livewire/Association/Election/Admin.php @@ -0,0 +1,171 @@ + 'handleNostrLoggedOut', + 'nostrLoggedIn' => 'handleNostrLoggedIn', + 'echo:votes,.newVote' => 'handleNewVote', + ]; + + public function mount(Election $election): void + { + $this->election = $election; + $this->loadEvents(); + $this->loadBoardEvents(); + $this->loadVotes(); + $this->loadBoardVotes(); + } + + public function handleNostrLoggedOut(): void + { + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function handleNostrLoggedIn($pubkey): void + { + $this->currentPubkey = $pubkey; + $allowedPubkeys = [ + '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033', + '430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279', + ]; + if (in_array($this->currentPubkey, $allowedPubkeys, true)) { + $this->isAllowed = true; + } + dd($this->isAllowed); + } + + public function handleNewVote(): void + { + $this->loadEvents(); + $this->loadBoardEvents(); + $this->loadVotes(); + $this->loadBoardVotes(); + } + + public function loadVotes(): void + { + $this->votes = collect($this->events) + ->map(fn ($event) => [ + 'created_at' => $event['created_at'], + 'pubkey' => $event['pubkey'], + 'forpubkey' => $this->fetchProfile($event['content']), + 'type' => str($event['content'])->after(',')->toString(), + ]) + ->sortByDesc('created_at') + ->unique(fn ($event) => $event['pubkey'].$event['type']) + ->values() + ->groupBy('type') + ->map(fn ($votes) => [ + 'type' => $votes[0]['type'], + 'votes' => $votes->groupBy('forpubkey')->map(fn ($group) => ['count' => $group->count()])->toArray(), + ]) + ->values() + ->toArray(); + } + + public function loadBoardVotes(): void + { + $this->boardVotes = collect($this->boardEvents) + ->map(fn ($event) => [ + 'created_at' => $event['created_at'], + 'pubkey' => $event['pubkey'], + 'forpubkey' => $this->fetchProfile($event['content']), + 'type' => str($event['content'])->after(',')->toString(), + ]) + ->sortByDesc('created_at') + ->values() + ->groupBy('type') + ->map(fn ($votes) => [ + 'type' => $votes[0]['type'], + 'votes' => $votes->groupBy('forpubkey')->map(fn ($group) => ['count' => $group->count()])->toArray(), + ]) + ->values() + ->toArray(); + } + + public function loadEvents(): void + { + $this->events = $this->loadNostrEvents([32122]); + } + + public function loadBoardEvents(): void + { + $this->boardEvents = $this->loadNostrEvents([2121]); + } + + public function fetchProfile($content): string + { + $pubkey = str($content)->before(',')->toString(); + $profile = \App\Models\Profile::query()->where('pubkey', $pubkey)->first(); + if (! $profile) { + \Artisan::call(\App\Console\Commands\Nostr\FetchProfile::class, ['--pubkey' => $pubkey]); + $profile = \App\Models\Profile::query()->where('pubkey', $pubkey)->first(); + } + + return $profile->pubkey; + } + + public function loadNostrEvents($kinds): array + { + $subscription = new Subscription; + $subscriptionId = $subscription->setId(); + $filter = new Filter; + $filter->setKinds($kinds); + $requestMessage = new RequestMessage($subscriptionId, [$filter]); + $relaySet = new RelaySet; + $relaySet->setRelays([new Relay(config('services.relay'))]); + $request = new Request($relaySet, $requestMessage); + $response = $request->send(); + + return collect($response[config('services.relay')]) + ->map(function ($event) { + if (! isset($event->event)) { + return false; + } + + return [ + 'id' => $event->event->id, + 'kind' => $event->event->kind, + 'content' => $event->event->content, + 'pubkey' => $event->event->pubkey, + 'tags' => $event->event->tags, + 'created_at' => $event->event->created_at, + ]; + }) + ->filter() + ->toArray(); + } +} diff --git a/app/Livewire/Association/Election/Index.php b/app/Livewire/Association/Election/Index.php new file mode 100644 index 0000000..eb4c3be --- /dev/null +++ b/app/Livewire/Association/Election/Index.php @@ -0,0 +1,71 @@ + 'handleNostrLoggedOut', + 'nostrLoggedIn' => 'handleNostrLoggedIn', + ]; + + public function mount(): void + { + $this->elections = Election::query() + ->get() + ->toArray(); + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $logPubkeys = [ + '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033', + '430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279', + ]; + if (in_array($this->currentPubkey, $logPubkeys, true)) { + $this->isAllowed = true; + } + } + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + $this->currentPubkey = $pubkey; + $this->currentPleb = \App\Models\EinundzwanzigPleb::query() + ->where('pubkey', $pubkey)->first(); + $logPubkeys = [ + '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033', + '430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279', + ]; + if (in_array($this->currentPubkey, $logPubkeys, true)) { + $this->isAllowed = true; + } + } + + public function saveElection($index): void + { + $election = $this->elections[$index]; + $electionModel = Election::find($election['id']); + $electionModel->candidates = $election['candidates']; + $electionModel->save(); + } +} diff --git a/app/Livewire/Association/Election/Show.php b/app/Livewire/Association/Election/Show.php new file mode 100644 index 0000000..b6e0185 --- /dev/null +++ b/app/Livewire/Association/Election/Show.php @@ -0,0 +1,186 @@ + 'handleNostrLoggedIn', + 'nostrLoggedOut' => 'handleNostrLoggedOut', + 'echo:votes,.newVote' => 'handleNewVote', + ]; + + public function mount(Election $election): void + { + $this->election = $election; + $this->plebs = EinundzwanzigPleb::query() + ->with(['profile']) + ->whereIn('association_status', [3, 4]) + ->orderBy('association_status', 'desc') + ->get() + ->toArray(); + $this->loadEvents(); + $this->loadBoardEvents(); + if ($this->election->end_time?->isPast() || ! config('services.voting')) { + $this->isNotClosed = false; + } + } + + public function updatedSearch($value): void + { + $this->plebs = EinundzwanzigPleb::query() + ->with(['profile']) + ->whereIn('association_status', [3, 4]) + ->where(fn ($query) => $query + ->where('pubkey', 'like', "%$value%") + ->orWhereHas('profile', fn ($query) => $query->where('name', 'ilike', "%$value%"))) + ->orderBy('association_status', 'desc') + ->get() + ->toArray(); + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + $this->currentPubkey = $pubkey; + $this->currentPleb = EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); + $logPubkeys = [ + '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033', + '430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279', + ]; + if (in_array($this->currentPubkey, $logPubkeys, true)) { + $this->showLog = true; + $this->isAllowed = true; + } + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function handleNewVote(): void + { + $this->loadEvents(); + $this->loadBoardEvents(); + } + + public function loadEvents(): void + { + $this->events = $this->loadNostrEvents([32122]); + } + + public function loadBoardEvents(): void + { + $this->boardEvents = $this->loadNostrEvents([2121]); + } + + public function loadNostrEvents($kinds): array + { + $subscription = new Subscription; + $subscriptionId = $subscription->setId(); + $filter = new Filter; + $filter->setKinds($kinds); + $requestMessage = new RequestMessage($subscriptionId, [$filter]); + $relaySet = new RelaySet; + $relaySet->setRelays([new Relay(config('services.relay'))]); + $request = new Request($relaySet, $requestMessage); + $response = $request->send(); + + return collect($response[config('services.relay')]) + ->map(function ($event) { + if (! isset($event->event)) { + return false; + } + + return [ + 'id' => $event->event->id, + 'kind' => $event->event->kind, + 'content' => $event->event->content, + 'pubkey' => $event->event->pubkey, + 'tags' => $event->event->tags, + 'created_at' => $event->event->created_at, + ]; + }) + ->filter() + ->toArray(); + } + + public function vote($pubkey, $type, $board = false): void + { + if ($this->election->end_time?->isPast()) { + $this->isNotClosed = false; + + return; + } + $note = new NostrEvent; + $note->setKind($board ? 2121 : 32122); + if (! $board) { + $dTag = sprintf('%s,%s,%s', $this->currentPleb->pubkey, date('Y'), $type); + $note->setTags([['d', $dTag]]); + } + $note->setContent("$pubkey,$type"); + $this->signThisEvent = $note->toJson(); + } + + public function checkElection(): void + { + if ($this->election->end_time?->isPast()) { + $this->isNotClosed = false; + } + } + + public function signEvent($event): void + { + $note = new NostrEvent; + $note->setId($event['id']); + $note->setSignature($event['sig']); + $note->setKind($event['kind']); + $note->setContent($event['content']); + $note->setPublicKey($event['pubkey']); + $note->setTags($event['tags']); + $note->setCreatedAt($event['created_at']); + $eventMessage = new EventMessage($note); + $relay = new Relay(config('services.relay')); + $relay->setMessage($eventMessage); + $relay->send(); + \App\Support\Broadcast::on('votes')->as('newVote')->sendNow(); + } +} diff --git a/app/Livewire/Association/Members/Admin.php b/app/Livewire/Association/Members/Admin.php new file mode 100644 index 0000000..3935a3a --- /dev/null +++ b/app/Livewire/Association/Members/Admin.php @@ -0,0 +1,66 @@ + 'handleNostrLoggedOut', + 'nostrLoggedIn' => 'handleNostrLoggedIn', + ]; + + public function mount(): void + { + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $this->currentPleb = \App\Models\EinundzwanzigPleb::query() + ->where('pubkey', $this->currentPubkey)->first(); + $allowedPubkeys = [ + '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033', + '430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279', + '7acf30cf60b85c62b8f654556cc21e4016df8f5604b3b6892794f88bb80d7a1d', + 'f240be2b684f85cc81566f2081386af81d7427ea86250c8bde6b7a8500c761ba', + '19e358b8011f5f4fc653c565c6d4c2f33f32661f4f90982c9eedc292a8774ec3', + 'acbcec475a1a4f9481939ecfbd1c3d111f5b5a474a39ae039bbc720fdd305bec', + ]; + if (in_array($this->currentPubkey, $allowedPubkeys, true)) { + $this->isAllowed = true; + } + } + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + $this->currentPubkey = $pubkey; + $this->currentPleb = \App\Models\EinundzwanzigPleb::query() + ->where('pubkey', $pubkey)->first(); + $allowedPubkeys = [ + '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033', + '430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279', + '7acf30cf60b85c62b8f654556cc21e4016df8f5604b3b6892794f88bb80d7a1d', + 'f240be2b684f85cc81566f2081386af81d7427ea86250c8bde6b7a8500c761ba', + '19e358b8011f5f4fc653c565c6d4c2f33f32661f4f90982c9eedc292a8774ec3', + 'acbcec475a1a4f9481939ecfbd1c3d111f5b5a474a39ae039bbc720fdd305bec', + ]; + if (in_array($this->currentPubkey, $allowedPubkeys, true)) { + $this->isAllowed = true; + } + } +} diff --git a/app/Livewire/Association/News/Index.php b/app/Livewire/Association/News/Index.php new file mode 100644 index 0000000..64e1664 --- /dev/null +++ b/app/Livewire/Association/News/Index.php @@ -0,0 +1,122 @@ + 'handleNostrLoggedIn', + 'nostrLoggedOut' => 'handleNostrLoggedOut', + ]; + + public function mount(): void + { + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $this->currentPubkey)->first(); + if (in_array($this->currentPleb->npub, config('einundzwanzig.config.current_board'), true)) { + $this->canEdit = true; + } + $this->isAllowed = true; + } + $this->refreshNews(); + } + + public function refreshNews(): void + { + $this->news = Notification::query() + ->orderBy('created_at', 'desc') + ->get(); + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + $this->currentPubkey = $pubkey; + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); + if (in_array($this->currentPleb->npub, config('einundzwanzig.config.current_board'), true)) { + $this->canEdit = true; + } + $this->isAllowed = true; + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function save(): void + { + $this->form->validate(); + + $this->validate([ + 'file' => 'required|file|mimes:pdf|max:1024', + ]); + + $notification = Notification::query() + ->orderBy('created_at', 'desc') + ->create([ + 'einundzwanzig_pleb_id' => $this->currentPleb->id, + 'category' => $this->form->category, + 'name' => $this->form->name, + 'description' => $this->form->description, + ]); + + $notification + ->addMedia($this->file->getRealPath()) + ->usingName($this->file->getClientOriginalName()) + ->toMediaCollection('pdf'); + + $this->form->reset(); + $this->file = null; + + $this->refreshNews(); + } + + public function delete($id): void + { + $notification = new WireNotification($this); + $notification->confirm([ + 'title' => 'Post löschen', + 'message' => 'Bist du sicher, dass du diesen Post löschen möchtest?', + 'accept' => [ + 'label' => 'Ja, löschen', + 'method' => 'deleteNow', + 'params' => $id, + ], + ]); + } + + public function deleteNow($id): void + { + $notification = Notification::query()->find($id); + $notification->delete(); + $this->refreshNews(); + } +} diff --git a/app/Livewire/Association/Profile.php b/app/Livewire/Association/Profile.php new file mode 100644 index 0000000..19288fe --- /dev/null +++ b/app/Livewire/Association/Profile.php @@ -0,0 +1,304 @@ + 'handleNostrLoggedIn', + 'nostrLoggedOut' => 'handleNostrLoggedOut', + ]; + + public function mount(): void + { + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $this->currentPleb = EinundzwanzigPleb::query() + ->with([ + 'paymentEvents' => fn ($query) => $query->where('year', date('Y')), + ]) + ->where('pubkey', $this->currentPubkey)->first(); + $this->email = $this->currentPleb->email; + $this->no = $this->currentPleb->no_email; + $this->showEmail = ! $this->no; + if ($this->currentPleb->association_status === AssociationStatus::ACTIVE) { + $this->amountToPay = config('app.env') === 'production' ? 21000 : 1; + } + if ($this->currentPleb->paymentEvents->count() < 1) { + $this->createPaymentEvent(); + $this->currentPleb->load('paymentEvents'); + } + $this->loadEvents(); + $this->listenForPayment(); + } + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + + $this->currentPubkey = $pubkey; + $this->currentPleb = EinundzwanzigPleb::query() + ->with([ + 'paymentEvents' => fn ($query) => $query->where('year', date('Y')), + ]) + ->where('pubkey', $pubkey)->first(); + $this->email = $this->currentPleb->email; + $this->no = $this->currentPleb->no_email; + $this->showEmail = ! $this->no; + if ($this->currentPleb->association_status === AssociationStatus::ACTIVE) { + $this->amountToPay = config('app.env') === 'production' ? 21000 : 1; + } + if ($this->currentPleb->paymentEvents->count() < 1) { + $this->createPaymentEvent(); + $this->currentPleb->load('paymentEvents'); + } + $this->loadEvents(); + $this->listenForPayment(); + } + + public function handleNostrLoggedOut(): void + { + NostrAuth::logout(); + + $this->currentPubkey = null; + $this->currentPleb = null; + $this->yearsPaid = []; + $this->events = []; + $this->payments = []; + $this->qrCode = null; + $this->amountToPay = config('app.env') === 'production' ? 21000 : 1; + $this->currentYearIsPaid = false; + } + + public function updatedNo(): void + { + $this->showEmail = ! $this->no; + $this->currentPleb->update([ + 'no_email' => $this->no, + ]); + } + + public function updatedFax(): void + { + $this->js('alert("Markus Turm wird sich per Fax melden!")'); + } + + public function saveEmail(): void + { + $this->validate([ + 'email' => 'required|email', + ]); + $this->currentPleb->update([ + 'email' => $this->email, + ]); + $notification = new Notification($this); + $notification->success('E-Mail Adresse gespeichert.'); + } + + public function pay($comment): \Illuminate\Http\RedirectResponse + { + $paymentEvent = $this->currentPleb + ->paymentEvents() + ->where('year', date('Y')) + ->first(); + if ($paymentEvent->btc_pay_invoice) { + return redirect('https://pay.einundzwanzig.space/i/'.$paymentEvent->btc_pay_invoice); + } + try { + $response = \Illuminate\Support\Facades\Http::withHeaders([ + 'Authorization' => 'token '.config('services.btc_pay.api_key'), + ])->post( + 'https://pay.einundzwanzig.space/api/v1/stores/98PF86BoMd3C8P1nHHyFdoeznCwtcm5yehcAgoCYDQ2a/invoices', + [ + 'amount' => $this->amountToPay, + 'metadata' => [ + 'orderId' => $comment, + 'orderUrl' => url()->route('association.profile'), + 'itemDesc' => 'Mitgliedsbeitrag '.date('Y').' von nostr:'.$this->currentPleb->npub, + 'posData' => [ + 'event' => $paymentEvent->event_id, + 'pubkey' => $this->currentPleb->pubkey, + 'npub' => $this->currentPleb->npub, + ], + ], + 'checkout' => [ + 'expirationMinutes' => 60 * 24, + 'redirectURL' => url()->route('association.profile'), + 'redirectAutomatically' => true, + 'defaultLanguage' => 'de', + ], + ], + )->throw(); + $paymentEvent->btc_pay_invoice = $response->json()['id']; + $paymentEvent->save(); + + return redirect($response->json()['checkoutLink']); + } catch (\Exception $e) { + $notification = new Notification($this); + $notification->error( + 'Fehler beim Erstellen der Rechnung. Bitte versuche es später erneut: '.$e->getMessage(), + ); + } + } + + public function listenForPayment(): void + { + $paymentEvent = $this->currentPleb + ->paymentEvents() + ->where('year', date('Y')) + ->first(); + if ($paymentEvent->btc_pay_invoice) { + $response = \Illuminate\Support\Facades\Http::withHeaders([ + 'Authorization' => 'token '.config('services.btc_pay.api_key'), + ]) + ->get( + 'https://pay.einundzwanzig.space/api/v1/stores/98PF86BoMd3C8P1nHHyFdoeznCwtcm5yehcAgoCYDQ2a/invoices/'.$paymentEvent->btc_pay_invoice, + ); + if ($response->json()['status'] === 'Expired') { + $paymentEvent->btc_pay_invoice = null; + $paymentEvent->paid = false; + $paymentEvent->save(); + } + if ($response->json()['status'] === 'Settled') { + $paymentEvent->paid = true; + $paymentEvent->save(); + $this->currentYearIsPaid = true; + } + } + if ($paymentEvent->paid) { + $this->currentYearIsPaid = true; + } + $paymentEvent = $paymentEvent->refresh(); + $this->payments = $this->currentPleb + ->paymentEvents() + ->where('paid', true) + ->get(); + } + + public function save($type): void + { + $this->form->validate(); + if (! $this->form->check) { + $this->js('alert("Du musst den Statuten zustimmen.")'); + + return; + } + + $this->currentPleb + ->update([ + 'association_status' => $type, + ]); + } + + public function createPaymentEvent(): void + { + $note = new NostrEvent; + $note->setKind(32121); + $note->setContent( + 'Dieses Event dient der Zahlung des Mitgliedsbeitrags für das Jahr '.date( + 'Y', + ).'. Bitte bezahle den Betrag von '.number_format($this->amountToPay, 0, ',', '.').' Satoshis.', + ); + $note->setTags([ + ['d', $this->currentPleb->pubkey.','.date('Y')], + ['zap', 'daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6', config('services.relay'), '1'], + ]); + $signer = new Sign; + $signer->signEvent($note, config('services.nostr')); + + $eventMessage = new EventMessage($note); + + $relayUrl = config('services.relay'); + $relay = new Relay($relayUrl); + $relay->setMessage($eventMessage); + $result = $relay->send(); + + $this->currentPleb->paymentEvents()->create([ + 'year' => date('Y'), + 'event_id' => $result->eventId, + 'amount' => $this->amountToPay, + ]); + } + + public function loadEvents(): void + { + $subscription = new Subscription; + $subscriptionId = $subscription->setId(); + + $filter1 = new Filter; + $filter1->setKinds([32121]); + $filter1->setAuthors(['daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6']); + $filters = [$filter1]; + + $requestMessage = new RequestMessage($subscriptionId, $filters); + + $relays = [ + new Relay(config('services.relay')), + ]; + $relaySet = new RelaySet; + $relaySet->setRelays($relays); + + $request = new Request($relaySet, $requestMessage); + $response = $request->send(); + + $this->events = collect($response[config('services.relay')]) + ->map(function ($event) { + if (! isset($event->event)) { + return false; + } + + return [ + 'id' => $event->event->id, + 'kind' => $event->event->kind, + 'content' => $event->event->content, + 'pubkey' => $event->event->pubkey, + 'tags' => $event->event->tags, + 'created_at' => $event->event->created_at, + ]; + }) + ->filter() + ->unique('id') + ->toArray(); + } +} diff --git a/app/Livewire/Association/ProjectSupport/Form/Create.php b/app/Livewire/Association/ProjectSupport/Form/Create.php new file mode 100644 index 0000000..96c4f7c --- /dev/null +++ b/app/Livewire/Association/ProjectSupport/Form/Create.php @@ -0,0 +1,70 @@ + 'handleNostrLoggedIn', + 'nostrLoggedOut' => 'handleNostrLoggedOut', + ]; + + public function mount(): void + { + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $this->currentPubkey)->first(); + $this->isAllowed = true; + } + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + $this->currentPubkey = $pubkey; + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); + $this->isAllowed = true; + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function save(): \Illuminate\Http\RedirectResponse + { + $this->form->validate(); + + $projectProposal = \App\Models\ProjectProposal::query()->create([ + ...$this->form->all(), + 'einundzwanzig_pleb_id' => $this->currentPleb->id, + ]); + if ($this->image) { + $this->validate([ + 'image' => 'image|max:1024', + ]); + $projectProposal + ->addMedia($this->image->getRealPath()) + ->toMediaCollection('main'); + } + + return redirect()->route('association.projectSupport'); + } +} diff --git a/app/Livewire/Association/ProjectSupport/Form/Edit.php b/app/Livewire/Association/ProjectSupport/Form/Edit.php new file mode 100644 index 0000000..781c3b6 --- /dev/null +++ b/app/Livewire/Association/ProjectSupport/Form/Edit.php @@ -0,0 +1,75 @@ + 'handleNostrLoggedIn', + 'nostrLoggedOut' => 'handleNostrLoggedOut', + ]; + + public function mount(ProjectProposal $projectProposal): void + { + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $this->currentPubkey)->first(); + $this->isAllowed = true; + $this->form->fill($projectProposal->toArray()); + $this->projectProposal = $projectProposal; + $this->image = $projectProposal->getFirstMedia('main'); + } + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + $this->currentPubkey = $pubkey; + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); + $this->isAllowed = true; + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function save(): \Illuminate\Http\RedirectResponse + { + $this->form->validate(); + if ($this->image && method_exists($this->image, 'temporaryUrl')) { + $this->validate([ + 'image' => 'nullable|image|max:1024', + ]); + $this->projectProposal + ->addMedia($this->image->getRealPath()) + ->toMediaCollection('main'); + } + + $this->projectProposal->update([ + ...$this->form->except('id', 'slug'), + ]); + + return redirect()->route('association.projectSupport'); + } +} diff --git a/app/Livewire/Association/ProjectSupport/Index.php b/app/Livewire/Association/ProjectSupport/Index.php new file mode 100644 index 0000000..4c64dc1 --- /dev/null +++ b/app/Livewire/Association/ProjectSupport/Index.php @@ -0,0 +1,102 @@ + 'handleNostrLoggedIn', + 'nostrLoggedOut' => 'handleNostrLoggedOut', + ]; + + public function mount(): void + { + $this->loadProjects(); + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $this->currentPubkey)->first(); + $this->isAllowed = true; + } + } + + public function updatedSearch(): void + { + $this->loadProjects(); + } + + public function loadProjects(): void + { + $this->projects = ProjectProposal::query() + ->with([ + 'einundzwanzigPleb.profile', + 'votes', + ]) + ->where(function ($query) { + $query + ->where('name', 'ilike', '%'.$this->search.'%') + ->orWhere('description', 'ilike', '%'.$this->search.'%') + ->orWhereHas('einundzwanzigPleb.profile', function ($q) { + $q->where('name', 'ilike', '%'.$this->search.'%'); + }); + }) + ->orderBy('created_at', 'desc') + ->get(); + } + + public function handleNostrLoggedIn($pubkey): void + { + NostrAuth::login($pubkey); + $this->currentPubkey = $pubkey; + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); + $this->isAllowed = true; + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function confirmDelete($id): void + { + $notification = new Notification($this); + $notification->confirm([ + 'title' => 'Projektunterstützung löschen', + 'message' => 'Bist du sicher, dass du diese Projektunterstützung löschen möchtest?', + 'accept' => [ + 'label' => 'Ja, löschen', + 'method' => 'delete', + 'params' => $id, + ], + ]); + } + + public function setFilter($filter): void + { + $this->activeFilter = $filter; + } + + public function delete($id): void + { + ProjectProposal::query()->findOrFail($id)->delete(); + $this->loadProjects(); + } +} diff --git a/app/Livewire/Association/ProjectSupport/Show.php b/app/Livewire/Association/ProjectSupport/Show.php new file mode 100644 index 0000000..0dab2d1 --- /dev/null +++ b/app/Livewire/Association/ProjectSupport/Show.php @@ -0,0 +1,109 @@ + 'handleNostrLoggedIn', + 'nostrLoggedOut' => 'handleNostrLoggedOut', + ]; + + public function mount(ProjectProposal $projectProposal): void + { + $this->projectProposal = $projectProposal; + if (NostrAuth::check()) { + $this->currentPubkey = NostrAuth::pubkey(); + $this->handleNostrLoggedIn($this->currentPubkey); + } + $this->boardVotes = $this->getBoardVotes(); + $this->otherVotes = $this->getOtherVotes(); + } + + public function handleNostrLoggedIn($pubkey): void + { + $this->currentPubkey = $pubkey; + $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); + $this->isAllowed = true; + $this->ownVoteExists = Vote::query() + ->where('project_proposal_id', $this->projectProposal->id) + ->where('einundzwanzig_pleb_id', $this->currentPleb->id) + ->exists(); + } + + public function handleNostrLoggedOut(): void + { + $this->isAllowed = false; + $this->currentPubkey = null; + $this->currentPleb = null; + } + + public function getBoardVotes(): \Illuminate\Database\Eloquent\Collection + { + return Vote::query() + ->where('project_proposal_id', $this->projectProposal->id) + ->whereHas('einundzwanzigPleb', fn ($q) => $q->whereIn('npub', config('einundzwanzig.config.current_board'))) + ->get(); + } + + public function getOtherVotes(): \Illuminate\Database\Eloquent\Collection + { + return Vote::query() + ->where('project_proposal_id', $this->projectProposal->id) + ->whereDoesntHave( + 'einundzwanzigPleb', + fn ($q) => $q->whereIn('npub', config('einundzwanzig.config.current_board')) + ) + ->get(); + } + + public function approve(): void + { + Vote::query()->updateOrCreate([ + 'project_proposal_id' => $this->projectProposal->id, + 'einundzwanzig_pleb_id' => $this->currentPleb->id, + ], [ + 'value' => true, + ]); + $this->form->reset(); + $this->ownVoteExists = true; + $this->boardVotes = $this->getBoardVotes(); + $this->otherVotes = $this->getOtherVotes(); + } + + public function notApprove(): void + { + $this->form->validate(); + + Vote::query()->updateOrCreate([ + 'project_proposal_id' => $this->projectProposal->id, + 'einundzwanzig_pleb_id' => $this->currentPleb->id, + ], [ + 'value' => false, + ]); + $this->form->reset(); + $this->ownVoteExists = true; + } +} diff --git a/app/Livewire/Changelog.php b/app/Livewire/Changelog.php new file mode 100644 index 0000000..46e63bb --- /dev/null +++ b/app/Livewire/Changelog.php @@ -0,0 +1,28 @@ + $hash, + 'message' => $message, + 'author' => $author, + 'date' => $date, + ]; + } + $this->entries = $entries; + } +} diff --git a/app/Livewire/EinundzwanzigFeed/Index.php b/app/Livewire/EinundzwanzigFeed/Index.php new file mode 100644 index 0000000..595d6ba --- /dev/null +++ b/app/Livewire/EinundzwanzigFeed/Index.php @@ -0,0 +1,51 @@ +events = Event::query() + ->where('type', 'root') + ->orderBy('created_at', 'desc') + ->with([ + 'renderedEvent', + ]) + ->get() + ->toArray(); + } + + public function hydrate(): void + { + if ($this->newEvents) { + $this->loadMore(); + } + } + + #[Rule('echo:events,.newEvents')] + public function updated(): void + { + $this->newEvents = true; + } + + public function loadMore(): void + { + $this->newEvents = false; + $this->events = Event::query() + ->where('type', 'root') + ->orderBy('created_at', 'desc') + ->with([ + 'renderedEvent', + ]) + ->get() + ->toArray(); + } +} diff --git a/app/Livewire/Meetups/Grid.php b/app/Livewire/Meetups/Grid.php new file mode 100644 index 0000000..5eef74c --- /dev/null +++ b/app/Livewire/Meetups/Grid.php @@ -0,0 +1,10 @@ +loadEvents(); + } + + public function loadEvents(): void + { + $subscription = new Subscription; + $subscriptionId = $subscription->setId(); + + $filter1 = new Filter; + $filter1->setKinds([31924]); + $filter1->setLimit(25); + $filters = [$filter1]; + + $requestMessage = new RequestMessage($subscriptionId, $filters); + + $relays = [ + new Relay('ws://nostream:8008'), + ]; + $relaySet = new RelaySet; + $relaySet->setRelays($relays); + + $request = new Request($relaySet, $requestMessage); + $response = $request->send(); + + $this->events = collect($response['ws://nostream:8008']) + ->map(function ($event) { + if (! isset($event->event)) { + return false; + } + + return [ + 'id' => $event->event->id, + 'kind' => $event->event->kind, + 'content' => $event->event->content, + 'pubkey' => $event->event->pubkey, + 'tags' => $event->event->tags, + 'created_at' => $event->event->created_at, + ]; + }) + ->filter() + ->toArray(); + } + + public function save(): void + { + $note = new NostrEvent; + $note->setContent($this->description); + $note->setKind(31924); + $note->setTags([ + ['d', str()->uuid()->toString()], + ['title', $this->title], + ]); + $this->signThisEvent = $note->toJson(); + } + + public function signEvent($event): void + { + $note = new NostrEvent; + $note->setId($event['id']); + $note->setSignature($event['sig']); + $note->setKind($event['kind']); + $note->setContent($event['content']); + $note->setPublicKey($event['pubkey']); + $note->setTags($event['tags']); + $note->setCreatedAt($event['created_at']); + $eventMessage = new EventMessage($note); + $relayUrl = 'ws://nostream:8008'; + $relay = new Relay($relayUrl); + $relay->setMessage($eventMessage); + $relay->send(); + + $this->title = ''; + $this->description = ''; + $this->loadEvents(); + } +} diff --git a/app/Livewire/Meetups/Table.php b/app/Livewire/Meetups/Table.php new file mode 100644 index 0000000..0685fbd --- /dev/null +++ b/app/Livewire/Meetups/Table.php @@ -0,0 +1,10 @@ +markers = []; + } + + public function filterByMarker($id): void + { + // + } +} diff --git a/app/Livewire/Welcome.php b/app/Livewire/Welcome.php new file mode 100644 index 0000000..403d86c --- /dev/null +++ b/app/Livewire/Welcome.php @@ -0,0 +1,10 @@ +=8.1" + }, + "require-dev": { + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpunit/phpunit": "~12.4" + }, + "type": "library", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "ChaCha20\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Leigh", + "homepage": "https://github.com/lt" + }, + { + "name": "Djuri Baars", + "homepage": "https://github.com/dsbaars" + } + ], + "description": "Pure PHP implementation of the ChaCha20 encryption algorithm.", + "homepage": "https://github.com/dsbaars/PHP-ChaCha20", + "keywords": [ + "cipher", + "encryption", + "security", + "stream" + ], + "support": { + "source": "https://github.com/dsbaars/PHP-ChaCha20/tree/0.3.0" + }, + "time": "2025-11-28T16:51:46+00:00" + }, { "name": "egulias/email-validator", "version": "4.0.4", @@ -1134,31 +1192,31 @@ }, { "name": "fruitcake/php-cors", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/fruitcake/php-cors.git", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", "shasum": "" }, "require": { - "php": "^7.4|^8.0", - "symfony/http-foundation": "^4.4|^5.4|^6|^7" + "php": "^8.1", + "symfony/http-foundation": "^5.4|^6.4|^7.3|^8" }, "require-dev": { - "phpstan/phpstan": "^1.4", + "phpstan/phpstan": "^2", "phpunit/phpunit": "^9", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -1189,7 +1247,7 @@ ], "support": { "issues": "https://github.com/fruitcake/php-cors/issues", - "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0" }, "funding": [ { @@ -1201,24 +1259,24 @@ "type": "github" } ], - "time": "2023-10-12T05:21:21+00:00" + "time": "2025-12-03T09:33:47+00:00" }, { "name": "genkgo/php-asn1", - "version": "v2.8.0", + "version": "v2.9.0", "source": { "type": "git", "url": "https://github.com/genkgo/php-asn1.git", - "reference": "4de712c68bbf51c00551cb45f55642e30fed1fdb" + "reference": "dc535345d0ecc69181c6a1e17e57a625bd01f891" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/genkgo/php-asn1/zipball/4de712c68bbf51c00551cb45f55642e30fed1fdb", - "reference": "4de712c68bbf51c00551cb45f55642e30fed1fdb", + "url": "https://api.github.com/repos/genkgo/php-asn1/zipball/dc535345d0ecc69181c6a1e17e57a625bd01f891", + "reference": "dc535345d0ecc69181c6a1e17e57a625bd01f891", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" }, "require-dev": { "php-coveralls/php-coveralls": "~2.0", @@ -1279,30 +1337,30 @@ ], "support": { "issues": "https://github.com/genkgo/php-asn1/issues", - "source": "https://github.com/genkgo/php-asn1/tree/v2.8.0" + "source": "https://github.com/genkgo/php-asn1/tree/v2.9.0" }, - "time": "2025-02-12T20:20:53+00:00" + "time": "2026-01-06T11:43:05+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.1.3", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", "autoload": { @@ -1331,7 +1389,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -1343,7 +1401,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { "name": "guzzlehttp/guzzle", @@ -1818,16 +1876,16 @@ }, { "name": "laravel/folio", - "version": "v1.1.11", + "version": "v1.1.12", "source": { "type": "git", "url": "https://github.com/laravel/folio.git", - "reference": "8233c26268a04a828c34e37d5fc185248f932b4b" + "reference": "8ada43c28f9da9bcf71cd1a8c933007b6f906599" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/folio/zipball/8233c26268a04a828c34e37d5fc185248f932b4b", - "reference": "8233c26268a04a828c34e37d5fc185248f932b4b", + "url": "https://api.github.com/repos/laravel/folio/zipball/8ada43c28f9da9bcf71cd1a8c933007b6f906599", + "reference": "8ada43c28f9da9bcf71cd1a8c933007b6f906599", "shasum": "" }, "require": { @@ -1844,8 +1902,8 @@ "symfony/console": "^6.0|^7.0" }, "require-dev": { - "orchestra/testbench": "^8.6.0|^9.0|^10.0", - "pestphp/pest": "^2.5|^3.0", + "orchestra/testbench": "^8.36|^9.15|^10.8", + "pestphp/pest": "^2.5|^3.0|^4.0", "phpstan/phpstan": "^1.10" }, "type": "library", @@ -1887,20 +1945,20 @@ "issues": "https://github.com/laravel/folio/issues", "source": "https://github.com/laravel/folio" }, - "time": "2025-11-05T15:47:07+00:00" + "time": "2025-11-25T14:45:02+00:00" }, { "name": "laravel/framework", - "version": "v11.46.1", + "version": "v11.47.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "5fd457f807570a962a53b403b1346efe4cc80bb8" + "reference": "86693ffa1ba32f56f8c44e31416c6665095a62c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/5fd457f807570a962a53b403b1346efe4cc80bb8", - "reference": "5fd457f807570a962a53b403b1346efe4cc80bb8", + "url": "https://api.github.com/repos/laravel/framework/zipball/86693ffa1ba32f56f8c44e31416c6665095a62c5", + "reference": "86693ffa1ba32f56f8c44e31416c6665095a62c5", "shasum": "" }, "require": { @@ -2102,25 +2160,25 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-09-30T14:51:32+00:00" + "time": "2025-11-28T18:20:11+00:00" }, { "name": "laravel/prompts", - "version": "v0.1.25", + "version": "v0.3.10", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "7b4029a84c37cb2725fc7f011586e2997040bc95" + "reference": "360ba095ef9f51017473505191fbd4ab73e1cab3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/7b4029a84c37cb2725fc7f011586e2997040bc95", - "reference": "7b4029a84c37cb2725fc7f011586e2997040bc95", + "url": "https://api.github.com/repos/laravel/prompts/zipball/360ba095ef9f51017473505191fbd4ab73e1cab3", + "reference": "360ba095ef9f51017473505191fbd4ab73e1cab3", "shasum": "" }, "require": { + "composer-runtime-api": "^2.2", "ext-mbstring": "*", - "illuminate/collections": "^10.0|^11.0", "php": "^8.1", "symfony/console": "^6.2|^7.0" }, @@ -2129,10 +2187,11 @@ "laravel/framework": ">=10.17.0 <10.25.0" }, "require-dev": { + "illuminate/collections": "^10.0|^11.0|^12.0", "mockery/mockery": "^1.5", - "pestphp/pest": "^2.3", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-mockery": "^1.1" + "pestphp/pest": "^2.3|^3.4|^4.0", + "phpstan/phpstan": "^1.12.28", + "phpstan/phpstan-mockery": "^1.1.3" }, "suggest": { "ext-pcntl": "Required for the spinner to be animated." @@ -2140,7 +2199,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "0.1.x-dev" + "dev-main": "0.3.x-dev" } }, "autoload": { @@ -2158,22 +2217,22 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.25" + "source": "https://github.com/laravel/prompts/tree/v0.3.10" }, - "time": "2024-08-12T22:06:33+00:00" + "time": "2026-01-13T20:29:29+00:00" }, { "name": "laravel/pulse", - "version": "v1.4.3", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/laravel/pulse.git", - "reference": "8c57f30aa6e094c138cd191314fe060d60773c14" + "reference": "ee70e069f0386060bc668d3b63a30bae403d0485" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pulse/zipball/8c57f30aa6e094c138cd191314fe060d60773c14", - "reference": "8c57f30aa6e094c138cd191314fe060d60773c14", + "url": "https://api.github.com/repos/laravel/pulse/zipball/ee70e069f0386060bc668d3b63a30bae403d0485", + "reference": "ee70e069f0386060bc668d3b63a30bae403d0485", "shasum": "" }, "require": { @@ -2192,7 +2251,7 @@ "illuminate/routing": "^10.48.4|^11.0.8|^12.0", "illuminate/support": "^10.48.4|^11.0.8|^12.0", "illuminate/view": "^10.48.4|^11.0.8|^12.0", - "livewire/livewire": "^3.6.4", + "livewire/livewire": "^3.6.4|^4.0", "nesbot/carbon": "^2.67|^3.0", "php": "^8.1", "symfony/console": "^6.0|^7.0" @@ -2203,9 +2262,9 @@ "require-dev": { "guzzlehttp/guzzle": "^7.7", "mockery/mockery": "^1.0", - "orchestra/testbench": "^8.23.1|^9.0|^10.0", - "pestphp/pest": "^2.0", - "pestphp/pest-plugin-laravel": "^2.2", + "orchestra/testbench": "^8.36|^9.15|^10.8", + "pestphp/pest": "^2.0|^3.0|^4.0", + "pestphp/pest-plugin-laravel": "^2.2|^3.0|^4.0", "phpstan/phpstan": "^1.12.21", "predis/predis": "^1.0|^2.0" }, @@ -2247,20 +2306,20 @@ "issues": "https://github.com/laravel/pulse/issues", "source": "https://github.com/laravel/pulse" }, - "time": "2025-07-18T15:54:11+00:00" + "time": "2026-01-14T22:52:32+00:00" }, { "name": "laravel/reverb", - "version": "v1.6.1", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/laravel/reverb.git", - "reference": "a85ba34d2e23cc4a356296363e9a14dfefc4ac8f" + "reference": "4300fbbc3535f5cbbdf600b00edca1e4c515bfcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/reverb/zipball/a85ba34d2e23cc4a356296363e9a14dfefc4ac8f", - "reference": "a85ba34d2e23cc4a356296363e9a14dfefc4ac8f", + "url": "https://api.github.com/repos/laravel/reverb/zipball/4300fbbc3535f5cbbdf600b00edca1e4c515bfcf", + "reference": "4300fbbc3535f5cbbdf600b00edca1e4c515bfcf", "shasum": "" }, "require": { @@ -2280,8 +2339,8 @@ "symfony/http-foundation": "^6.3|^7.0" }, "require-dev": { - "orchestra/testbench": "^8.0|^9.0|^10.0", - "pestphp/pest": "^2.0|^3.0", + "orchestra/testbench": "^8.36|^9.15|^10.8", + "pestphp/pest": "^2.0|^3.0|^4.0", "phpstan/phpstan": "^1.10", "ratchet/pawl": "^0.4.1", "react/async": "^4.2", @@ -2327,22 +2386,22 @@ ], "support": { "issues": "https://github.com/laravel/reverb/issues", - "source": "https://github.com/laravel/reverb/tree/v1.6.1" + "source": "https://github.com/laravel/reverb/tree/v1.7.0" }, - "time": "2025-11-11T22:48:00+00:00" + "time": "2026-01-06T16:26:25+00:00" }, { "name": "laravel/sail", - "version": "v1.48.1", + "version": "v1.52.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "ef122b223f5fca5e5d88bda5127c846710886329" + "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/ef122b223f5fca5e5d88bda5127c846710886329", - "reference": "ef122b223f5fca5e5d88bda5127c846710886329", + "url": "https://api.github.com/repos/laravel/sail/zipball/64ac7d8abb2dbcf2b76e61289451bae79066b0b3", + "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3", "shasum": "" }, "require": { @@ -2392,20 +2451,20 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2025-11-17T22:05:34+00:00" + "time": "2026-01-01T02:46:03+00:00" }, { "name": "laravel/sanctum", - "version": "v4.2.0", + "version": "v4.2.3", "source": { "type": "git", "url": "https://github.com/laravel/sanctum.git", - "reference": "fd6df4f79f48a72992e8d29a9c0ee25422a0d677" + "reference": "47d26f1d310879ff757b971f5a6fc631d18663fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sanctum/zipball/fd6df4f79f48a72992e8d29a9c0ee25422a0d677", - "reference": "fd6df4f79f48a72992e8d29a9c0ee25422a0d677", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/47d26f1d310879ff757b971f5a6fc631d18663fd", + "reference": "47d26f1d310879ff757b971f5a6fc631d18663fd", "shasum": "" }, "require": { @@ -2419,9 +2478,8 @@ }, "require-dev": { "mockery/mockery": "^1.6", - "orchestra/testbench": "^9.0|^10.0", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^11.3" + "orchestra/testbench": "^9.15|^10.8", + "phpstan/phpstan": "^1.10" }, "type": "library", "extra": { @@ -2456,20 +2514,20 @@ "issues": "https://github.com/laravel/sanctum/issues", "source": "https://github.com/laravel/sanctum" }, - "time": "2025-07-09T19:45:24+00:00" + "time": "2026-01-11T18:20:25+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.6", + "version": "v2.0.8", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "038ce42edee619599a1debb7e81d7b3759492819" + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/038ce42edee619599a1debb7e81d7b3759492819", - "reference": "038ce42edee619599a1debb7e81d7b3759492819", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b", + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b", "shasum": "" }, "require": { @@ -2478,7 +2536,7 @@ "require-dev": { "illuminate/support": "^10.0|^11.0|^12.0", "nesbot/carbon": "^2.67|^3.0", - "pestphp/pest": "^2.36|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", "phpstan/phpstan": "^2.0", "symfony/var-dumper": "^6.2.0|^7.0.0" }, @@ -2517,20 +2575,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2025-10-09T13:42:30+00:00" + "time": "2026-01-08T16:22:46+00:00" }, { "name": "laravel/tinker", - "version": "v2.10.1", + "version": "v2.11.0", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "url": "https://api.github.com/repos/laravel/tinker/zipball/3d34b97c9a1747a81a3fde90482c092bd8b66468", + "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468", "shasum": "" }, "require": { @@ -2539,7 +2597,7 @@ "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", "php": "^7.2.5|^8.0", "psy/psysh": "^0.11.1|^0.12.0", - "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0|^8.0" }, "require-dev": { "mockery/mockery": "~1.3.3|^1.4.2", @@ -2581,22 +2639,22 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.10.1" + "source": "https://github.com/laravel/tinker/tree/v2.11.0" }, - "time": "2025-01-27T14:24:01+00:00" + "time": "2025-12-19T19:16:45+00:00" }, { "name": "league/commonmark", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "10732241927d3971d28e7ea7b5712721fa2296ca" + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca", - "reference": "10732241927d3971d28e7ea7b5712721fa2296ca", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", "shasum": "" }, "require": { @@ -2633,7 +2691,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.8-dev" + "dev-main": "2.9-dev" } }, "autoload": { @@ -2690,7 +2748,7 @@ "type": "tidelift" } ], - "time": "2025-07-20T12:47:49+00:00" + "time": "2025-11-26T21:48:24+00:00" }, { "name": "league/config", @@ -2964,20 +3022,20 @@ }, { "name": "league/uri", - "version": "7.6.0", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "f625804987a0a9112d954f9209d91fec52182344" + "reference": "4436c6ec8d458e4244448b069cc572d088230b76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/f625804987a0a9112d954f9209d91fec52182344", - "reference": "f625804987a0a9112d954f9209d91fec52182344", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.6", + "league/uri-interfaces": "^7.8", "php": "^8.1", "psr/http-factory": "^1" }, @@ -2991,11 +3049,11 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "ext-uri": "to use the PHP native URI class", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", - "league/uri-polyfill": "Needed to backport the PHP URI extension for older versions of PHP", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", - "rowbot/url": "to handle WHATWG URL", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3050,7 +3108,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.6.0" + "source": "https://github.com/thephpleague/uri/tree/7.8.0" }, "funding": [ { @@ -3058,20 +3116,20 @@ "type": "github" } ], - "time": "2025-11-18T12:17:23+00:00" + "time": "2026-01-14T17:24:56+00:00" }, { "name": "league/uri-interfaces", - "version": "7.6.0", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "ccbfb51c0445298e7e0b7f4481b942f589665368" + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/ccbfb51c0445298e7e0b7f4481b942f589665368", - "reference": "ccbfb51c0445298e7e0b7f4481b942f589665368", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", "shasum": "" }, "require": { @@ -3084,7 +3142,7 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "php-64bit": "to improve IPV4 host parsing", - "rowbot/url": "to handle WHATWG URL", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3134,7 +3192,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.6.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" }, "funding": [ { @@ -3142,74 +3200,20 @@ "type": "github" } ], - "time": "2025-11-18T12:17:23+00:00" - }, - { - "name": "leigh/chacha20", - "version": "0.2.0", - "source": { - "type": "git", - "url": "https://github.com/lt/PHP-ChaCha20.git", - "reference": "7aeffd53228be384b4a8986c9a8d9578acb171a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/lt/PHP-ChaCha20/zipball/7aeffd53228be384b4a8986c9a8d9578acb171a4", - "reference": "7aeffd53228be384b4a8986c9a8d9578acb171a4", - "shasum": "" - }, - "require": { - "php": ">=7.0" - }, - "require-dev": { - "phpunit/phpunit": "~5.0" - }, - "type": "library", - "autoload": { - "files": [ - "lib/functions.php" - ], - "psr-4": { - "ChaCha20\\": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Leigh", - "homepage": "https://github.com/lt" - } - ], - "description": "Pure PHP implementation of the ChaCha20 encryption algorithm.", - "homepage": "https://github.com/lt/PHP-ChaCha20", - "keywords": [ - "cipher", - "encryption", - "security", - "stream" - ], - "support": { - "issues": "https://github.com/lt/PHP-ChaCha20/issues", - "source": "https://github.com/lt/PHP-ChaCha20/tree/0.2.0" - }, - "abandoned": true, - "time": "2016-01-14T11:24:17+00:00" + "time": "2026-01-15T06:54:53+00:00" }, { "name": "livewire/livewire", - "version": "v3.6.4", + "version": "v4.0.1", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "ef04be759da41b14d2d129e670533180a44987dc" + "reference": "c7539589d5af82691bef17da17ce4e289269f8d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/ef04be759da41b14d2d129e670533180a44987dc", - "reference": "ef04be759da41b14d2d129e670533180a44987dc", + "url": "https://api.github.com/repos/livewire/livewire/zipball/c7539589d5af82691bef17da17ce4e289269f8d9", + "reference": "c7539589d5af82691bef17da17ce4e289269f8d9", "shasum": "" }, "require": { @@ -3264,7 +3268,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v3.6.4" + "source": "https://github.com/livewire/livewire/tree/v4.0.1" }, "funding": [ { @@ -3272,92 +3276,20 @@ "type": "github" } ], - "time": "2025-07-17T05:12:15+00:00" - }, - { - "name": "livewire/volt", - "version": "v1.10.0", - "source": { - "type": "git", - "url": "https://github.com/livewire/volt.git", - "reference": "79a5e2367944aad6f4af9edef31a3d688cc8875c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/livewire/volt/zipball/79a5e2367944aad6f4af9edef31a3d688cc8875c", - "reference": "79a5e2367944aad6f4af9edef31a3d688cc8875c", - "shasum": "" - }, - "require": { - "laravel/framework": "^10.38.2|^11.0|^12.0", - "livewire/livewire": "^3.6.1|^4.0", - "php": "^8.1" - }, - "require-dev": { - "laravel/folio": "^1.1", - "mockery/mockery": "^1.6", - "orchestra/testbench": "^8.15.0|^9.0|^10.0", - "pestphp/pest": "^2.9.5|^3.0", - "phpstan/phpstan": "^1.10" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Livewire\\Volt\\VoltServiceProvider" - ] - }, - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "files": [ - "functions.php" - ], - "psr-4": { - "Livewire\\Volt\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - }, - { - "name": "Nuno Maduro", - "email": "nuno@laravel.com" - } - ], - "description": "An elegantly crafted functional API for Laravel Livewire.", - "homepage": "https://github.com/livewire/volt", - "keywords": [ - "laravel", - "livewire", - "volt" - ], - "support": { - "issues": "https://github.com/livewire/volt/issues", - "source": "https://github.com/livewire/volt" - }, - "time": "2025-11-14T15:10:57+00:00" + "time": "2026-01-14T18:40:41+00:00" }, { "name": "maennchen/zipstream-php", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/maennchen/ZipStream-PHP.git", - "reference": "9712d8fa4cdf9240380b01eb4be55ad8dcf71416" + "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/9712d8fa4cdf9240380b01eb4be55ad8dcf71416", - "reference": "9712d8fa4cdf9240380b01eb4be55ad8dcf71416", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/682f1098a8fddbaf43edac2306a691c7ad508ec5", + "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5", "shasum": "" }, "require": { @@ -3368,7 +3300,7 @@ "require-dev": { "brianium/paratest": "^7.7", "ext-zip": "*", - "friendsofphp/php-cs-fixer": "^3.16", + "friendsofphp/php-cs-fixer": "^3.86", "guzzlehttp/guzzle": "^7.5", "mikey179/vfsstream": "^1.6", "php-coveralls/php-coveralls": "^2.5", @@ -3414,7 +3346,7 @@ ], "support": { "issues": "https://github.com/maennchen/ZipStream-PHP/issues", - "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.0" + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.1" }, "funding": [ { @@ -3422,20 +3354,20 @@ "type": "github" } ], - "time": "2025-07-17T11:15:13+00:00" + "time": "2025-12-10T09:58:31+00:00" }, { "name": "monolog/monolog", - "version": "3.9.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", "shasum": "" }, "require": { @@ -3453,7 +3385,7 @@ "graylog2/gelf-php": "^1.4.2 || ^2.0", "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", + "mongodb/mongodb": "^1.8 || ^2.0", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.8", "phpstan/phpstan": "^2", @@ -3513,7 +3445,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" }, "funding": [ { @@ -3525,20 +3457,20 @@ "type": "tidelift" } ], - "time": "2025-03-24T10:02:05+00:00" + "time": "2026-01-02T08:56:05+00:00" }, { "name": "nesbot/carbon", - "version": "3.10.3", + "version": "3.11.0", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f" + "reference": "bdb375400dcd162624531666db4799b36b64e4a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/bdb375400dcd162624531666db4799b36b64e4a1", + "reference": "bdb375400dcd162624531666db4799b36b64e4a1", "shasum": "" }, "require": { @@ -3546,9 +3478,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3.12 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -3630,7 +3562,7 @@ "type": "tidelift" } ], - "time": "2025-09-06T13:39:36+00:00" + "time": "2025-12-02T21:04:28+00:00" }, { "name": "nette/schema", @@ -3699,20 +3631,20 @@ }, { "name": "nette/utils", - "version": "v4.0.8", + "version": "v4.1.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "url": "https://api.github.com/repos/nette/utils/zipball/c99059c0315591f1a0db7ad6002000288ab8dc72", + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72", "shasum": "" }, "require": { - "php": "8.0 - 8.5" + "php": "8.2 - 8.5" }, "conflict": { "nette/finder": "<3", @@ -3735,7 +3667,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3782,22 +3714,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.8" + "source": "https://github.com/nette/utils/tree/v4.1.1" }, - "time": "2025-08-06T21:43:34+00:00" + "time": "2025-12-22T12:14:32+00:00" }, { "name": "nikic/php-parser", - "version": "v5.6.2", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -3840,9 +3772,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-21T19:32:17+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "nunomaduro/termwind", @@ -4325,16 +4257,16 @@ }, { "name": "paragonie/sodium_compat", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/paragonie/sodium_compat.git", - "reference": "547e2dc4d45107440e76c17ab5a46e4252460158" + "reference": "4714da6efdc782c06690bc72ce34fae7941c2d9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/547e2dc4d45107440e76c17ab5a46e4252460158", - "reference": "547e2dc4d45107440e76c17ab5a46e4252460158", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/4714da6efdc782c06690bc72ce34fae7941c2d9f", + "reference": "4714da6efdc782c06690bc72ce34fae7941c2d9f", "shasum": "" }, "require": { @@ -4415,22 +4347,22 @@ ], "support": { "issues": "https://github.com/paragonie/sodium_compat/issues", - "source": "https://github.com/paragonie/sodium_compat/tree/v2.4.0" + "source": "https://github.com/paragonie/sodium_compat/tree/v2.5.0" }, - "time": "2025-10-06T08:47:40+00:00" + "time": "2025-12-30T16:12:18+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.4", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { @@ -4480,7 +4412,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -4492,30 +4424,30 @@ "type": "tidelift" } ], - "time": "2025-08-21T11:53:16+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { "name": "phrity/comparison", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/sirn-se/phrity-comparison.git", - "reference": "aedd44d59db08de7d6c31812d1490c22aab35c92" + "reference": "cf80abb822537eeaaeb4142157cd667ca6372a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-comparison/zipball/aedd44d59db08de7d6c31812d1490c22aab35c92", - "reference": "aedd44d59db08de7d6c31812d1490c22aab35c92", + "url": "https://api.github.com/repos/sirn-se/phrity-comparison/zipball/cf80abb822537eeaaeb4142157cd667ca6372a13", + "reference": "cf80abb822537eeaaeb4142157cd667ca6372a13", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "php-coveralls/php-coveralls": "^2.0", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.0 | ^11.0 | ^12.0", - "squizlabs/php_codesniffer": "^3.5" + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "robiningelbrecht/phpunit-coverage-tools": "^1.9", + "squizlabs/php_codesniffer": "^3.5 || ^4.0" }, "type": "library", "autoload": { @@ -4546,35 +4478,35 @@ ], "support": { "issues": "https://github.com/sirn-se/phrity-comparison/issues", - "source": "https://github.com/sirn-se/phrity-comparison/tree/1.4.0" + "source": "https://github.com/sirn-se/phrity-comparison/tree/1.4.1" }, - "time": "2025-05-26T20:12:39+00:00" + "time": "2025-12-05T07:38:30+00:00" }, { "name": "phrity/http", - "version": "1.0.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/sirn-se/phrity-http.git", - "reference": "536e3e46e6220d171a59599ed1f4da9f6b6244fc" + "reference": "1e7eee67359287b94aae2b7d40b730d5f5394943" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-http/zipball/536e3e46e6220d171a59599ed1f4da9f6b6244fc", - "reference": "536e3e46e6220d171a59599ed1f4da9f6b6244fc", + "url": "https://api.github.com/repos/sirn-se/phrity-http/zipball/1e7eee67359287b94aae2b7d40b730d5f5394943", + "reference": "1e7eee67359287b94aae2b7d40b730d5f5394943", "shasum": "" }, "require": { "php": "^8.1", "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 | ^2.0" + "psr/http-message": "^1.1 || ^2.0" }, "require-dev": { "guzzlehttp/psr7": "^2.0", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.0 | ^11.0 | ^12.0", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", "robiningelbrecht/phpunit-coverage-tools": "^1.9", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^3.5 || ^4.0" }, "type": "library", "autoload": { @@ -4597,41 +4529,43 @@ "homepage": "https://phrity.sirn.se/http", "keywords": [ "HTTP Factories", + "HTTP Serializer", "http", - "psr-17" + "psr-17", + "psr-7" ], "support": { "issues": "https://github.com/sirn-se/phrity-http/issues", - "source": "https://github.com/sirn-se/phrity-http/tree/1.0.0" + "source": "https://github.com/sirn-se/phrity-http/tree/1.1.0" }, - "time": "2025-09-07T17:04:26+00:00" + "time": "2025-12-22T20:22:29+00:00" }, { "name": "phrity/net-stream", - "version": "2.3.1", + "version": "2.3.3", "source": { "type": "git", "url": "https://github.com/sirn-se/phrity-net-stream.git", - "reference": "c621bb3108a5a02bba64df2e5f0cd7ada02665b5" + "reference": "f46694e1b721867ec3c19731a7fcbbead3c6ac89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-net-stream/zipball/c621bb3108a5a02bba64df2e5f0cd7ada02665b5", - "reference": "c621bb3108a5a02bba64df2e5f0cd7ada02665b5", + "url": "https://api.github.com/repos/sirn-se/phrity-net-stream/zipball/f46694e1b721867ec3c19731a7fcbbead3c6ac89", + "reference": "f46694e1b721867ec3c19731a7fcbbead3c6ac89", "shasum": "" }, "require": { "php": "^8.1", "phrity/util-errorhandler": "^1.1", "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 | ^2.0" + "psr/http-message": "^1.1 || ^2.0" }, "require-dev": { - "php-coveralls/php-coveralls": "^2.0", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.0 | ^11.0 | ^12.0", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", "phrity/net-uri": "^2.0", - "squizlabs/php_codesniffer": "^3.5" + "robiningelbrecht/phpunit-coverage-tools": "^1.9", + "squizlabs/php_codesniffer": "^3.5 || ^4.0" }, "type": "library", "autoload": { @@ -4663,22 +4597,22 @@ ], "support": { "issues": "https://github.com/sirn-se/phrity-net-stream/issues", - "source": "https://github.com/sirn-se/phrity-net-stream/tree/2.3.1" + "source": "https://github.com/sirn-se/phrity-net-stream/tree/2.3.3" }, - "time": "2025-08-08T09:51:04+00:00" + "time": "2025-12-24T12:07:07+00:00" }, { "name": "phrity/net-uri", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/sirn-se/phrity-net-uri.git", - "reference": "08de4cf07e439c4708f572249659f09198ac99f0" + "reference": "0737de026b75177ae302ac9fdbbd0ffc2610f3b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-net-uri/zipball/08de4cf07e439c4708f572249659f09198ac99f0", - "reference": "08de4cf07e439c4708f572249659f09198ac99f0", + "url": "https://api.github.com/repos/sirn-se/phrity-net-uri/zipball/0737de026b75177ae302ac9fdbbd0ffc2610f3b8", + "reference": "0737de026b75177ae302ac9fdbbd0ffc2610f3b8", "shasum": "" }, "require": { @@ -4689,11 +4623,11 @@ "psr/http-message": "^1.1 | ^2.0" }, "require-dev": { - "php-coveralls/php-coveralls": "^2.0", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.0 | ^11.0 | ^12.0", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", "phrity/util-errorhandler": "^1.1", - "squizlabs/php_codesniffer": "^3.5" + "robiningelbrecht/phpunit-coverage-tools": "^1.9", + "squizlabs/php_codesniffer": "^3.5 || ^4.0" }, "suggest": { "ext-intl": "Enables IDN conversion for non-ASCII domains" @@ -4725,32 +4659,32 @@ ], "support": { "issues": "https://github.com/sirn-se/phrity-net-uri/issues", - "source": "https://github.com/sirn-se/phrity-net-uri/tree/2.2.0" + "source": "https://github.com/sirn-se/phrity-net-uri/tree/2.2.1" }, - "time": "2025-05-25T13:05:13+00:00" + "time": "2025-12-05T10:39:22+00:00" }, { "name": "phrity/util-errorhandler", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/sirn-se/phrity-util-errorhandler.git", - "reference": "9825f15ef9b4a93252ce53ca8962278832d834da" + "reference": "70a669cc22db2eed6a109ec66fd95168a4332c9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-util-errorhandler/zipball/9825f15ef9b4a93252ce53ca8962278832d834da", - "reference": "9825f15ef9b4a93252ce53ca8962278832d834da", + "url": "https://api.github.com/repos/sirn-se/phrity-util-errorhandler/zipball/70a669cc22db2eed6a109ec66fd95168a4332c9b", + "reference": "70a669cc22db2eed6a109ec66fd95168a4332c9b", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "php-coveralls/php-coveralls": "^2.0", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.0 | ^11.0 | ^12.0", - "squizlabs/php_codesniffer": "^3.5" + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "robiningelbrecht/phpunit-coverage-tools": "^1.9", + "squizlabs/php_codesniffer": "^3.5 || ^4.0" }, "type": "library", "autoload": { @@ -4777,22 +4711,22 @@ ], "support": { "issues": "https://github.com/sirn-se/phrity-util-errorhandler/issues", - "source": "https://github.com/sirn-se/phrity-util-errorhandler/tree/1.2.1" + "source": "https://github.com/sirn-se/phrity-util-errorhandler/tree/1.2.2" }, - "time": "2025-08-08T09:48:45+00:00" + "time": "2025-12-05T21:25:36+00:00" }, { "name": "phrity/websocket", - "version": "3.6.0", + "version": "3.6.2", "source": { "type": "git", "url": "https://github.com/sirn-se/websocket-php.git", - "reference": "3f16b2564a230bbce716cccaff2f6156a60a8798" + "reference": "b9816ed2b4a10c8c42bd0b6398044ab506869756" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirn-se/websocket-php/zipball/3f16b2564a230bbce716cccaff2f6156a60a8798", - "reference": "3f16b2564a230bbce716cccaff2f6156a60a8798", + "url": "https://api.github.com/repos/sirn-se/websocket-php/zipball/b9816ed2b4a10c8c42bd0b6398044ab506869756", + "reference": "b9816ed2b4a10c8c42bd0b6398044ab506869756", "shasum": "" }, "require": { @@ -4801,18 +4735,17 @@ "phrity/net-stream": "^2.3", "phrity/net-uri": "^2.1", "psr/http-message": "^1.1 | ^2.0", - "psr/log": "^1.0 | ^2.0 | ^3.0" + "psr/log": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { "guzzlehttp/psr7": "^2.0", - "php-coveralls/php-coveralls": "^2.0", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.0 | ^11.0 | ^12.0", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", "phrity/logger-console": "^1.0", "phrity/net-mock": "^2.3", "phrity/util-errorhandler": "^1.1", "robiningelbrecht/phpunit-coverage-tools": "^1.9", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^3.5 || ^4.0" }, "type": "library", "autoload": { @@ -4843,41 +4776,38 @@ ], "support": { "issues": "https://github.com/sirn-se/websocket-php/issues", - "source": "https://github.com/sirn-se/websocket-php/tree/3.6.0" + "source": "https://github.com/sirn-se/websocket-php/tree/3.6.2" }, - "time": "2025-09-08T16:21:41+00:00" + "time": "2025-12-21T09:58:16+00:00" }, { "name": "power-components/livewire-powergrid", - "version": "v5.10.7", + "version": "v6.7.5", "source": { "type": "git", "url": "https://github.com/Power-Components/livewire-powergrid.git", - "reference": "98690cdb62ceafd46984f210688b4fb28bb432c1" + "reference": "be620d2aa125816195abb7756a57ddaf3849ab40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Power-Components/livewire-powergrid/zipball/98690cdb62ceafd46984f210688b4fb28bb432c1", - "reference": "98690cdb62ceafd46984f210688b4fb28bb432c1", + "url": "https://api.github.com/repos/Power-Components/livewire-powergrid/zipball/be620d2aa125816195abb7756a57ddaf3849ab40", + "reference": "be620d2aa125816195abb7756a57ddaf3849ab40", "shasum": "" }, "require": { - "laravel/prompts": "^0.1.15", - "livewire/livewire": "^3.4.6", - "php": "^8.1" - }, - "conflict": { - "laravel/framework": "10.40.0" + "laravel/prompts": "*", + "livewire/livewire": "^3.7|^4.0", + "php": "^8.2" }, "require-dev": { - "composer/composer": "^2.7.1", - "laradumps/laradumps": "^3.1", - "laradumps/laradumps-core": "^2.0", - "larastan/larastan": "^2.9.0", - "laravel/pint": "^1.14.0", - "laravel/scout": "^10.9", - "orchestra/testbench": "8.19|^9.0", - "pestphp/pest": "^2.34.0" + "composer/composer": "^2.8", + "laradumps/laradumps": "^4.6", + "larastan/larastan": "^2.0|^3.0", + "laravel/pint": "^1.26", + "laravel/scout": "^10.11.3", + "openspout/openspout": "^4.24.5", + "orchestra/testbench": "^9.4|^10.0", + "pestphp/pest": "^3.0|^4.0" }, "suggest": { "openspout/openspout": "Required to export XLS and CSV" @@ -4918,7 +4848,7 @@ "homepage": "https://github.com/power-components/livewire-powergrid", "support": { "issues": "https://github.com/Power-Components/livewire-powergrid/issues", - "source": "https://github.com/Power-Components/livewire-powergrid/tree/v5.10.7" + "source": "https://github.com/Power-Components/livewire-powergrid/tree/v6.7.5" }, "funding": [ { @@ -4926,7 +4856,7 @@ "type": "github" } ], - "time": "2024-10-01T11:12:07+00:00" + "time": "2026-01-12T11:43:44+00:00" }, { "name": "psr/clock", @@ -5342,16 +5272,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.14", + "version": "v0.12.18", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "95c29b3756a23855a30566b745d218bee690bef2" + "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/95c29b3756a23855a30566b745d218bee690bef2", - "reference": "95c29b3756a23855a30566b745d218bee690bef2", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/ddff0ac01beddc251786fe70367cd8bbdb258196", + "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196", "shasum": "" }, "require": { @@ -5359,8 +5289,8 @@ "ext-tokenizer": "*", "nikic/php-parser": "^5.0 || ^4.0", "php": "^8.0 || ^7.4", - "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", - "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" }, "conflict": { "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" @@ -5415,9 +5345,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.14" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.18" }, - "time": "2025-10-27T17:15:31+00:00" + "time": "2025-12-17T14:35:46+00:00" }, { "name": "pusher/pusher-php-server", @@ -5602,29 +5532,30 @@ }, { "name": "ralphjsmit/laravel-seo", - "version": "1.7.2", + "version": "1.7.3", "source": { "type": "git", "url": "https://github.com/ralphjsmit/laravel-seo.git", - "reference": "55f72af14357b22665ed8428f46356f41a61c713" + "reference": "c020d92e4d31eb903c31a905ef258d4629bff75b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ralphjsmit/laravel-seo/zipball/55f72af14357b22665ed8428f46356f41a61c713", - "reference": "55f72af14357b22665ed8428f46356f41a61c713", + "url": "https://api.github.com/repos/ralphjsmit/laravel-seo/zipball/c020d92e4d31eb903c31a905ef258d4629bff75b", + "reference": "c020d92e4d31eb903c31a905ef258d4629bff75b", "shasum": "" }, "require": { - "illuminate/contracts": "^10.0|^11.0|^12.0", - "php": "^8.0", + "illuminate/contracts": "^11.11|^12.0", + "php": "^8.2", "ralphjsmit/laravel-helpers": "^1.10", "spatie/laravel-package-tools": "^1.9.2" }, "require-dev": { "laravel/pint": "^1.16", - "nesbot/carbon": "^2.66|^3.0", - "nunomaduro/collision": "^7.0|^8.0|^9.0", - "orchestra/testbench": "^9.0|^10.0", + "nesbot/carbon": "^3.0", + "nunomaduro/collision": "^8.0|^9.0", + "orchestra/testbench": "^9.16|^10.0", + "orchestra/testbench-core": "^9.1.4|^10.0", "pestphp/pest": "^2.0|^3.0", "pestphp/pest-plugin-laravel": "^2.0|^3.0", "phpunit/phpunit": "^10.5|^11.5", @@ -5671,9 +5602,9 @@ ], "support": { "issues": "https://github.com/ralphjsmit/laravel-seo/issues", - "source": "https://github.com/ralphjsmit/laravel-seo/tree/1.7.2" + "source": "https://github.com/ralphjsmit/laravel-seo/tree/1.7.3" }, - "time": "2025-09-22T14:21:04+00:00" + "time": "2026-01-15T22:23:17+00:00" }, { "name": "ramsey/collection", @@ -5753,20 +5684,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.1", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440" + "reference": "8429c78ca35a09f27565311b98101e2826affde0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -5825,9 +5756,9 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.1" + "source": "https://github.com/ramsey/uuid/tree/4.9.2" }, - "time": "2025-09-04T20:59:21+00:00" + "time": "2025-12-14T04:43:48+00:00" }, { "name": "ratchet/rfc6455", @@ -6420,16 +6351,16 @@ }, { "name": "sentry/sentry", - "version": "4.18.1", + "version": "4.19.1", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "04dcf20b39742b731b676f8b8d4f02d1db488af8" + "reference": "1c21d60bebe67c0122335bd3fe977990435af0a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/04dcf20b39742b731b676f8b8d4f02d1db488af8", - "reference": "04dcf20b39742b731b676f8b8d4f02d1db488af8", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/1c21d60bebe67c0122335bd3fe977990435af0a3", + "reference": "1c21d60bebe67c0122335bd3fe977990435af0a3", "shasum": "" }, "require": { @@ -6492,7 +6423,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.18.1" + "source": "https://github.com/getsentry/sentry-php/tree/4.19.1" }, "funding": [ { @@ -6504,28 +6435,28 @@ "type": "custom" } ], - "time": "2025-11-11T09:34:53+00:00" + "time": "2025-12-02T15:57:41+00:00" }, { "name": "sentry/sentry-laravel", - "version": "4.19.0", + "version": "4.20.1", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-laravel.git", - "reference": "7fdffd57e8fff0a6f9a18d9a83f32e960af63e3f" + "reference": "503853fa7ee74b34b64e76f1373db86cd11afe72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/7fdffd57e8fff0a6f9a18d9a83f32e960af63e3f", - "reference": "7fdffd57e8fff0a6f9a18d9a83f32e960af63e3f", + "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/503853fa7ee74b34b64e76f1373db86cd11afe72", + "reference": "503853fa7ee74b34b64e76f1373db86cd11afe72", "shasum": "" }, "require": { "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0", "nyholm/psr7": "^1.0", "php": "^7.2 | ^8.0", - "sentry/sentry": "^4.18.0", - "symfony/psr-http-message-bridge": "^1.0 | ^2.0 | ^6.0 | ^7.0" + "sentry/sentry": "^4.19.0", + "symfony/psr-http-message-bridge": "^1.0 | ^2.0 | ^6.0 | ^7.0 | ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.11", @@ -6582,7 +6513,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-laravel/issues", - "source": "https://github.com/getsentry/sentry-laravel/tree/4.19.0" + "source": "https://github.com/getsentry/sentry-laravel/tree/4.20.1" }, "funding": [ { @@ -6594,7 +6525,7 @@ "type": "custom" } ], - "time": "2025-11-11T09:01:14+00:00" + "time": "2026-01-07T08:53:19+00:00" }, { "name": "simplesoftwareio/simple-qrcode", @@ -6813,23 +6744,23 @@ }, { "name": "spatie/commonmark-shiki-highlighter", - "version": "2.5.1", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/spatie/commonmark-shiki-highlighter.git", - "reference": "595c7e0b45d4a63b17dfc1ccbd13532d431ec351" + "reference": "ef23368cff226658e9a348fd839b33ae6d95d2c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/commonmark-shiki-highlighter/zipball/595c7e0b45d4a63b17dfc1ccbd13532d431ec351", - "reference": "595c7e0b45d4a63b17dfc1ccbd13532d431ec351", + "url": "https://api.github.com/repos/spatie/commonmark-shiki-highlighter/zipball/ef23368cff226658e9a348fd839b33ae6d95d2c6", + "reference": "ef23368cff226658e9a348fd839b33ae6d95d2c6", "shasum": "" }, "require": { "league/commonmark": "^2.4.2", "php": "^8.0", "spatie/shiki-php": "^2.2.2", - "symfony/process": "^5.4|^6.4|^7.1" + "symfony/process": "^5.4|^6.4|^7.1|^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.19|^v3.49.0", @@ -6861,7 +6792,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/commonmark-shiki-highlighter/tree/2.5.1" + "source": "https://github.com/spatie/commonmark-shiki-highlighter/tree/2.5.2" }, "funding": [ { @@ -6869,25 +6800,25 @@ "type": "github" } ], - "time": "2025-01-13T11:25:47+00:00" + "time": "2025-11-24T15:27:35+00:00" }, { "name": "spatie/db-dumper", - "version": "3.8.0", + "version": "3.8.3", "source": { "type": "git", "url": "https://github.com/spatie/db-dumper.git", - "reference": "91e1fd4dc000aefc9753cda2da37069fc996baee" + "reference": "eac3221fbe27fac51f388600d27b67b1b079406e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/db-dumper/zipball/91e1fd4dc000aefc9753cda2da37069fc996baee", - "reference": "91e1fd4dc000aefc9753cda2da37069fc996baee", + "url": "https://api.github.com/repos/spatie/db-dumper/zipball/eac3221fbe27fac51f388600d27b67b1b079406e", + "reference": "eac3221fbe27fac51f388600d27b67b1b079406e", "shasum": "" }, "require": { "php": "^8.0", - "symfony/process": "^5.0|^6.0|^7.0" + "symfony/process": "^5.0|^6.0|^7.0|^8.0" }, "require-dev": { "pestphp/pest": "^1.22" @@ -6920,7 +6851,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/db-dumper/tree/3.8.0" + "source": "https://github.com/spatie/db-dumper/tree/3.8.3" }, "funding": [ { @@ -6932,7 +6863,7 @@ "type": "github" } ], - "time": "2025-02-14T15:04:22+00:00" + "time": "2026-01-05T16:26:03+00:00" }, { "name": "spatie/eloquent-sortable", @@ -7010,16 +6941,16 @@ }, { "name": "spatie/image", - "version": "3.8.6", + "version": "3.9.1", "source": { "type": "git", "url": "https://github.com/spatie/image.git", - "reference": "0872c5968a7f044fe1e960c26433e54ceaede696" + "reference": "9a8e02839897b236f37708d24bcb12381ba050ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/image/zipball/0872c5968a7f044fe1e960c26433e54ceaede696", - "reference": "0872c5968a7f044fe1e960c26433e54ceaede696", + "url": "https://api.github.com/repos/spatie/image/zipball/9a8e02839897b236f37708d24bcb12381ba050ff", + "reference": "9a8e02839897b236f37708d24bcb12381ba050ff", "shasum": "" }, "require": { @@ -7029,18 +6960,18 @@ "php": "^8.2", "spatie/image-optimizer": "^1.7.5", "spatie/temporary-directory": "^2.2", - "symfony/process": "^6.4|^7.0" + "symfony/process": "^6.4|^7.0|^8.0" }, "require-dev": { "ext-gd": "*", "ext-imagick": "*", "laravel/sail": "^1.34", - "pestphp/pest": "^2.28", + "pestphp/pest": "^3.0|^4.0", "phpstan/phpstan": "^1.10.50", "spatie/pest-plugin-snapshots": "^2.1", "spatie/pixelmatch-php": "^1.0", "spatie/ray": "^1.40.1", - "symfony/var-dumper": "^6.4|7.0" + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7067,7 +6998,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/image/tree/3.8.6" + "source": "https://github.com/spatie/image/tree/3.9.1" }, "funding": [ { @@ -7079,32 +7010,32 @@ "type": "github" } ], - "time": "2025-09-25T12:06:17+00:00" + "time": "2026-01-12T07:34:13+00:00" }, { "name": "spatie/image-optimizer", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/spatie/image-optimizer.git", - "reference": "4fd22035e81d98fffced65a8c20d9ec4daa9671c" + "reference": "2ad9ac7c19501739183359ae64ea6c15869c23d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/4fd22035e81d98fffced65a8c20d9ec4daa9671c", - "reference": "4fd22035e81d98fffced65a8c20d9ec4daa9671c", + "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/2ad9ac7c19501739183359ae64ea6c15869c23d9", + "reference": "2ad9ac7c19501739183359ae64ea6c15869c23d9", "shasum": "" }, "require": { "ext-fileinfo": "*", "php": "^7.3|^8.0", "psr/log": "^1.0 | ^2.0 | ^3.0", - "symfony/process": "^4.2|^5.0|^6.0|^7.0" + "symfony/process": "^4.2|^5.0|^6.0|^7.0|^8.0" }, "require-dev": { - "pestphp/pest": "^1.21", - "phpunit/phpunit": "^8.5.21|^9.4.4", - "symfony/var-dumper": "^4.2|^5.0|^6.0|^7.0" + "pestphp/pest": "^1.21|^2.0|^3.0|^4.0", + "phpunit/phpunit": "^8.5.21|^9.4.4|^10.0|^11.0|^12.0", + "symfony/var-dumper": "^4.2|^5.0|^6.0|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7132,9 +7063,9 @@ ], "support": { "issues": "https://github.com/spatie/image-optimizer/issues", - "source": "https://github.com/spatie/image-optimizer/tree/1.8.0" + "source": "https://github.com/spatie/image-optimizer/tree/1.8.1" }, - "time": "2024-11-04T08:24:54+00:00" + "time": "2025-11-26T10:57:19+00:00" }, { "name": "spatie/laravel-backup", @@ -7467,16 +7398,16 @@ }, { "name": "spatie/laravel-medialibrary", - "version": "11.17.5", + "version": "11.17.8", "source": { "type": "git", "url": "https://github.com/spatie/laravel-medialibrary.git", - "reference": "eef29bbc701d786f2f6233ca4c40deb61282ac36" + "reference": "ce3edb8c163e159e41a945a24e4bf9ad7a7499c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/eef29bbc701d786f2f6233ca4c40deb61282ac36", - "reference": "eef29bbc701d786f2f6233ca4c40deb61282ac36", + "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/ce3edb8c163e159e41a945a24e4bf9ad7a7499c9", + "reference": "ce3edb8c163e159e41a945a24e4bf9ad7a7499c9", "shasum": "" }, "require": { @@ -7509,8 +7440,8 @@ "larastan/larastan": "^2.7|^3.0", "league/flysystem-aws-s3-v3": "^3.22", "mockery/mockery": "^1.6.7", - "orchestra/testbench": "^7.0|^8.17|^9.0|^10.0", - "pestphp/pest": "^2.28|^3.5|^4.0", + "orchestra/testbench": "^8.36|^9.15|^10.8", + "pestphp/pest": "^2.36|^3.0|^4.0", "phpstan/extension-installer": "^1.3.1", "spatie/laravel-ray": "^1.33", "spatie/pdf-to-image": "^2.2|^3.0", @@ -7561,7 +7492,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-medialibrary/issues", - "source": "https://github.com/spatie/laravel-medialibrary/tree/11.17.5" + "source": "https://github.com/spatie/laravel-medialibrary/tree/11.17.8" }, "funding": [ { @@ -7573,7 +7504,7 @@ "type": "github" } ], - "time": "2025-11-13T11:36:18+00:00" + "time": "2026-01-05T09:32:05+00:00" }, { "name": "spatie/laravel-package-tools", @@ -7638,23 +7569,23 @@ }, { "name": "spatie/laravel-signal-aware-command", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/spatie/laravel-signal-aware-command.git", - "reference": "8e8a226ed7fb45302294878ef339e75ffa9a878d" + "reference": "70207ba2702a9ee8f523af0cd4711d1104c5ca53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-signal-aware-command/zipball/8e8a226ed7fb45302294878ef339e75ffa9a878d", - "reference": "8e8a226ed7fb45302294878ef339e75ffa9a878d", + "url": "https://api.github.com/repos/spatie/laravel-signal-aware-command/zipball/70207ba2702a9ee8f523af0cd4711d1104c5ca53", + "reference": "70207ba2702a9ee8f523af0cd4711d1104c5ca53", "shasum": "" }, "require": { "illuminate/contracts": "^11.0|^12.0", "php": "^8.2", "spatie/laravel-package-tools": "^1.4.3", - "symfony/console": "^7.0" + "symfony/console": "^7.0|^8.0" }, "require-dev": { "brianium/paratest": "^6.2|^7.0", @@ -7701,7 +7632,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-signal-aware-command/issues", - "source": "https://github.com/spatie/laravel-signal-aware-command/tree/2.1.0" + "source": "https://github.com/spatie/laravel-signal-aware-command/tree/2.1.1" }, "funding": [ { @@ -7709,7 +7640,7 @@ "type": "github" } ], - "time": "2025-02-14T09:55:51+00:00" + "time": "2025-11-27T09:17:52+00:00" }, { "name": "spatie/laravel-sluggable", @@ -7842,29 +7773,29 @@ }, { "name": "spatie/laravel-translatable", - "version": "6.11.4", + "version": "6.12.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-translatable.git", - "reference": "032d85b28de315310dab2048b857016f1194f68b" + "reference": "8fc0c1dd5ab4013c27a28e5d5590f2ce849bd349" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-translatable/zipball/032d85b28de315310dab2048b857016f1194f68b", - "reference": "032d85b28de315310dab2048b857016f1194f68b", + "url": "https://api.github.com/repos/spatie/laravel-translatable/zipball/8fc0c1dd5ab4013c27a28e5d5590f2ce849bd349", + "reference": "8fc0c1dd5ab4013c27a28e5d5590f2ce849bd349", "shasum": "" }, "require": { - "illuminate/database": "^10.0|^11.0|^12.0", - "illuminate/support": "^10.0|^11.0|^12.0", - "php": "^8.0", - "spatie/laravel-package-tools": "^1.11" + "illuminate/database": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "php": "^8.3", + "spatie/laravel-package-tools": "^1.92.7" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.64", - "mockery/mockery": "^1.4", - "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", - "pestphp/pest": "^1.20|^2.0|^3.0" + "friendsofphp/php-cs-fixer": "^3.90", + "mockery/mockery": "^1.6.12", + "orchestra/testbench": "^9.0|^10.0", + "pestphp/pest": "^4.0.0" }, "type": "library", "extra": { @@ -7913,7 +7844,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-translatable/issues", - "source": "https://github.com/spatie/laravel-translatable/tree/6.11.4" + "source": "https://github.com/spatie/laravel-translatable/tree/6.12.0" }, "funding": [ { @@ -7921,7 +7852,7 @@ "type": "github" } ], - "time": "2025-02-20T15:51:22+00:00" + "time": "2025-11-24T15:57:48+00:00" }, { "name": "spatie/shiki-php", @@ -7990,16 +7921,16 @@ }, { "name": "spatie/temporary-directory", - "version": "2.3.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/spatie/temporary-directory.git", - "reference": "580eddfe9a0a41a902cac6eeb8f066b42e65a32b" + "reference": "662e481d6ec07ef29fd05010433428851a42cd07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/580eddfe9a0a41a902cac6eeb8f066b42e65a32b", - "reference": "580eddfe9a0a41a902cac6eeb8f066b42e65a32b", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/662e481d6ec07ef29fd05010433428851a42cd07", + "reference": "662e481d6ec07ef29fd05010433428851a42cd07", "shasum": "" }, "require": { @@ -8035,7 +7966,7 @@ ], "support": { "issues": "https://github.com/spatie/temporary-directory/issues", - "source": "https://github.com/spatie/temporary-directory/tree/2.3.0" + "source": "https://github.com/spatie/temporary-directory/tree/2.3.1" }, "funding": [ { @@ -8047,7 +7978,7 @@ "type": "github" } ], - "time": "2025-01-13T13:04:43+00:00" + "time": "2026-01-12T07:42:22+00:00" }, { "name": "staudenmeir/eloquent-has-many-deep", @@ -8159,25 +8090,25 @@ }, { "name": "swentel/nostr-php", - "version": "1.9.2", + "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/nostrver-se/nostr-php.git", - "reference": "8fb8337354b2e9d48a901276c7814d7fa7b25653" + "reference": "c415dd1bf20c1b414eca94005288cc137a79e0d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nostrver-se/nostr-php/zipball/8fb8337354b2e9d48a901276c7814d7fa7b25653", - "reference": "8fb8337354b2e9d48a901276c7814d7fa7b25653", + "url": "https://api.github.com/repos/nostrver-se/nostr-php/zipball/c415dd1bf20c1b414eca94005288cc137a79e0d7", + "reference": "c415dd1bf20c1b414eca94005288cc137a79e0d7", "shasum": "" }, "require": { "bitwasp/bech32": "^0.0.1", + "dsbaars/chacha20": "^0.3.0", "ext-gmp": "*", "ext-xml": "*", - "leigh/chacha20": "^0.2.0", "paragonie/ecc": "^2.4", - "php": ">=8.1 <8.5", + "php": ">=8.2 <8.6", "phrity/websocket": "^3.0", "simplito/elliptic-php": "^1.0" }, @@ -8218,22 +8149,22 @@ "chat": "https://t.me/nostr_php", "issue": "https://github.com/swentel/nostr-php/issues", "issues": "https://github.com/nostrver-se/nostr-php/issues", - "source": "https://github.com/nostrver-se/nostr-php/tree/1.9.2" + "source": "https://github.com/nostrver-se/nostr-php/tree/1.9.3" }, - "time": "2025-06-04T14:51:06+00:00" + "time": "2025-12-04T09:09:22+00:00" }, { "name": "symfony/clock", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", "shasum": "" }, "require": { @@ -8278,7 +8209,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.3.0" + "source": "https://github.com/symfony/clock/tree/v7.4.0" }, "funding": [ { @@ -8289,25 +8220,29 @@ "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": "2024-09-25T14:21:43+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/console", - "version": "v7.3.6", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", - "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "url": "https://api.github.com/repos/symfony/console/zipball/732a9ca6cd9dfd940c639062d5edbde2f6727fb6", + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6", "shasum": "" }, "require": { @@ -8315,7 +8250,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2" + "symfony/string": "^7.2|^8.0" }, "conflict": { "symfony/dependency-injection": "<6.4", @@ -8329,16 +8264,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8372,7 +8307,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.6" + "source": "https://github.com/symfony/console/tree/v7.4.3" }, "funding": [ { @@ -8392,20 +8327,20 @@ "type": "tidelift" } ], - "time": "2025-11-04T01:21:42+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/css-selector", - "version": "v7.3.6", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "84321188c4754e64273b46b406081ad9b18e8614" + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/84321188c4754e64273b46b406081ad9b18e8614", - "reference": "84321188c4754e64273b46b406081ad9b18e8614", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ab862f478513e7ca2fe9ec117a6f01a8da6e1135", + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135", "shasum": "" }, "require": { @@ -8441,7 +8376,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.3.6" + "source": "https://github.com/symfony/css-selector/tree/v7.4.0" }, "funding": [ { @@ -8461,7 +8396,7 @@ "type": "tidelift" } ], - "time": "2025-10-29T17:24:25+00:00" + "time": "2025-10-30T13:39:42+00:00" }, { "name": "symfony/deprecation-contracts", @@ -8532,32 +8467,33 @@ }, { "name": "symfony/error-handler", - "version": "v7.3.6", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "bbe40bfab84323d99dab491b716ff142410a92a8" + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/bbe40bfab84323d99dab491b716ff142410a92a8", - "reference": "bbe40bfab84323d99dab491b716ff142410a92a8", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/48be2b0653594eea32dcef130cca1c811dcf25c2", + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "conflict": { "symfony/deprecation-contracts": "<2.5", "symfony/http-kernel": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ @@ -8589,7 +8525,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.6" + "source": "https://github.com/symfony/error-handler/tree/v7.4.0" }, "funding": [ { @@ -8609,20 +8545,20 @@ "type": "tidelift" } ], - "time": "2025-10-31T19:12:50+00:00" + "time": "2025-11-05T14:29:59+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.3.3", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d" }, "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/9dddcddff1ef974ad87b3708e4b442dc38b2261d", + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d", "shasum": "" }, "require": { @@ -8639,13 +8575,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8673,7 +8610,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.4.0" }, "funding": [ { @@ -8693,7 +8630,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-10-28T09:38:46+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -8773,23 +8710,23 @@ }, { "name": "symfony/finder", - "version": "v7.3.5", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9f696d2f1e340484b4683f7853b273abff94421f" + "reference": "fffe05569336549b20a1be64250b40516d6e8d06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f", - "reference": "9f696d2f1e340484b4683f7853b273abff94421f", + "url": "https://api.github.com/repos/symfony/finder/zipball/fffe05569336549b20a1be64250b40516d6e8d06", + "reference": "fffe05569336549b20a1be64250b40516d6e8d06", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8817,7 +8754,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.5" + "source": "https://github.com/symfony/finder/tree/v7.4.3" }, "funding": [ { @@ -8837,27 +8774,26 @@ "type": "tidelift" } ], - "time": "2025-10-15T18:45:57+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.3.7", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4" + "reference": "a70c745d4cea48dbd609f4075e5f5cbce453bd52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/db488a62f98f7a81d5746f05eea63a74e55bb7c4", - "reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a70c745d4cea48dbd609f4075e5f5cbce453bd52", + "reference": "a70c745d4cea48dbd609f4075e5f5cbce453bd52", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" }, "conflict": { "doctrine/dbal": "<3.6", @@ -8866,13 +8802,13 @@ "require-dev": { "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5", - "symfony/clock": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0" + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8900,7 +8836,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.7" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.3" }, "funding": [ { @@ -8920,29 +8856,29 @@ "type": "tidelift" } ], - "time": "2025-11-08T16:41:12+00:00" + "time": "2025-12-23T14:23:49+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.7", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "10b8e9b748ea95fa4539c208e2487c435d3c87ce" + "reference": "885211d4bed3f857b8c964011923528a55702aa5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/10b8e9b748ea95fa4539c208e2487c435d3c87ce", - "reference": "10b8e9b748ea95fa4539c208e2487c435d3c87ce", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/885211d4bed3f857b8c964011923528a55702aa5", + "reference": "885211d4bed3f857b8c964011923528a55702aa5", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0", - "symfony/event-dispatcher": "^7.3", - "symfony/http-foundation": "^7.3", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -8952,6 +8888,7 @@ "symfony/console": "<6.4", "symfony/dependency-injection": "<6.4", "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", "symfony/form": "<6.4", "symfony/http-client": "<6.4", "symfony/http-client-contracts": "<2.5", @@ -8969,27 +8906,27 @@ }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^7.1", - "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^7.1", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0", - "symfony/var-exporter": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "type": "library", @@ -9018,7 +8955,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.7" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.3" }, "funding": [ { @@ -9038,20 +8975,20 @@ "type": "tidelift" } ], - "time": "2025-11-12T11:38:40+00:00" + "time": "2025-12-31T08:43:57+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.5", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba" + "reference": "e472d35e230108231ccb7f51eb6b2100cac02ee4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba", - "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba", + "url": "https://api.github.com/repos/symfony/mailer/zipball/e472d35e230108231ccb7f51eb6b2100cac02ee4", + "reference": "e472d35e230108231ccb7f51eb6b2100cac02ee4", "shasum": "" }, "require": { @@ -9059,8 +8996,8 @@ "php": ">=8.2", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^7.2", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -9071,10 +9008,10 @@ "symfony/twig-bridge": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9102,7 +9039,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.5" + "source": "https://github.com/symfony/mailer/tree/v7.4.3" }, "funding": [ { @@ -9122,24 +9059,25 @@ "type": "tidelift" } ], - "time": "2025-10-24T14:27:20+00:00" + "time": "2025-12-16T08:02:06+00:00" }, { "name": "symfony/mime", - "version": "v7.3.4", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35" + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35", + "url": "https://api.github.com/repos/symfony/mime/zipball/bdb02729471be5d047a3ac4a69068748f1a6be7a", + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, @@ -9154,11 +9092,11 @@ "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" }, "type": "library", "autoload": { @@ -9190,7 +9128,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.4" + "source": "https://github.com/symfony/mime/tree/v7.4.0" }, "funding": [ { @@ -9210,20 +9148,20 @@ "type": "tidelift" } ], - "time": "2025-09-16T08:38:17+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.3.3", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d" + "reference": "b38026df55197f9e39a44f3215788edf83187b80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d", - "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", + "reference": "b38026df55197f9e39a44f3215788edf83187b80", "shasum": "" }, "require": { @@ -9261,7 +9199,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.3.3" + "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" }, "funding": [ { @@ -9281,7 +9219,7 @@ "type": "tidelift" } ], - "time": "2025-08-05T10:16:07+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/polyfill-ctype", @@ -9869,6 +9807,86 @@ ], "time": "2025-07-08T02:45:35+00:00" }, + { + "name": "symfony/polyfill-php85", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "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-06-23T16:12:55+00:00" + }, { "name": "symfony/polyfill-uuid", "version": "v1.33.0", @@ -9954,16 +9972,16 @@ }, { "name": "symfony/process", - "version": "v7.3.4", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" + "reference": "2f8e1a6cdf590ca63715da4d3a7a3327404a523f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", + "url": "https://api.github.com/repos/symfony/process/zipball/2f8e1a6cdf590ca63715da4d3a7a3327404a523f", + "reference": "2f8e1a6cdf590ca63715da4d3a7a3327404a523f", "shasum": "" }, "require": { @@ -9995,7 +10013,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.4" + "source": "https://github.com/symfony/process/tree/v7.4.3" }, "funding": [ { @@ -10015,26 +10033,26 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-12-19T10:00:43+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f" + "reference": "0101ff8bd0506703b045b1670960302d302a726c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/03f2f72319e7acaf2a9f6fcbe30ef17eec51594f", - "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/0101ff8bd0506703b045b1670960302d302a726c", + "reference": "0101ff8bd0506703b045b1670960302d302a726c", "shasum": "" }, "require": { "php": ">=8.2", "psr/http-message": "^1.0|^2.0", - "symfony/http-foundation": "^6.4|^7.0" + "symfony/http-foundation": "^6.4|^7.0|^8.0" }, "conflict": { "php-http/discovery": "<1.15", @@ -10044,11 +10062,12 @@ "nyholm/psr7": "^1.1", "php-http/discovery": "^1.15", "psr/log": "^1.1.4|^2|^3", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0" + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -10082,7 +10101,7 @@ "psr-7" ], "support": { - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.3.0" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.4.0" }, "funding": [ { @@ -10093,25 +10112,29 @@ "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": "2024-09-26T08:57:56+00:00" + "time": "2025-11-13T08:38:49+00:00" }, { "name": "symfony/routing", - "version": "v7.3.6", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "c97abe725f2a1a858deca629a6488c8fc20c3091" + "reference": "5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/c97abe725f2a1a858deca629a6488c8fc20c3091", - "reference": "c97abe725f2a1a858deca629a6488c8fc20c3091", + "url": "https://api.github.com/repos/symfony/routing/zipball/5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090", + "reference": "5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090", "shasum": "" }, "require": { @@ -10125,11 +10148,11 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10163,7 +10186,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.6" + "source": "https://github.com/symfony/routing/tree/v7.4.3" }, "funding": [ { @@ -10183,7 +10206,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T07:57:47+00:00" + "time": "2025-12-19T10:00:43+00:00" }, { "name": "symfony/service-contracts", @@ -10274,22 +10297,23 @@ }, { "name": "symfony/string", - "version": "v7.3.4", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", + "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003", + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -10297,11 +10321,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10340,7 +10364,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.4" + "source": "https://github.com/symfony/string/tree/v7.4.0" }, "funding": [ { @@ -10360,27 +10384,27 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:36:48+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/translation", - "version": "v7.3.4", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "ec25870502d0c7072d086e8ffba1420c85965174" + "reference": "7ef27c65d78886f7599fdd5c93d12c9243ecf44d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/ec25870502d0c7072d086e8ffba1420c85965174", - "reference": "ec25870502d0c7072d086e8ffba1420c85965174", + "url": "https://api.github.com/repos/symfony/translation/zipball/7ef27c65d78886f7599fdd5c93d12c9243ecf44d", + "reference": "7ef27c65d78886f7599fdd5c93d12c9243ecf44d", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "symfony/translation-contracts": "^2.5.3|^3.3" }, "conflict": { "nikic/php-parser": "<5.0", @@ -10399,17 +10423,17 @@ "require-dev": { "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10440,7 +10464,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.4" + "source": "https://github.com/symfony/translation/tree/v7.4.3" }, "funding": [ { @@ -10460,7 +10484,7 @@ "type": "tidelift" } ], - "time": "2025-09-07T11:39:36+00:00" + "time": "2025-12-29T09:31:36+00:00" }, { "name": "symfony/translation-contracts", @@ -10546,16 +10570,16 @@ }, { "name": "symfony/uid", - "version": "v7.3.1", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb" + "reference": "2498e9f81b7baa206f44de583f2f48350b90142c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb", + "url": "https://api.github.com/repos/symfony/uid/zipball/2498e9f81b7baa206f44de583f2f48350b90142c", + "reference": "2498e9f81b7baa206f44de583f2f48350b90142c", "shasum": "" }, "require": { @@ -10563,7 +10587,7 @@ "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10600,7 +10624,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.3.1" + "source": "https://github.com/symfony/uid/tree/v7.4.0" }, "funding": [ { @@ -10611,25 +10635,29 @@ "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-06-27T19:55:54+00:00" + "time": "2025-09-25T11:02:55+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.3.5", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d" + "reference": "7e99bebcb3f90d8721890f2963463280848cba92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7e99bebcb3f90d8721890f2963463280848cba92", + "reference": "7e99bebcb3f90d8721890f2963463280848cba92", "shasum": "" }, "require": { @@ -10641,10 +10669,10 @@ "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -10683,7 +10711,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.5" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.3" }, "funding": [ { @@ -10703,32 +10731,32 @@ "type": "tidelift" } ], - "time": "2025-09-27T09:00:46+00:00" + "time": "2025-12-18T07:04:31+00:00" }, { "name": "symfony/yaml", - "version": "v7.3.5", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc" + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc", - "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -10759,7 +10787,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.5" + "source": "https://github.com/symfony/yaml/tree/v7.4.1" }, "funding": [ { @@ -10779,27 +10807,27 @@ "type": "tidelift" } ], - "time": "2025-09-27T09:00:46+00:00" + "time": "2025-12-04T18:11:45+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "php": "^7.4 || ^8.0", - "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^2.0", @@ -10832,32 +10860,32 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.4.0" }, - "time": "2024-12-21T16:25:41+00:00" + "time": "2025-12-02T11:56:42+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.2", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", + "graham-campbell/result-type": "^1.1.4", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -10906,7 +10934,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -10918,7 +10946,7 @@ "type": "tidelift" } ], - "time": "2025-04-30T23:37:27+00:00" + "time": "2025-12-27T19:49:13+00:00" }, { "name": "voku/portable-ascii", @@ -11513,17 +11541,282 @@ "time": "2025-04-30T06:54:44+00:00" }, { - "name": "laravel/pint", - "version": "v1.25.1", + "name": "illuminate/json-schema", + "version": "v12.47.0", "source": { "type": "git", - "url": "https://github.com/laravel/pint.git", - "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9" + "url": "https://github.com/illuminate/json-schema.git", + "reference": "d161f398dab36f08cf131997362bc2e3ecb0309a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/5016e263f95d97670d71b9a987bd8996ade6d8d9", - "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9", + "url": "https://api.github.com/repos/illuminate/json-schema/zipball/d161f398dab36f08cf131997362bc2e3ecb0309a", + "reference": "d161f398dab36f08cf131997362bc2e3ecb0309a", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.50.0|^11.47.0|^12.40.2", + "php": "^8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\JsonSchema\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Json Schema package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-11-28T18:45:48+00:00" + }, + { + "name": "laravel/boost", + "version": "v1.8.10", + "source": { + "type": "git", + "url": "https://github.com/laravel/boost.git", + "reference": "aad8b2a423b0a886c2ce7ee92abbfde69992ff32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/boost/zipball/aad8b2a423b0a886c2ce7ee92abbfde69992ff32", + "reference": "aad8b2a423b0a886c2ce7ee92abbfde69992ff32", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^7.9", + "illuminate/console": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/contracts": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/routing": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/support": "^10.49.0|^11.45.3|^12.41.1", + "laravel/mcp": "^0.5.1", + "laravel/prompts": "0.1.25|^0.3.6", + "laravel/roster": "^0.2.9", + "php": "^8.1" + }, + "require-dev": { + "laravel/pint": "^1.20.0", + "mockery/mockery": "^1.6.12", + "orchestra/testbench": "^8.36.0|^9.15.0|^10.6", + "pestphp/pest": "^2.36.0|^3.8.4|^4.1.5", + "phpstan/phpstan": "^2.1.27", + "rector/rector": "^2.1" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Boost\\BoostServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Boost\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Laravel Boost accelerates AI-assisted development by providing the essential context and structure that AI needs to generate high-quality, Laravel-specific code.", + "homepage": "https://github.com/laravel/boost", + "keywords": [ + "ai", + "dev", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/boost/issues", + "source": "https://github.com/laravel/boost" + }, + "time": "2026-01-14T14:51:16+00:00" + }, + { + "name": "laravel/mcp", + "version": "v0.5.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/mcp.git", + "reference": "b9bdd8d6f8b547c8733fe6826b1819341597ba3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/mcp/zipball/b9bdd8d6f8b547c8733fe6826b1819341597ba3c", + "reference": "b9bdd8d6f8b547c8733fe6826b1819341597ba3c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "illuminate/console": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/container": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/contracts": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/http": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/json-schema": "^12.41.1", + "illuminate/routing": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/support": "^10.49.0|^11.45.3|^12.41.1", + "illuminate/validation": "^10.49.0|^11.45.3|^12.41.1", + "php": "^8.1" + }, + "require-dev": { + "laravel/pint": "^1.20", + "orchestra/testbench": "^8.36|^9.15|^10.8", + "pestphp/pest": "^2.36.0|^3.8.4|^4.1.0", + "phpstan/phpstan": "^2.1.27", + "rector/rector": "^2.2.4" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Mcp": "Laravel\\Mcp\\Server\\Facades\\Mcp" + }, + "providers": [ + "Laravel\\Mcp\\Server\\McpServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Mcp\\": "src/", + "Laravel\\Mcp\\Server\\": "src/Server/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Rapidly build MCP servers for your Laravel applications.", + "homepage": "https://github.com/laravel/mcp", + "keywords": [ + "laravel", + "mcp" + ], + "support": { + "issues": "https://github.com/laravel/mcp/issues", + "source": "https://github.com/laravel/mcp" + }, + "time": "2025-12-19T19:32:34+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.4", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/49f92285ff5d6fc09816e976a004f8dec6a0ea30", + "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0|^12.0", + "illuminate/contracts": "^10.24|^11.0|^12.0", + "illuminate/log": "^10.24|^11.0|^12.0", + "illuminate/process": "^10.24|^11.0|^12.0", + "illuminate/support": "^10.24|^11.0|^12.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.0", + "laravel/pint": "^1.13", + "orchestra/testbench-core": "^8.13|^9.17|^10.8", + "pestphp/pest": "^2.20|^3.0|^4.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0|^4.0", + "phpstan/phpstan": "^1.12.27", + "symfony/var-dumper": "^6.3|^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "dev", + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2025-11-20T16:29:35+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/c67b4195b75491e4dfc6b00b1c78b68d86f54c90", + "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90", "shasum": "" }, "require": { @@ -11534,13 +11827,13 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.87.2", - "illuminate/view": "^11.46.0", - "larastan/larastan": "^3.7.1", - "laravel-zero/framework": "^11.45.0", + "friendsofphp/php-cs-fixer": "^3.92.4", + "illuminate/view": "^12.44.0", + "larastan/larastan": "^3.8.1", + "laravel-zero/framework": "^12.0.4", "mockery/mockery": "^1.6.12", - "nunomaduro/termwind": "^2.3.1", - "pestphp/pest": "^2.36.0" + "nunomaduro/termwind": "^2.3.3", + "pestphp/pest": "^3.8.4" }, "bin": [ "builds/pint" @@ -11566,6 +11859,7 @@ "description": "An opinionated code formatter for PHP.", "homepage": "https://laravel.com", "keywords": [ + "dev", "format", "formatter", "lint", @@ -11576,7 +11870,68 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2025-09-19T02:57:12+00:00" + "time": "2026-01-05T16:49:17+00:00" + }, + { + "name": "laravel/roster", + "version": "v0.2.9", + "source": { + "type": "git", + "url": "https://github.com/laravel/roster.git", + "reference": "82bbd0e2de614906811aebdf16b4305956816fa6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/roster/zipball/82bbd0e2de614906811aebdf16b4305956816fa6", + "reference": "82bbd0e2de614906811aebdf16b4305956816fa6", + "shasum": "" + }, + "require": { + "illuminate/console": "^10.0|^11.0|^12.0", + "illuminate/contracts": "^10.0|^11.0|^12.0", + "illuminate/routing": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0", + "php": "^8.1|^8.2", + "symfony/yaml": "^6.4|^7.2" + }, + "require-dev": { + "laravel/pint": "^1.14", + "mockery/mockery": "^1.6", + "orchestra/testbench": "^8.22.0|^9.0|^10.0", + "pestphp/pest": "^2.0|^3.0", + "phpstan/phpstan": "^2.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Roster\\RosterServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Roster\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Detect packages & approaches in use within a Laravel project", + "homepage": "https://github.com/laravel/roster", + "keywords": [ + "dev", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/roster/issues", + "source": "https://github.com/laravel/roster" + }, + "time": "2025-10-20T09:56:46+00:00" }, { "name": "mockery/mockery", @@ -12315,16 +12670,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.4", + "version": "5.6.6", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2" + "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90a04bcbf03784066f16038e87e23a0a83cee3c2", - "reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/5cee1d3dfc2d2aa6599834520911d246f656bcb8", + "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8", "shasum": "" }, "require": { @@ -12334,7 +12689,7 @@ "phpdocumentor/reflection-common": "^2.2", "phpdocumentor/type-resolver": "^1.7", "phpstan/phpdoc-parser": "^1.7|^2.0", - "webmozart/assert": "^1.9.1" + "webmozart/assert": "^1.9.1 || ^2" }, "require-dev": { "mockery/mockery": "~1.3.5 || ~1.6.0", @@ -12373,22 +12728,22 @@ "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.4" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.6" }, - "time": "2025-11-17T21:13:10+00:00" + "time": "2025-12-22T21:13:58+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.11.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "8cbe6100e8971efbf8e2e7da3a202ba83eafd5a3" + "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/8cbe6100e8971efbf8e2e7da3a202ba83eafd5a3", - "reference": "8cbe6100e8971efbf8e2e7da3a202ba83eafd5a3", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195", + "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195", "shasum": "" }, "require": { @@ -12431,22 +12786,22 @@ "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.11.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0" }, - "time": "2025-11-19T20:28:58+00:00" + "time": "2025-11-21T15:09:14+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374" }, "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/16dbf9937da8d4528ceb2145c9c7c0bd29e26374", + "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374", "shasum": "" }, "require": { @@ -12478,9 +12833,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.3.1" }, - "time": "2025-08-30T15:50:23+00:00" + "time": "2026-01-12T11:33:04+00:00" }, { "name": "phpunit/php-code-coverage", @@ -13968,23 +14323,23 @@ }, { "name": "webmozart/assert", - "version": "1.12.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", + "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", "shasum": "" }, "require": { "ext-ctype": "*", "ext-date": "*", "ext-filter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.2" }, "suggest": { "ext-intl": "", @@ -13994,7 +14349,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10-dev" + "dev-feature/2-0": "2.0-dev" } }, "autoload": { @@ -14010,6 +14365,10 @@ { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" } ], "description": "Assertions to validate method input/output with nice error messages.", @@ -14020,9 +14379,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.1" + "source": "https://github.com/webmozarts/assert/tree/2.1.2" }, - "time": "2025-10-29T15:56:20+00:00" + "time": "2026-01-13T14:02:24+00:00" } ], "aliases": [], @@ -14034,5 +14393,5 @@ "php": "^8.2" }, "platform-dev": {}, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/config/livewire.php b/config/livewire.php new file mode 100644 index 0000000..2690e9b --- /dev/null +++ b/config/livewire.php @@ -0,0 +1,282 @@ + [ + resource_path('views/livewire'), + resource_path('views/components'), + ], + + /* + |--------------------------------------------------------------------------- + | Component Namespaces + |--------------------------------------------------------------------------- + | + | This value sets default namespaces that will be used to resolve view-based + | components like single-file and multi-file components. These folders'll + | also be referenced when creating new components via the make command. + | + */ + + 'component_namespaces' => [ + 'layouts' => resource_path('views/layouts'), + 'pages' => resource_path('views/pages'), + ], + + /* + |--------------------------------------------------------------------------- + | Page Layout + |--------------------------------------------------------------------------- + | The view that will be used as the layout when rendering a single component as + | an entire page via `Route::livewire('/post/create', 'pages::create-post')`. + | In this case, the content of pages::create-post will render into $slot. + | + */ + + 'component_layout' => 'layouts::app', + + /* + |--------------------------------------------------------------------------- + | Lazy Loading Placeholder + |--------------------------------------------------------------------------- + | Livewire allows you to lazy load components that would otherwise slow down + | the initial page load. Every component can have a custom placeholder or + | you can define the default placeholder view for all components below. + | + */ + + 'component_placeholder' => null, // Example: 'placeholders::skeleton' + + /* + |--------------------------------------------------------------------------- + | Make Command + |--------------------------------------------------------------------------- + | This value determines the default configuration for the artisan make command + | You can configure the component type (sfc, mfc, class) and whether to use + | the high-voltage (⚡) emoji as a prefix in the sfc|mfc component names. + | + */ + + 'make_command' => [ + 'type' => 'sfc', // Options: 'sfc', 'mfc', 'class' + 'emoji' => true, // Options: true, false + 'with' => [ + 'js' => false, + 'css' => false, + 'test' => false, + ], + ], + + /* + |--------------------------------------------------------------------------- + | Class Namespace + |--------------------------------------------------------------------------- + | + | This value sets the root class namespace for Livewire component classes in + | your application. This value will change where component auto-discovery + | finds components. It's also referenced by the file creation commands. + | + */ + + 'class_namespace' => 'App\\Livewire', + + /* + |--------------------------------------------------------------------------- + | Class Path + |--------------------------------------------------------------------------- + | + | This value is used to specify the path where Livewire component class files + | are created when running creation commands like `artisan make:livewire`. + | This path is customizable to match your projects directory structure. + | + */ + + 'class_path' => app_path('Livewire'), + + /* + |--------------------------------------------------------------------------- + | View Path + |--------------------------------------------------------------------------- + | + | This value is used to specify where Livewire component Blade templates are + | stored when running file creation commands like `artisan make:livewire`. + | It is also used if you choose to omit a component's render() method. + | + */ + + 'view_path' => resource_path('views/livewire'), + + /* + |--------------------------------------------------------------------------- + | Temporary File Uploads + |--------------------------------------------------------------------------- + | + | Livewire handles file uploads by storing uploads in a temporary directory + | before the file is stored permanently. All file uploads are directed to + | a global endpoint for temporary storage. You may configure this below: + | + */ + + 'temporary_file_upload' => [ + 'disk' => env('LIVEWIRE_TEMPORARY_FILE_UPLOAD_DISK'), // Example: 'local', 's3' | Default: 'default' + 'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB) + 'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp' + 'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1' + 'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs... + 'png', 'gif', 'bmp', 'svg', 'wav', 'mp4', + 'mov', 'avi', 'wmv', 'mp3', 'm4a', + 'jpg', 'jpeg', 'mpga', 'webp', 'wma', + ], + 'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated... + 'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs... + ], + + /* + |--------------------------------------------------------------------------- + | Render On Redirect + |--------------------------------------------------------------------------- + | + | This value determines if Livewire will run a component's `render()` method + | after a redirect has been triggered using something like `redirect(...)` + | Setting this to true will render the view once more before redirecting + | + */ + + 'render_on_redirect' => false, + + /* + |--------------------------------------------------------------------------- + | Eloquent Model Binding + |--------------------------------------------------------------------------- + | + | Previous versions of Livewire supported binding directly to eloquent model + | properties using wire:model by default. However, this behavior has been + | deemed too "magical" and has therefore been put under a feature flag. + | + */ + + 'legacy_model_binding' => false, + + /* + |--------------------------------------------------------------------------- + | Auto-inject Frontend Assets + |--------------------------------------------------------------------------- + | + | By default, Livewire automatically injects its JavaScript and CSS into the + | and of pages containing Livewire components. By disabling + | this behavior, you need to use @livewireStyles and @livewireScripts. + | + */ + + 'inject_assets' => true, + + /* + |--------------------------------------------------------------------------- + | Navigate (SPA mode) + |--------------------------------------------------------------------------- + | + | By adding `wire:navigate` to links in your Livewire application, Livewire + | will prevent the default link handling and instead request those pages + | via AJAX, creating an SPA-like effect. Configure this behavior here. + | + */ + + 'navigate' => [ + 'show_progress_bar' => true, + 'progress_bar_color' => '#2299dd', + ], + + /* + |--------------------------------------------------------------------------- + | HTML Morph Markers + |--------------------------------------------------------------------------- + | + | Livewire intelligently "morphs" existing HTML into the newly rendered HTML + | after each update. To make this process more reliable, Livewire injects + | "markers" into the rendered Blade surrounding @if, @class & @foreach. + | + */ + + 'inject_morph_markers' => true, + + /* + |--------------------------------------------------------------------------- + | Smart Wire Keys + |--------------------------------------------------------------------------- + | + | Livewire uses loops and keys used within loops to generate smart keys that + | are applied to nested components that don't have them. This makes using + | nested components more reliable by ensuring that they all have keys. + | + */ + + 'smart_wire_keys' => true, + + /* + |--------------------------------------------------------------------------- + | Pagination Theme + |--------------------------------------------------------------------------- + | + | When enabling Livewire's pagination feature by using the `WithPagination` + | trait, Livewire will use Tailwind templates to render pagination views + | on the page. If you want Bootstrap CSS, you can specify: "bootstrap" + | + */ + + 'pagination_theme' => 'tailwind', + + /* + |--------------------------------------------------------------------------- + | Release Token + |--------------------------------------------------------------------------- + | + | This token is stored client-side and sent along with each request to check + | a users session to see if a new release has invalidated it. If there is + | a mismatch it will throw an error and prompt for a browser refresh. + | + */ + + 'release_token' => 'a', + + /* + |--------------------------------------------------------------------------- + | CSP Safe + |--------------------------------------------------------------------------- + | + | This config is used to determine if Livewire will use the CSP-safe version + | of Alpine in its bundle. This is useful for applications that are using + | strict Content Security Policy (CSP) to protect against XSS attacks. + | + */ + + 'csp_safe' => false, + + /* + |--------------------------------------------------------------------------- + | Payload Guards + |--------------------------------------------------------------------------- + | + | These settings protect against malicious or oversized payloads that could + | cause denial of service. The default values should feel reasonable for + | most web applications. Each can be set to null to disable the limit. + | + */ + + 'payload' => [ + 'max_size' => 1024 * 1024, // 1MB - maximum request payload size in bytes + 'max_nesting_depth' => 10, // Maximum depth of dot-notation property paths + 'max_calls' => 50, // Maximum method calls per request + 'max_components' => 20, // Maximum components per batch request + ], +]; diff --git a/opencode.json b/opencode.json new file mode 100644 index 0000000..6f800ed --- /dev/null +++ b/opencode.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://opencode.ai/config.json", + "mcp": { + "laravel-boost": { + "type": "local", + "enabled": true, + "command": [ + "vendor/bin/sail", + "artisan", + "boost:mcp" + ] + } + } +} \ No newline at end of file diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..f884b3d --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,197 @@ + + + + + + {!! seo($seo ?? null) !!} + + {{ $title ?? 'Page Title' }} + @livewireStyles + @wireUiScripts + @stack('scripts') + @vite(['resources/js/app.js','resources/css/app.css']) + @googlefonts + + + + @include('components.layouts.partials.styles') + + + + + +
+ +
+ +
+
+
+ + +
+ + + +
+ + +
+ + {{--@include('components.layouts.partials.search-button')--}} + + {{--@include('components.layouts.partials.notification-buttons')--}} + + + @if(\App\Support\NostrAuth::check()) +
+ @csrf + + + @else + + @endif + + +
+ + +
+ + {{--@include('components.layouts.partials.dark-mode-toggle')--}} + + + {{--
--}} + + {{--@include('components.layouts.partials.user-button')--}} + +
+ +
+
+
+
+ {{ $slot }} +
+
+
+@livewireScriptConfig + + + + diff --git a/resources/views/livewire/association/election/admin.blade.php b/resources/views/livewire/association/election/admin.blade.php new file mode 100644 index 0000000..b3d1411 --- /dev/null +++ b/resources/views/livewire/association/election/admin.blade.php @@ -0,0 +1,74 @@ +
+ ['icon' => 'fa-crown', 'title' => 'Präsidium'], + 'board' => ['icon' => 'fa-users', 'title' => 'Vorstandsmitglieder'], + ]; + ?> + + + +
+ + +
+ + +
+

+ Wahl des Vorstands year); ?> +

+
+ +
+ + + + +
+
+
+

+

+
+
+ + +
+
+
+
+

+

+
+
+ + +
+
+
+ +
+ + +
+
+
+

Mitglieder

+

+ Du bist nicht berechtigt, Mitglieder zu bearbeiten. +

+
+
+
+ +
diff --git a/resources/views/livewire/association/election/index.blade.php b/resources/views/livewire/association/election/index.blade.php new file mode 100644 index 0000000..f1e0f03 --- /dev/null +++ b/resources/views/livewire/association/election/index.blade.php @@ -0,0 +1,33 @@ + +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+
+

Einstellungen

+

+ Du bist nicht berechtigt, die Einstellungen zu bearbeiten. +

+
+
+
+ +
+
diff --git a/resources/views/pages/association/election/[Election:year].blade.php b/resources/views/livewire/association/election/show.blade.php similarity index 80% rename from resources/views/pages/association/election/[Election:year].blade.php rename to resources/views/livewire/association/election/show.blade.php index 35ba73b..7f0f33d 100644 --- a/resources/views/pages/association/election/[Election:year].blade.php +++ b/resources/views/livewire/association/election/show.blade.php @@ -1,177 +1,12 @@ - false, - 'showLog' => false, - 'currentPubkey' => null, - 'currentPleb' => null, - 'events' => [], - 'boardEvents' => [], - 'election' => fn() => $election, - 'plebs' => [], - 'search' => '', - 'signThisEvent' => '', - 'isNotClosed' => true, -]); - -mount(function () { - $this->plebs = \App\Models\EinundzwanzigPleb::query() - ->with(['profile']) - ->whereIn('association_status', [3, 4]) - ->orderBy('association_status', 'desc') - ->get() - ->toArray(); - $this->loadEvents(); - $this->loadBoardEvents(); - if ($this->election->end_time?->isPast() || !config('services.voting')) { - $this->isNotClosed = false; - } -}); - -on([ - 'nostrLoggedIn' => function ($pubkey) { - \App\Support\NostrAuth::login($pubkey); - $this->currentPubkey = $pubkey; - $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); - $logPubkeys = [ - '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033', - '430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279', - ]; - if (in_array($this->currentPubkey, $logPubkeys, true)) { - $this->showLog = true; - $this->isAllowed = true; - } - }, - 'echo:votes,.newVote' => function () { - $this->loadEvents(); - $this->loadBoardEvents(); - }, - 'nostrLoggedOut' => function () { - $this->isAllowed = false; - $this->currentPubkey = null; - $this->currentPleb = null; - }, -]); - -updated([ - 'search' => function ($value) { - $this->plebs = \App\Models\EinundzwanzigPleb::query() - ->with(['profile']) - ->whereIn('association_status', [3, 4]) - ->where(fn($query) - => $query - ->where('pubkey', 'like', "%$value%") - ->orWhereHas('profile', fn($query) => $query->where('name', 'ilike', "%$value%"))) - ->orderBy('association_status', 'desc') - ->get() - ->toArray(); - }, -]); - -$loadEvents = function () { - $this->events = $this->loadNostrEvents([32122]); -}; - -$loadBoardEvents = function () { - $this->boardEvents = $this->loadNostrEvents([2121]); -}; - -$loadNostrEvents = function ($kinds) { - $subscription = new Subscription(); - $subscriptionId = $subscription->setId(); - $filter = new Filter(); - $filter->setKinds($kinds); - $requestMessage = new RequestMessage($subscriptionId, [$filter]); - $relaySet = new RelaySet(); - $relaySet->setRelays([new Relay(config('services.relay'))]); - $request = new Request($relaySet, $requestMessage); - $response = $request->send(); - return collect($response[config('services.relay')]) - ->map(function($event) { - if(!isset($event->event)) { - return false; - } - return [ - 'id' => $event->event->id, - 'kind' => $event->event->kind, - 'content' => $event->event->content, - 'pubkey' => $event->event->pubkey, - 'tags' => $event->event->tags, - 'created_at' => $event->event->created_at, - ]; - }) - ->filter() - ->toArray(); -}; - -$vote = function ($pubkey, $type, $board = false) { - if ($this->election->end_time?->isPast()) { - $this->isNotClosed = false; - return; - } - $note = new NostrEvent(); - $note->setKind($board ? 2121 : 32122); - if (!$board) { - $dTag = sprintf('%s,%s,%s', $this->currentPleb->pubkey, date('Y'), $type); - $note->setTags([['d', $dTag]]); - } - $note->setContent("$pubkey,$type"); - $this->signThisEvent = $note->toJson(); -}; - -$checkElection = function () { - if ($this->election->end_time?->isPast()) { - $this->isNotClosed = false; - } -}; - -$signEvent = function ($event) { - $note = new NostrEvent(); - $note->setId($event['id']); - $note->setSignature($event['sig']); - $note->setKind($event['kind']); - $note->setContent($event['content']); - $note->setPublicKey($event['pubkey']); - $note->setTags($event['tags']); - $note->setCreatedAt($event['created_at']); - $eventMessage = new EventMessage($note); - $relay = new Relay(config('services.relay')); - $relay->setMessage($eventMessage); - $relay->send(); - Broadcast::on('votes')->as('newVote')->sendNow(); -}; - -?> - - @volt
- @if($isAllowed) +
- @php + ['icon' => 'fa-crown', 'title' => 'Präsidium'], 'board' => ['icon' => 'fa-users', 'title' => 'Vizepräsidium'], @@ -227,7 +62,7 @@ $signEvent = function ($event) { }) ->sortByDesc('created_at') ->values(); - @endphp + ?>
    - @foreach($plebs as $pleb) +
  • {{ $pleb['profile']['name'] ?? $pleb['pubkey'] }} + class="text-sm font-semibold text-gray-800 dark:text-gray-100 truncate">
    + color="color()); ?>" + label="label()); ?>"/>
    - @foreach($positions as $name => $p) - @php + $p): ?> + filter(fn ($e) => $e['pubkey'] === $pleb['pubkey'])->firstWhere('type', $name); - @endphp + ?>
    - @if($votedResult) - - @endif + wire:key="p_"> + + +
    - @endforeach +
- @endforeach +
@@ -369,9 +204,9 @@ $signEvent = function ($event) { - @if($currentPubkey) + - @php + candidates, true, 512, JSON_THROW_ON_ERROR)) ->map(function ($c) use ($loadedEvents, $currentPubkey) { $candidates = \App\Models\Profile::query() @@ -425,7 +260,7 @@ $signEvent = function ($event) { 'candidates' => $candidates, ]; }); - @endphp + ?>
@@ -437,12 +272,12 @@ $signEvent = function ($event) {
- @if($isNotClosed) + - @else + label="Die Wahl ist geöffnet bis zum end_time?->timezone('Europe/Berlin')->format('d.m.Y H:i')); ?>"/> + - @endif +
Wahl des Präsidiums - @php +
- +
-

{{ $president['title'] }}

+

- @php + filter(fn ($event) => $event['pubkey'] === $currentPubkey)->firstWhere('type', 'presidency'); - @endphp - @if($votedResult) - Du hast "{{ $votedResult['votedFor']['name'] ?? 'error' }}" gewählt - @else + ?> + + Du hast "" gewählt + Wähle deinen Kandidaten für das Präsidium. - @endif +
- @foreach($electionConfig->firstWhere('type', 'presidency')['candidates'] ?? [] as $c) + firstWhere('type', 'presidency')['candidates'] ?? [] as $c): ?>
+ wire:click="vote('', 'presidency')" + + class=" cursor-pointer text-xs inline-flex font-medium rounded-full text-center px-2.5 py-1">
{{ $c['name'] }} - {{ $c['name'] }} + alt=""/> +
- @endforeach +
@@ -543,21 +378,21 @@ $signEvent = function ($event) {
- @foreach($electionConfigBoard->firstWhere('type', 'board')['candidates'] ?? [] as $c) + firstWhere('type', 'board')['candidates'] ?? [] as $c): ?>
+ wire:click="vote('', 'board', true)" + + class=" cursor-pointer text-xs inline-flex font-medium rounded-full text-center px-2.5 py-1">
{{ $c['name'] }} - {{ $c['name'] }} + alt=""/> +
- @endforeach +
@@ -573,7 +408,7 @@ $signEvent = function ($event) {

Präsidium Log {{ $loadedEvents->count() }} + class="text-gray-400 dark:text-gray-500 font-medium">count()); ?>

@@ -607,29 +442,29 @@ $signEvent = function ($event) { - @foreach($loadedEvents as $event) +
{{ \Illuminate\Support\Str::limit($event['id'], 10) }}
+ class="font-medium">
-
{{ $event['kind'] }}
+
-
{{ $event['profile']['name'] ?? '' }}
+
-
{{ $event['created_at'] }}
+
-
{{ $event['votedFor']['name'] ?? '' }}
+
-
{{ $event['type'] }}
+
- @endforeach +
@@ -640,7 +475,7 @@ $signEvent = function ($event) {

Board Log {{ $loadedBoardEvents->count() }} + class="text-gray-400 dark:text-gray-500 font-medium">count()); ?>

@@ -674,29 +509,29 @@ $signEvent = function ($event) { - @foreach($loadedBoardEvents as $event) +
{{ \Illuminate\Support\Str::limit($event['id'], 10) }}
+ class="font-medium">
-
{{ $event['kind'] }}
+
-
{{ $event['profile']['name'] ?? '' }}
+
-
{{ $event['created_at'] }}
+
-
{{ $event['votedFor']['name'] ?? '' }}
+
-
{{ $event['type'] }}
+
- @endforeach +
@@ -707,10 +542,10 @@ $signEvent = function ($event) {
- @endif +
- @else +
@@ -721,8 +556,7 @@ $signEvent = function ($event) {
- @endif + - @endvolt
diff --git a/resources/views/livewire/association/members/admin.blade.php b/resources/views/livewire/association/members/admin.blade.php new file mode 100644 index 0000000..6017995 --- /dev/null +++ b/resources/views/livewire/association/members/admin.blade.php @@ -0,0 +1,20 @@ + +
+ +
+ +
+ +
+
+
+

Mitglieder

+

+ Du bist nicht berechtigt, Mitglieder zu bearbeiten. +

+
+
+
+ +
+
diff --git a/resources/views/pages/association/news/index.blade.php b/resources/views/livewire/association/news/index.blade.php similarity index 71% rename from resources/views/pages/association/news/index.blade.php rename to resources/views/livewire/association/news/index.blade.php index 66f987d..2182b8b 100644 --- a/resources/views/pages/association/news/index.blade.php +++ b/resources/views/livewire/association/news/index.blade.php @@ -1,122 +1,8 @@ - fn() - => \App\Models\Notification::query() - ->orderBy('created_at', 'desc') - ->get(), - 'isAllowed' => false, - 'canEdit' => false, - 'currentPubkey' => null, - 'currentPleb' => null, -]); - -mount(function () { - if (\App\Support\NostrAuth::check()) { - $this->currentPubkey = \App\Support\NostrAuth::pubkey(); - $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $this->currentPubkey)->first(); - if (in_array($this->currentPleb->npub, config('einundzwanzig.config.current_board'), true)) { - $this->canEdit = true; - } - $this->isAllowed = true; - } -}); - -on([ - 'nostrLoggedIn' => function ($pubkey) { - \App\Support\NostrAuth::login($pubkey); - $this->currentPubkey = $pubkey; - $this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first(); - if (in_array($this->currentPleb->npub, config('einundzwanzig.config.current_board'), true)) { - $this->canEdit = true; - } - $this->isAllowed = true; - }, - 'nostrLoggedOut' => function () { - $this->isAllowed = false; - $this->currentPubkey = null; - $this->currentPleb = null; - }, -]); - -$save = function () { - $this->form->validate(); - - $this->validate([ - 'file' => 'required|file|mimes:pdf|max:1024', - ]); - - $notification = \App\Models\Notification::query() - ->orderBy('created_at', 'desc') - ->create([ - 'einundzwanzig_pleb_id' => $this->currentPleb->id, - 'category' => $this->form->category, - 'name' => $this->form->name, - 'description' => $this->form->description, - ]); - - $notification - ->addMedia($this->file->getRealPath()) - ->usingName($this->file->getClientOriginalName()) - ->toMediaCollection('pdf'); - - $this->form->reset(); - $this->file = null; - - $this->news = \App\Models\Notification::query() - ->orderBy('created_at', 'desc') - ->get(); -}; - -$delete = function ($id) { - $notification = new WireNotification($this); - $notification->confirm([ - 'title' => 'Post löschen', - 'message' => 'Bist du sicher, dass du diesen Post löschen möchtest?', - 'accept' => [ - 'label' => 'Ja, löschen', - 'method' => 'deleteNow', - 'params' => $id, - ], - ]); -}; - -$deleteNow = function ($id) { - $notification = \App\Models\Notification::query()->find($id); - $notification->delete(); - $this->news = \App\Models\Notification::query() - ->orderBy('created_at', 'desc') - ->get(); -}; - -?> - - @volt
- @if($isAllowed) +
@@ -151,17 +37,17 @@ $deleteNow = function ($id) { Menu
    - @foreach(\App\Enums\NewsCategory::selectOptions() as $category) +
  • + wire:key="category_">
    - + {{ $category['label'] }} + class="text-sm font-medium text-amber-500">
  • - @endforeach +
@@ -174,25 +60,27 @@ $deleteNow = function ($id) {
- @forelse($news as $post) -
+ + +
{{ $post->einundzwanzigPleb->profile?->name }} + alt="einundzwanzigPleb->profile?->name); ?>">

- {{ $post->name }} + name); ?>

- {{ $post->description }} + description); ?>

@@ -207,14 +95,14 @@ $deleteNow = function ($id) { - {{ $post->einundzwanzigPleb->profile->name }} + einundzwanzigPleb->profile->name); ?>
{{ $post->created_at->format('d.m.Y') }} + class="text-gray-500">created_at->format('d.m.Y')); ?>
@@ -226,20 +114,21 @@ $deleteNow = function ($id) { :href="url()->temporarySignedRoute('dl', now()->addMinutes(30), ['media' => $post->getFirstMedia('pdf')])" label="Öffnen" primary icon="cloud-arrow-down"/> - @if($canEdit) + - @endif + - @empty + +

Keine News vorhanden.

- @endforelse + @@ -256,7 +145,7 @@ $deleteNow = function ($id) {
- @if($canEdit) +
@@ -265,8 +154,16 @@ $deleteNow = function ($id) {
- @error('file') {{ $message }} @enderror + getBag($__errorProps ?? 'default'); +if ($__bag->has($__errorArgs)) : +if (isset($message)) { $__messageOriginal = $message; } +$message = $__bag->first($__errorArgs); ?> + +
- @endif +
@@ -302,7 +199,7 @@ $deleteNow = function ($id) {
- @else +
@@ -315,7 +212,6 @@ $deleteNow = function ($id) {
- @endif + - @endvolt
diff --git a/resources/views/pages/association/profile.blade.php b/resources/views/livewire/association/profile.blade.php similarity index 67% rename from resources/views/pages/association/profile.blade.php rename to resources/views/livewire/association/profile.blade.php index f568709..561d880 100644 --- a/resources/views/pages/association/profile.blade.php +++ b/resources/views/livewire/association/profile.blade.php @@ -1,287 +1,6 @@ - false, - 'showEmail' => true, - 'fax' => '', - 'email' => '', - 'yearsPaid' => [], - 'events' => [], - 'payments' => [], - 'amountToPay' => config('app.env') === 'production' ? 21000 : 1, - 'currentYearIsPaid' => false, - 'currentPubkey' => null, - 'currentPleb' => null, -]); - -form(\App\Livewire\Forms\ApplicationForm::class); - -mount(function () { - if (\App\Support\NostrAuth::check()) { - $this->currentPubkey = \App\Support\NostrAuth::pubkey(); - $this->currentPleb = \App\Models\EinundzwanzigPleb::query() - ->with([ - 'paymentEvents' => fn($query) - => $query->where('year', date('Y')), - ]) - ->where('pubkey', $this->currentPubkey)->first(); - $this->email = $this->currentPleb->email; - $this->no = $this->currentPleb->no_email; - $this->showEmail = !$this->no; - if ($this->currentPleb->association_status === \App\Enums\AssociationStatus::ACTIVE) { - $this->amountToPay = config('app.env') === 'production' ? 21000 : 1; - } - if ($this->currentPleb->paymentEvents->count() < 1) { - $this->createPaymentEvent(); - $this->currentPleb->load('paymentEvents'); - } - $this->loadEvents(); - $this->listenForPayment(); - } -}); - -on([ - 'nostrLoggedIn' => function ($pubkey) { - \App\Support\NostrAuth::login($pubkey); - - $this->currentPubkey = $pubkey; - $this->currentPleb = \App\Models\EinundzwanzigPleb::query() - ->with([ - 'paymentEvents' => fn($query) - => $query->where('year', date('Y')), - ]) - ->where('pubkey', $pubkey)->first(); - $this->email = $this->currentPleb->email; - $this->no = $this->currentPleb->no_email; - $this->showEmail = !$this->no; - if ($this->currentPleb->association_status === \App\Enums\AssociationStatus::ACTIVE) { - $this->amountToPay = config('app.env') === 'production' ? 21000 : 1; - } - if ($this->currentPleb->paymentEvents->count() < 1) { - $this->createPaymentEvent(); - $this->currentPleb->load('paymentEvents'); - } - $this->loadEvents(); - $this->listenForPayment(); - }, - 'nostrLoggedOut' => function () { - \App\Support\NostrAuth::logout(); - - $this->currentPubkey = null; - $this->currentPleb = null; - $this->yearsPaid = []; - $this->events = []; - $this->payments = []; - $this->qrCode = null; - $this->amountToPay = config('app.env') === 'production' ? 21000 : 1; - $this->currentYearIsPaid = false; - }, -]); - -updated([ - 'no' => function () { - $this->showEmail = !$this->no; - $this->currentPleb->update([ - 'no_email' => $this->no, - ]); - }, - 'fax' => function () { - $this->js('alert("Markus Turm wird sich per Fax melden!")'); - }, -]); - -$saveEmail = function () { - $this->validate([ - 'email' => 'required|email', - ]); - $this->currentPleb->update([ - 'email' => $this->email, - ]); - $notification = new Notification($this); - $notification->success('E-Mail Adresse gespeichert.'); -}; - -$pay = function ($comment) { - $paymentEvent = $this->currentPleb - ->paymentEvents() - ->where('year', date('Y')) - ->first(); - if ($paymentEvent->btc_pay_invoice) { - return redirect('https://pay.einundzwanzig.space/i/'.$paymentEvent->btc_pay_invoice); - } - try { - $response = Http::withHeaders([ - 'Authorization' => 'token '.config('services.btc_pay.api_key'), - ])->post( - 'https://pay.einundzwanzig.space/api/v1/stores/98PF86BoMd3C8P1nHHyFdoeznCwtcm5yehcAgoCYDQ2a/invoices', - [ - 'amount' => $this->amountToPay, - 'metadata' => [ - 'orderId' => $comment, - 'orderUrl' => url()->route('association.profile'), - 'itemDesc' => 'Mitgliedsbeitrag '.date('Y').' von nostr:'.$this->currentPleb->npub, - 'posData' => [ - 'event' => $paymentEvent->event_id, - 'pubkey' => $this->currentPleb->pubkey, - 'npub' => $this->currentPleb->npub, - ], - ], - 'checkout' => [ - 'expirationMinutes' => 60 * 24, - 'redirectURL' => url()->route('association.profile'), - 'redirectAutomatically' => true, - 'defaultLanguage' => 'de', - ], - ], - )->throw(); - $paymentEvent->btc_pay_invoice = $response->json()['id']; - $paymentEvent->save(); - - return redirect($response->json()['checkoutLink']); - } catch (Exception $e) { - $notification = new Notification($this); - $notification->error( - 'Fehler beim Erstellen der Rechnung. Bitte versuche es später erneut: '.$e->getMessage(), - ); - } -}; - -$listenForPayment = function () { - $paymentEvent = $this->currentPleb - ->paymentEvents() - ->where('year', date('Y')) - ->first(); - if ($paymentEvent->btc_pay_invoice) { - $response = Http::withHeaders([ - 'Authorization' => 'token '.config('services.btc_pay.api_key'), - ]) - ->get( - 'https://pay.einundzwanzig.space/api/v1/stores/98PF86BoMd3C8P1nHHyFdoeznCwtcm5yehcAgoCYDQ2a/invoices/'.$paymentEvent->btc_pay_invoice, - ); - if ($response->json()['status'] === 'Expired') { - $paymentEvent->btc_pay_invoice = null; - $paymentEvent->paid = false; - $paymentEvent->save(); - } - if ($response->json()['status'] === 'Settled') { - $paymentEvent->paid = true; - $paymentEvent->save(); - $this->currentYearIsPaid = true; - } - } - if ($paymentEvent->paid) { - $this->currentYearIsPaid = true; - } - $paymentEvent = $paymentEvent->refresh(); - $this->payments = $this->currentPleb - ->paymentEvents() - ->where('paid', true) - ->get(); -}; - -$save = function ($type) { - $this->form->validate(); - if (!$this->form->check) { - $this->js('alert("Du musst den Statuten zustimmen.")'); - return; - } - - $this->currentPleb - ->update([ - 'association_status' => $type, - ]); -}; - -$createPaymentEvent = function () { - $note = new NostrEvent(); - $note->setKind(32121); - $note->setContent( - 'Dieses Event dient der Zahlung des Mitgliedsbeitrags für das Jahr '.date( - 'Y', - ).'. Bitte bezahle den Betrag von '.number_format($this->amountToPay, 0, ',', '.').' Satoshis.', - ); - $note->setTags([ - ['d', $this->currentPleb->pubkey.','.date('Y')], - ['zap', 'daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6', config('services.relay'), '1'], - ]); - $signer = new Sign(); - $signer->signEvent($note, config('services.nostr')); - - $eventMessage = new EventMessage($note); - - $relayUrl = config('services.relay'); - $relay = new Relay($relayUrl); - $relay->setMessage($eventMessage); - $result = $relay->send(); - - $this->currentPleb->paymentEvents()->create([ - 'year' => date('Y'), - 'event_id' => $result->eventId, - 'amount' => $this->amountToPay, - ]); -}; - -$loadEvents = function () { - $subscription = new Subscription(); - $subscriptionId = $subscription->setId(); - - $filter1 = new Filter(); - $filter1->setKinds([32121]); - $filter1->setAuthors(['daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6']); - $filters = [$filter1]; - - $requestMessage = new RequestMessage($subscriptionId, $filters); - - $relays = [ - new Relay(config('services.relay')), - ]; - $relaySet = new RelaySet(); - $relaySet->setRelays($relays); - - $request = new Request($relaySet, $requestMessage); - $response = $request->send(); - - $this->events = collect($response[config('services.relay')]) - ->map(function ($event) { - if (!isset($event->event)) { - return false; - } - return [ - 'id' => $event->event->id, - 'kind' => $event->event->kind, - 'content' => $event->event->content, - 'pubkey' => $event->event->pubkey, - 'tags' => $event->event->tags, - 'created_at' => $event->event->created_at, - ]; - }) - ->filter() - ->unique('id') - ->toArray(); -}; - -?> - - @volt
@@ -314,39 +33,8 @@ $loadEvents = function () { class="text-sm font-medium text-orange-500 dark:text-orange-400">Status - {{--
  • - - - - - My Notifications - -
  • --}}
    - - {{--
    -
    Experience -
    - -
    --}} @@ -466,7 +154,6 @@ $loadEvents = function () { @endif
    - {{-- https://v.nostr.build/bomfuwLnOTIDrP4y.mp4 --}}