diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index c8327d3..a4ff129 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -6,6 +6,7 @@ on: env: REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} jobs: build-and-push: @@ -39,9 +40,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: | - ${{ env.REGISTRY }}/usetrmnl/byos_laravel - ${{ env.REGISTRY }}/usetrmnl/larapaper + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=semver,pattern={{version}} diff --git a/.gitignore b/.gitignore index 838d9c1..390761f 100644 --- a/.gitignore +++ b/.gitignore @@ -40,5 +40,3 @@ yarn-error.log /.cursor /.opencode /build.sh -/.junie -/.agents diff --git a/Dockerfile b/Dockerfile index 4dc531b..2d761ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ ######################## # Base Image ######################## -FROM bnussbau/serversideup-php:8.4-fpm-nginx-alpine-imagick-chromium@sha256:ed705a4060d50143ddc538c1288afff217eaf76ad5791f7556a97943854cf745 AS base +FROM bnussbau/serversideup-php:8.4-fpm-nginx-alpine-imagick-chromium@sha256:52ac545fdb57b2ab7568b1c7fc0a98cb1a69a275d8884249778a80914272fa48 AS base -LABEL org.opencontainers.image.source=https://github.com/usetrmnl/larapaper -LABEL org.opencontainers.image.description="LaraPaper" +LABEL org.opencontainers.image.source=https://github.com/usetrmnl/byos_laravel +LABEL org.opencontainers.image.description="TRMNL BYOS Laravel" LABEL org.opencontainers.image.licenses=MIT ARG APP_VERSION @@ -18,7 +18,7 @@ ENV TRMNL_LIQUID_ENABLED=1 # Switch to the root user so we can do root things USER root -COPY --chown=www-data:www-data --from=bnussbau/trmnl-liquid-cli:0.2.0 /usr/local/bin/trmnl-liquid-cli /usr/local/bin/ +COPY --chown=www-data:www-data --from=bnussbau/trmnl-liquid-cli:0.1.0 /usr/local/bin/trmnl-liquid-cli /usr/local/bin/ # Set the working directory WORKDIR /var/www/html diff --git a/README.md b/README.md index c1ebafe..2231b24 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -## LaraPaper (PHP/Laravel) +## TRMNL BYOS (PHP/Laravel) -[![tests](https://github.com/usetrmnl/larapaper/actions/workflows/test.yml/badge.svg)](https://github.com/usetrmnl/larapaper/actions/workflows/test.yml) +[![tests](https://github.com/usetrmnl/byos_laravel/actions/workflows/test.yml/badge.svg)](https://github.com/usetrmnl/byos_laravel/actions/workflows/test.yml) -LaraPaper is a self-hostable implementation of a TRMNL server (BYOS), built with Laravel. +TRMNL BYOS Laravel is a self-hostable implementation of a TRMNL server, built with Laravel. It allows you to manage TRMNL devices, generate screens using **native plugins** (Screens API, Markup), **recipes** (130+ from the [OSS community catalog](https://bnussbau.github.io/trmnl-recipe-catalog/), 700+ from the [TRMNL catalog](https://trmnl.com/recipes), or your own), or the **API**, and can also act as a **proxy** for the native cloud service (Core). With over 50k downloads and 200+ stars, it’s the most popular community-driven BYOS. ![Screenshot](README_byos-screenshot.png) @@ -26,7 +26,7 @@ It allows you to manage TRMNL devices, generate screens using **native plugins** * Custom ESP32 with TRMNL firmware * E-Reader Devices * KOReader ([trmnl-koreader](https://github.com/usetrmnl/trmnl-koreader)) - * Kindle ([trmnl-kindle](https://github.com/usetrmnl/larapaper/pull/27)) + * Kindle ([trmnl-kindle](https://github.com/usetrmnl/byos_laravel/pull/27)) * Nook ([trmnl-nook](https://github.com/usetrmnl/trmnl-nook)) * Kobo ([trmnl-kobo](https://github.com/usetrmnl/trmnl-kobo)) * Android Devices with [trmnl-android](https://github.com/usetrmnl/trmnl-android) @@ -61,7 +61,7 @@ Docker Compose file located at: [docker/prod/docker-compose.yml](docker/prod/doc ##### Backup Database ```sh -docker ps #find container id of larapaper container +docker ps #find container id of byos_laravel container docker cp {{CONTAINER_ID}}:/var/www/html/database/storage/database.sqlite database_backup.sqlite ``` @@ -73,11 +73,11 @@ docker compose up -d ``` #### VPS -If you’re using a VPS (e.g., Hetzner) and prefer an alternative to native Docker, you can install Dokploy and deploy LaraPaper using the integrated [Template](https://templates.dokploy.com/?q=trmnl+byos+laravel). +If you’re using a VPS (e.g., Hetzner) and prefer an alternative to native Docker, you can install Dokploy and deploy BYOS Laravel using the integrated [Template](https://templates.dokploy.com/?q=trmnl+byos+laravel). It’s a quick way to get started without having to manually manage Docker setup. #### PikaPods -You can vote for LaraPaper to be included as PikaPods Template here: [feedback.pikapods.com](https://feedback.pikapods.com/posts/842/add-app-trmnl-byos-laravel) +You can vote for TRMNL BYOS Laravel to be included as PikaPods Template here: [feedback.pikapods.com](https://feedback.pikapods.com/posts/842/add-app-trmnl-byos-laravel) #### Umbrel Umbrel is supported through a community store, [see](http://github.com/bnussbau/umbrel-store). @@ -121,16 +121,10 @@ php artisan db:seed --class=ExampleRecipesSeeder | `TRMNL_PROXY_REFRESH_MINUTES` | How often should the server fetch new images from native service | 15 | | `REGISTRATION_ENABLED` | Allow user registration via Webinterface | 1 | | `SSL_MODE` | SSL Mode, if not using a Reverse Proxy ([docs](https://serversideup.net/open-source/docker-php/docs/customizing-the-image/configuring-ssl)) | `off` | -| `FORCE_HTTPS` | If your server handles SSL termination, enforce HTTPS. Alternative: `TRUSTED_PROXIES`. | 0 | -| `TRUSTED_PROXIES` | If your server handles SSL termination, allow mixed mode. e.g. `"172.0.0.0/8"` or `*` | null | +| `FORCE_HTTPS` | If your server handles SSL termination, enforce HTTPS. | 0 | | `PHP_OPCACHE_ENABLE` | Enable PHP Opcache | 0 | | `TRMNL_IMAGE_URL_TIMEOUT` | How long TRMNL waits for a response on the display endpoint. (sec) | 30 | -| `APP_TIMEZONE` | Default timezone, which will be used by the PHP date functions. UTC is recommended. | UTC | - -##### Experimental Environment Variables -| Environment Variable | Description | Default | -|----------------------------------|--------------------------------------------------------------------------------|---------| -| `PUPPETEER_WINDOW_SIZE_STRATEGY` | Set to `v2` to size the browser window to match the device’s screen dimensions | `null` | +| `APP_TIMEZONE` | Default timezone, which will be used by the PHP date functions | UTC | #### Login @@ -173,13 +167,13 @@ See this YouTube guide: [https://www.youtube.com/watch?v=3xehPW-PCOM](https://ww ### ☁️ Activate fresh TRMNL Device with Cloud Proxy 1) Setup the TRMNL as in the official docs with the cloud service (connect one of the plugins to later verify it works) -2) Setup LaraPaper, create a user and login -3) In LaraPaper in the header bar, activate the toggle "Permit Auto-Join" +2) Setup Laravel BYOS, create a user and login +3) In Laravel BYOS in the header bar, activate the toggle "Permit Auto-Join" 4) Press and hold the button on the back of your TRMNL for 5 seconds to reactivate the captive portal (or reflash). -5) Go through the setup process again, in the screen where you provide the Wi-Fi credentials there is also option to set the Server URL. Use the local address of LaraPaper. +5) Go through the setup process again, in the screen where you provide the Wi-Fi credentials there is also option to set the Server URL. Use the local address of your Laravel BYOS 6) The device should automatically appear in the device list; you can deactivate the "Permit Auto-Join" toggle again. 7) In the devices list, activate the toggle "☁️ Proxy" for your device. (Make sure that the queue worker is active. In the docker image it should be running automatically.) -8) As long as no LaraPaper plugin is scheduled, the device will show your cloud plugins. +8) As long as no Laravel BYOS plugin is scheduled, the device will show your cloud plugins. ###### Troubleshooting diff --git a/app/Console/Commands/GenerateDefaultImagesCommand.php b/app/Console/Commands/GenerateDefaultImagesCommand.php index 42e22ba..e2887df 100644 --- a/app/Console/Commands/GenerateDefaultImagesCommand.php +++ b/app/Console/Commands/GenerateDefaultImagesCommand.php @@ -184,7 +184,7 @@ class GenerateDefaultImagesCommand extends Command }; // Determine device properties from DeviceModel - $deviceVariant = $deviceModel->css_name ?? $deviceModel->name ?? 'og'; + $deviceVariant = $deviceModel->name ?? 'og'; $colorDepth = $deviceModel->color_depth ?? '1bit'; // Use the accessor method $scaleLevel = $deviceModel->scale_level; // Use the accessor method $darkMode = $imageType === 'sleep'; // Sleep mode uses dark mode, setup uses light mode @@ -196,7 +196,6 @@ class GenerateDefaultImagesCommand extends Command 'deviceVariant' => $deviceVariant, 'colorDepth' => $colorDepth, 'scaleLevel' => $scaleLevel, - 'cssVariables' => $deviceModel->css_variables, ])->render(); } } diff --git a/app/Jobs/CheckVersionUpdateJob.php b/app/Jobs/CheckVersionUpdateJob.php index c2413c0..0794688 100644 --- a/app/Jobs/CheckVersionUpdateJob.php +++ b/app/Jobs/CheckVersionUpdateJob.php @@ -156,7 +156,7 @@ class CheckVersionUpdateJob private function extractLatestVersion(array $response, bool $enablePrereleases): array { - if (! $enablePrereleases || ! isset($response[0])) { + if (! $enablePrereleases || ! is_array($response) || ! isset($response[0])) { return [ Arr::get($response, 'tag_name'), $response, diff --git a/app/Jobs/FetchDeviceModelsJob.php b/app/Jobs/FetchDeviceModelsJob.php index 2cd39d7..9e148b9 100644 --- a/app/Jobs/FetchDeviceModelsJob.php +++ b/app/Jobs/FetchDeviceModelsJob.php @@ -12,10 +12,8 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Arr; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; final class FetchDeviceModelsJob implements ShouldQueue { @@ -211,41 +209,12 @@ final class FetchDeviceModelsJob implements ShouldQueue $attributes['palette_id'] = $firstPaletteId; } - $attributes['css_name'] = $this->parseCssNameFromApi($modelData['css'] ?? null); - $attributes['css_variables'] = $this->parseCssVariablesFromApi($modelData['css'] ?? null); - DeviceModel::updateOrCreate( ['name' => $name], $attributes ); } - /** - * Extract css_name from API css payload (strip "screen--" prefix from classes.device). - */ - private function parseCssNameFromApi(mixed $css): ?string - { - $deviceClass = is_array($css) ? Arr::get($css, 'classes.device') : null; - - return (is_string($deviceClass) ? Str::after($deviceClass, 'screen--') : null) ?: null; - } - - /** - * Extract css_variables from API css payload (convert [[key, value], ...] to associative array). - */ - private function parseCssVariablesFromApi(mixed $css): ?array - { - $pairs = is_array($css) ? Arr::get($css, 'variables', []) : []; - if (! is_array($pairs)) { - return null; - } - - $validPairs = Arr::where($pairs, fn (mixed $pair): bool => is_array($pair) && isset($pair[0], $pair[1])); - $variables = Arr::pluck($validPairs, 1, 0); - - return $variables !== [] ? $variables : null; - } - /** * Get the first palette ID from model data. */ diff --git a/app/Jobs/GenerateScreenJob.php b/app/Jobs/GenerateScreenJob.php index 4af43dd..b9661cc 100644 --- a/app/Jobs/GenerateScreenJob.php +++ b/app/Jobs/GenerateScreenJob.php @@ -34,13 +34,8 @@ class GenerateScreenJob implements ShouldQueue Device::find($this->deviceId)->update(['current_screen_image' => $newImageUuid]); if ($this->pluginId) { - $plugin = Plugin::find($this->pluginId); - $update = ['current_image' => $newImageUuid]; - if ($plugin->plugin_type === 'recipe') { - $device = Device::with(['deviceModel', 'deviceModel.palette'])->find($this->deviceId); - $update['current_image_metadata'] = ImageGenerationService::buildImageMetadataFromDevice($device); - } - $plugin->update($update); + // cache current image + Plugin::find($this->pluginId)->update(['current_image' => $newImageUuid]); } ImageGenerationService::cleanupFolder(); diff --git a/app/Liquid/Tags/PluginRenderTag.php b/app/Liquid/Tags/PluginRenderTag.php deleted file mode 100644 index e4c441a..0000000 --- a/app/Liquid/Tags/PluginRenderTag.php +++ /dev/null @@ -1,45 +0,0 @@ - - */ - private const PARENT_CONTEXT_KEYS = ['trmnl', 'size', 'data', 'config']; - - protected function buildPartialContext(RenderContext $rootContext, string $templateName, array $variables = []): RenderContext - { - $partialContext = $rootContext->newIsolatedSubContext($templateName); - - foreach (self::PARENT_CONTEXT_KEYS as $key) { - $value = $rootContext->get($key); - if ($value !== null && ! $value instanceof MissingValue) { - $partialContext->set($key, $value); - } - } - - foreach ($variables as $key => $value) { - $partialContext->set($key, $value); - } - - foreach ($this->attributes as $key => $value) { - $partialContext->set($key, $rootContext->evaluate($value)); - } - - return $partialContext; - } -} diff --git a/app/Models/DeviceModel.php b/app/Models/DeviceModel.php index bdc4b98..6132a76 100644 --- a/app/Models/DeviceModel.php +++ b/app/Models/DeviceModel.php @@ -4,14 +4,11 @@ declare(strict_types=1); namespace App\Models; -use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; /** - * @property-read array $css_variables - * @property-read string|null $css_name * @property-read DevicePalette|null $palette */ final class DeviceModel extends Model @@ -30,7 +27,6 @@ final class DeviceModel extends Model 'offset_x' => 'integer', 'offset_y' => 'integer', 'published_at' => 'datetime', - 'css_variables' => 'array', ]; public function getColorDepthAttribute(): ?string @@ -75,54 +71,8 @@ final class DeviceModel extends Model return null; } - /** - * Returns css_name for v2 (per-device sizing); for v1 returns 'og' to preserve legacy single-variant behaviour. - * - * @return Attribute - */ - protected function cssName(): Attribute - { - /** @var Attribute */ - return Attribute::get( - fn (mixed $value): ?string => config('app.puppeteer_window_size_strategy') === 'v2' ? ($value !== null ? (string) $value : null) : 'og' - ); - } - public function palette(): BelongsTo { return $this->belongsTo(DevicePalette::class, 'palette_id'); } - - /** - * Returns css_variables with --screen-w and --screen-h filled from width/height - * when puppeteer_window_size_strategy is v2 and they are not set. - * - * @return Attribute, array> - */ - protected function cssVariables(): Attribute - { - /** @var Attribute, array> */ - return Attribute::get( - /** @return array */ - function (mixed $value, array $attributes): array { - $vars = is_array($value) ? $value : (is_string($value) ? (json_decode($value, true) ?? []) : []); - - if (config('app.puppeteer_window_size_strategy') !== 'v2') { - return $vars; - } - - $width = $attributes['width'] ?? null; - $height = $attributes['height'] ?? null; - - if (empty($vars['--screen-w']) && $width !== null && $width !== '') { - $vars['--screen-w'] = is_numeric($width) ? (int) $width.'px' : (string) $width; - } - if (empty($vars['--screen-h']) && $height !== null && $height !== '') { - $vars['--screen-h'] = is_numeric($height) ? (int) $height.'px' : (string) $height; - } - - /** @var array $vars */ - return $vars; - }); - } } diff --git a/app/Models/PlaylistItem.php b/app/Models/PlaylistItem.php index 744a012..31a6b69 100644 --- a/app/Models/PlaylistItem.php +++ b/app/Models/PlaylistItem.php @@ -140,9 +140,8 @@ class PlaylistItem extends Model if (! $this->isMashup()) { return view('trmnl-layouts.single', [ 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceModel?->css_name ?? $device?->deviceVariant() ?? 'og', + 'deviceVariant' => $device?->deviceVariant() ?? 'og', 'scaleLevel' => $device?->scaleLevel(), - 'cssVariables' => $device?->deviceModel?->css_variables, 'slot' => $this->plugin instanceof Plugin ? $this->plugin->render('full', false, $device) : throw new Exception('Invalid plugin instance'), @@ -163,9 +162,8 @@ class PlaylistItem extends Model return view('trmnl-layouts.mashup', [ 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceModel?->css_name ?? $device?->deviceVariant() ?? 'og', + 'deviceVariant' => $device?->deviceVariant() ?? 'og', 'scaleLevel' => $device?->scaleLevel(), - 'cssVariables' => $device?->deviceModel?->css_variables, 'mashupLayout' => $this->getMashupLayoutType(), 'slot' => implode('', $pluginMarkups), ])->render(); diff --git a/app/Models/Plugin.php b/app/Models/Plugin.php index 7090ec3..bc46559 100644 --- a/app/Models/Plugin.php +++ b/app/Models/Plugin.php @@ -10,7 +10,6 @@ use App\Liquid\Filters\Numbers; use App\Liquid\Filters\StandardFilters; use App\Liquid\Filters\StringMarkup; use App\Liquid\Filters\Uniqueness; -use App\Liquid\Tags\PluginRenderTag; use App\Liquid\Tags\TemplateTag; use App\Services\Plugin\Parsers\ResponseParserRegistry; use App\Services\PluginImportService; @@ -29,7 +28,6 @@ use InvalidArgumentException; use Keepsuit\LaravelLiquid\LaravelLiquidExtension; use Keepsuit\Liquid\Exceptions\LiquidException; use Keepsuit\Liquid\Extensions\StandardExtension; -use Symfony\Component\Yaml\Yaml; class Plugin extends Model { @@ -49,7 +47,6 @@ class Plugin extends Model 'preferred_renderer' => 'string', 'plugin_type' => 'string', 'alias' => 'boolean', - 'current_image_metadata' => 'array', ]; protected static function boot() @@ -63,16 +60,9 @@ class Plugin extends Model }); static::updating(function ($model): void { - // Reset image cache when any markup changes - if ($model->isDirty([ - 'render_markup', - 'render_markup_half_horizontal', - 'render_markup_half_vertical', - 'render_markup_quadrant', - 'render_markup_shared', - ])) { + // Reset image cache when markup changes + if ($model->isDirty('render_markup')) { $model->current_image = null; - $model->current_image_metadata = null; } }); @@ -82,68 +72,11 @@ class Plugin extends Model }); } - public const CUSTOM_FIELDS_KEY = 'custom_fields'; - public function user() { return $this->belongsTo(User::class); } - /** - * YAML for the custom_fields editor - */ - public function getCustomFieldsEditorYaml(): string - { - $template = $this->configuration_template; - $list = $template[self::CUSTOM_FIELDS_KEY] ?? null; - if ($list === null || $list === []) { - return ''; - } - - return Yaml::dump($list, 4, 2); - } - - /** - * Parse editor YAML and return configuration_template for DB (custom_fields key). Returns null when empty. - */ - public static function configurationTemplateFromCustomFieldsYaml(string $yaml, ?array $existingTemplate): ?array - { - $list = $yaml !== '' ? Yaml::parse($yaml) : []; - if ($list === null || (is_array($list) && $list === [])) { - return null; - } - - $template = $existingTemplate ?? []; - $template[self::CUSTOM_FIELDS_KEY] = is_array($list) ? $list : []; - - return $template; - } - - /** - * Validate that each custom field entry has field_type and name. For use with parsed editor YAML. - * - * @param array> $list - * - * @throws \Illuminate\Validation\ValidationException - */ - public static function validateCustomFieldsList(array $list): void - { - $validator = \Illuminate\Support\Facades\Validator::make( - ['custom_fields' => $list], - [ - 'custom_fields' => ['required', 'array'], - 'custom_fields.*.field_type' => ['required', 'string'], - 'custom_fields.*.name' => ['required', 'string'], - ], - [ - 'custom_fields.*.field_type.required' => 'Each custom field must have a field_type.', - 'custom_fields.*.name.required' => 'Each custom field must have a name.', - ] - ); - - $validator->validate(); - } - // sanitize configuration template descriptions and help texts (since they allow HTML rendering) protected function sanitizeTemplate(): void { @@ -224,7 +157,7 @@ class Plugin extends Model if ($this->data_strategy !== 'polling' || ! $this->polling_url) { return; } - $headers = ['User-Agent' => 'usetrmnl/larapaper', 'Accept' => 'application/json']; + $headers = ['User-Agent' => 'usetrmnl/byos_laravel', 'Accept' => 'application/json']; // resolve headers if ($this->polling_header) { @@ -252,12 +185,8 @@ class Plugin extends Model $httpRequest = Http::withHeaders($headers); if ($this->polling_verb === 'post' && $this->polling_body) { - $contentType = (array_key_exists('Content-Type', $headers)) - ? $headers['Content-Type'] - : 'application/json'; - $resolvedBody = $this->resolveLiquidVariables($this->polling_body); - $httpRequest = $httpRequest->withBody($resolvedBody, $contentType); + $httpRequest = $httpRequest->withBody($resolvedBody); } try { @@ -492,9 +421,7 @@ class Plugin extends Model throw new InvalidArgumentException('Render method is only applicable for recipe plugins.'); } - $markup = $this->getMarkupForSize($size); - - if ($markup) { + if ($this->render_markup) { $renderedContent = ''; if ($this->markup_language === 'liquid') { @@ -544,7 +471,7 @@ class Plugin extends Model // Check if external renderer should be used if ($this->preferred_renderer === 'trmnl-liquid' && config('services.trmnl.liquid_enabled')) { // Use external Ruby renderer - pass raw template without preprocessing - $renderedContent = $this->renderWithExternalLiquidRenderer($markup, $context); + $renderedContent = $this->renderWithExternalLiquidRenderer($this->render_markup, $context); } else { // Use PHP keepsuit/liquid renderer // Create a custom environment with inline templates support @@ -564,56 +491,19 @@ class Plugin extends Model // Register the template tag for inline templates $environment->tagRegistry->register(TemplateTag::class); - // Use plugin render tag so partials receive trmnl, size, data, config - $environment->tagRegistry->register(PluginRenderTag::class); // Apply Liquid replacements (including 'with' syntax conversion) - $processedMarkup = $this->applyLiquidReplacements($markup); + $processedMarkup = $this->applyLiquidReplacements($this->render_markup); $template = $environment->parseString($processedMarkup); $liquidContext = $environment->newRenderContext(data: $context); $renderedContent = $template->render($liquidContext); } } else { - // Get timezone from user or fall back to app timezone - $timezone = $this->user->timezone ?? config('app.timezone'); - - // Calculate UTC offset in seconds - $utcOffset = (string) Carbon::now($timezone)->getOffset(); - - $renderedContent = Blade::render($markup, [ + $renderedContent = Blade::render($this->render_markup, [ 'size' => $size, 'data' => $this->data_payload, 'config' => $this->configuration ?? [], - 'trmnl' => [ - 'system' => [ - 'timestamp_utc' => now()->utc()->timestamp, - ], - 'user' => [ - 'utc_offset' => $utcOffset, - 'name' => $this->user->name ?? 'Unknown User', - 'locale' => 'en', - 'time_zone_iana' => $timezone, - ], - 'device' => [ - 'friendly_id' => $device?->friendly_id, - 'percent_charged' => $device?->battery_percent, - 'wifi_strength' => $device?->wifi_strength, - 'height' => $device?->height, - 'width' => $device?->width, - ], - 'plugin_settings' => [ - 'instance_name' => $this->name, - 'strategy' => $this->data_strategy, - 'dark_mode' => $this->dark_mode ? 'yes' : 'no', - 'no_screen_padding' => $this->no_bleed ? 'yes' : 'no', - 'polling_headers' => $this->polling_header, - 'polling_url' => $this->polling_url, - 'custom_fields_values' => [ - ...(is_array($this->configuration) ? $this->configuration : []), - ], - ], - ], ]); } @@ -621,11 +511,10 @@ class Plugin extends Model if ($size === 'full') { return view('trmnl-layouts.single', [ 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceModel?->css_name ?? $device?->deviceVariant() ?? 'og', + 'deviceVariant' => $device?->deviceVariant() ?? 'og', 'noBleed' => $this->no_bleed, 'darkMode' => $this->dark_mode, 'scaleLevel' => $device?->scaleLevel(), - 'cssVariables' => $device?->deviceModel?->css_variables, 'slot' => $renderedContent, ])->render(); } @@ -633,10 +522,9 @@ class Plugin extends Model return view('trmnl-layouts.mashup', [ 'mashupLayout' => $this->getPreviewMashupLayoutForSize($size), 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceModel?->css_name ?? $device?->deviceVariant() ?? 'og', + 'deviceVariant' => $device?->deviceVariant() ?? 'og', 'darkMode' => $this->dark_mode, 'scaleLevel' => $device?->scaleLevel(), - 'cssVariables' => $device?->deviceModel?->css_variables, 'slot' => $renderedContent, ])->render(); @@ -656,11 +544,10 @@ class Plugin extends Model if ($size === 'full') { return view('trmnl-layouts.single', [ 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceModel?->css_name ?? $device?->deviceVariant() ?? 'og', + 'deviceVariant' => $device?->deviceVariant() ?? 'og', 'noBleed' => $this->no_bleed, 'darkMode' => $this->dark_mode, 'scaleLevel' => $device?->scaleLevel(), - 'cssVariables' => $device?->deviceModel?->css_variables, 'slot' => $renderedView, ])->render(); } @@ -668,10 +555,9 @@ class Plugin extends Model return view('trmnl-layouts.mashup', [ 'mashupLayout' => $this->getPreviewMashupLayoutForSize($size), 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceModel?->css_name ?? $device?->deviceVariant() ?? 'og', + 'deviceVariant' => $device?->deviceVariant() ?? 'og', 'darkMode' => $this->dark_mode, 'scaleLevel' => $device?->scaleLevel(), - 'cssVariables' => $device?->deviceModel?->css_variables, 'slot' => $renderedView, ])->render(); } @@ -695,30 +581,6 @@ class Plugin extends Model return $this->configuration[$key] ?? $default; } - /** - * Get the appropriate markup for a given size, including shared prepending logic - * - * @param string $size The layout size (full, half_horizontal, half_vertical, quadrant) - * @return string|null The markup code for the given size, with shared prepended if available - */ - public function getMarkupForSize(string $size): ?string - { - $markup = match ($size) { - 'full' => $this->render_markup, - 'half_horizontal' => $this->render_markup_half_horizontal ?? $this->render_markup, - 'half_vertical' => $this->render_markup_half_vertical ?? $this->render_markup, - 'quadrant' => $this->render_markup_quadrant ?? $this->render_markup, - default => $this->render_markup, - }; - - // Prepend shared markup if it exists - if ($markup && $this->render_markup_shared) { - $markup = $this->render_markup_shared."\n".$markup; - } - - return $markup; - } - public function getPreviewMashupLayoutForSize(string $size): string { return match ($size) { @@ -775,8 +637,8 @@ class Plugin extends Model } } - // Append "_copy" to the name - $attributes['name'] = $this->name.'_copy'; + // Append " (Copy)" to the name + $attributes['name'] = $this->name.' (Copy)'; // Set user_id - use provided userId or fall back to original plugin's user_id $attributes['user_id'] = $userId ?? $this->user_id; diff --git a/app/Services/ImageGenerationService.php b/app/Services/ImageGenerationService.php index 75f374e..87fb6d9 100644 --- a/app/Services/ImageGenerationService.php +++ b/app/Services/ImageGenerationService.php @@ -331,88 +331,36 @@ class ImageGenerationService } } - /** - * Ensure plugin image cache is valid for the current context. No-op for image_webhook. - * When deviceOrModel is provided (recipe only), clears cache if stored metadata does not match. - */ - public static function resetIfNotCacheable(?Plugin $plugin, Device|DeviceModel|null $deviceOrModel = null): void + public static function resetIfNotCacheable(?Plugin $plugin): void { - if (! $plugin?->id || $plugin->plugin_type === 'image_webhook') { - return; - } - if ($deviceOrModel === null || $plugin->plugin_type !== 'recipe') { - return; - } - if ($plugin->current_image === null) { - return; - } - if (self::imageMetadataMatches($plugin->current_image_metadata, $deviceOrModel)) { - return; - } - $plugin->update([ - 'current_image' => null, - 'current_image_metadata' => null, - ]); - Log::debug("Plugin {$plugin->id}: cleared image cache due to metadata mismatch"); - } + if ($plugin?->id) { + // Image webhook plugins have finalized images that shouldn't be reset + if ($plugin->plugin_type === 'image_webhook') { + return; + } + // Check if any devices have custom dimensions or use non-standard DeviceModels + $hasCustomDimensions = Device::query() + ->where(function ($query): void { + $query->where('width', '!=', 800) + ->orWhere('height', '!=', 480) + ->orWhere('rotate', '!=', 0); + }) + ->orWhereHas('deviceModel', function ($query): void { + // Only allow caching if all device models have standard dimensions (800x480, rotation=0) + $query->where(function ($subQuery): void { + $subQuery->where('width', '!=', 800) + ->orWhere('height', '!=', 480) + ->orWhere('rotation', '!=', 0); + }); + }) + ->exists(); - /** - * Build canonical image metadata from a Device for cache comparison. - * - * @return array{width: int, height: int, rotation: int, palette_id: int|null, mime_type: string} - */ - public static function buildImageMetadataFromDevice(Device $device): array - { - $device->loadMissing(['deviceModel', 'deviceModel.palette']); - $settings = self::getImageSettings($device); - $paletteId = $device->palette_id ?? $device->deviceModel?->palette_id; - - return [ - 'width' => $settings['width'], - 'height' => $settings['height'], - 'rotation' => $settings['rotation'] ?? 0, - 'palette_id' => $paletteId, - 'mime_type' => $settings['mime_type'], - ]; - } - - /** - * Build canonical image metadata from a DeviceModel for cache comparison. - * - * @return array{width: int, height: int, rotation: int, palette_id: int|null, mime_type: string} - */ - public static function buildImageMetadataFromDeviceModel(DeviceModel $model): array - { - return [ - 'width' => $model->width, - 'height' => $model->height, - 'rotation' => $model->rotation ?? 0, - 'palette_id' => $model->palette_id, - 'mime_type' => $model->mime_type, - ]; - } - - /** - * Check if stored metadata matches the current device or device model. - * Returns false if stored is null or empty so cache is regenerated and metadata is stored. - */ - public static function imageMetadataMatches(?array $stored, Device|DeviceModel $deviceOrModel): bool - { - if ($stored === null || $stored === []) { - return false; - } - - $current = $deviceOrModel instanceof Device - ? self::buildImageMetadataFromDevice($deviceOrModel) - : self::buildImageMetadataFromDeviceModel($deviceOrModel); - - foreach (['width', 'height', 'rotation', 'palette_id', 'mime_type'] as $key) { - if (($stored[$key] ?? null) !== ($current[$key] ?? null)) { - return false; + if ($hasCustomDimensions) { + // TODO cache image per device + $plugin->update(['current_image' => null]); + Log::debug('Skip cache as devices with custom dimensions or non-standard DeviceModels exist'); } } - - return true; } /** @@ -566,7 +514,7 @@ class ImageGenerationService }; // Determine device properties from DeviceModel or device settings - $deviceVariant = $device->deviceModel?->css_name ?? $device->deviceVariant(); + $deviceVariant = $device->deviceVariant(); $deviceOrientation = $device->rotate > 0 ? 'portrait' : 'landscape'; $colorDepth = $device->colorDepth() ?? '1bit'; $scaleLevel = $device->scaleLevel(); @@ -580,7 +528,6 @@ class ImageGenerationService 'deviceOrientation' => $deviceOrientation, 'colorDepth' => $colorDepth, 'scaleLevel' => $scaleLevel, - 'cssVariables' => $device->deviceModel?->css_variables ?? [], ]; // Add plugin name for error screens diff --git a/app/Services/Plugin/Parsers/IcalResponseParser.php b/app/Services/Plugin/Parsers/IcalResponseParser.php index a1caedb..c8f2b58 100644 --- a/app/Services/Plugin/Parsers/IcalResponseParser.php +++ b/app/Services/Plugin/Parsers/IcalResponseParser.php @@ -25,12 +25,7 @@ class IcalResponseParser implements ResponseParser } try { - // Workaround for om/icalparser v4.0.0 bug where it fails if ORGANIZER or ATTENDEE has no parameters. - // When ORGANIZER or ATTENDEE has no parameters (no semicolon after the key), - // IcalParser::parseRow returns an empty string for $middle instead of an array, - // which causes a type error in a foreach loop in IcalParser::parseString. - $normalizedBody = preg_replace('/^(ORGANIZER|ATTENDEE):/m', '$1;CN=Unknown:', $body); - $this->parser->parseString($normalizedBody); + $this->parser->parseString($body); $events = $this->parser->getEvents()->sorted()->getArrayCopy(); $windowStart = now()->subDays(7); diff --git a/app/Services/Plugin/Parsers/XmlResponseParser.php b/app/Services/Plugin/Parsers/XmlResponseParser.php index 6556de8..b82ba80 100644 --- a/app/Services/Plugin/Parsers/XmlResponseParser.php +++ b/app/Services/Plugin/Parsers/XmlResponseParser.php @@ -18,12 +18,12 @@ class XmlResponseParser implements ResponseParser } try { - $xml = $this->simplexml_load_string_strip_namespaces($response->body()); + $xml = simplexml_load_string($response->body()); if ($xml === false) { throw new Exception('Invalid XML content'); } - return [$xml->getName() => $this->xmlToArray($xml)]; + return ['rss' => $this->xmlToArray($xml)]; } catch (Exception $exception) { Log::warning('Failed to parse XML response: '.$exception->getMessage()); @@ -43,25 +43,4 @@ class XmlResponseParser implements ResponseParser return $array; } - - function simplexml_load_string_strip_namespaces($xml_response) { - $xml = simplexml_load_string($xml_response); - if ($xml === false) { - return false; - } - - $namespaces = array_keys($xml->getDocNamespaces(true)); - $namespaces = array_filter($namespaces, function($name) { return !empty($name); }); - if (count($namespaces) == 0) { - return $xml; - } - $namespaces = array_map(function($ns) { return "$ns:"; }, $namespaces); - - $xml_no_namespaces = str_replace( - array_merge(["xmlns="], $namespaces), - array_merge(["ns="], array_fill(0, count($namespaces), '')), - $xml_response - ); - return simplexml_load_string($xml_no_namespaces); - } } diff --git a/app/Services/PluginExportService.php b/app/Services/PluginExportService.php index be98461..241764d 100644 --- a/app/Services/PluginExportService.php +++ b/app/Services/PluginExportService.php @@ -51,35 +51,17 @@ class PluginExportService $settings = $this->generateSettingsYaml($plugin); $settingsYaml = Yaml::dump($settings, 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); File::put($tempDir.'/settings.yml', $settingsYaml); - + // Generate full template content + $fullTemplate = $this->generateFullTemplate($plugin); $extension = $plugin->markup_language === 'liquid' ? 'liquid' : 'blade.php'; - - // Export full template if it exists - if ($plugin->render_markup) { - $fullTemplate = $this->generateLayoutTemplate($plugin->render_markup); - File::put($tempDir.'/full.'.$extension, $fullTemplate); - } - - // Export layout-specific templates if they exist - if ($plugin->render_markup_half_horizontal) { - $halfHorizontalTemplate = $this->generateLayoutTemplate($plugin->render_markup_half_horizontal); - File::put($tempDir.'/half_horizontal.'.$extension, $halfHorizontalTemplate); - } - - if ($plugin->render_markup_half_vertical) { - $halfVerticalTemplate = $this->generateLayoutTemplate($plugin->render_markup_half_vertical); - File::put($tempDir.'/half_vertical.'.$extension, $halfVerticalTemplate); - } - - if ($plugin->render_markup_quadrant) { - $quadrantTemplate = $this->generateLayoutTemplate($plugin->render_markup_quadrant); - File::put($tempDir.'/quadrant.'.$extension, $quadrantTemplate); - } - - // Export shared template if it exists - if ($plugin->render_markup_shared) { - $sharedTemplate = $this->generateLayoutTemplate($plugin->render_markup_shared); - File::put($tempDir.'/shared.'.$extension, $sharedTemplate); + File::put($tempDir.'/full.'.$extension, $fullTemplate); + // Generate shared.liquid if needed (for liquid templates) + if ($plugin->markup_language === 'liquid') { + $sharedTemplate = $this->generateSharedTemplate(); + /** @phpstan-ignore-next-line */ + if ($sharedTemplate) { + File::put($tempDir.'/shared.liquid', $sharedTemplate); + } } // Create ZIP file $zipPath = $tempDir.'/plugin_'.$plugin->trmnlp_id.'.zip'; @@ -142,21 +124,29 @@ class PluginExportService } /** - * Generate template content from markup, removing wrapper divs if present + * Generate the full template content */ - private function generateLayoutTemplate(?string $markup): string + private function generateFullTemplate(Plugin $plugin): string { - if (! $markup) { - return ''; - } + $markup = $plugin->render_markup; - // Remove the wrapper div if it exists (it will be added during import for liquid) + // Remove the wrapper div if it exists (it will be added during import) $markup = preg_replace('/^
\s*/', '', $markup); $markup = preg_replace('/\s*<\/div>\s*$/', '', $markup); return mb_trim($markup); } + /** + * Generate the shared template content (for liquid templates) + */ + private function generateSharedTemplate(): null + { + // For now, we don't have a way to store shared templates separately + // TODO - add support for shared templates + return null; + } + /** * Add a directory and its contents to a ZIP file */ diff --git a/app/Services/PluginImportService.php b/app/Services/PluginImportService.php index f3e7a5c..51a9aee 100644 --- a/app/Services/PluginImportService.php +++ b/app/Services/PluginImportService.php @@ -93,59 +93,37 @@ class PluginImportService $settings = Yaml::parse($settingsYaml); $this->validateYAML($settings); - // Determine markup language from the first available file + // Determine which template file to use and read its content + $templatePath = null; $markupLanguage = 'blade'; - $firstTemplatePath = $filePaths['fullLiquidPath'] - ?? ($filePaths['halfHorizontalLiquidPath'] ?? null) - ?? ($filePaths['halfVerticalLiquidPath'] ?? null) - ?? ($filePaths['quadrantLiquidPath'] ?? null) - ?? ($filePaths['sharedLiquidPath'] ?? null) - ?? ($filePaths['sharedBladePath'] ?? null); - if ($firstTemplatePath && pathinfo((string) $firstTemplatePath, PATHINFO_EXTENSION) === 'liquid') { - $markupLanguage = 'liquid'; - } + if ($filePaths['fullLiquidPath']) { + $templatePath = $filePaths['fullLiquidPath']; + $fullLiquid = File::get($templatePath); - // Read full markup (don't prepend shared - it will be prepended at render time) - $fullLiquid = null; - if (isset($filePaths['fullLiquidPath']) && $filePaths['fullLiquidPath']) { - $fullLiquid = File::get($filePaths['fullLiquidPath']); - if ($markupLanguage === 'liquid') { + // Prepend shared.liquid or shared.blade.php content if available + if ($filePaths['sharedLiquidPath'] && File::exists($filePaths['sharedLiquidPath'])) { + $sharedLiquid = File::get($filePaths['sharedLiquidPath']); + $fullLiquid = $sharedLiquid."\n".$fullLiquid; + } elseif ($filePaths['sharedBladePath'] && File::exists($filePaths['sharedBladePath'])) { + $sharedBlade = File::get($filePaths['sharedBladePath']); + $fullLiquid = $sharedBlade."\n".$fullLiquid; + } + + // Check if the file ends with .liquid to set markup language + if (pathinfo((string) $templatePath, PATHINFO_EXTENSION) === 'liquid') { + $markupLanguage = 'liquid'; $fullLiquid = '
'."\n".$fullLiquid."\n".'
'; } - } - - // Read shared markup separately - $sharedMarkup = null; - if (isset($filePaths['sharedLiquidPath']) && $filePaths['sharedLiquidPath'] && File::exists($filePaths['sharedLiquidPath'])) { - $sharedMarkup = File::get($filePaths['sharedLiquidPath']); - } elseif (isset($filePaths['sharedBladePath']) && $filePaths['sharedBladePath'] && File::exists($filePaths['sharedBladePath'])) { - $sharedMarkup = File::get($filePaths['sharedBladePath']); - } - - // Read layout-specific markups - $halfHorizontalMarkup = null; - if (isset($filePaths['halfHorizontalLiquidPath']) && $filePaths['halfHorizontalLiquidPath'] && File::exists($filePaths['halfHorizontalLiquidPath'])) { - $halfHorizontalMarkup = File::get($filePaths['halfHorizontalLiquidPath']); - if ($markupLanguage === 'liquid') { - $halfHorizontalMarkup = '
'."\n".$halfHorizontalMarkup."\n".'
'; - } - } - - $halfVerticalMarkup = null; - if (isset($filePaths['halfVerticalLiquidPath']) && $filePaths['halfVerticalLiquidPath'] && File::exists($filePaths['halfVerticalLiquidPath'])) { - $halfVerticalMarkup = File::get($filePaths['halfVerticalLiquidPath']); - if ($markupLanguage === 'liquid') { - $halfVerticalMarkup = '
'."\n".$halfVerticalMarkup."\n".'
'; - } - } - - $quadrantMarkup = null; - if (isset($filePaths['quadrantLiquidPath']) && $filePaths['quadrantLiquidPath'] && File::exists($filePaths['quadrantLiquidPath'])) { - $quadrantMarkup = File::get($filePaths['quadrantLiquidPath']); - if ($markupLanguage === 'liquid') { - $quadrantMarkup = '
'."\n".$quadrantMarkup."\n".'
'; - } + } elseif ($filePaths['sharedLiquidPath']) { + $templatePath = $filePaths['sharedLiquidPath']; + $fullLiquid = File::get($templatePath); + $markupLanguage = 'liquid'; + $fullLiquid = '
'."\n".$fullLiquid."\n".'
'; + } elseif ($filePaths['sharedBladePath']) { + $templatePath = $filePaths['sharedBladePath']; + $fullLiquid = File::get($templatePath); + $markupLanguage = 'blade'; } // Ensure custom_fields is properly formatted @@ -182,10 +160,6 @@ class PluginImportService 'polling_body' => $settings['polling_body'] ?? null, 'markup_language' => $markupLanguage, 'render_markup' => $fullLiquid ?? null, - 'render_markup_half_horizontal' => $halfHorizontalMarkup, - 'render_markup_half_vertical' => $halfVerticalMarkup, - 'render_markup_quadrant' => $quadrantMarkup, - 'render_markup_shared' => $sharedMarkup, 'configuration_template' => $configurationTemplate, 'data_payload' => json_decode($settings['static_data'] ?? '{}', true), ]); @@ -272,59 +246,37 @@ class PluginImportService $settings = Yaml::parse($settingsYaml); $this->validateYAML($settings); - // Determine markup language from the first available file + // Determine which template file to use and read its content + $templatePath = null; $markupLanguage = 'blade'; - $firstTemplatePath = $filePaths['fullLiquidPath'] - ?? ($filePaths['halfHorizontalLiquidPath'] ?? null) - ?? ($filePaths['halfVerticalLiquidPath'] ?? null) - ?? ($filePaths['quadrantLiquidPath'] ?? null) - ?? ($filePaths['sharedLiquidPath'] ?? null) - ?? ($filePaths['sharedBladePath'] ?? null); - if ($firstTemplatePath && pathinfo((string) $firstTemplatePath, PATHINFO_EXTENSION) === 'liquid') { - $markupLanguage = 'liquid'; - } + if ($filePaths['fullLiquidPath']) { + $templatePath = $filePaths['fullLiquidPath']; + $fullLiquid = File::get($templatePath); - // Read full markup (don't prepend shared - it will be prepended at render time) - $fullLiquid = null; - if (isset($filePaths['fullLiquidPath']) && $filePaths['fullLiquidPath']) { - $fullLiquid = File::get($filePaths['fullLiquidPath']); - if ($markupLanguage === 'liquid') { + // Prepend shared.liquid or shared.blade.php content if available + if ($filePaths['sharedLiquidPath'] && File::exists($filePaths['sharedLiquidPath'])) { + $sharedLiquid = File::get($filePaths['sharedLiquidPath']); + $fullLiquid = $sharedLiquid."\n".$fullLiquid; + } elseif ($filePaths['sharedBladePath'] && File::exists($filePaths['sharedBladePath'])) { + $sharedBlade = File::get($filePaths['sharedBladePath']); + $fullLiquid = $sharedBlade."\n".$fullLiquid; + } + + // Check if the file ends with .liquid to set markup language + if (pathinfo((string) $templatePath, PATHINFO_EXTENSION) === 'liquid') { + $markupLanguage = 'liquid'; $fullLiquid = '
'."\n".$fullLiquid."\n".'
'; } - } - - // Read shared markup separately - $sharedMarkup = null; - if (isset($filePaths['sharedLiquidPath']) && $filePaths['sharedLiquidPath'] && File::exists($filePaths['sharedLiquidPath'])) { - $sharedMarkup = File::get($filePaths['sharedLiquidPath']); - } elseif (isset($filePaths['sharedBladePath']) && $filePaths['sharedBladePath'] && File::exists($filePaths['sharedBladePath'])) { - $sharedMarkup = File::get($filePaths['sharedBladePath']); - } - - // Read layout-specific markups - $halfHorizontalMarkup = null; - if (isset($filePaths['halfHorizontalLiquidPath']) && $filePaths['halfHorizontalLiquidPath'] && File::exists($filePaths['halfHorizontalLiquidPath'])) { - $halfHorizontalMarkup = File::get($filePaths['halfHorizontalLiquidPath']); - if ($markupLanguage === 'liquid') { - $halfHorizontalMarkup = '
'."\n".$halfHorizontalMarkup."\n".'
'; - } - } - - $halfVerticalMarkup = null; - if (isset($filePaths['halfVerticalLiquidPath']) && $filePaths['halfVerticalLiquidPath'] && File::exists($filePaths['halfVerticalLiquidPath'])) { - $halfVerticalMarkup = File::get($filePaths['halfVerticalLiquidPath']); - if ($markupLanguage === 'liquid') { - $halfVerticalMarkup = '
'."\n".$halfVerticalMarkup."\n".'
'; - } - } - - $quadrantMarkup = null; - if (isset($filePaths['quadrantLiquidPath']) && $filePaths['quadrantLiquidPath'] && File::exists($filePaths['quadrantLiquidPath'])) { - $quadrantMarkup = File::get($filePaths['quadrantLiquidPath']); - if ($markupLanguage === 'liquid') { - $quadrantMarkup = '
'."\n".$quadrantMarkup."\n".'
'; - } + } elseif ($filePaths['sharedLiquidPath']) { + $templatePath = $filePaths['sharedLiquidPath']; + $fullLiquid = File::get($templatePath); + $markupLanguage = 'liquid'; + $fullLiquid = '
'."\n".$fullLiquid."\n".'
'; + } elseif ($filePaths['sharedBladePath']) { + $templatePath = $filePaths['sharedBladePath']; + $fullLiquid = File::get($templatePath); + $markupLanguage = 'blade'; } // Ensure custom_fields is properly formatted @@ -370,10 +322,6 @@ class PluginImportService 'polling_body' => $settings['polling_body'] ?? null, 'markup_language' => $markupLanguage, 'render_markup' => $fullLiquid ?? null, - 'render_markup_half_horizontal' => $halfHorizontalMarkup, - 'render_markup_half_vertical' => $halfVerticalMarkup, - 'render_markup_quadrant' => $quadrantMarkup, - 'render_markup_shared' => $sharedMarkup, 'configuration_template' => $configurationTemplate, 'data_payload' => json_decode($settings['static_data'] ?? '{}', true), 'preferred_renderer' => $preferredRenderer, @@ -409,9 +357,6 @@ class PluginImportService $fullLiquidPath = null; $sharedLiquidPath = null; $sharedBladePath = null; - $halfHorizontalLiquidPath = null; - $halfVerticalLiquidPath = null; - $quadrantLiquidPath = null; // If zipEntryPath is specified, look for files in that specific directory first if ($zipEntryPath) { @@ -432,25 +377,6 @@ class PluginImportService } elseif (File::exists($targetDir.'/shared.blade.php')) { $sharedBladePath = $targetDir.'/shared.blade.php'; } - - // Check for layout-specific files - if (File::exists($targetDir.'/half_horizontal.liquid')) { - $halfHorizontalLiquidPath = $targetDir.'/half_horizontal.liquid'; - } elseif (File::exists($targetDir.'/half_horizontal.blade.php')) { - $halfHorizontalLiquidPath = $targetDir.'/half_horizontal.blade.php'; - } - - if (File::exists($targetDir.'/half_vertical.liquid')) { - $halfVerticalLiquidPath = $targetDir.'/half_vertical.liquid'; - } elseif (File::exists($targetDir.'/half_vertical.blade.php')) { - $halfVerticalLiquidPath = $targetDir.'/half_vertical.blade.php'; - } - - if (File::exists($targetDir.'/quadrant.liquid')) { - $quadrantLiquidPath = $targetDir.'/quadrant.liquid'; - } elseif (File::exists($targetDir.'/quadrant.blade.php')) { - $quadrantLiquidPath = $targetDir.'/quadrant.blade.php'; - } } // Check if files are in src subdirectory of target directory @@ -468,25 +394,6 @@ class PluginImportService } elseif (File::exists($targetDir.'/src/shared.blade.php')) { $sharedBladePath = $targetDir.'/src/shared.blade.php'; } - - // Check for layout-specific files in src - if (File::exists($targetDir.'/src/half_horizontal.liquid')) { - $halfHorizontalLiquidPath = $targetDir.'/src/half_horizontal.liquid'; - } elseif (File::exists($targetDir.'/src/half_horizontal.blade.php')) { - $halfHorizontalLiquidPath = $targetDir.'/src/half_horizontal.blade.php'; - } - - if (File::exists($targetDir.'/src/half_vertical.liquid')) { - $halfVerticalLiquidPath = $targetDir.'/src/half_vertical.liquid'; - } elseif (File::exists($targetDir.'/src/half_vertical.blade.php')) { - $halfVerticalLiquidPath = $targetDir.'/src/half_vertical.blade.php'; - } - - if (File::exists($targetDir.'/src/quadrant.liquid')) { - $quadrantLiquidPath = $targetDir.'/src/quadrant.liquid'; - } elseif (File::exists($targetDir.'/src/quadrant.blade.php')) { - $quadrantLiquidPath = $targetDir.'/src/quadrant.blade.php'; - } } // If we found the required files in the target directory, return them @@ -518,25 +425,6 @@ class PluginImportService } elseif (File::exists($tempDir.'/src/shared.blade.php')) { $sharedBladePath = $tempDir.'/src/shared.blade.php'; } - - // Check for layout-specific files - if (File::exists($tempDir.'/src/half_horizontal.liquid')) { - $halfHorizontalLiquidPath = $tempDir.'/src/half_horizontal.liquid'; - } elseif (File::exists($tempDir.'/src/half_horizontal.blade.php')) { - $halfHorizontalLiquidPath = $tempDir.'/src/half_horizontal.blade.php'; - } - - if (File::exists($tempDir.'/src/half_vertical.liquid')) { - $halfVerticalLiquidPath = $tempDir.'/src/half_vertical.liquid'; - } elseif (File::exists($tempDir.'/src/half_vertical.blade.php')) { - $halfVerticalLiquidPath = $tempDir.'/src/half_vertical.blade.php'; - } - - if (File::exists($tempDir.'/src/quadrant.liquid')) { - $quadrantLiquidPath = $tempDir.'/src/quadrant.liquid'; - } elseif (File::exists($tempDir.'/src/quadrant.blade.php')) { - $quadrantLiquidPath = $tempDir.'/src/quadrant.blade.php'; - } } else { // Search for the files in the extracted directory structure $directories = new RecursiveDirectoryIterator($tempDir, RecursiveDirectoryIterator::SKIP_DOTS); @@ -554,12 +442,6 @@ class PluginImportService $sharedLiquidPath = $filepath; } elseif ($filename === 'shared.blade.php') { $sharedBladePath = $filepath; - } elseif ($filename === 'half_horizontal.liquid' || $filename === 'half_horizontal.blade.php') { - $halfHorizontalLiquidPath = $filepath; - } elseif ($filename === 'half_vertical.liquid' || $filename === 'half_vertical.blade.php') { - $halfVerticalLiquidPath = $filepath; - } elseif ($filename === 'quadrant.liquid' || $filename === 'quadrant.blade.php') { - $quadrantLiquidPath = $filepath; } } @@ -603,25 +485,6 @@ class PluginImportService $sharedBladePath = $newSrcDir.'/shared.blade.php'; } - // Copy layout-specific files if they exist - if ($halfHorizontalLiquidPath) { - $extension = pathinfo((string) $halfHorizontalLiquidPath, PATHINFO_EXTENSION); - File::copy($halfHorizontalLiquidPath, $newSrcDir.'/half_horizontal.'.$extension); - $halfHorizontalLiquidPath = $newSrcDir.'/half_horizontal.'.$extension; - } - - if ($halfVerticalLiquidPath) { - $extension = pathinfo((string) $halfVerticalLiquidPath, PATHINFO_EXTENSION); - File::copy($halfVerticalLiquidPath, $newSrcDir.'/half_vertical.'.$extension); - $halfVerticalLiquidPath = $newSrcDir.'/half_vertical.'.$extension; - } - - if ($quadrantLiquidPath) { - $extension = pathinfo((string) $quadrantLiquidPath, PATHINFO_EXTENSION); - File::copy($quadrantLiquidPath, $newSrcDir.'/quadrant.'.$extension); - $quadrantLiquidPath = $newSrcDir.'/quadrant.'.$extension; - } - // Update the paths $settingsYamlPath = $newSrcDir.'/settings.yml'; } @@ -633,9 +496,6 @@ class PluginImportService 'fullLiquidPath' => $fullLiquidPath, 'sharedLiquidPath' => $sharedLiquidPath, 'sharedBladePath' => $sharedBladePath, - 'halfHorizontalLiquidPath' => $halfHorizontalLiquidPath, - 'halfVerticalLiquidPath' => $halfVerticalLiquidPath, - 'quadrantLiquidPath' => $quadrantLiquidPath, ]; } diff --git a/composer.json b/composer.json index 9ff1f90..555ad57 100644 --- a/composer.json +++ b/composer.json @@ -11,12 +11,12 @@ ], "license": "MIT", "require": { - "php": "^8.4", + "php": "^8.2", "ext-imagick": "*", "ext-simplexml": "*", "ext-zip": "*", - "bnussbau/laravel-trmnl-blade": "^2.3", - "bnussbau/trmnl-pipeline-php": "^0.8", + "bnussbau/laravel-trmnl-blade": "2.1.*", + "bnussbau/trmnl-pipeline-php": "^0.6.0", "keepsuit/laravel-liquid": "^0.5.2", "laravel/fortify": "^1.30", "laravel/framework": "^12.1", @@ -25,7 +25,7 @@ "laravel/tinker": "^2.10.1", "livewire/flux": "^2.0", "livewire/livewire": "^4.0", - "om/icalparser": "^4.0", + "om/icalparser": "^3.2", "spatie/browsershot": "^5.0", "spatie/laravel-settings": "^3.6", "stevebauman/purify": "^6.3", diff --git a/composer.lock b/composer.lock index e9d30cf..0719a49 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c13d003eb08beac106e67bfbeff85dd9", + "content-hash": "324bc90c0d60675c736e4001ba845a5a", "packages": [ { "name": "aws/aws-crt-php", @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.372.3", + "version": "3.369.26", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "d207d2ca972c9b10674e535dacd4a5d956a80bad" + "reference": "ad0916c6595d98f9052f60e1d7204f4740369e94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d207d2ca972c9b10674e535dacd4a5d956a80bad", - "reference": "d207d2ca972c9b10674e535dacd4a5d956a80bad", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ad0916c6595d98f9052f60e1d7204f4740369e94", + "reference": "ad0916c6595d98f9052f60e1d7204f4740369e94", "shasum": "" }, "require": { @@ -135,11 +135,11 @@ "authors": [ { "name": "Amazon Web Services", - "homepage": "https://aws.amazon.com" + "homepage": "http://aws.amazon.com" } ], "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", - "homepage": "https://aws.amazon.com/sdk-for-php", + "homepage": "http://aws.amazon.com/sdkforphp", "keywords": [ "amazon", "aws", @@ -153,9 +153,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.372.3" + "source": "https://github.com/aws/aws-sdk-php/tree/3.369.26" }, - "time": "2026-03-10T18:07:21+00:00" + "time": "2026-02-03T19:16:42+00:00" }, { "name": "bacon/bacon-qr-code", @@ -214,16 +214,16 @@ }, { "name": "bnussbau/laravel-trmnl-blade", - "version": "2.3.3", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/bnussbau/laravel-trmnl-blade.git", - "reference": "777af3e26a6bee154efd87caf06131cc18c84452" + "reference": "6ad96eba917ebc30ebe550e6fce4a995e94f6b35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bnussbau/laravel-trmnl-blade/zipball/777af3e26a6bee154efd87caf06131cc18c84452", - "reference": "777af3e26a6bee154efd87caf06131cc18c84452", + "url": "https://api.github.com/repos/bnussbau/laravel-trmnl-blade/zipball/6ad96eba917ebc30ebe550e6fce4a995e94f6b35", + "reference": "6ad96eba917ebc30ebe550e6fce4a995e94f6b35", "shasum": "" }, "require": { @@ -278,7 +278,7 @@ ], "support": { "issues": "https://github.com/bnussbau/laravel-trmnl-blade/issues", - "source": "https://github.com/bnussbau/laravel-trmnl-blade/tree/2.3.3" + "source": "https://github.com/bnussbau/laravel-trmnl-blade/tree/2.1.1" }, "funding": [ { @@ -294,20 +294,20 @@ "type": "github" } ], - "time": "2026-03-03T06:47:48+00:00" + "time": "2026-01-29T20:40:42+00:00" }, { "name": "bnussbau/trmnl-pipeline-php", - "version": "0.8.0", + "version": "0.6.0", "source": { "type": "git", "url": "https://github.com/bnussbau/trmnl-pipeline-php.git", - "reference": "f7c86bf655d6f8ddd88e48575d0c9588c33eb07b" + "reference": "228505afa8a39a5033916e9ae5ccbf1733092c1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bnussbau/trmnl-pipeline-php/zipball/f7c86bf655d6f8ddd88e48575d0c9588c33eb07b", - "reference": "f7c86bf655d6f8ddd88e48575d0c9588c33eb07b", + "url": "https://api.github.com/repos/bnussbau/trmnl-pipeline-php/zipball/228505afa8a39a5033916e9ae5ccbf1733092c1f", + "reference": "228505afa8a39a5033916e9ae5ccbf1733092c1f", "shasum": "" }, "require": { @@ -349,7 +349,7 @@ ], "support": { "issues": "https://github.com/bnussbau/trmnl-pipeline-php/issues", - "source": "https://github.com/bnussbau/trmnl-pipeline-php/tree/0.8.0" + "source": "https://github.com/bnussbau/trmnl-pipeline-php/tree/0.6.0" }, "funding": [ { @@ -357,7 +357,7 @@ "type": "buy_me_a_coffee" }, { - "url": "https://trmnl.com/?ref=laravel-trmnl", + "url": "https://usetrmnl.com/?ref=laravel-trmnl", "type": "custom" }, { @@ -365,20 +365,20 @@ "type": "github" } ], - "time": "2026-02-12T16:53:44+00:00" + "time": "2025-12-02T15:18:51+00:00" }, { "name": "brick/math", - "version": "0.14.8", + "version": "0.14.5", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" + "reference": "618a8077b3c326045e10d5788ed713b341fcfe40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", - "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", + "url": "https://api.github.com/repos/brick/math/zipball/618a8077b3c326045e10d5788ed713b341fcfe40", + "reference": "618a8077b3c326045e10d5788ed713b341fcfe40", "shasum": "" }, "require": { @@ -417,7 +417,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.8" + "source": "https://github.com/brick/math/tree/0.14.5" }, "funding": [ { @@ -425,7 +425,7 @@ "type": "github" } ], - "time": "2026-02-10T14:33:43+00:00" + "time": "2026-02-03T18:06:51+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -623,29 +623,29 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.6", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", - "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "phpunit/phpunit": "<=7.5 || >=14" + "phpunit/phpunit": "<=7.5 || >=13" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^14", - "phpstan/phpstan": "1.4.10 || 2.1.30", + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -665,9 +665,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.6" + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" }, - "time": "2026-02-07T07:09:04+00:00" + "time": "2025-04-07T20:06:18+00:00" }, { "name": "doctrine/inflector", @@ -1030,16 +1030,16 @@ }, { "name": "firebase/php-jwt", - "version": "v7.0.3", + "version": "v7.0.2", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "28aa0694bcfdfa5e2959c394d5a1ee7a5083629e" + "reference": "5645b43af647b6947daac1d0f659dd1fbe8d3b65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/28aa0694bcfdfa5e2959c394d5a1ee7a5083629e", - "reference": "28aa0694bcfdfa5e2959c394d5a1ee7a5083629e", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/5645b43af647b6947daac1d0f659dd1fbe8d3b65", + "reference": "5645b43af647b6947daac1d0f659dd1fbe8d3b65", "shasum": "" }, "require": { @@ -1087,9 +1087,9 @@ ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", - "source": "https://github.com/firebase/php-jwt/tree/v7.0.3" + "source": "https://github.com/firebase/php-jwt/tree/v7.0.2" }, - "time": "2026-02-25T22:16:40+00:00" + "time": "2025-12-16T22:17:28+00:00" }, { "name": "fruitcake/php-cors", @@ -1435,16 +1435,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.9.0", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" + "reference": "21dc724a0583619cd1652f673303492272778051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", - "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -1460,7 +1460,6 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "jshttp/mime-db": "1.54.0.1", "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { @@ -1532,7 +1531,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.9.0" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -1548,7 +1547,7 @@ "type": "tidelift" } ], - "time": "2026-03-10T16:41:02+00:00" + "time": "2025-08-23T21:21:41+00:00" }, { "name": "guzzlehttp/uri-template", @@ -1696,16 +1695,16 @@ }, { "name": "keepsuit/laravel-liquid", - "version": "v0.5.5", + "version": "v0.5.4", "source": { "type": "git", "url": "https://github.com/keepsuit/laravel-liquid.git", - "reference": "7f9996cc2eac16489d33d76e265939c2d556bded" + "reference": "ba426f44798042e3635a29ea91bbf2a4b2874a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/keepsuit/laravel-liquid/zipball/7f9996cc2eac16489d33d76e265939c2d556bded", - "reference": "7f9996cc2eac16489d33d76e265939c2d556bded", + "url": "https://api.github.com/repos/keepsuit/laravel-liquid/zipball/ba426f44798042e3635a29ea91bbf2a4b2874a04", + "reference": "ba426f44798042e3635a29ea91bbf2a4b2874a04", "shasum": "" }, "require": { @@ -1713,7 +1712,7 @@ "keepsuit/liquid": "^0.7 || ^0.8 || ^0.9", "php": "^8.1", "spatie/laravel-package-tools": "^1.16", - "symfony/var-exporter": "^6.3 || ^7.0 || ^8.0" + "symfony/var-exporter": "^6.3 || ^7.0" }, "require-dev": { "itsgoingd/clockwork": "^5.3", @@ -1765,9 +1764,9 @@ ], "support": { "issues": "https://github.com/keepsuit/laravel-liquid/issues", - "source": "https://github.com/keepsuit/laravel-liquid/tree/v0.5.5" + "source": "https://github.com/keepsuit/laravel-liquid/tree/v0.5.4" }, - "time": "2026-03-04T16:46:40+00:00" + "time": "2025-06-15T12:06:40+00:00" }, { "name": "keepsuit/liquid", @@ -1832,28 +1831,28 @@ }, { "name": "laravel/fortify", - "version": "v1.36.1", + "version": "v1.34.0", "source": { "type": "git", "url": "https://github.com/laravel/fortify.git", - "reference": "cad8bfeb63f6818f173d40090725c565c92651d4" + "reference": "c322715f2786210a722ed56966f7c9877b653b25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/fortify/zipball/cad8bfeb63f6818f173d40090725c565c92651d4", - "reference": "cad8bfeb63f6818f173d40090725c565c92651d4", + "url": "https://api.github.com/repos/laravel/fortify/zipball/c322715f2786210a722ed56966f7c9877b653b25", + "reference": "c322715f2786210a722ed56966f7c9877b653b25", "shasum": "" }, "require": { "bacon/bacon-qr-code": "^3.0", "ext-json": "*", - "illuminate/console": "^10.0|^11.0|^12.0|^13.0", - "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^10.0|^11.0|^12.0", "php": "^8.1", - "pragmarx/google2fa": "^9.0" + "pragmarx/google2fa": "^9.0", + "symfony/console": "^6.0|^7.0" }, "require-dev": { - "orchestra/testbench": "^8.36|^9.15|^10.8|^11.0", + "orchestra/testbench": "^8.36|^9.15|^10.8", "phpstan/phpstan": "^1.10" }, "type": "library", @@ -1891,20 +1890,20 @@ "issues": "https://github.com/laravel/fortify/issues", "source": "https://github.com/laravel/fortify" }, - "time": "2026-03-10T19:59:49+00:00" + "time": "2026-01-26T10:23:19+00:00" }, { "name": "laravel/framework", - "version": "v12.54.1", + "version": "v12.49.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "325497463e7599cd14224c422c6e5dd2fe832868" + "reference": "4bde4530545111d8bdd1de6f545fa8824039fcb5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/325497463e7599cd14224c422c6e5dd2fe832868", - "reference": "325497463e7599cd14224c422c6e5dd2fe832868", + "url": "https://api.github.com/repos/laravel/framework/zipball/4bde4530545111d8bdd1de6f545fa8824039fcb5", + "reference": "4bde4530545111d8bdd1de6f545fa8824039fcb5", "shasum": "" }, "require": { @@ -1925,7 +1924,7 @@ "guzzlehttp/uri-template": "^1.0", "laravel/prompts": "^0.3.0", "laravel/serializable-closure": "^1.3|^2.0", - "league/commonmark": "^2.8.1", + "league/commonmark": "^2.7", "league/flysystem": "^3.25.1", "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", @@ -2113,34 +2112,34 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-03-10T20:25:56+00:00" + "time": "2026-01-28T03:40:49+00:00" }, { "name": "laravel/prompts", - "version": "v0.3.14", + "version": "v0.3.11", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "9f0e371244eedfe2ebeaa72c79c54bb5df6e0176" + "reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/9f0e371244eedfe2ebeaa72c79c54bb5df6e0176", - "reference": "9f0e371244eedfe2ebeaa72c79c54bb5df6e0176", + "url": "https://api.github.com/repos/laravel/prompts/zipball/dd2a2ed95acacbcccd32fd98dee4c946ae7a7217", + "reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", "ext-mbstring": "*", "php": "^8.1", - "symfony/console": "^6.2|^7.0|^8.0" + "symfony/console": "^6.2|^7.0" }, "conflict": { "illuminate/console": ">=10.17.0 <10.25.0", "laravel/framework": ">=10.17.0 <10.25.0" }, "require-dev": { - "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", + "illuminate/collections": "^10.0|^11.0|^12.0", "mockery/mockery": "^1.5", "pestphp/pest": "^2.3|^3.4|^4.0", "phpstan/phpstan": "^1.12.28", @@ -2170,36 +2169,36 @@ "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.3.14" + "source": "https://github.com/laravel/prompts/tree/v0.3.11" }, - "time": "2026-03-01T09:02:38+00:00" + "time": "2026-01-27T02:55:06+00:00" }, { "name": "laravel/sanctum", - "version": "v4.3.1", + "version": "v4.3.0", "source": { "type": "git", "url": "https://github.com/laravel/sanctum.git", - "reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76" + "reference": "c978c82b2b8ab685468a7ca35224497d541b775a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sanctum/zipball/e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76", - "reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/c978c82b2b8ab685468a7ca35224497d541b775a", + "reference": "c978c82b2b8ab685468a7ca35224497d541b775a", "shasum": "" }, "require": { "ext-json": "*", - "illuminate/console": "^11.0|^12.0|^13.0", - "illuminate/contracts": "^11.0|^12.0|^13.0", - "illuminate/database": "^11.0|^12.0|^13.0", - "illuminate/support": "^11.0|^12.0|^13.0", + "illuminate/console": "^11.0|^12.0", + "illuminate/contracts": "^11.0|^12.0", + "illuminate/database": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", "php": "^8.2", - "symfony/console": "^7.0|^8.0" + "symfony/console": "^7.0" }, "require-dev": { "mockery/mockery": "^1.6", - "orchestra/testbench": "^9.15|^10.8|^11.0", + "orchestra/testbench": "^9.15|^10.8", "phpstan/phpstan": "^1.10" }, "type": "library", @@ -2235,31 +2234,31 @@ "issues": "https://github.com/laravel/sanctum/issues", "source": "https://github.com/laravel/sanctum" }, - "time": "2026-02-07T17:19:31+00:00" + "time": "2026-01-22T22:27:01+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.10", + "version": "v2.0.8", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669" + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/870fc81d2f879903dfc5b60bf8a0f94a1609e669", - "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b", + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^10.0|^11.0|^12.0", "nesbot/carbon": "^2.67|^3.0", "pestphp/pest": "^2.36|^3.0|^4.0", "phpstan/phpstan": "^2.0", - "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" + "symfony/var-dumper": "^6.2.0|^7.0.0" }, "type": "library", "extra": { @@ -2296,36 +2295,36 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2026-02-20T19:59:49+00:00" + "time": "2026-01-08T16:22:46+00:00" }, { "name": "laravel/socialite", - "version": "v5.25.0", + "version": "v5.24.2", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "231f572e1a37c9ca1fb8085e9fb8608285beafb3" + "reference": "5cea2eebf11ca4bc6c2f20495c82a70a9b3d1613" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/231f572e1a37c9ca1fb8085e9fb8608285beafb3", - "reference": "231f572e1a37c9ca1fb8085e9fb8608285beafb3", + "url": "https://api.github.com/repos/laravel/socialite/zipball/5cea2eebf11ca4bc6c2f20495c82a70a9b3d1613", + "reference": "5cea2eebf11ca4bc6c2f20495c82a70a9b3d1613", "shasum": "" }, "require": { "ext-json": "*", "firebase/php-jwt": "^6.4|^7.0", "guzzlehttp/guzzle": "^6.0|^7.0", - "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0|^13.0", - "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0|^13.0", - "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0|^13.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", "league/oauth1-client": "^1.11", "php": "^7.2|^8.0", "phpseclib/phpseclib": "^3.0" }, "require-dev": { "mockery/mockery": "^1.0", - "orchestra/testbench": "^4.18|^5.20|^6.47|^7.55|^8.36|^9.15|^10.8|^11.0", + "orchestra/testbench": "^4.18|^5.20|^6.47|^7.55|^8.36|^9.15|^10.8", "phpstan/phpstan": "^1.12.23", "phpunit/phpunit": "^8.0|^9.3|^10.4|^11.5|^12.0" }, @@ -2368,20 +2367,20 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2026-02-27T13:56:35+00:00" + "time": "2026-01-10T16:07:28+00:00" }, { "name": "laravel/tinker", - "version": "v2.11.1", + "version": "v2.11.0", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" + "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", - "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", + "url": "https://api.github.com/repos/laravel/tinker/zipball/3d34b97c9a1747a81a3fde90482c092bd8b66468", + "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468", "shasum": "" }, "require": { @@ -2432,22 +2431,22 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.11.1" + "source": "https://github.com/laravel/tinker/tree/v2.11.0" }, - "time": "2026-02-06T14:12:35+00:00" + "time": "2025-12-19T19:16:45+00:00" }, { "name": "league/commonmark", - "version": "2.8.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "84b1ca48347efdbe775426f108622a42735a6579" + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/84b1ca48347efdbe775426f108622a42735a6579", - "reference": "84b1ca48347efdbe775426f108622a42735a6579", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", "shasum": "" }, "require": { @@ -2472,9 +2471,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0", - "symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" }, @@ -2541,7 +2540,7 @@ "type": "tidelift" } ], - "time": "2026-03-05T21:37:03+00:00" + "time": "2025-11-26T21:48:24+00:00" }, { "name": "league/config", @@ -2627,16 +2626,16 @@ }, { "name": "league/flysystem", - "version": "3.32.0", + "version": "3.31.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "254b1595b16b22dbddaaef9ed6ca9fdac4956725" + "reference": "1717e0b3642b0df65ecb0cc89cdd99fa840672ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/254b1595b16b22dbddaaef9ed6ca9fdac4956725", - "reference": "254b1595b16b22dbddaaef9ed6ca9fdac4956725", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1717e0b3642b0df65ecb0cc89cdd99fa840672ff", + "reference": "1717e0b3642b0df65ecb0cc89cdd99fa840672ff", "shasum": "" }, "require": { @@ -2704,9 +2703,9 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.32.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.31.0" }, - "time": "2026-02-25T17:01:41+00:00" + "time": "2026-01-23T15:38:47+00:00" }, { "name": "league/flysystem-local", @@ -3129,29 +3128,29 @@ }, { "name": "livewire/flux", - "version": "v2.13.0", + "version": "v2.11.1", "source": { "type": "git", "url": "https://github.com/livewire/flux.git", - "reference": "741be2d4526e90b97c7a59e079a2f27ecdce2461" + "reference": "3ada3b2644215fd1ccb7003ce8e6bc185c22e70a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/flux/zipball/741be2d4526e90b97c7a59e079a2f27ecdce2461", - "reference": "741be2d4526e90b97c7a59e079a2f27ecdce2461", + "url": "https://api.github.com/repos/livewire/flux/zipball/3ada3b2644215fd1ccb7003ce8e6bc185c22e70a", + "reference": "3ada3b2644215fd1ccb7003ce8e6bc185c22e70a", "shasum": "" }, "require": { - "illuminate/console": "^10.0|^11.0|^12.0|^13.0", - "illuminate/support": "^10.0|^11.0|^12.0|^13.0", - "illuminate/view": "^10.0|^11.0|^12.0|^13.0", + "illuminate/console": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/view": "^10.0|^11.0|^12.0", "laravel/prompts": "^0.1|^0.2|^0.3", "livewire/livewire": "^3.7.4|^4.0", "php": "^8.1", - "symfony/console": "^6.0|^7.0|^8.0" + "symfony/console": "^6.0|^7.0" }, "conflict": { - "livewire/blaze": "<1.0.0-beta.2" + "livewire/blaze": "<1.0.0" }, "type": "library", "extra": { @@ -3189,42 +3188,42 @@ ], "support": { "issues": "https://github.com/livewire/flux/issues", - "source": "https://github.com/livewire/flux/tree/v2.13.0" + "source": "https://github.com/livewire/flux/tree/v2.11.1" }, - "time": "2026-03-03T03:32:35+00:00" + "time": "2026-01-21T17:09:56+00:00" }, { "name": "livewire/livewire", - "version": "v4.2.1", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "93e972fa42c1b34fff1550093ab94f778d81ea5a" + "reference": "8adef21f35f4ffa87fd2f3655b350236df0c39a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/93e972fa42c1b34fff1550093ab94f778d81ea5a", - "reference": "93e972fa42c1b34fff1550093ab94f778d81ea5a", + "url": "https://api.github.com/repos/livewire/livewire/zipball/8adef21f35f4ffa87fd2f3655b350236df0c39a8", + "reference": "8adef21f35f4ffa87fd2f3655b350236df0c39a8", "shasum": "" }, "require": { - "illuminate/database": "^10.0|^11.0|^12.0|^13.0", - "illuminate/routing": "^10.0|^11.0|^12.0|^13.0", - "illuminate/support": "^10.0|^11.0|^12.0|^13.0", - "illuminate/validation": "^10.0|^11.0|^12.0|^13.0", + "illuminate/database": "^10.0|^11.0|^12.0", + "illuminate/routing": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/validation": "^10.0|^11.0|^12.0", "laravel/prompts": "^0.1.24|^0.2|^0.3", "league/mime-type-detection": "^1.9", "php": "^8.1", - "symfony/console": "^6.0|^7.0|^8.0", - "symfony/http-kernel": "^6.2|^7.0|^8.0" + "symfony/console": "^6.0|^7.0", + "symfony/http-kernel": "^6.2|^7.0" }, "require-dev": { "calebporzio/sushi": "^2.1", - "laravel/framework": "^10.15.0|^11.0|^12.0|^13.0", + "laravel/framework": "^10.15.0|^11.0|^12.0", "mockery/mockery": "^1.3.1", - "orchestra/testbench": "^8.21.0|^9.0|^10.0|^11.0", - "orchestra/testbench-dusk": "^8.24|^9.1|^10.0|^11.0", - "phpunit/phpunit": "^10.4|^11.5|^12.5", + "orchestra/testbench": "^8.21.0|^9.0|^10.0", + "orchestra/testbench-dusk": "^8.24|^9.1|^10.0", + "phpunit/phpunit": "^10.4|^11.5", "psy/psysh": "^0.11.22|^0.12" }, "type": "library", @@ -3259,7 +3258,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v4.2.1" + "source": "https://github.com/livewire/livewire/tree/v4.1.2" }, "funding": [ { @@ -3267,7 +3266,7 @@ "type": "github" } ], - "time": "2026-02-28T00:01:19+00:00" + "time": "2026-02-03T03:01:29+00:00" }, { "name": "maennchen/zipstream-php", @@ -3623,16 +3622,16 @@ }, { "name": "nette/schema", - "version": "v1.3.5", + "version": "v1.3.3", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" + "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", - "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", + "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004", + "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004", "shasum": "" }, "require": { @@ -3640,10 +3639,8 @@ "php": "8.1 - 8.5" }, "require-dev": { - "nette/phpstan-rules": "^1.0", - "nette/tester": "^2.6", - "phpstan/extension-installer": "^1.4@stable", - "phpstan/phpstan": "^2.1.39@stable", + "nette/tester": "^2.5.2", + "phpstan/phpstan-nette": "^2.0@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -3684,22 +3681,22 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.5" + "source": "https://github.com/nette/schema/tree/v1.3.3" }, - "time": "2026-02-23T03:47:12+00:00" + "time": "2025-10-30T22:57:59+00:00" }, { "name": "nette/utils", - "version": "v4.1.3", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" + "reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", - "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", + "url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5", + "reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5", "shasum": "" }, "require": { @@ -3711,10 +3708,8 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "^1.2", - "nette/phpstan-rules": "^1.0", "nette/tester": "^2.5", - "phpstan/extension-installer": "^1.4@stable", - "phpstan/phpstan": "^2.1@stable", + "phpstan/phpstan": "^2.0@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -3775,9 +3770,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.1.3" + "source": "https://github.com/nette/utils/tree/v4.1.2" }, - "time": "2026-02-13T03:05:33+00:00" + "time": "2026-02-03T17:21:09+00:00" }, { "name": "nikic/php-parser", @@ -3839,31 +3834,31 @@ }, { "name": "nunomaduro/termwind", - "version": "v2.4.0", + "version": "v2.3.3", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "712a31b768f5daea284c2169a7d227031001b9a8" + "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", - "reference": "712a31b768f5daea284c2169a7d227031001b9a8", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017", + "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.4.4 || ^8.0.4" + "symfony/console": "^7.3.6" }, "require-dev": { - "illuminate/console": "^11.47.0", - "laravel/pint": "^1.27.1", + "illuminate/console": "^11.46.1", + "laravel/pint": "^1.25.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3", "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.3.5 || ^8.0.4", + "symfony/var-dumper": "^7.3.5", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -3895,7 +3890,7 @@ "email": "enunomaduro@gmail.com" } ], - "description": "It's like Tailwind CSS, but for the console.", + "description": "Its like Tailwind CSS, but for the console.", "keywords": [ "cli", "console", @@ -3906,7 +3901,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.3" }, "funding": [ { @@ -3922,36 +3917,36 @@ "type": "github" } ], - "time": "2026-02-16T23:10:27+00:00" + "time": "2025-11-20T02:34:59+00:00" }, { "name": "om/icalparser", - "version": "v4.0.0", + "version": "v3.2.1", "source": { "type": "git", "url": "https://github.com/OzzyCzech/icalparser.git", - "reference": "3e60e2edf0bdfed6c81b69dccf0b7f2852cd87a6" + "reference": "bc7a82b12455ae9b62ce8e7f2d0273e86c931ecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/OzzyCzech/icalparser/zipball/3e60e2edf0bdfed6c81b69dccf0b7f2852cd87a6", - "reference": "3e60e2edf0bdfed6c81b69dccf0b7f2852cd87a6", + "url": "https://api.github.com/repos/OzzyCzech/icalparser/zipball/bc7a82b12455ae9b62ce8e7f2d0273e86c931ecc", + "reference": "bc7a82b12455ae9b62ce8e7f2d0273e86c931ecc", "shasum": "" }, "require": { - "php": "^8.4" + "php": ">=8.1.0" }, "require-dev": { - "nette/tester": "^2.6.0" + "nette/tester": "^2.5.7" }, "suggest": { "ext-dom": "for timezone tool" }, "type": "library", "autoload": { - "psr-4": { - "om\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3971,9 +3966,9 @@ ], "support": { "issues": "https://github.com/OzzyCzech/icalparser/issues", - "source": "https://github.com/OzzyCzech/icalparser/tree/v4.0.0" + "source": "https://github.com/OzzyCzech/icalparser/tree/v3.2.1" }, - "time": "2026-01-29T16:45:33+00:00" + "time": "2025-12-15T06:25:09+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -4903,16 +4898,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.21", + "version": "v0.12.19", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97" + "reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/4821fab5b7cd8c49a673a9fd5754dc9162bb9e97", - "reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/a4f766e5c5b6773d8399711019bb7d90875a50ee", + "reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee", "shasum": "" }, "require": { @@ -4976,9 +4971,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.21" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.19" }, - "time": "2026-03-06T21:21:28+00:00" + "time": "2026-01-30T17:33:13+00:00" }, { "name": "ralouphie/getallheaders", @@ -5180,16 +5175,16 @@ }, { "name": "spatie/browsershot", - "version": "5.2.3", + "version": "5.2.0", "source": { "type": "git", "url": "https://github.com/spatie/browsershot.git", - "reference": "d2e4ac7c69162999940172a674bf83ddc5ac59ea" + "reference": "9bc6b8d67175810d7a399b2588c3401efe2d02a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/browsershot/zipball/d2e4ac7c69162999940172a674bf83ddc5ac59ea", - "reference": "d2e4ac7c69162999940172a674bf83ddc5ac59ea", + "url": "https://api.github.com/repos/spatie/browsershot/zipball/9bc6b8d67175810d7a399b2588c3401efe2d02a8", + "reference": "9bc6b8d67175810d7a399b2588c3401efe2d02a8", "shasum": "" }, "require": { @@ -5236,7 +5231,7 @@ "webpage" ], "support": { - "source": "https://github.com/spatie/browsershot/tree/5.2.3" + "source": "https://github.com/spatie/browsershot/tree/5.2.0" }, "funding": [ { @@ -5244,33 +5239,33 @@ "type": "github" } ], - "time": "2026-02-18T16:10:58+00:00" + "time": "2025-12-22T10:02:16+00:00" }, { "name": "spatie/laravel-package-tools", - "version": "1.93.0", + "version": "1.92.7", "source": { "type": "git", "url": "https://github.com/spatie/laravel-package-tools.git", - "reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7" + "reference": "f09a799850b1ed765103a4f0b4355006360c49a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/0d097bce95b2bf6802fb1d83e1e753b0f5a948e7", - "reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/f09a799850b1ed765103a4f0b4355006360c49a5", + "reference": "f09a799850b1ed765103a4f0b4355006360c49a5", "shasum": "" }, "require": { - "illuminate/contracts": "^10.0|^11.0|^12.0|^13.0", - "php": "^8.1" + "illuminate/contracts": "^9.28|^10.0|^11.0|^12.0", + "php": "^8.0" }, "require-dev": { "mockery/mockery": "^1.5", - "orchestra/testbench": "^8.0|^9.2|^10.0|^11.0", - "pestphp/pest": "^2.1|^3.1|^4.0", - "phpunit/php-code-coverage": "^10.0|^11.0|^12.0", - "phpunit/phpunit": "^10.5|^11.5|^12.5", - "spatie/pest-plugin-test-time": "^2.2|^3.0" + "orchestra/testbench": "^7.7|^8.0|^9.0|^10.0", + "pestphp/pest": "^1.23|^2.1|^3.1", + "phpunit/php-code-coverage": "^9.0|^10.0|^11.0", + "phpunit/phpunit": "^9.5.24|^10.5|^11.5", + "spatie/pest-plugin-test-time": "^1.1|^2.2" }, "type": "library", "autoload": { @@ -5297,7 +5292,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-package-tools/issues", - "source": "https://github.com/spatie/laravel-package-tools/tree/1.93.0" + "source": "https://github.com/spatie/laravel-package-tools/tree/1.92.7" }, "funding": [ { @@ -5305,20 +5300,20 @@ "type": "github" } ], - "time": "2026-02-21T12:49:54+00:00" + "time": "2025-07-17T15:46:43+00:00" }, { "name": "spatie/laravel-settings", - "version": "3.7.0", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-settings.git", - "reference": "83b179e8097645a30d402d75ba3c19621464494d" + "reference": "fae93dadb8f748628ecaf5710f494adf790255b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-settings/zipball/83b179e8097645a30d402d75ba3c19621464494d", - "reference": "83b179e8097645a30d402d75ba3c19621464494d", + "url": "https://api.github.com/repos/spatie/laravel-settings/zipball/fae93dadb8f748628ecaf5710f494adf790255b2", + "reference": "fae93dadb8f748628ecaf5710f494adf790255b2", "shasum": "" }, "require": { @@ -5378,7 +5373,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-settings/issues", - "source": "https://github.com/spatie/laravel-settings/tree/3.7.0" + "source": "https://github.com/spatie/laravel-settings/tree/3.6.0" }, "funding": [ { @@ -5390,7 +5385,7 @@ "type": "github" } ], - "time": "2026-02-09T15:22:32+00:00" + "time": "2025-12-03T10:29:27+00:00" }, { "name": "spatie/temporary-directory", @@ -5598,16 +5593,16 @@ }, { "name": "symfony/console", - "version": "v7.4.7", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d" + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d", - "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "url": "https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894", + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894", "shasum": "" }, "require": { @@ -5672,7 +5667,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.7" + "source": "https://github.com/symfony/console/tree/v7.4.4" }, "funding": [ { @@ -5692,20 +5687,20 @@ "type": "tidelift" } ], - "time": "2026-03-06T14:06:20+00:00" + "time": "2026-01-13T11:36:38+00:00" }, { "name": "symfony/css-selector", - "version": "v8.0.6", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "2a178bf80f05dbbe469a337730eba79d61315262" + "reference": "6225bd458c53ecdee056214cb4a2ffaf58bd592b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/2a178bf80f05dbbe469a337730eba79d61315262", - "reference": "2a178bf80f05dbbe469a337730eba79d61315262", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/6225bd458c53ecdee056214cb4a2ffaf58bd592b", + "reference": "6225bd458c53ecdee056214cb4a2ffaf58bd592b", "shasum": "" }, "require": { @@ -5741,7 +5736,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v8.0.6" + "source": "https://github.com/symfony/css-selector/tree/v8.0.0" }, "funding": [ { @@ -5761,7 +5756,7 @@ "type": "tidelift" } ], - "time": "2026-02-17T13:07:04+00:00" + "time": "2025-10-30T14:17:19+00:00" }, { "name": "symfony/deprecation-contracts", @@ -6075,16 +6070,16 @@ }, { "name": "symfony/filesystem", - "version": "v8.0.6", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7bf9162d7a0dff98d079b72948508fa48018a770" + "reference": "d937d400b980523dc9ee946bb69972b5e619058d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7bf9162d7a0dff98d079b72948508fa48018a770", - "reference": "7bf9162d7a0dff98d079b72948508fa48018a770", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d", + "reference": "d937d400b980523dc9ee946bb69972b5e619058d", "shasum": "" }, "require": { @@ -6121,7 +6116,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v8.0.6" + "source": "https://github.com/symfony/filesystem/tree/v8.0.1" }, "funding": [ { @@ -6141,20 +6136,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:59:43+00:00" + "time": "2025-12-01T09:13:36+00:00" }, { "name": "symfony/finder", - "version": "v7.4.6", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", "shasum": "" }, "require": { @@ -6189,7 +6184,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.6" + "source": "https://github.com/symfony/finder/tree/v7.4.5" }, "funding": [ { @@ -6209,20 +6204,20 @@ "type": "tidelift" } ], - "time": "2026-01-29T09:40:50+00:00" + "time": "2026-01-26T15:07:59+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.4.7", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81" + "reference": "446d0db2b1f21575f1284b74533e425096abdfb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f94b3e7b7dafd40e666f0c9ff2084133bae41e81", - "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/446d0db2b1f21575f1284b74533e425096abdfb6", + "reference": "446d0db2b1f21575f1284b74533e425096abdfb6", "shasum": "" }, "require": { @@ -6271,7 +6266,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.4.7" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.5" }, "funding": [ { @@ -6291,20 +6286,20 @@ "type": "tidelift" } ], - "time": "2026-03-06T13:15:18+00:00" + "time": "2026-01-27T16:16:02+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.4.7", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1" + "reference": "229eda477017f92bd2ce7615d06222ec0c19e82a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3b3fcf386c809be990c922e10e4c620d6367cab1", - "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/229eda477017f92bd2ce7615d06222ec0c19e82a", + "reference": "229eda477017f92bd2ce7615d06222ec0c19e82a", "shasum": "" }, "require": { @@ -6346,7 +6341,7 @@ "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.1|^7.0.1|^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", @@ -6390,7 +6385,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.4.7" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.5" }, "funding": [ { @@ -6410,20 +6405,20 @@ "type": "tidelift" } ], - "time": "2026-03-06T16:33:18+00:00" + "time": "2026-01-28T10:33:42+00:00" }, { "name": "symfony/mailer", - "version": "v7.4.6", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9" + "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/b02726f39a20bc65e30364f5c750c4ddbf1f58e9", - "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "url": "https://api.github.com/repos/symfony/mailer/zipball/7b750074c40c694ceb34cb926d6dffee231c5cd6", + "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6", "shasum": "" }, "require": { @@ -6474,7 +6469,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.4.6" + "source": "https://github.com/symfony/mailer/tree/v7.4.4" }, "funding": [ { @@ -6494,20 +6489,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-01-08T08:25:11+00:00" }, { "name": "symfony/mime", - "version": "v7.4.7", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1" + "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1", - "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1", + "url": "https://api.github.com/repos/symfony/mime/zipball/b18c7e6e9eee1e19958138df10412f3c4c316148", + "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148", "shasum": "" }, "require": { @@ -6518,7 +6513,7 @@ }, "conflict": { "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/reflection-docblock": "<5.2|>=6", "phpdocumentor/type-resolver": "<1.5.1", "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" @@ -6526,7 +6521,7 @@ "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "phpdocumentor/reflection-docblock": "^5.2", "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", @@ -6563,7 +6558,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.7" + "source": "https://github.com/symfony/mime/tree/v7.4.5" }, "funding": [ { @@ -6583,7 +6578,7 @@ "type": "tidelift" } ], - "time": "2026-03-05T15:24:09+00:00" + "time": "2026-01-27T08:59:58+00:00" }, { "name": "symfony/polyfill-ctype", @@ -7481,16 +7476,16 @@ }, { "name": "symfony/routing", - "version": "v7.4.6", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "238d749c56b804b31a9bf3e26519d93b65a60938" + "reference": "0798827fe2c79caeed41d70b680c2c3507d10147" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/238d749c56b804b31a9bf3e26519d93b65a60938", - "reference": "238d749c56b804b31a9bf3e26519d93b65a60938", + "url": "https://api.github.com/repos/symfony/routing/zipball/0798827fe2c79caeed41d70b680c2c3507d10147", + "reference": "0798827fe2c79caeed41d70b680c2c3507d10147", "shasum": "" }, "require": { @@ -7542,7 +7537,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.4.6" + "source": "https://github.com/symfony/routing/tree/v7.4.4" }, "funding": [ { @@ -7562,7 +7557,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-01-12T12:19:02+00:00" }, { "name": "symfony/service-contracts", @@ -7653,16 +7648,16 @@ }, { "name": "symfony/string", - "version": "v8.0.6", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4" + "reference": "758b372d6882506821ed666032e43020c4f57194" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/6c9e1108041b5dce21a9a4984b531c4923aa9ec4", - "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4", + "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194", + "reference": "758b372d6882506821ed666032e43020c4f57194", "shasum": "" }, "require": { @@ -7719,7 +7714,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.6" + "source": "https://github.com/symfony/string/tree/v8.0.4" }, "funding": [ { @@ -7739,20 +7734,20 @@ "type": "tidelift" } ], - "time": "2026-02-09T10:14:57+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "symfony/translation", - "version": "v8.0.6", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "13ff19bcf2bea492d3c2fbeaa194dd6f4599ce1b" + "reference": "db70c8ce7db74fd2da7b1d268db46b2a8ce32c10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/13ff19bcf2bea492d3c2fbeaa194dd6f4599ce1b", - "reference": "13ff19bcf2bea492d3c2fbeaa194dd6f4599ce1b", + "url": "https://api.github.com/repos/symfony/translation/zipball/db70c8ce7db74fd2da7b1d268db46b2a8ce32c10", + "reference": "db70c8ce7db74fd2da7b1d268db46b2a8ce32c10", "shasum": "" }, "require": { @@ -7812,7 +7807,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v8.0.6" + "source": "https://github.com/symfony/translation/tree/v8.0.4" }, "funding": [ { @@ -7832,7 +7827,7 @@ "type": "tidelift" } ], - "time": "2026-02-17T13:07:04+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/translation-contracts", @@ -7996,16 +7991,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.4.6", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291" + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/045321c440ac18347b136c63d2e9bf28a2dc0291", - "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e4769b46a0c3c62390d124635ce59f66874b282", + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282", "shasum": "" }, "require": { @@ -8059,7 +8054,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.6" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.4" }, "funding": [ { @@ -8079,29 +8074,30 @@ "type": "tidelift" } ], - "time": "2026-02-15T10:53:20+00:00" + "time": "2026-01-01T22:13:48+00:00" }, { "name": "symfony/var-exporter", - "version": "v8.0.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04" + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04", - "reference": "7345f46c251f2eb27c7b3ebdb5bb076b3ffcae04", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f", + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f", "shasum": "" }, "require": { - "php": ">=8.4" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { - "symfony/property-access": "^7.4|^8.0", - "symfony/serializer": "^7.4|^8.0", - "symfony/var-dumper": "^7.4|^8.0" + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8139,7 +8135,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v8.0.0" + "source": "https://github.com/symfony/var-exporter/tree/v7.4.0" }, "funding": [ { @@ -8159,20 +8155,20 @@ "type": "tidelift" } ], - "time": "2025-11-05T18:53:00+00:00" + "time": "2025-09-11T10:15:23+00:00" }, { "name": "symfony/yaml", - "version": "v7.4.6", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "58751048de17bae71c5aa0d13cb19d79bca26391" + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/58751048de17bae71c5aa0d13cb19d79bca26391", - "reference": "58751048de17bae71c5aa0d13cb19d79bca26391", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", "shasum": "" }, "require": { @@ -8215,7 +8211,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.6" + "source": "https://github.com/symfony/yaml/tree/v7.4.1" }, "funding": [ { @@ -8235,7 +8231,7 @@ "type": "tidelift" } ], - "time": "2026-02-09T09:33:46+00:00" + "time": "2025-12-04T18:11:45+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -8452,23 +8448,23 @@ }, { "name": "wnx/sidecar-browsershot", - "version": "v2.8.0", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/stefanzweifel/sidecar-browsershot.git", - "reference": "1d2a20a6723b74c139f98f7a020fe5c0f57d05a5" + "reference": "e42a996c6fab4357919cd5e3f3fab33f019cdd80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stefanzweifel/sidecar-browsershot/zipball/1d2a20a6723b74c139f98f7a020fe5c0f57d05a5", - "reference": "1d2a20a6723b74c139f98f7a020fe5c0f57d05a5", + "url": "https://api.github.com/repos/stefanzweifel/sidecar-browsershot/zipball/e42a996c6fab4357919cd5e3f3fab33f019cdd80", + "reference": "e42a996c6fab4357919cd5e3f3fab33f019cdd80", "shasum": "" }, "require": { - "hammerstone/sidecar": "^0.7.1", + "hammerstone/sidecar": "^0.7", "illuminate/contracts": "^12.0", "php": "^8.4", - "spatie/browsershot": "^5.0", + "spatie/browsershot": "^4.0 || ^5.0", "spatie/laravel-package-tools": "^1.9.2" }, "require-dev": { @@ -8484,7 +8480,7 @@ "phpstan/phpstan-phpunit": "^1.0|^2.0", "phpunit/phpunit": "^11.0 | ^12.0", "spatie/image": "^3.3", - "spatie/pixelmatch-php": "^1.2" + "spatie/pixelmatch-php": "^1.0" }, "type": "library", "extra": { @@ -8526,7 +8522,7 @@ ], "support": { "issues": "https://github.com/stefanzweifel/sidecar-browsershot/issues", - "source": "https://github.com/stefanzweifel/sidecar-browsershot/tree/v2.8.0" + "source": "https://github.com/stefanzweifel/sidecar-browsershot/tree/v2.7.0" }, "funding": [ { @@ -8534,22 +8530,22 @@ "type": "github" } ], - "time": "2026-03-07T18:24:28+00:00" + "time": "2025-11-22T08:49:08+00:00" } ], "packages-dev": [ { "name": "brianium/paratest", - "version": "v7.19.0", + "version": "v7.16.1", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "7c6c29af7c4b406b49ce0c6b0a3a81d3684474e6" + "reference": "f0fdfd8e654e0d38bc2ba756a6cabe7be287390b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/7c6c29af7c4b406b49ce0c6b0a3a81d3684474e6", - "reference": "7c6c29af7c4b406b49ce0c6b0a3a81d3684474e6", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/f0fdfd8e654e0d38bc2ba756a6cabe7be287390b", + "reference": "f0fdfd8e654e0d38bc2ba756a6cabe7be287390b", "shasum": "" }, "require": { @@ -8560,24 +8556,24 @@ "fidry/cpu-core-counter": "^1.3.0", "jean85/pretty-package-versions": "^2.1.1", "php": "~8.3.0 || ~8.4.0 || ~8.5.0", - "phpunit/php-code-coverage": "^12.5.3 || ^13.0.1", - "phpunit/php-file-iterator": "^6.0.1 || ^7", - "phpunit/php-timer": "^8 || ^9", - "phpunit/phpunit": "^12.5.9 || ^13", - "sebastian/environment": "^8.0.3 || ^9", - "symfony/console": "^7.4.4 || ^8.0.4", - "symfony/process": "^7.4.5 || ^8.0.5" + "phpunit/php-code-coverage": "^12.5.2", + "phpunit/php-file-iterator": "^6", + "phpunit/php-timer": "^8", + "phpunit/phpunit": "^12.5.4", + "sebastian/environment": "^8.0.3", + "symfony/console": "^7.3.4 || ^8.0.0", + "symfony/process": "^7.3.4 || ^8.0.0" }, "require-dev": { "doctrine/coding-standard": "^14.0.0", "ext-pcntl": "*", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^2.1.38", + "phpstan/phpstan": "^2.1.33", "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.12", - "phpstan/phpstan-strict-rules": "^2.0.8", - "symfony/filesystem": "^7.4.0 || ^8.0.1" + "phpstan/phpstan-phpunit": "^2.0.11", + "phpstan/phpstan-strict-rules": "^2.0.7", + "symfony/filesystem": "^7.3.2 || ^8.0.0" }, "bin": [ "bin/paratest", @@ -8617,7 +8613,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.19.0" + "source": "https://github.com/paratestphp/paratest/tree/v7.16.1" }, "funding": [ { @@ -8629,7 +8625,7 @@ "type": "paypal" } ], - "time": "2026-02-06T10:53:26+00:00" + "time": "2026-01-08T07:23:06+00:00" }, { "name": "fakerphp/faker", @@ -8980,40 +8976,40 @@ }, { "name": "larastan/larastan", - "version": "v3.9.3", + "version": "v3.9.2", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "64a52bcc5347c89fdf131cb59f96ebfbc8d1ad65" + "reference": "2e9ed291bdc1969e7f270fb33c9cdf3c912daeb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/64a52bcc5347c89fdf131cb59f96ebfbc8d1ad65", - "reference": "64a52bcc5347c89fdf131cb59f96ebfbc8d1ad65", + "url": "https://api.github.com/repos/larastan/larastan/zipball/2e9ed291bdc1969e7f270fb33c9cdf3c912daeb2", + "reference": "2e9ed291bdc1969e7f270fb33c9cdf3c912daeb2", "shasum": "" }, "require": { "ext-json": "*", "iamcal/sql-parser": "^0.7.0", - "illuminate/console": "^11.44.2 || ^12.4.1 || ^13", - "illuminate/container": "^11.44.2 || ^12.4.1 || ^13", - "illuminate/contracts": "^11.44.2 || ^12.4.1 || ^13", - "illuminate/database": "^11.44.2 || ^12.4.1 || ^13", - "illuminate/http": "^11.44.2 || ^12.4.1 || ^13", - "illuminate/pipeline": "^11.44.2 || ^12.4.1 || ^13", - "illuminate/support": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/console": "^11.44.2 || ^12.4.1", + "illuminate/container": "^11.44.2 || ^12.4.1", + "illuminate/contracts": "^11.44.2 || ^12.4.1", + "illuminate/database": "^11.44.2 || ^12.4.1", + "illuminate/http": "^11.44.2 || ^12.4.1", + "illuminate/pipeline": "^11.44.2 || ^12.4.1", + "illuminate/support": "^11.44.2 || ^12.4.1", "php": "^8.2", "phpstan/phpstan": "^2.1.32" }, "require-dev": { "doctrine/coding-standard": "^13", - "laravel/framework": "^11.44.2 || ^12.7.2 || ^13", + "laravel/framework": "^11.44.2 || ^12.7.2", "mockery/mockery": "^1.6.12", "nikic/php-parser": "^5.4", - "orchestra/canvas": "^v9.2.2 || ^10.0.1 || ^11", - "orchestra/testbench-core": "^9.12.0 || ^10.1 || ^11", + "orchestra/canvas": "^v9.2.2 || ^10.0.1", + "orchestra/testbench-core": "^9.12.0 || ^10.1", "phpstan/phpstan-deprecation-rules": "^2.0.1", - "phpunit/phpunit": "^10.5.35 || ^11.5.15 || ^12.5.8" + "phpunit/phpunit": "^10.5.35 || ^11.5.15" }, "suggest": { "orchestra/testbench": "Using Larastan for analysing a package needs Testbench", @@ -9058,7 +9054,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v3.9.3" + "source": "https://github.com/larastan/larastan/tree/v3.9.2" }, "funding": [ { @@ -9066,37 +9062,37 @@ "type": "github" } ], - "time": "2026-02-20T12:07:12+00:00" + "time": "2026-01-30T15:16:32+00:00" }, { "name": "laravel/boost", - "version": "v2.2.3", + "version": "v2.0.5", "source": { "type": "git", "url": "https://github.com/laravel/boost.git", - "reference": "44ab65a5455c2d6fceb71d6145f8d5d89c02d889" + "reference": "00eede2041a9bac83eabbd3b3f16bd4aa91277c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/boost/zipball/44ab65a5455c2d6fceb71d6145f8d5d89c02d889", - "reference": "44ab65a5455c2d6fceb71d6145f8d5d89c02d889", + "url": "https://api.github.com/repos/laravel/boost/zipball/00eede2041a9bac83eabbd3b3f16bd4aa91277c9", + "reference": "00eede2041a9bac83eabbd3b3f16bd4aa91277c9", "shasum": "" }, "require": { "guzzlehttp/guzzle": "^7.9", - "illuminate/console": "^11.45.3|^12.41.1|^13.0", - "illuminate/contracts": "^11.45.3|^12.41.1|^13.0", - "illuminate/routing": "^11.45.3|^12.41.1|^13.0", - "illuminate/support": "^11.45.3|^12.41.1|^13.0", - "laravel/mcp": "^0.5.1|^0.6.0", + "illuminate/console": "^11.45.3|^12.41.1", + "illuminate/contracts": "^11.45.3|^12.41.1", + "illuminate/routing": "^11.45.3|^12.41.1", + "illuminate/support": "^11.45.3|^12.41.1", + "laravel/mcp": "^0.5.1", "laravel/prompts": "^0.3.10", - "laravel/roster": "^0.5.0", + "laravel/roster": "^0.2.9", "php": "^8.2" }, "require-dev": { "laravel/pint": "^1.27.0", "mockery/mockery": "^1.6.12", - "orchestra/testbench": "^9.15.0|^10.6|^11.0", + "orchestra/testbench": "^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" @@ -9132,39 +9128,39 @@ "issues": "https://github.com/laravel/boost/issues", "source": "https://github.com/laravel/boost" }, - "time": "2026-03-06T20:20:28+00:00" + "time": "2026-02-01T09:52:44+00:00" }, { "name": "laravel/mcp", - "version": "v0.6.2", + "version": "v0.5.3", "source": { "type": "git", "url": "https://github.com/laravel/mcp.git", - "reference": "f696e44735b95ff275392eab8ce5a3b4b42a2223" + "reference": "39b9791b989927642137dd5b55dde0529f1614f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/mcp/zipball/f696e44735b95ff275392eab8ce5a3b4b42a2223", - "reference": "f696e44735b95ff275392eab8ce5a3b4b42a2223", + "url": "https://api.github.com/repos/laravel/mcp/zipball/39b9791b989927642137dd5b55dde0529f1614f9", + "reference": "39b9791b989927642137dd5b55dde0529f1614f9", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", - "illuminate/console": "^11.45.3|^12.41.1|^13.0", - "illuminate/container": "^11.45.3|^12.41.1|^13.0", - "illuminate/contracts": "^11.45.3|^12.41.1|^13.0", - "illuminate/http": "^11.45.3|^12.41.1|^13.0", - "illuminate/json-schema": "^12.41.1|^13.0", - "illuminate/routing": "^11.45.3|^12.41.1|^13.0", - "illuminate/support": "^11.45.3|^12.41.1|^13.0", - "illuminate/validation": "^11.45.3|^12.41.1|^13.0", - "php": "^8.2" + "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": "^9.15|^10.8|^11.0", - "pestphp/pest": "^3.8.5|^4.3.2", + "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" }, @@ -9205,42 +9201,41 @@ "issues": "https://github.com/laravel/mcp/issues", "source": "https://github.com/laravel/mcp" }, - "time": "2026-03-10T20:00:23+00:00" + "time": "2026-01-26T10:25:21+00:00" }, { "name": "laravel/pail", - "version": "v1.2.6", + "version": "v1.2.4", "source": { "type": "git", "url": "https://github.com/laravel/pail.git", - "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf" + "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pail/zipball/aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", - "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "url": "https://api.github.com/repos/laravel/pail/zipball/49f92285ff5d6fc09816e976a004f8dec6a0ea30", + "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30", "shasum": "" }, "require": { "ext-mbstring": "*", - "illuminate/console": "^10.24|^11.0|^12.0|^13.0", - "illuminate/contracts": "^10.24|^11.0|^12.0|^13.0", - "illuminate/log": "^10.24|^11.0|^12.0|^13.0", - "illuminate/process": "^10.24|^11.0|^12.0|^13.0", - "illuminate/support": "^10.24|^11.0|^12.0|^13.0", + "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|^8.0" + "symfony/console": "^6.0|^7.0" }, "require-dev": { - "laravel/framework": "^10.24|^11.0|^12.0|^13.0", + "laravel/framework": "^10.24|^11.0|^12.0", "laravel/pint": "^1.13", - "orchestra/testbench-core": "^8.13|^9.17|^10.8|^11.0", + "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|^8.0", - "symfony/yaml": "^6.3|^7.0|^8.0" + "symfony/var-dumper": "^6.3|^7.0" }, "type": "library", "extra": { @@ -9285,20 +9280,20 @@ "issues": "https://github.com/laravel/pail/issues", "source": "https://github.com/laravel/pail" }, - "time": "2026-02-09T13:44:54+00:00" + "time": "2025-11-20T16:29:35+00:00" }, { "name": "laravel/pint", - "version": "v1.28.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9" + "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9", - "reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9", + "url": "https://api.github.com/repos/laravel/pint/zipball/c67b4195b75491e4dfc6b00b1c78b68d86f54c90", + "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90", "shasum": "" }, "require": { @@ -9309,14 +9304,13 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.94.2", - "illuminate/view": "^12.54.1", - "larastan/larastan": "^3.9.3", - "laravel-zero/framework": "^12.0.5", + "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.4.0", - "pestphp/pest": "^3.8.5", - "shipfastlabs/agent-detector": "^1.0.2" + "nunomaduro/termwind": "^2.3.3", + "pestphp/pest": "^3.8.4" }, "bin": [ "builds/pint" @@ -9353,35 +9347,35 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2026-03-10T20:37:18+00:00" + "time": "2026-01-05T16:49:17+00:00" }, { "name": "laravel/roster", - "version": "v0.5.1", + "version": "v0.2.9", "source": { "type": "git", "url": "https://github.com/laravel/roster.git", - "reference": "5089de7615f72f78e831590ff9d0435fed0102bb" + "reference": "82bbd0e2de614906811aebdf16b4305956816fa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/roster/zipball/5089de7615f72f78e831590ff9d0435fed0102bb", - "reference": "5089de7615f72f78e831590ff9d0435fed0102bb", + "url": "https://api.github.com/repos/laravel/roster/zipball/82bbd0e2de614906811aebdf16b4305956816fa6", + "reference": "82bbd0e2de614906811aebdf16b4305956816fa6", "shasum": "" }, "require": { - "illuminate/console": "^11.0|^12.0|^13.0", - "illuminate/contracts": "^11.0|^12.0|^13.0", - "illuminate/routing": "^11.0|^12.0|^13.0", - "illuminate/support": "^11.0|^12.0|^13.0", - "php": "^8.2", - "symfony/yaml": "^7.2|^8.0" + "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": "^9.0|^10.0|^11.0", - "pestphp/pest": "^3.0|^4.1", + "orchestra/testbench": "^8.22.0|^9.0|^10.0", + "pestphp/pest": "^2.0|^3.0", "phpstan/phpstan": "^2.0" }, "type": "library", @@ -9414,32 +9408,32 @@ "issues": "https://github.com/laravel/roster/issues", "source": "https://github.com/laravel/roster" }, - "time": "2026-03-05T07:58:43+00:00" + "time": "2025-10-20T09:56:46+00:00" }, { "name": "laravel/sail", - "version": "v1.53.0", + "version": "v1.52.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb" + "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/e340eaa2bea9b99192570c48ed837155dbf24fbb", - "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb", + "url": "https://api.github.com/repos/laravel/sail/zipball/64ac7d8abb2dbcf2b76e61289451bae79066b0b3", + "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3", "shasum": "" }, "require": { - "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0", - "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0", - "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0", "php": "^8.0", - "symfony/console": "^6.0|^7.0|^8.0", - "symfony/yaml": "^6.0|^7.0|^8.0" + "symfony/console": "^6.0|^7.0", + "symfony/yaml": "^6.0|^7.0" }, "require-dev": { - "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0", + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", "phpstan/phpstan": "^2.0" }, "bin": [ @@ -9477,7 +9471,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2026-02-06T12:16:02+00:00" + "time": "2026-01-01T02:46:03+00:00" }, { "name": "mockery/mockery", @@ -9624,36 +9618,39 @@ }, { "name": "nunomaduro/collision", - "version": "v8.9.1", + "version": "v8.8.3", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935" + "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", - "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4", + "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4", "shasum": "" }, "require": { - "filp/whoops": "^2.18.4", - "nunomaduro/termwind": "^2.4.0", + "filp/whoops": "^2.18.1", + "nunomaduro/termwind": "^2.3.1", "php": "^8.2.0", - "symfony/console": "^7.4.4 || ^8.0.4" + "symfony/console": "^7.3.0" }, "conflict": { - "laravel/framework": "<11.48.0 || >=14.0.0", - "phpunit/phpunit": "<11.5.50 || >=14.0.0" + "laravel/framework": "<11.44.2 || >=13.0.0", + "phpunit/phpunit": "<11.5.15 || >=13.0.0" }, "require-dev": { - "brianium/paratest": "^7.8.5", - "larastan/larastan": "^3.9.2", - "laravel/framework": "^11.48.0 || ^12.52.0", - "laravel/pint": "^1.27.1", - "orchestra/testbench-core": "^9.12.0 || ^10.9.0", - "pestphp/pest": "^3.8.5 || ^4.4.1 || ^5.0.0", - "sebastian/environment": "^7.2.1 || ^8.0.3 || ^9.0.0" + "brianium/paratest": "^7.8.3", + "larastan/larastan": "^3.4.2", + "laravel/framework": "^11.44.2 || ^12.18", + "laravel/pint": "^1.22.1", + "laravel/sail": "^1.43.1", + "laravel/sanctum": "^4.1.1", + "laravel/tinker": "^2.10.1", + "orchestra/testbench-core": "^9.12.0 || ^10.4", + "pestphp/pest": "^3.8.2 || ^4.0.0", + "sebastian/environment": "^7.2.1 || ^8.0" }, "type": "library", "extra": { @@ -9716,45 +9713,45 @@ "type": "patreon" } ], - "time": "2026-02-17T17:33:08+00:00" + "time": "2025-11-20T02:55:25+00:00" }, { "name": "pestphp/pest", - "version": "v4.4.2", + "version": "v4.3.2", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "5d42e8fe3ae1d9fdf7c9f73ee88138fd30265701" + "reference": "3a4329ddc7a2b67c19fca8342a668b39be3ae398" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/5d42e8fe3ae1d9fdf7c9f73ee88138fd30265701", - "reference": "5d42e8fe3ae1d9fdf7c9f73ee88138fd30265701", + "url": "https://api.github.com/repos/pestphp/pest/zipball/3a4329ddc7a2b67c19fca8342a668b39be3ae398", + "reference": "3a4329ddc7a2b67c19fca8342a668b39be3ae398", "shasum": "" }, "require": { - "brianium/paratest": "^7.19.0", - "nunomaduro/collision": "^8.9.1", - "nunomaduro/termwind": "^2.4.0", + "brianium/paratest": "^7.16.1", + "nunomaduro/collision": "^8.8.3", + "nunomaduro/termwind": "^2.3.3", "pestphp/pest-plugin": "^4.0.0", "pestphp/pest-plugin-arch": "^4.0.0", "pestphp/pest-plugin-mutate": "^4.0.1", "pestphp/pest-plugin-profanity": "^4.2.1", "php": "^8.3.0", - "phpunit/phpunit": "^12.5.12", - "symfony/process": "^7.4.5|^8.0.5" + "phpunit/phpunit": "^12.5.8", + "symfony/process": "^7.4.4|^8.0.0" }, "conflict": { "filp/whoops": "<2.18.3", - "phpunit/phpunit": ">12.5.12", + "phpunit/phpunit": ">12.5.8", "sebastian/exporter": "<7.0.0", "webmozart/assert": "<1.11.0" }, "require-dev": { - "pestphp/pest-dev-tools": "^4.1.0", - "pestphp/pest-plugin-browser": "^4.3.0", + "pestphp/pest-dev-tools": "^4.0.0", + "pestphp/pest-plugin-browser": "^4.2.1", "pestphp/pest-plugin-type-coverage": "^4.0.3", - "psy/psysh": "^0.12.21" + "psy/psysh": "^0.12.18" }, "bin": [ "bin/pest" @@ -9820,7 +9817,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v4.4.2" + "source": "https://github.com/pestphp/pest/tree/v4.3.2" }, "funding": [ { @@ -9832,7 +9829,7 @@ "type": "github" } ], - "time": "2026-03-10T21:09:12+00:00" + "time": "2026-01-28T01:01:19+00:00" }, { "name": "pestphp/pest-plugin", @@ -10045,27 +10042,27 @@ }, { "name": "pestphp/pest-plugin-laravel", - "version": "v4.1.0", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest-plugin-laravel.git", - "reference": "3057a36669ff11416cc0dc2b521b3aec58c488d0" + "reference": "e12a07046b826a40b1c8632fd7b80d6b8d7b628e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/3057a36669ff11416cc0dc2b521b3aec58c488d0", - "reference": "3057a36669ff11416cc0dc2b521b3aec58c488d0", + "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/e12a07046b826a40b1c8632fd7b80d6b8d7b628e", + "reference": "e12a07046b826a40b1c8632fd7b80d6b8d7b628e", "shasum": "" }, "require": { - "laravel/framework": "^11.45.2|^12.52.0|^13.0", - "pestphp/pest": "^4.4.1", + "laravel/framework": "^11.45.2|^12.25.0", + "pestphp/pest": "^4.0.0", "php": "^8.3.0" }, "require-dev": { - "laravel/dusk": "^8.3.6", - "orchestra/testbench": "^9.13.0|^10.9.0|^11.0", - "pestphp/pest-dev-tools": "^4.1.0" + "laravel/dusk": "^8.3.3", + "orchestra/testbench": "^9.13.0|^10.5.0", + "pestphp/pest-dev-tools": "^4.0.0" }, "type": "library", "extra": { @@ -10103,7 +10100,7 @@ "unit" ], "support": { - "source": "https://github.com/pestphp/pest-plugin-laravel/tree/v4.1.0" + "source": "https://github.com/pestphp/pest-plugin-laravel/tree/v4.0.0" }, "funding": [ { @@ -10115,7 +10112,7 @@ "type": "github" } ], - "time": "2026-02-21T00:29:45+00:00" + "time": "2025-08-20T12:46:37+00:00" }, { "name": "pestphp/pest-plugin-mutate", @@ -10433,11 +10430,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.40", + "version": "2.1.38", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", - "reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dfaf1f530e1663aa167bc3e52197adb221582629", + "reference": "dfaf1f530e1663aa167bc3e52197adb221582629", "shasum": "" }, "require": { @@ -10482,20 +10479,20 @@ "type": "github" } ], - "time": "2026-02-23T15:04:35+00:00" + "time": "2026-01-30T17:12:46+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "12.5.3", + "version": "12.5.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d" + "reference": "4a9739b51cbcb355f6e95659612f92e282a7077b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b015312f28dd75b75d3422ca37dff2cd1a565e8d", - "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4a9739b51cbcb355f6e95659612f92e282a7077b", + "reference": "4a9739b51cbcb355f6e95659612f92e282a7077b", "shasum": "" }, "require": { @@ -10551,7 +10548,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.3" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.2" }, "funding": [ { @@ -10571,7 +10568,7 @@ "type": "tidelift" } ], - "time": "2026-02-06T06:01:44+00:00" + "time": "2025-12-24T07:03:04+00:00" }, { "name": "phpunit/php-file-iterator", @@ -10832,16 +10829,16 @@ }, { "name": "phpunit/phpunit", - "version": "12.5.12", + "version": "12.5.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "418e06b3b46b0d54bad749ff4907fc7dfb530199" + "reference": "37ddb96c14bfee10304825edbb7e66d341ec6889" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/418e06b3b46b0d54bad749ff4907fc7dfb530199", - "reference": "418e06b3b46b0d54bad749ff4907fc7dfb530199", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/37ddb96c14bfee10304825edbb7e66d341ec6889", + "reference": "37ddb96c14bfee10304825edbb7e66d341ec6889", "shasum": "" }, "require": { @@ -10855,8 +10852,8 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.3", - "phpunit/php-code-coverage": "^12.5.3", - "phpunit/php-file-iterator": "^6.0.1", + "phpunit/php-code-coverage": "^12.5.2", + "phpunit/php-file-iterator": "^6.0.0", "phpunit/php-invoker": "^6.0.0", "phpunit/php-text-template": "^5.0.0", "phpunit/php-timer": "^8.0.0", @@ -10867,7 +10864,6 @@ "sebastian/exporter": "^7.0.2", "sebastian/global-state": "^8.0.2", "sebastian/object-enumerator": "^7.0.0", - "sebastian/recursion-context": "^7.0.1", "sebastian/type": "^6.0.3", "sebastian/version": "^6.0.0", "staabm/side-effects-detector": "^1.0.5" @@ -10910,7 +10906,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.12" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.8" }, "funding": [ { @@ -10934,25 +10930,25 @@ "type": "tidelift" } ], - "time": "2026-02-16T08:34:36+00:00" + "time": "2026-01-27T06:12:29+00:00" }, { "name": "rector/rector", - "version": "2.3.8", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c" + "reference": "9442f4037de6a5347ae157fe8e6c7cda9d909070" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/bbd37aedd8df749916cffa2a947cfc4714d1ba2c", - "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/9442f4037de6a5347ae157fe8e6c7cda9d909070", + "reference": "9442f4037de6a5347ae157fe8e6c7cda9d909070", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.38" + "phpstan/phpstan": "^2.1.36" }, "conflict": { "rector/rector-doctrine": "*", @@ -10986,7 +10982,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.3.8" + "source": "https://github.com/rectorphp/rector/tree/2.3.5" }, "funding": [ { @@ -10994,7 +10990,7 @@ "type": "github" } ], - "time": "2026-02-22T09:45:50+00:00" + "time": "2026-01-28T15:22:48+00:00" }, { "name": "sebastian/cli-parser", @@ -11947,23 +11943,23 @@ }, { "name": "ta-tikoma/phpunit-architecture-test", - "version": "0.8.7", + "version": "0.8.6", "source": { "type": "git", "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", - "reference": "1248f3f506ca9641d4f68cebcd538fa489754db8" + "reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/1248f3f506ca9641d4f68cebcd538fa489754db8", - "reference": "1248f3f506ca9641d4f68cebcd538fa489754db8", + "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/ad48430b92901fd7d003fdaf2d7b139f96c0906e", + "reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e", "shasum": "" }, "require": { "nikic/php-parser": "^4.18.0 || ^5.0.0", "php": "^8.1.0", "phpdocumentor/reflection-docblock": "^5.3.0 || ^6.0.0", - "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0 || ^13.0.0", + "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0", "symfony/finder": "^6.4.0 || ^7.0.0 || ^8.0.0" }, "require-dev": { @@ -12000,9 +11996,9 @@ ], "support": { "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", - "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.7" + "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.6" }, - "time": "2026-02-17T17:25:14+00:00" + "time": "2026-01-30T07:16:00+00:00" }, { "name": "theseer/tokenizer", @@ -12056,16 +12052,16 @@ }, { "name": "webmozart/assert", - "version": "2.1.6", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8" + "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/ff31ad6efc62e66e518fbab1cde3453d389bcdc8", - "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", + "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", "shasum": "" }, "require": { @@ -12112,9 +12108,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/2.1.6" + "source": "https://github.com/webmozarts/assert/tree/2.1.2" }, - "time": "2026-02-27T10:28:38+00:00" + "time": "2026-01-13T14:02:24+00:00" } ], "aliases": [], @@ -12123,7 +12119,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^8.4", + "php": "^8.2", "ext-imagick": "*", "ext-simplexml": "*", "ext-zip": "*" diff --git a/config/app.php b/config/app.php index 176342e..6a47a72 100644 --- a/config/app.php +++ b/config/app.php @@ -13,7 +13,7 @@ return [ | */ - 'name' => env('APP_NAME', 'LaraPaper'), + 'name' => env('APP_NAME', 'Laravel'), /* |-------------------------------------------------------------------------- @@ -127,13 +127,11 @@ return [ 'enabled' => env('REGISTRATION_ENABLED', true), ], - 'pixel_logo_enabled' => env('PIXELLOGO_ENABLED', true), - 'force_https' => env('FORCE_HTTPS', false), 'puppeteer_docker' => env('PUPPETEER_DOCKER', false), 'puppeteer_mode' => env('PUPPETEER_MODE', 'local'), 'puppeteer_wait_for_network_idle' => env('PUPPETEER_WAIT_FOR_NETWORK_IDLE', true), - 'puppeteer_window_size_strategy' => env('PUPPETEER_WINDOW_SIZE_STRATEGY', 'v2'), + 'puppeteer_window_size_strategy' => env('PUPPETEER_WINDOW_SIZE_STRATEGY', null), 'notifications' => [ 'battery_low' => [ @@ -156,5 +154,5 @@ return [ 'catalog_url' => env('CATALOG_URL', 'https://raw.githubusercontent.com/bnussbau/trmnl-recipe-catalog/refs/heads/main/catalog.yaml'), - 'github_repo' => env('GITHUB_REPO', 'usetrmnl/larapaper'), + 'github_repo' => env('GITHUB_REPO', 'usetrmnl/byos_laravel'), ]; diff --git a/database/migrations/2026_01_28_143142_add_layout_markup_columns_to_plugins_table.php b/database/migrations/2026_01_28_143142_add_layout_markup_columns_to_plugins_table.php deleted file mode 100644 index e56751c..0000000 --- a/database/migrations/2026_01_28_143142_add_layout_markup_columns_to_plugins_table.php +++ /dev/null @@ -1,38 +0,0 @@ -text('render_markup_half_horizontal')->nullable()->after('render_markup'); - $table->text('render_markup_half_vertical')->nullable()->after('render_markup_half_horizontal'); - $table->text('render_markup_quadrant')->nullable()->after('render_markup_half_vertical'); - $table->text('render_markup_shared')->nullable()->after('render_markup_quadrant'); - $table->text('transform_code')->nullable()->after('render_markup_shared'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::table('plugins', function (Blueprint $table) { - $table->dropColumn([ - 'render_markup_half_horizontal', - 'render_markup_half_vertical', - 'render_markup_quadrant', - 'render_markup_shared', - 'transform_code', - ]); - }); - } -}; diff --git a/database/migrations/2026_02_01_121714_add_maximum_compatibility_to_devices_table.php b/database/migrations/2026_02_01_121714_add_maximum_compatibility_to_devices_table.php index bd0d54b..a682c62 100644 --- a/database/migrations/2026_02_01_121714_add_maximum_compatibility_to_devices_table.php +++ b/database/migrations/2026_02_01_121714_add_maximum_compatibility_to_devices_table.php @@ -8,15 +8,15 @@ return new class extends Migration { public function up(): void { - Schema::table('devices', function (Blueprint $table): void { - $table->boolean('maximum_compatibility')->default(false); + Schema::table("devices", function (Blueprint $table): void { + $table->boolean("maximum_compatibility")->default(false); }); } public function down(): void { - Schema::table('devices', function (Blueprint $table): void { - $table->dropColumn('maximum_compatibility'); + Schema::table("devices", function (Blueprint $table): void { + $table->dropColumn("maximum_compatibility"); }); } }; diff --git a/database/migrations/2026_02_17_153908_add_css_device_and_css_variables_to_device_models_table.php b/database/migrations/2026_02_17_153908_add_css_device_and_css_variables_to_device_models_table.php deleted file mode 100644 index cd1b7db..0000000 --- a/database/migrations/2026_02_17_153908_add_css_device_and_css_variables_to_device_models_table.php +++ /dev/null @@ -1,29 +0,0 @@ -string('css_name')->nullable()->after('kind'); - $table->json('css_variables')->nullable()->after('css_name'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::table('device_models', function (Blueprint $table) { - $table->dropColumn(['css_name', 'css_variables']); - }); - } -}; diff --git a/database/migrations/2026_02_17_221924_set_css_name_and_css_variables_for_seeded_device_models.php b/database/migrations/2026_02_17_221924_set_css_name_and_css_variables_for_seeded_device_models.php deleted file mode 100644 index 728fe4f..0000000 --- a/database/migrations/2026_02_17_221924_set_css_name_and_css_variables_for_seeded_device_models.php +++ /dev/null @@ -1,160 +0,0 @@ -}> - */ - private const SEEDED_CSS = [ - 'og_png' => [ - 'css_name' => 'og_png', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '480px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'og_plus' => [ - 'css_name' => 'ogv2', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '480px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'amazon_kindle_2024' => [ - 'css_name' => 'amazon_kindle_2024', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '480px', - '--ui-scale' => '0.8', - '--gap-scale' => '1.0', - ], - ], - 'amazon_kindle_paperwhite_6th_gen' => [ - 'css_name' => 'amazon_kindle_paperwhite_6th_gen', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '600px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'amazon_kindle_paperwhite_7th_gen' => [ - 'css_name' => 'amazon_kindle_paperwhite_7th_gen', - 'css_variables' => [ - '--screen-w' => '905px', - '--screen-h' => '670px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'inkplate_10' => [ - 'css_name' => 'inkplate_10', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '547px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'amazon_kindle_7' => [ - 'css_name' => 'amazon_kindle_7', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '600px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'inky_impression_7_3' => [ - 'css_name' => 'inky_impression_7_3', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '480px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'kobo_libra_2' => [ - 'css_name' => 'kobo_libra_2', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '602px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'amazon_kindle_oasis_2' => [ - 'css_name' => 'amazon_kindle_oasis_2', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '602px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'kobo_aura_one' => [ - 'css_name' => 'kobo_aura_one', - 'css_variables' => [ - '--screen-w' => '1040px', - '--screen-h' => '780px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'kobo_aura_hd' => [ - 'css_name' => 'kobo_aura_hd', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '600px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - 'inky_impression_13_3' => [ - 'css_name' => 'inky_impression_13_3', - 'css_variables' => [ - '--screen-w' => '800px', - '--screen-h' => '600px', - '--ui-scale' => '1.0', - '--gap-scale' => '1.0', - ], - ], - ]; - - /** - * Run the migrations. - */ - public function up(): void - { - foreach (self::SEEDED_CSS as $name => $payload) { - DeviceModel::query() - ->where('name', $name) - ->update([ - 'css_name' => $payload['css_name'], - 'css_variables' => $payload['css_variables'], - ]); - } - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - DeviceModel::query() - ->whereIn('name', array_keys(self::SEEDED_CSS)) - ->update([ - 'css_name' => null, - 'css_variables' => null, - ]); - } -}; diff --git a/database/migrations/2026_02_27_153837_add_current_image_metadata_to_plugins_table.php b/database/migrations/2026_02_27_153837_add_current_image_metadata_to_plugins_table.php deleted file mode 100644 index d212fe7..0000000 --- a/database/migrations/2026_02_27_153837_add_current_image_metadata_to_plugins_table.php +++ /dev/null @@ -1,28 +0,0 @@ -json('current_image_metadata')->nullable()->after('current_image'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::table('plugins', function (Blueprint $table) { - $table->dropColumn('current_image_metadata'); - }); - } -}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 5811f4c..c7125c5 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -3,7 +3,6 @@ namespace Database\Seeders; use App\Models\Device; -use App\Models\Playlist; use App\Models\Plugin; use App\Models\User; use Illuminate\Database\Seeder; @@ -24,19 +23,9 @@ class DatabaseSeeder extends Seeder 'password' => bcrypt('admin@example.com'), ]); - $device = Device::factory()->create([ + Device::factory(1)->create([ 'mac_address' => '00:00:00:00:00:00', 'api_key' => 'test-api-key', - 'proxy_cloud' => false, - ]); - - Playlist::factory()->create([ - 'device_id' => $device->id, - 'name' => 'Default', - 'is_active' => true, - 'active_from' => null, - 'active_until' => null, - 'weekdays' => null ]); // Device::factory(5)->create(); diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index eaa48fb..38cac0e 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -1,10 +1,9 @@ services: app: - image: ghcr.io/usetrmnl/larapaper:latest + image: ghcr.io/usetrmnl/byos_laravel:latest ports: - "4567:8080" environment: - # Generate the APP_KEY with `echo "base64:$(openssl rand -base64 32)"` #- APP_KEY= - PHP_OPCACHE_ENABLE=1 - TRMNL_PROXY_REFRESH_MINUTES=15 diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index e2246bc..40bcbd3 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -9,7 +9,7 @@ #### Clone the repository ```bash -git clone git@github.com:usetrmnl/larapaper.git +git clone git@github.com:usetrmnl/byos_laravel.git ``` #### Copy environment file diff --git a/package-lock.json b/package-lock.json index cbcac8c..92ade6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,10 +1,9 @@ { - "name": "laravel-trmnl-server", + "name": "laravel", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "laravel-trmnl-server", "dependencies": { "@codemirror/commands": "^6.9.0", "@codemirror/lang-css": "^6.3.1", @@ -12,7 +11,6 @@ "@codemirror/lang-javascript": "^6.2.4", "@codemirror/lang-json": "^6.0.2", "@codemirror/lang-liquid": "^6.3.0", - "@codemirror/lang-yaml": "^6.1.2", "@codemirror/language": "^6.11.3", "@codemirror/search": "^6.5.11", "@codemirror/state": "^6.5.2", @@ -25,7 +23,7 @@ "codemirror": "^6.0.2", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0", - "puppeteer": "24.37.0", + "puppeteer": "24.30.0", "tailwindcss": "^4.0.7", "vite": "^7.0.4" }, @@ -36,9 +34,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -71,9 +69,9 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.2.tgz", - "integrity": "sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.1.tgz", + "integrity": "sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q==", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -153,21 +151,6 @@ "@lezer/lr": "^1.3.1" } }, - "node_modules/@codemirror/lang-yaml": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.2.tgz", - "integrity": "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==", - "license": "MIT", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.2.0", - "@lezer/lr": "^1.0.0", - "@lezer/yaml": "^1.0.0" - } - }, "node_modules/@codemirror/language": { "version": "6.12.1", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.1.tgz", @@ -183,9 +166,9 @@ } }, "node_modules/@codemirror/lint": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.4.tgz", - "integrity": "sha512-ABc9vJ8DEmvOWuH26P3i8FpMWPQkduD9Rvba5iwb6O3hxASgclm3T3krGo8NASXkHCidz6b++LWlzWIUfEPSWw==", + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.3.tgz", + "integrity": "sha512-y3YkYhdnhjDBAe0VIA0c4wVoFOvnp8CnAvfLqi0TqotIv92wIlAAP7HELOpLBsKwjAX6W92rSflA6an/2zBvXw==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -226,9 +209,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.39.15", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.15.tgz", - "integrity": "sha512-aCWjgweIIXLBHh7bY6cACvXuyrZ0xGafjQ2VInjp4RM4gMfscK5uESiNdrH0pE+e1lZr2B4ONGsjchl2KsKZzg==", + "version": "6.39.11", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.11.tgz", + "integrity": "sha512-bWdeR8gWM87l4DB/kYSF9A+dVackzDb/V56Tq7QVrQ7rn86W0rgZFtlL3g3pem6AeGcb9NQNoy3ao4WpW4h5tQ==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.5.0", @@ -238,9 +221,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -254,9 +237,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -270,9 +253,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -286,9 +269,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -302,9 +285,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -318,9 +301,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -334,9 +317,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -350,9 +333,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -366,9 +349,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -382,9 +365,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -398,9 +381,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -414,9 +397,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -430,9 +413,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -446,9 +429,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -462,9 +445,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -478,9 +461,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -494,9 +477,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -510,9 +493,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -526,9 +509,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -542,9 +525,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -558,9 +541,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -574,9 +557,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -590,9 +573,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -606,9 +589,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -622,9 +605,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -638,9 +621,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -711,15 +694,15 @@ } }, "node_modules/@lezer/common": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.1.tgz", - "integrity": "sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.0.tgz", + "integrity": "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==", "license": "MIT" }, "node_modules/@lezer/css": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.1.tgz", - "integrity": "sha512-PYAKeUVBo3HFThruRyp/iK91SwiZJnzXh8QzkQlwijB5y+N5iB28+iLk78o2zmKqqV0uolNhCwFqB8LA7b0Svg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz", + "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -778,17 +761,6 @@ "@lezer/common": "^1.0.0" } }, - "node_modules/@lezer/yaml": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.4.tgz", - "integrity": "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==", - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.4.0" - } - }, "node_modules/@marijn/find-cluster-break": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", @@ -796,9 +768,9 @@ "license": "MIT" }, "node_modules/@puppeteer/browsers": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.12.0.tgz", - "integrity": "sha512-Xuq42yxcQJ54ti8ZHNzF5snFvtpgXzNToJ1bXUGQRaiO8t+B6UM8sTUJfvV+AJnqtkJU/7hdy6nbKyA12aHtRw==", + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.13.tgz", + "integrity": "sha512-a9Ruw3j3qlnB5a/zHRTkruppynxqaeE4H9WNj5eYGRWqw0ZauZ23f4W2ARf3hghF5doozyD+CRtt7XSYuYRI/Q==", "license": "Apache-2.0", "dependencies": { "debug": "^4.4.3", @@ -817,9 +789,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz", + "integrity": "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==", "cpu": [ "arm" ], @@ -830,9 +802,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.0.tgz", + "integrity": "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==", "cpu": [ "arm64" ], @@ -843,9 +815,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.0.tgz", + "integrity": "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==", "cpu": [ "arm64" ], @@ -856,9 +828,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.0.tgz", + "integrity": "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==", "cpu": [ "x64" ], @@ -869,9 +841,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.0.tgz", + "integrity": "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==", "cpu": [ "arm64" ], @@ -882,9 +854,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.0.tgz", + "integrity": "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==", "cpu": [ "x64" ], @@ -895,9 +867,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.0.tgz", + "integrity": "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==", "cpu": [ "arm" ], @@ -908,9 +880,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.0.tgz", + "integrity": "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==", "cpu": [ "arm" ], @@ -921,9 +893,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.0.tgz", + "integrity": "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==", "cpu": [ "arm64" ], @@ -934,9 +906,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.0.tgz", + "integrity": "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==", "cpu": [ "arm64" ], @@ -947,9 +919,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.0.tgz", + "integrity": "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==", "cpu": [ "loong64" ], @@ -960,9 +932,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.0.tgz", + "integrity": "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==", "cpu": [ "loong64" ], @@ -973,9 +945,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.0.tgz", + "integrity": "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==", "cpu": [ "ppc64" ], @@ -986,9 +958,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.0.tgz", + "integrity": "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==", "cpu": [ "ppc64" ], @@ -999,9 +971,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.0.tgz", + "integrity": "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==", "cpu": [ "riscv64" ], @@ -1012,9 +984,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.0.tgz", + "integrity": "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==", "cpu": [ "riscv64" ], @@ -1025,9 +997,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.0.tgz", + "integrity": "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==", "cpu": [ "s390x" ], @@ -1051,9 +1023,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.0.tgz", + "integrity": "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==", "cpu": [ "x64" ], @@ -1064,9 +1036,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.0.tgz", + "integrity": "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==", "cpu": [ "x64" ], @@ -1077,9 +1049,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.0.tgz", + "integrity": "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==", "cpu": [ "arm64" ], @@ -1090,9 +1062,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.0.tgz", + "integrity": "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==", "cpu": [ "arm64" ], @@ -1103,9 +1075,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.0.tgz", + "integrity": "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==", "cpu": [ "ia32" ], @@ -1116,9 +1088,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.0.tgz", + "integrity": "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==", "cpu": [ "x64" ], @@ -1129,9 +1101,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz", + "integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==", "cpu": [ "x64" ], @@ -1142,47 +1114,47 @@ ] }, "node_modules/@tailwindcss/node": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.0.tgz", - "integrity": "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", "license": "MIT", "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", - "lightningcss": "1.31.1", + "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.2.0" + "tailwindcss": "4.1.18" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.0.tgz", - "integrity": "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", "license": "MIT", "engines": { - "node": ">= 20" + "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.0", - "@tailwindcss/oxide-darwin-arm64": "4.2.0", - "@tailwindcss/oxide-darwin-x64": "4.2.0", - "@tailwindcss/oxide-freebsd-x64": "4.2.0", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.0", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.0", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.0", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.0", - "@tailwindcss/oxide-linux-x64-musl": "4.2.0", - "@tailwindcss/oxide-wasm32-wasi": "4.2.0", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.0", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.0" + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.0.tgz", - "integrity": "sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", "cpu": [ "arm64" ], @@ -1192,13 +1164,13 @@ "android" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.0.tgz", - "integrity": "sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", "cpu": [ "arm64" ], @@ -1208,13 +1180,13 @@ "darwin" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.0.tgz", - "integrity": "sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", "cpu": [ "x64" ], @@ -1224,13 +1196,13 @@ "darwin" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.0.tgz", - "integrity": "sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", "cpu": [ "x64" ], @@ -1240,13 +1212,13 @@ "freebsd" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.0.tgz", - "integrity": "sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", "cpu": [ "arm" ], @@ -1256,13 +1228,13 @@ "linux" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.0.tgz", - "integrity": "sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", "cpu": [ "arm64" ], @@ -1272,13 +1244,13 @@ "linux" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.0.tgz", - "integrity": "sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", "cpu": [ "arm64" ], @@ -1288,13 +1260,13 @@ "linux" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.0.tgz", - "integrity": "sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", "cpu": [ "x64" ], @@ -1304,13 +1276,13 @@ "linux" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.0.tgz", - "integrity": "sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", "cpu": [ "x64" ], @@ -1320,13 +1292,13 @@ "linux" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.0.tgz", - "integrity": "sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -1341,21 +1313,21 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", + "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" + "tslib": "^2.4.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.0.tgz", - "integrity": "sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", "cpu": [ "arm64" ], @@ -1365,13 +1337,13 @@ "win32" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.0.tgz", - "integrity": "sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", "cpu": [ "x64" ], @@ -1381,18 +1353,18 @@ "win32" ], "engines": { - "node": ">= 20" + "node": ">= 10" } }, "node_modules/@tailwindcss/vite": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.0.tgz", - "integrity": "sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz", + "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==", "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.2.0", - "@tailwindcss/oxide": "4.2.0", - "tailwindcss": "4.2.0" + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" @@ -1411,13 +1383,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", - "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", + "version": "25.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", + "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", "license": "MIT", "optional": true, "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/yauzl": { @@ -1488,9 +1460,9 @@ "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.24", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", - "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "version": "10.4.23", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", + "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", "funding": [ { "type": "opencollective", @@ -1508,7 +1480,7 @@ "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001766", + "caniuse-lite": "^1.0.30001760", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -1524,20 +1496,20 @@ } }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", + "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "node_modules/b4a": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" @@ -1563,9 +1535,9 @@ } }, "node_modules/bare-fs": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.4.tgz", - "integrity": "sha512-POK4oplfA7P7gqvetNmCs4CNtm9fNsx+IAh7jH7GgU0OJdge2rso0R20TNWVq6VoWcCvsTdlNDaleLHGaKx8CA==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.3.tgz", + "integrity": "sha512-9+kwVx8QYvt3hPWnmb19tPnh38c6Nihz8Lx3t0g9+4GoIf3/fTgYwM4Z6NxgI+B9elLQA7mLE9PpqcWtOMRDiQ==", "license": "Apache-2.0", "optional": true, "dependencies": { @@ -1608,14 +1580,13 @@ } }, "node_modules/bare-stream": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", - "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", + "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", "license": "Apache-2.0", "optional": true, "dependencies": { - "streamx": "^2.21.0", - "teex": "^1.0.1" + "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", @@ -1641,21 +1612,18 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "version": "2.9.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.18.tgz", + "integrity": "sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" + "baseline-browser-mapping": "dist/cli.js" } }, "node_modules/basic-ftp": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", - "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz", + "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -1726,9 +1694,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001770", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", - "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", + "version": "1.0.30001766", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", + "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", "funding": [ { "type": "opencollective", @@ -1774,13 +1742,12 @@ } }, "node_modules/chromium-bidi": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-13.1.0.tgz", - "integrity": "sha512-IdGNojX6S04+wgJOALzvkkIyLelhEGqI8xSctwiYJJGSi9T2eBjwAQW2UjBD/mCXv/rUkNlH2+h7jz+58vT74A==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-11.0.0.tgz", + "integrity": "sha512-cM3DI+OOb89T3wO8cpPSro80Q9eKYJ7hGVXoGS3GkDPxnYSqiv+6xwpIf6XERyJ9Tdsl09hmNmY94BkgZdVekw==", "license": "Apache-2.0", "dependencies": { "mitt": "^3.0.1", - "puppeteer": "^24.36.0", "zod": "^3.24.1" }, "peerDependencies": { @@ -1961,9 +1928,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1566079", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1566079.tgz", - "integrity": "sha512-MJfAEA1UfVhSs7fbSQOG4czavUp1ajfg6prlAN0+cmfa2zNjaIbvq8VneP7do1WAQQIvgNJWSMeP6UyI90gIlQ==", + "version": "0.0.1521046", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1521046.tgz", + "integrity": "sha512-vhE6eymDQSKWUXwwA37NtTTVEzjtGVfDr3pRbsWEQ5onH/Snp2c+2xZHWJJawG/0hCCJLRGt4xVtEVUVILol4w==", "license": "BSD-3-Clause" }, "node_modules/dunder-proto": { @@ -1981,9 +1948,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.302", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", - "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "version": "1.5.279", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.279.tgz", + "integrity": "sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -2002,13 +1969,13 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "tapable": "^2.2.0" }, "engines": { "node": ">=10.13.0" @@ -2078,9 +2045,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -2090,32 +2057,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -2572,9 +2539,9 @@ } }, "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -2587,23 +2554,23 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", "cpu": [ "arm64" ], @@ -2621,9 +2588,9 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", "cpu": [ "arm64" ], @@ -2641,9 +2608,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", "cpu": [ "x64" ], @@ -2661,9 +2628,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", "cpu": [ "x64" ], @@ -2681,9 +2648,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", "cpu": [ "arm" ], @@ -2701,9 +2668,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", "cpu": [ "arm64" ], @@ -2721,9 +2688,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", "cpu": [ "arm64" ], @@ -2761,9 +2728,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", "cpu": [ "x64" ], @@ -2781,9 +2748,9 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", "cpu": [ "arm64" ], @@ -2801,9 +2768,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", "cpu": [ "x64" ], @@ -2820,6 +2787,26 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -3093,17 +3080,17 @@ } }, "node_modules/puppeteer": { - "version": "24.37.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.37.0.tgz", - "integrity": "sha512-s1jHugVhPtQjiJE6wUyonj4VEGWF+mfRDASqPMPsXgKcjZX0GaznBmcT9nLQ7bBL90phuQUqO4jiV5vTecZg4g==", + "version": "24.30.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.30.0.tgz", + "integrity": "sha512-A5OtCi9WpiXBQgJ2vQiZHSyrAzQmO/WDsvghqlN4kgw21PhxA5knHUaUQq/N3EMt8CcvSS0RM+kmYLJmedR3TQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.12.0", - "chromium-bidi": "13.1.0", + "@puppeteer/browsers": "2.10.13", + "chromium-bidi": "11.0.0", "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1566079", - "puppeteer-core": "24.37.0", + "devtools-protocol": "0.0.1521046", + "puppeteer-core": "24.30.0", "typed-query-selector": "^2.12.0" }, "bin": { @@ -3114,18 +3101,18 @@ } }, "node_modules/puppeteer-core": { - "version": "24.37.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.37.0.tgz", - "integrity": "sha512-WoCBK36cBlbaxwuvPWhOp2+lR6O6ynHdDuvD8rEIkxPOPpUoMXSJuyiOWhHtexJBCLaMCAJk33QdYambvQl+og==", + "version": "24.30.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.30.0.tgz", + "integrity": "sha512-2S3Smy0t0W4wJnNvDe7W0bE7wDmZjfZ3ljfMgJd6hn2Hq/f0jgN+x9PULZo2U3fu5UUIJ+JP8cNUGllu8P91Pg==", "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.12.0", - "chromium-bidi": "13.1.0", + "@puppeteer/browsers": "2.10.13", + "chromium-bidi": "11.0.0", "debug": "^4.4.3", - "devtools-protocol": "0.0.1566079", + "devtools-protocol": "0.0.1521046", "typed-query-selector": "^2.12.0", - "webdriver-bidi-protocol": "0.4.0", - "ws": "^8.19.0" + "webdriver-bidi-protocol": "0.3.8", + "ws": "^8.18.3" }, "engines": { "node": ">=18" @@ -3150,9 +3137,9 @@ } }, "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.0.tgz", + "integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==", "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -3165,38 +3152,38 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", + "@rollup/rollup-android-arm-eabi": "4.57.0", + "@rollup/rollup-android-arm64": "4.57.0", + "@rollup/rollup-darwin-arm64": "4.57.0", + "@rollup/rollup-darwin-x64": "4.57.0", + "@rollup/rollup-freebsd-arm64": "4.57.0", + "@rollup/rollup-freebsd-x64": "4.57.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", + "@rollup/rollup-linux-arm-musleabihf": "4.57.0", + "@rollup/rollup-linux-arm64-gnu": "4.57.0", + "@rollup/rollup-linux-arm64-musl": "4.57.0", + "@rollup/rollup-linux-loong64-gnu": "4.57.0", + "@rollup/rollup-linux-loong64-musl": "4.57.0", + "@rollup/rollup-linux-ppc64-gnu": "4.57.0", + "@rollup/rollup-linux-ppc64-musl": "4.57.0", + "@rollup/rollup-linux-riscv64-gnu": "4.57.0", + "@rollup/rollup-linux-riscv64-musl": "4.57.0", + "@rollup/rollup-linux-s390x-gnu": "4.57.0", + "@rollup/rollup-linux-x64-gnu": "4.57.0", + "@rollup/rollup-linux-x64-musl": "4.57.0", + "@rollup/rollup-openbsd-x64": "4.57.0", + "@rollup/rollup-openharmony-arm64": "4.57.0", + "@rollup/rollup-win32-arm64-msvc": "4.57.0", + "@rollup/rollup-win32-ia32-msvc": "4.57.0", + "@rollup/rollup-win32-x64-gnu": "4.57.0", + "@rollup/rollup-win32-x64-msvc": "4.57.0", "fsevents": "~2.3.2" } }, "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.0.tgz", + "integrity": "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==", "cpu": [ "x64" ], @@ -3216,9 +3203,9 @@ } }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3355,9 +3342,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.0.tgz", - "integrity": "sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", "license": "MIT" }, "node_modules/tapable": { @@ -3398,20 +3385,10 @@ "streamx": "^2.15.0" } }, - "node_modules/teex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", - "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", - "license": "MIT", - "optional": true, - "dependencies": { - "streamx": "^2.12.5" - } - }, "node_modules/text-decoder": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" @@ -3455,9 +3432,9 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT", "optional": true }, @@ -3594,9 +3571,9 @@ "license": "MIT" }, "node_modules/webdriver-bidi-protocol": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.0.tgz", - "integrity": "sha512-U9VIlNRrq94d1xxR9JrCEAx5Gv/2W7ERSv8oWRoNe/QYbfccS0V3h/H6qeNeCRJxXGMhhnkqvwNrvPAYeuP9VA==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.3.8.tgz", + "integrity": "sha512-21Yi2GhGntMc671vNBCjiAeEVknXjVRoyu+k+9xOMShu+ZQfpGQwnBqbNz/Sv4GXZ6JmutlPAi2nIJcrymAWuQ==", "license": "Apache-2.0" }, "node_modules/wrap-ansi": { diff --git a/package.json b/package.json index ec6e486..7262ad1 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "@codemirror/lang-javascript": "^6.2.4", "@codemirror/lang-json": "^6.0.2", "@codemirror/lang-liquid": "^6.3.0", - "@codemirror/lang-yaml": "^6.1.2", "@codemirror/language": "^6.11.3", "@codemirror/search": "^6.5.11", "@codemirror/state": "^6.5.2", @@ -25,7 +24,7 @@ "codemirror": "^6.0.2", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0", - "puppeteer": "24.37.0", + "puppeteer": "24.30.0", "tailwindcss": "^4.0.7", "vite": "^7.0.4" }, diff --git a/public/mirror/index.html b/public/mirror/index.html index 02e99cf..64746fe 100644 --- a/public/mirror/index.html +++ b/public/mirror/index.html @@ -22,7 +22,6 @@ refreshTimer: null, renderedAt: 0, ui: {}, - wakeLock: null, showStatus: function (message) { trmnl.ui.img.style.display = "none"; @@ -40,9 +39,8 @@ var data = trmnl.getSettings(); trmnl.ui.apiKeyInput.value = data.api_key || ""; trmnl.ui.baseURLInput.value = data.base_url || ""; + trmnl.ui.macAddressInput.value = data.mac_address || ""; trmnl.ui.displayModeSelect.value = data.display_mode || ""; - trmnl.ui.fullscreenToggle.checked = !!data.fullscreen; - trmnl.ui.wakeLockToggle.checked = !!trmnl.wakeLock || !!data.wake_lock; trmnl.ui.setup.style.display = "flex"; }, @@ -52,9 +50,8 @@ var apiKey = trmnl.ui.apiKeyInput.value; var baseURL = trmnl.ui.baseURLInput.value; + var macAddress = trmnl.ui.macAddressInput.value; var displayMode = trmnl.ui.displayModeSelect.value; - var fullscreenEnabled = trmnl.ui.fullscreenToggle.checked; - var wakeLockEnabled = trmnl.ui.wakeLockToggle.checked; if (!apiKey) { return; @@ -63,26 +60,10 @@ trmnl.saveSettings({ api_key: apiKey, base_url: baseURL, - display_mode: displayMode, - fullscreen: fullscreenEnabled, - wake_lock: wakeLockEnabled + mac_address: macAddress, + display_mode: displayMode }); - if (wakeLockEnabled) { - trmnl.acquireWakeLock().then(function () { - trmnl.ui.wakeLockToggle.checked = !!trmnl.wakeLock; - }).catch(function (err) { - console.warn("Wake Lock request failed:", err); - trmnl.ui.wakeLockToggle.checked = false; - }); - } else { - trmnl.releaseWakeLock().then(function () { - trmnl.ui.wakeLockToggle.checked = false; - }).catch(function (err) { - console.warn("Wake Lock release failed:", err); - }); - } - trmnl.fetchDisplay(); }, @@ -90,144 +71,6 @@ trmnl.ui.setup.style.display = "none"; }, - isFullscreenSupported: function () { - return !!( - document.fullscreenEnabled || - document.webkitFullscreenEnabled || - document.msFullscreenEnabled - ); - }, - - isFullscreenActive: function () { - return !!( - document.fullscreenElement || - document.webkitFullscreenElement || - document.msFullscreenElement - ); - }, - - enterFullscreen: function () { - if (!trmnl.isFullscreenSupported()) return; - - var el = document.documentElement; - var promise; - - if (el.requestFullscreen) { - promise = el.requestFullscreen(); - } else if (el.webkitRequestFullscreen) { - promise = el.webkitRequestFullscreen(); - } else if (el.msRequestFullscreen) { - promise = el.msRequestFullscreen(); - } - - if (promise && promise.catch) { - promise.catch(function (err) { - console.warn("Enter fullscreen failed:", err); - }); - } - }, - - exitFullscreen: function () { - if (!trmnl.isFullscreenSupported()) return; - if (!trmnl.isFullscreenActive()) return; - - var promise; - - if (document.exitFullscreen) { - promise = document.exitFullscreen(); - } else if (document.webkitExitFullscreen) { - promise = document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { - promise = document.msExitFullscreen(); - } - - if (promise && promise.catch) { - promise.catch(function (err) { - console.warn("Exit fullscreen failed:", err); - }); - } - }, - - syncFullscreenToggle: function () { - var active = trmnl.isFullscreenActive(); - trmnl.ui.fullscreenToggle.checked = active; - }, - - isWakeLockSupported: function () { - return ( - window.isSecureContext && - navigator.wakeLock && - typeof navigator.wakeLock.request === "function" - ); - }, - - acquireWakeLock: function () { - - if (!trmnl.isWakeLockSupported()) { - return { - then: function () { return this; }, - catch: function () { return this; } - }; - } - - if (trmnl.wakeLock) { - return Promise.resolve(); - } - - return navigator.wakeLock.request("screen") - .then(function (sentinel) { - - trmnl.wakeLock = sentinel; - - sentinel.addEventListener("release", function () { - trmnl.wakeLock = null; - trmnl.ui.wakeLockToggle.checked = false; - }); - - console.log("Wake Lock attivo"); - - }) - .catch(function (err) { - console.warn("Wake Lock failed:", err); - trmnl.wakeLock = null; - trmnl.ui.wakeLockToggle.checked = false; - }); - }, - - - releaseWakeLock: function () { - - if (!trmnl.wakeLock) { - return Promise.resolve(); - } - - return trmnl.wakeLock.release() - .then(function () { - trmnl.wakeLock = null; - console.log("Wake Lock rilasciato"); - }) - .catch(function (err) { - console.warn("Release failed:", err); - trmnl.wakeLock = null; - }); - }, - - - toggleWakeLock: function () { - if (!trmnl.isWakeLockSupported()) return; - if (trmnl.wakeLock) { - trmnl.releaseWakeLock().then(function () { - trmnl.ui.wakeLockToggle.checked = false; - }); - } else { - trmnl.acquireWakeLock().then(function () { - trmnl.ui.wakeLockToggle.checked = !!trmnl.wakeLock; - }); - } - }, - - - fetchDisplay: function (opts) { opts = opts || {}; clearTimeout(trmnl.refreshTimer); @@ -241,6 +84,7 @@ var apiKey = setup.api_key; var displayMode = setup.display_mode; var baseURL = setup.base_url || "https://your-byos-trmnl.com"; + var macAddress = setup.mac_address || "00:00:00:00:00:01"; document.body.classList.remove("dark", "night") if (displayMode) { @@ -248,7 +92,8 @@ } var headers = { - "Access-Token": apiKey + "Access-Token": apiKey, + "id": macAddress }; var url = baseURL + "/api/display"; @@ -292,12 +137,8 @@ trmnl.showStatus("Error processing response: " + e.message); } } else { - var msg = xhr.statusText - if (xhr.status == 404) { - msg = "Maybe wrong API key"; - } trmnl.showStatus( - "Failed to fetch screen: " + xhr.status + " " + msg + "Failed to fetch screen: " + xhr.status + " " + xhr.statusText ); } }; @@ -369,6 +210,10 @@ hasOverrides = true; } + if (key === "mac_address" && value) { + newSettings.mac_address = value; + hasOverrides = true; + } } if (hasOverrides) { @@ -429,111 +274,17 @@ // settings trmnl.ui.apiKeyInput = document.getElementById("api_key"); trmnl.ui.baseURLInput = document.getElementById("base_url"); + trmnl.ui.macAddressInput = document.getElementById("mac_address"); trmnl.ui.displayModeSelect = document.getElementById("display_mode"); - trmnl.ui.fullscreenToggle = document.getElementById("fullscreenToggle"); - trmnl.ui.wakeLockToggle = document.getElementById("wakeLockToggle"); trmnl.ui.setup = document.getElementById("setup"); - // Sync fullscreen state - document.addEventListener("fullscreenchange", trmnl.syncFullscreenToggle); - document.addEventListener("webkitfullscreenchange", trmnl.syncFullscreenToggle); - document.addEventListener("msfullscreenchange", trmnl.syncFullscreenToggle); - - // Fullscreen toggle - if (!trmnl.isFullscreenSupported()) { - trmnl.ui.fullscreenToggle.disabled = true; - trmnl.ui.fullscreenToggle.parentElement.style.opacity = "0.5"; - trmnl.ui.fullscreenToggle.parentElement.style.cursor = "not-allowed"; - } else { - trmnl.ui.fullscreenToggle.addEventListener("change", function (e) { - e.stopPropagation(); - - if (e.target.checked) { - trmnl.enterFullscreen(); - } else { - trmnl.exitFullscreen(); - } - }); - } - - var wakeLockHint = document.getElementById("wakeLockHint"); - - // Wake Lock toggle - if (trmnl.isWakeLockSupported()) { - - trmnl.ui.wakeLockToggle.disabled = false; - trmnl.ui.wakeLockToggle.parentElement.style.opacity = "1"; - trmnl.ui.wakeLockToggle.parentElement.style.cursor = "pointer"; - - if (wakeLockHint) wakeLockHint.style.display = "none"; - - trmnl.ui.wakeLockToggle.addEventListener("change", function () { - trmnl.toggleWakeLock(); - }); - - document.addEventListener("visibilitychange", function () { - if ( - document.visibilityState === "visible" && - trmnl.ui.wakeLockToggle.checked - ) { - trmnl.acquireWakeLock(); - } - }); - - } else { - - // unsupported (HTTP or old browser) - trmnl.ui.wakeLockToggle.disabled = true; - trmnl.ui.wakeLockToggle.checked = false; - trmnl.ui.wakeLockToggle.parentElement.style.opacity = "0.5"; - trmnl.ui.wakeLockToggle.parentElement.style.cursor = "not-allowed"; - - if (!window.isSecureContext && wakeLockHint) { - wakeLockHint.style.display = "block"; - } - - } - - // get settings from localstorage var settings = trmnl.getSettings(); - - // show setup form if missing apikey if (!settings || !settings.api_key) { trmnl.showSetupForm(); } else { trmnl.fetchDisplay(); } - - // Auto fullscreen at first click/touch if option enabled - if (settings.fullscreen && trmnl.isFullscreenSupported()) { - var activateFullscreenOnce = function () { - trmnl.enterFullscreen(); - document.removeEventListener("click", activateFullscreenOnce); - document.removeEventListener("touchstart", activateFullscreenOnce); - }; - document.addEventListener("click", activateFullscreenOnce, { once: true }); - document.addEventListener("touchstart", activateFullscreenOnce, { once: true }); - } - - // Auto Wake Lock at first click/touch if option enabled - if (settings.wake_lock && trmnl.isWakeLockSupported()) { - var acquireWakeLockOnce = function () { - trmnl.acquireWakeLock().then(function () { - trmnl.ui.wakeLockToggle.checked = !!trmnl.wakeLock; - }).catch(function (err) { - console.warn("Wake Lock request failed:", err); - trmnl.ui.wakeLockToggle.checked = false; - }); - document.removeEventListener("click", acquireWakeLockOnce); - document.removeEventListener("touchstart", acquireWakeLockOnce); - }; - document.addEventListener("click", acquireWakeLockOnce, { once: true }); - document.addEventListener("touchstart", acquireWakeLockOnce, { once: true }); - } - - trmnl.syncFullscreenToggle(); - } //init end - + } }; document.addEventListener("DOMContentLoaded", function () { @@ -652,7 +403,8 @@ display: block; } - label { + label, + summary { font-size: 1.25em; margin-bottom: 0.5em; cursor: pointer; @@ -681,10 +433,6 @@ width: 100%; } - .btn-secondary { - background-color: #777; - } - .btn-clear { margin-top: 1em; background-color: #777; @@ -709,127 +457,8 @@ background-color: #ffffff; } - .setting-row { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1em; - flex-wrap: nowrap; - } - - .setting-row label, - .setting-row .toggle-label { - font-size: 1.25em; - margin: 0; - cursor: default; - } - - .setting-row select, - .setting-row .switch { - width: auto; - min-width: 52px; - height: 28px; - } - - .switch { - position: relative; - display: inline-block; - width: 52px; - height: 28px; - } - - .switch input { - opacity: 0; - width: 0; - height: 0; - } - - .slider { - position: absolute; - cursor: pointer; - inset: 0; - background-color: #ccc; - border-radius: 28px; - transition: background-color 0.2s ease; - } - - .slider::before { - content: ""; - position: absolute; - height: 22px; - width: 22px; - left: 3px; - top: 3px; - background-color: white; - border-radius: 50%; - transition: transform 0.2s ease; - } - - .switch input:checked+.slider { - background-color: #f54900; - } - - .switch input:checked+.slider::before { - transform: translateX(24px); - } - - .switch input:disabled+.slider { - background-color: #ccc; - cursor: not-allowed; - } - - .switch input:disabled+.slider::before { - background-color: #eee; - } - - .form-select-small { - width: 6em; - font-size: 1em; - padding: 0.4em 0.5em; - border: 1px solid #ccc; - border-radius: 0.5em; - background-color: #ffffff; - } - - .toggle-label { - font-size: 1.25em; - margin: 0; - cursor: default; - pointer-events: auto; - } - - .setting-hint { - font-size: 0.75em; - color: #f41414; - margin-top: 0.2em; - margin-left: 0.5em; - } - - /* Fallback for iOS 9 */ - @media screen and (max-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) { - .setting-row { - display: block; - overflow: hidden; - } - - .setting-row label, - .setting-row .toggle-label { - float: left; - line-height: 28px; - margin-right: 0.5em; - } - - .setting-row select, - .setting-row .switch { - float: right; - width: auto; - min-width: 52px; - height: 28px; - } - - .setting-hint { - display: none !important; - } + #unsupported { + color: red; } @@ -840,11 +469,10 @@ TRMNL Logo
-
- - + +
@@ -852,38 +480,25 @@
-
- - + + +
-
- Fullscreen - -
- -
-
- Screen Wake Lock - -
- +
+ +
- + +
@@ -897,11 +512,10 @@
- +
- \ No newline at end of file diff --git a/resources/js/codemirror-core.js b/resources/js/codemirror-core.js index be9e15d..f23389f 100644 --- a/resources/js/codemirror-core.js +++ b/resources/js/codemirror-core.js @@ -9,7 +9,6 @@ import { javascript } from '@codemirror/lang-javascript'; import { json } from '@codemirror/lang-json'; import { css } from '@codemirror/lang-css'; import { liquid } from '@codemirror/lang-liquid'; -import { yaml } from '@codemirror/lang-yaml'; import { oneDark } from '@codemirror/theme-one-dark'; import { githubLight } from '@fsegurai/codemirror-theme-github-light'; @@ -21,8 +20,6 @@ const LANGUAGE_MAP = { 'css': css, 'liquid': liquid, 'html': html, - 'yaml': yaml, - 'yml': yaml, }; // Theme support mapping diff --git a/resources/views/components/app-logo.blade.php b/resources/views/components/app-logo.blade.php index f50634a..842020e 100644 --- a/resources/views/components/app-logo.blade.php +++ b/resources/views/components/app-logo.blade.php @@ -2,9 +2,5 @@
- @if(config('app.pixel_logo_enabled')) - - @else - LaraPaper - @endif + TRMNL BYOS Laravel
diff --git a/resources/views/components/auth-header.blade.php b/resources/views/components/auth-header.blade.php index 78aa2e5..e596a3f 100644 --- a/resources/views/components/auth-header.blade.php +++ b/resources/views/components/auth-header.blade.php @@ -4,10 +4,6 @@ ])
- @if(config('app.pixel_logo_enabled')) - - @else - LaraPaper - @endif + {{ $title }} {{ $description }}
diff --git a/resources/views/default-screens/error.blade.php b/resources/views/default-screens/error.blade.php index 7f0d084..be8063a 100644 --- a/resources/views/default-screens/error.blade.php +++ b/resources/views/default-screens/error.blade.php @@ -5,14 +5,12 @@ 'deviceOrientation' => null, 'colorDepth' => '1bit', 'scaleLevel' => null, - 'cssVariables' => null, 'pluginName' => 'Recipe', ]) + scale-level="{{$scaleLevel}}"> diff --git a/resources/views/default-screens/setup.blade.php b/resources/views/default-screens/setup.blade.php index 9113eb6..3b0ff05 100644 --- a/resources/views/default-screens/setup.blade.php +++ b/resources/views/default-screens/setup.blade.php @@ -5,20 +5,18 @@ 'deviceOrientation' => null, 'colorDepth' => '1bit', 'scaleLevel' => null, - 'cssVariables' => null, ]) + scale-level="{{$scaleLevel}}"> - Welcome to LaraPaper! + Welcome to BYOS Laravel! Your device is connected. - + diff --git a/resources/views/default-screens/sleep.blade.php b/resources/views/default-screens/sleep.blade.php index ef0a80c..89d6baa 100644 --- a/resources/views/default-screens/sleep.blade.php +++ b/resources/views/default-screens/sleep.blade.php @@ -5,13 +5,11 @@ 'deviceOrientation' => null, 'colorDepth' => '1bit', 'scaleLevel' => null, - 'cssVariables' => null, ]) + scale-level="{{$scaleLevel}}"> @@ -25,6 +23,6 @@ Sleep Mode - + diff --git a/resources/views/livewire/device-models/index.blade.php b/resources/views/livewire/device-models/index.blade.php index fea740a..6ec4014 100644 --- a/resources/views/livewire/device-models/index.blade.php +++ b/resources/views/livewire/device-models/index.blade.php @@ -1,6 +1,5 @@ */ - public array $css_variables = []; - protected $rules = [ 'name' => 'required|string|max:255|unique:device_models,name', 'label' => 'required|string|max:255', @@ -72,14 +66,6 @@ new class extends Component public $viewingDeviceModelId; - public function updateFromApi(): void - { - FetchDeviceModelsJob::dispatchSync(); - $this->deviceModels = DeviceModel::all(); - $this->devicePalettes = DevicePalette::all(); - session()->flash('message', 'Device models updated from API.'); - } - public function openDeviceModelModal(?string $deviceModelId = null, bool $viewOnly = false): void { if ($deviceModelId) { @@ -107,12 +93,10 @@ new class extends Component $this->offset_y = $deviceModel->offset_y; $this->published_at = $deviceModel->published_at?->format('Y-m-d\TH:i'); $this->palette_id = $deviceModel->palette_id; - $this->css_name = $deviceModel->css_name; - $this->css_variables = collect($deviceModel->css_variables ?? [])->map(fn (string $value, string $key): array => ['key' => $key, 'value' => $value])->values()->all(); } else { $this->editingDeviceModelId = null; $this->viewingDeviceModelId = null; - $this->reset(['name', 'label', 'description', 'width', 'height', 'colors', 'bit_depth', 'scale_factor', 'rotation', 'mime_type', 'offset_x', 'offset_y', 'published_at', 'palette_id', 'css_name', 'css_variables']); + $this->reset(['name', 'label', 'description', 'width', 'height', 'colors', 'bit_depth', 'scale_factor', 'rotation', 'mime_type', 'offset_x', 'offset_y', 'published_at', 'palette_id']); $this->mime_type = 'image/png'; $this->scale_factor = 1.0; $this->rotation = 0; @@ -138,10 +122,6 @@ new class extends Component 'offset_y' => 'required|integer', 'published_at' => 'nullable|date', 'palette_id' => 'nullable|exists:device_palettes,id', - 'css_name' => 'nullable|string|max:255', - 'css_variables' => 'nullable|array', - 'css_variables.*.key' => 'nullable|string|max:255', - 'css_variables.*.value' => 'nullable|string|max:500', ]; if ($this->editingDeviceModelId) { @@ -169,8 +149,6 @@ new class extends Component 'offset_y' => $this->offset_y, 'published_at' => $this->published_at, 'palette_id' => $this->palette_id ?: null, - 'css_name' => $this->css_name ?: null, - 'css_variables' => $this->normalizeCssVariables(), ]); $message = 'Device model updated successfully.'; } else { @@ -189,14 +167,12 @@ new class extends Component 'offset_y' => $this->offset_y, 'published_at' => $this->published_at, 'palette_id' => $this->palette_id ?: null, - 'css_name' => $this->css_name ?: null, - 'css_variables' => $this->normalizeCssVariables(), 'source' => 'manual', ]); $message = 'Device model created successfully.'; } - $this->reset(['name', 'label', 'description', 'width', 'height', 'colors', 'bit_depth', 'scale_factor', 'rotation', 'mime_type', 'offset_x', 'offset_y', 'published_at', 'palette_id', 'css_name', 'css_variables', 'editingDeviceModelId', 'viewingDeviceModelId']); + $this->reset(['name', 'label', 'description', 'width', 'height', 'colors', 'bit_depth', 'scale_factor', 'rotation', 'mime_type', 'offset_x', 'offset_y', 'published_at', 'palette_id', 'editingDeviceModelId', 'viewingDeviceModelId']); Flux::modal('device-model-modal')->close(); $this->deviceModels = DeviceModel::all(); @@ -232,38 +208,9 @@ new class extends Component $this->offset_y = $deviceModel->offset_y; $this->published_at = $deviceModel->published_at?->format('Y-m-d\TH:i'); $this->palette_id = $deviceModel->palette_id; - $this->css_name = $deviceModel->css_name; - $this->css_variables = collect($deviceModel->css_variables ?? [])->map(fn (string $value, string $key): array => ['key' => $key, 'value' => $value])->values()->all(); $this->js('Flux.modal("device-model-modal").show()'); } - - public function addCssVariable(): void - { - $this->css_variables = array_merge($this->css_variables, [['key' => '', 'value' => '']]); - } - - public function removeCssVariable(int $index): void - { - $vars = $this->css_variables; - array_splice($vars, $index, 1); - $this->css_variables = array_values($vars); - } - - /** - * @return array|null - */ - private function normalizeCssVariables(): ?array - { - $pairs = collect($this->css_variables) - ->filter(fn (array $p): bool => trim($p['key'] ?? '') !== ''); - - if ($pairs->isEmpty()) { - return null; - } - - return $pairs->mapWithKeys(fn (array $p): array => [$p['key'] => $p['value'] ?? ''])->all(); - } } ?> @@ -282,17 +229,9 @@ new class extends Component - - - Add Device Model - - - - - Update from Models API - - - + + Add Device Model + @if (session()->has('message'))
@@ -388,40 +327,6 @@ new class extends Component
-
- -
- -
- CSS Variables - @if ($viewingDeviceModelId) - @if (count($css_variables) > 0) -
- @foreach ($css_variables as $var) -
-
{{ $var['key'] }}
-
{{ $var['value'] }}
-
- @endforeach -
- @else -

No CSS variables

- @endif - @else -
- @foreach ($css_variables as $index => $var) -
- - - -
- @endforeach - Add variable -
- @endif -
- @if (!$viewingDeviceModelId)
diff --git a/resources/views/livewire/device-palettes/index.blade.php b/resources/views/livewire/device-palettes/index.blade.php index 4e96c31..6640545 100644 --- a/resources/views/livewire/device-palettes/index.blade.php +++ b/resources/views/livewire/device-palettes/index.blade.php @@ -1,6 +1,5 @@ devicePalettes = DevicePalette::all(); - session()->flash('message', 'Device palettes updated from API.'); - } - public function openDevicePaletteModal(?string $devicePaletteId = null, bool $viewOnly = false): void { if ($devicePaletteId) { @@ -210,17 +202,9 @@ new class extends Component
- - - Add Device Palette - - - - - Update from API - - - + + Add Device Palette + @if (session()->has('message'))
diff --git a/resources/views/livewire/devices/configure.blade.php b/resources/views/livewire/devices/configure.blade.php index f46b1d9..93183cf 100644 --- a/resources/views/livewire/devices/configure.blade.php +++ b/resources/views/livewire/devices/configure.blade.php @@ -31,10 +31,6 @@ new class extends Component public $device_model_id; - public $is_mirror = false; - - public $mirror_device_id = null; - // Signal to device to use high compatibility approaches when redrawing content public $maximum_compatibility = false; @@ -102,8 +98,6 @@ new class extends Component $this->sleep_mode_from = optional($device->sleep_mode_from)->format('H:i'); $this->sleep_mode_to = optional($device->sleep_mode_to)->format('H:i'); $this->special_function = $device->special_function; - $this->is_mirror = $device->mirror_device_id !== null; - $this->mirror_device_id = $device->mirror_device_id; return view('livewire.devices.configure', [ 'image' => ($current_image_uuid) ? url($current_image_path) : null, @@ -151,7 +145,6 @@ new class extends Component 'rotate' => 'required|integer|min:0|max:359', 'image_format' => 'required|string', 'device_model_id' => 'nullable|exists:device_models,id', - 'mirror_device_id' => 'required_if:is_mirror,true', 'maximum_compatibility' => 'boolean', 'sleep_mode_enabled' => 'boolean', 'sleep_mode_from' => 'nullable|date_format:H:i', @@ -159,13 +152,6 @@ new class extends Component 'special_function' => 'nullable|string', ]); - if ($this->is_mirror) { - $mirrorDevice = auth()->user()->devices()->find($this->mirror_device_id); - abort_unless($mirrorDevice, 403, 'Invalid mirror device selected'); - abort_if($mirrorDevice->mirror_device_id !== null, 403, 'Cannot mirror a device that is already a mirror device'); - abort_if((int) $this->mirror_device_id === (int) $this->device->id, 403, 'Device cannot mirror itself'); - } - // Convert empty string to null for custom selection $deviceModelId = empty($this->device_model_id) ? null : $this->device_model_id; @@ -179,7 +165,6 @@ new class extends Component 'rotate' => $this->rotate, 'image_format' => $this->image_format, 'device_model_id' => $deviceModelId, - 'mirror_device_id' => $this->is_mirror ? $this->mirror_device_id : null, 'maximum_compatibility' => $this->maximum_compatibility, 'sleep_mode_enabled' => $this->sleep_mode_enabled, 'sleep_mode_from' => $this->sleep_mode_from, @@ -448,18 +433,6 @@ new class extends Component @endforeach - - @if($is_mirror) - - Select a device - @foreach(auth()->user()->devices->where('mirror_device_id', null)->where('id', '!=', $device->id) as $mirrorOption) - - {{ $mirrorOption->name }} ({{ $mirrorOption->friendly_id }}) - - @endforeach - - @endif - @if(empty($device_model_id)) @@ -559,7 +532,7 @@ new class extends Component @php - $mirrorUrl = url('/mirror/index.html') . '?api_key=' . urlencode($device->api_key); + $mirrorUrl = url('/mirror/index.html') . '?mac_address=' . urlencode($device->mac_address) . '&api_key=' . urlencode($device->api_key); @endphp
diff --git a/resources/views/livewire/plugins/config-modal.blade.php b/resources/views/livewire/plugins/config-modal.blade.php index 49d6ed3..7ba3208 100644 --- a/resources/views/livewire/plugins/config-modal.blade.php +++ b/resources/views/livewire/plugins/config-modal.blade.php @@ -2,7 +2,6 @@ use App\Models\Plugin; use Illuminate\Support\Facades\Http; -use Livewire\Attributes\On; use Livewire\Component; /* @@ -55,22 +54,12 @@ new class extends Component /** * Triggered by @close on the modal to discard any typed but unsaved changes */ - public int $resetIndex = 0; - - /** - * When recipe settings (or this modal) save, reload so Configuration Fields form stays in sync. - */ - #[On('config-updated')] - public function refreshFromParent(): void - { - $this->loadData(); - $this->resetIndex++; - } + public int $resetIndex = 0; // Add this property public function resetForm(): void { $this->loadData(); - ++$this->resetIndex; + ++$this->resetIndex; // Increment to force DOM refresh } public function saveConfiguration() diff --git a/resources/views/livewire/plugins/index.blade.php b/resources/views/livewire/plugins/index.blade.php index 0985841..90f8aa0 100644 --- a/resources/views/livewire/plugins/index.blade.php +++ b/resources/views/livewire/plugins/index.blade.php @@ -258,13 +258,14 @@ new class extends Component
Limitations
    +
  • Only full view will be imported; shared markup will be prepended
  • Some Liquid filters may be not supported or behave differently
  • API responses in formats other than JSON are not yet supported
  • {{--
      --}} {{--
    • date: "%N" is unsupported. Use date: "u" instead
    • --}} {{--
    --}}
- Please report issues on GitHub. Include your example zip file. + Please report issues on GitHub. Include your example zip file.
@@ -311,11 +312,12 @@ new class extends Component Limitations
    +
  • Only full view will be imported; shared markup will be prepended
  • Requires trmnl-liquid-cli executable.
  • API responses in formats other than JSON are not yet fully supported.
  • There are limitations in payload size (Data Payload, Template).
- Please report issues, aside from the known limitations, on GitHub. Include the recipe URL. + Please report issues, aside from the known limitations, on GitHub. Include the recipe URL.
diff --git a/resources/views/livewire/plugins/markup.blade.php b/resources/views/livewire/plugins/markup.blade.php index 392b0b9..150e626 100644 --- a/resources/views/livewire/plugins/markup.blade.php +++ b/resources/views/livewire/plugins/markup.blade.php @@ -72,8 +72,8 @@ new class extends Component - LaraPaper - “This screen was rendered by BYOS LaraPaper” + TRMNL BYOS Laravel + “This screen was rendered by BYOS Laravel” Benjamin Nussbaum diff --git a/resources/views/livewire/plugins/recipe.blade.php b/resources/views/livewire/plugins/recipe.blade.php index 59b0f2f..cda019e 100644 --- a/resources/views/livewire/plugins/recipe.blade.php +++ b/resources/views/livewire/plugins/recipe.blade.php @@ -65,12 +65,6 @@ new class extends Component public string $preview_size = 'full'; - public array $markup_layouts = []; - - public array $active_tabs = []; - - public string $active_tab = 'full'; - public function mount(): void { abort_unless(auth()->user()->plugins->contains($this->plugin), 403); @@ -97,24 +91,7 @@ new class extends Component $this->view_content = null; } } else { - // Initialize layout markups from plugin columns - $this->markup_layouts = [ - 'full' => $this->plugin->render_markup ?? '', - 'half_horizontal' => $this->plugin->render_markup_half_horizontal ?? '', - 'half_vertical' => $this->plugin->render_markup_half_vertical ?? '', - 'quadrant' => $this->plugin->render_markup_quadrant ?? '', - 'shared' => $this->plugin->render_markup_shared ?? '', - ]; - - // Set active tabs based on which layouts have content - $this->active_tabs = ['full']; // Full is always active - foreach (['half_horizontal', 'half_vertical', 'quadrant', 'shared'] as $layout) { - if (! empty($this->markup_layouts[$layout])) { - $this->active_tabs[] = $layout; - } - } - - $this->markup_code = $this->markup_layouts['full']; + $this->markup_code = $this->plugin->render_markup; $this->markup_language = $this->plugin->markup_language ?? 'blade'; } @@ -148,108 +125,12 @@ new class extends Component { abort_unless(auth()->user()->plugins->contains($this->plugin), 403); $this->validate(); - - // Update markup_code for the active tab - if (isset($this->markup_layouts[$this->active_tab])) { - $this->markup_layouts[$this->active_tab] = $this->markup_code ?? ''; - } - - // Save all layout markups to respective columns $this->plugin->update([ - 'render_markup' => $this->markup_layouts['full'] ?? null, - 'render_markup_half_horizontal' => ! empty($this->markup_layouts['half_horizontal']) ? $this->markup_layouts['half_horizontal'] : null, - 'render_markup_half_vertical' => ! empty($this->markup_layouts['half_vertical']) ? $this->markup_layouts['half_vertical'] : null, - 'render_markup_quadrant' => ! empty($this->markup_layouts['quadrant']) ? $this->markup_layouts['quadrant'] : null, - 'render_markup_shared' => ! empty($this->markup_layouts['shared']) ? $this->markup_layouts['shared'] : null, + 'render_markup' => $this->markup_code ?? null, 'markup_language' => $this->markup_language ?? null, ]); } - public function addLayoutTab(string $layout): void - { - if (! in_array($layout, $this->active_tabs, true)) { - $this->active_tabs[] = $layout; - if (! isset($this->markup_layouts[$layout])) { - $this->markup_layouts[$layout] = ''; - } - $this->switchTab($layout); - } - } - - public function removeLayoutTab(string $layout): void - { - if ($layout !== 'full') { - $this->active_tabs = array_values(array_filter($this->active_tabs, fn ($tab) => $tab !== $layout)); - if (isset($this->markup_layouts[$layout])) { - $this->markup_layouts[$layout] = ''; - } - if ($this->active_tab === $layout) { - $this->active_tab = 'full'; - $this->markup_code = $this->markup_layouts['full'] ?? ''; - } - } - } - - public function switchTab(string $layout): void - { - if (in_array($layout, $this->active_tabs, true)) { - // Save current tab's content before switching - if (isset($this->markup_layouts[$this->active_tab])) { - $this->markup_layouts[$this->active_tab] = $this->markup_code ?? ''; - } - - $this->active_tab = $layout; - $this->markup_code = $this->markup_layouts[$layout] ?? ''; - } - } - - public function toggleLayoutTab(string $layout): void - { - if ($layout === 'full') { - return; - } - - if (in_array($layout, $this->active_tabs, true)) { - $this->removeLayoutTab($layout); - } else { - $this->addLayoutTab($layout); - } - } - - public function getAvailableLayouts(): array - { - return [ - 'half_horizontal' => 'Half Horizontal', - 'half_vertical' => 'Half Vertical', - 'quadrant' => 'Quadrant', - 'shared' => 'Shared', - ]; - } - - public function getLayoutLabel(string $layout): string - { - return match ($layout) { - 'full' => $this->getFullTabLabel(), - 'half_horizontal' => 'Half Horizontal', - 'half_vertical' => 'Half Vertical', - 'quadrant' => 'Quadrant', - 'shared' => 'Shared', - default => ucfirst($layout), - }; - } - - public function getFullTabLabel(): string - { - // Return "Full" if any layout-specific markup exists, otherwise "Responsive" - if (! empty($this->markup_layouts['half_horizontal']) - || ! empty($this->markup_layouts['half_vertical']) - || ! empty($this->markup_layouts['quadrant'])) { - return 'Full'; - } - - return 'Responsive'; - } - protected array $rules = [ 'name' => 'required|string|max:255', 'data_stale_minutes' => 'required|integer|min:1', @@ -569,10 +450,11 @@ HTML; } #[On('config-updated')] - public function refreshPlugin(): void + public function refreshPlugin() { + // This pulls the fresh 'configuration' from the DB + // and re-triggers the @if check in the Blade template $this->plugin = $this->plugin->fresh(); - $this->configuration_template = $this->plugin->configuration_template ?? []; } // Laravel Livewire computed property: access with $this->parsed_urls @@ -1136,75 +1018,41 @@ HTML; @if(!$plugin->render_markup_view)
-
-
- @foreach($active_tabs as $tab) - - @endforeach - - - - - @foreach($this->getAvailableLayouts() as $layout => $label) - -
- @if(in_array($layout, $active_tabs, true)) - - @else - - @endif - {{ $label }} -
-
- @endforeach -
-
-
- -
- - @php - $textareaId = 'code-' . $plugin->id; - @endphp - {{ $markup_language === 'liquid' ? 'Liquid Code' : 'Blade Code' }} - +
diff --git a/resources/views/livewire/plugins/recipes/settings.blade.php b/resources/views/livewire/plugins/recipes/settings.blade.php index 4291834..c83f52c 100644 --- a/resources/views/livewire/plugins/recipes/settings.blade.php +++ b/resources/views/livewire/plugins/recipes/settings.blade.php @@ -3,11 +3,9 @@ use App\Models\Plugin; use Illuminate\Validation\Rule; use Livewire\Component; -use Symfony\Component\Yaml\Exception\ParseException; -use Symfony\Component\Yaml\Yaml; /* - * This component contains the TRMNL Plugin Settings modal. + * This component contains the TRMNL Plugin Settings modal */ new class extends Component { @@ -19,21 +17,16 @@ new class extends Component public bool $alias = false; - public bool $use_trmnl_liquid_renderer = false; - - public string $configurationTemplateYaml = ''; - public int $resetIndex = 0; public function mount(): void { $this->resetErrorBag(); + // Reload data $this->plugin = $this->plugin->fresh(); $this->trmnlp_id = $this->plugin->trmnlp_id; $this->uuid = $this->plugin->uuid; $this->alias = $this->plugin->alias ?? false; - $this->use_trmnl_liquid_renderer = $this->plugin->preferred_renderer === 'trmnl-liquid'; - $this->configurationTemplateYaml = $this->plugin->getCustomFieldsEditorYaml(); } public function saveTrmnlpId(): void @@ -50,47 +43,13 @@ new class extends Component ->ignore($this->plugin->id), ], 'alias' => 'boolean', - 'use_trmnl_liquid_renderer' => 'boolean', - 'configurationTemplateYaml' => [ - 'nullable', - 'string', - function (string $attribute, mixed $value, \Closure $fail): void { - if ($value === '') { - return; - } - try { - $parsed = Yaml::parse($value); - if (! is_array($parsed)) { - $fail('The configuration must be valid YAML and evaluate to an object/array.'); - return; - } - Plugin::validateCustomFieldsList($parsed); - } catch (ParseException) { - $fail('The configuration must be valid YAML.'); - } catch (\Illuminate\Validation\ValidationException $e) { - foreach ($e->errors() as $messages) { - foreach ($messages as $message) { - $fail($message); - } - } - } - }, - ], ]); - $configurationTemplate = Plugin::configurationTemplateFromCustomFieldsYaml( - $this->configurationTemplateYaml, - $this->plugin->configuration_template - ); - $this->plugin->update([ 'trmnlp_id' => empty($this->trmnlp_id) ? null : $this->trmnlp_id, 'alias' => $this->alias, - 'preferred_renderer' => $this->use_trmnl_liquid_renderer ? 'trmnl-liquid' : null, - 'configuration_template' => $configurationTemplate, ]); - $this->dispatch('config-updated'); Flux::modal('trmnlp-settings')->close(); } @@ -100,7 +59,7 @@ new class extends Component } }; ?> - +
Recipe Settings @@ -124,53 +83,6 @@ new class extends Component Enable an Alias URL for this recipe. Your server does not need to be exposed to the internet, but your device must be able to reach the URL. Docs - @if(config('services.trmnl.liquid_enabled') && $plugin->markup_language === 'liquid') - - - trmnl-liquid is a Ruby-based renderer that matches the Core service’s Liquid behavior for better compatibility. - - @endif - - - Configuration template - - Build forms visually in the TRMNL YML Form Builder. - Check the docs for more information. - - @php - $configTemplateTextareaId = 'config-template-' . uniqid(); - @endphp - - @if($alias) Alias URL diff --git a/resources/views/pages/settings/update.blade.php b/resources/views/pages/settings/update.blade.php index 099b896..f613c29 100644 --- a/resources/views/pages/settings/update.blade.php +++ b/resources/views/pages/settings/update.blade.php @@ -248,7 +248,7 @@ new class extends Component Up to Date - You are running the latest version. + You are running the latest version {{ $latestVersion }}. @endif diff --git a/resources/views/partials/head.blade.php b/resources/views/partials/head.blade.php index 26a42a6..fa0f31a 100644 --- a/resources/views/partials/head.blade.php +++ b/resources/views/partials/head.blade.php @@ -1,7 +1,7 @@ -{{ $title ?? 'LaraPaper' }} +{{ $title ?? 'TRMNL BYOS Laravel' }} diff --git a/resources/views/recipes/zen.blade.php b/resources/views/recipes/zen.blade.php index cc62c63..0ae920f 100644 --- a/resources/views/recipes/zen.blade.php +++ b/resources/views/recipes/zen.blade.php @@ -1,13 +1,15 @@ {{--@dump($data)--}} @props(['size' => 'full']) - -
{{$data['data'][0]['a'] ?? ''}}
- @if (strlen($data['data'][0]['q'] ?? '') < 300 && $size != 'quadrant') -

{{ $data['data'][0]['q'] ?? '' }}

- @else -

{{ $data['data'][0]['q'] ?? '' }}

- @endif + + +
{{$data['data'][0]['a'] ?? ''}}
+ @if (strlen($data['data'][0]['q'] ?? '') < 300 && $size != 'quadrant') +

{{ $data['data'][0]['q'] ?? '' }}

+ @else +

{{ $data['data'][0]['q'] ?? '' }}

+ @endif +
diff --git a/resources/views/trmnl-layouts/mashup.blade.php b/resources/views/trmnl-layouts/mashup.blade.php index 0e1cb3c..1d8321f 100644 --- a/resources/views/trmnl-layouts/mashup.blade.php +++ b/resources/views/trmnl-layouts/mashup.blade.php @@ -6,22 +6,18 @@ 'deviceOrientation' => null, 'colorDepth' => '1bit', 'scaleLevel' => null, - 'cssVariables' => null, ]) @if(config('app.puppeteer_window_size_strategy') === 'v2') + scale-level="{{$scaleLevel}}"> {!! $slot !!} @else - + {!! $slot !!} diff --git a/resources/views/trmnl-layouts/single.blade.php b/resources/views/trmnl-layouts/single.blade.php index 09f5e52..c6d6499 100644 --- a/resources/views/trmnl-layouts/single.blade.php +++ b/resources/views/trmnl-layouts/single.blade.php @@ -5,21 +5,16 @@ 'deviceOrientation' => null, 'colorDepth' => '1bit', 'scaleLevel' => null, - 'cssVariables' => null, ]) @if(config('app.puppeteer_window_size_strategy') === 'v2') + scale-level="{{$scaleLevel}}"> {!! $slot !!} @else - + {!! $slot !!} @endif diff --git a/resources/views/vendor/trmnl/components/screen.blade.php b/resources/views/vendor/trmnl/components/screen.blade.php index 320a34b..4234a2d 100644 --- a/resources/views/vendor/trmnl/components/screen.blade.php +++ b/resources/views/vendor/trmnl/components/screen.blade.php @@ -1,11 +1,10 @@ @props([ 'noBleed' => false, 'darkMode' => false, - 'deviceVariant' => 'ogv2', + 'deviceVariant' => 'og', 'deviceOrientation' => null, 'colorDepth' => '1bit', 'scaleLevel' => null, - 'cssVariables' => null, ]) @@ -19,26 +18,17 @@ href="{{ config('trmnl-blade.framework_css_url') }}"> @else + href="{{ config('services.trmnl.base_url') }}/css/{{ config('trmnl-blade.framework_version', '1.2.0') }}/plugins.css"> @endif @if (config('trmnl-blade.framework_js_url')) @else - + @endif {{ $title ?? config('app.name') }} - @if(config('app.puppeteer_window_size_strategy') === 'v2' && !empty($cssVariables) && is_array($cssVariables)) - - @endif -
+
{{ $slot }}
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index ba608f9..100b57b 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -1,6 +1,6 @@
- +
@if (Route::has('login')) @@ -32,11 +32,6 @@ @endif
@auth - @if(config('app.version')) - Version: {{ config('app.version') }} - - @endif @endauth
diff --git a/routes/api.php b/routes/api.php index 8fc040c..73b2749 100644 --- a/routes/api.php +++ b/routes/api.php @@ -49,9 +49,8 @@ Route::get('/display', function (Request $request) { 'last_refreshed_at' => now(), ]); - $batteryPercent = $request->header('battery-percent') ?? $request->header('percent-charged'); - if ($batteryPercent !== null) { - $batteryPercent = (int) $batteryPercent; + if ($request->hasHeader('battery-percent')) { + $batteryPercent = (int) $request->header('battery-percent'); $batteryVoltage = $device->calculateVoltageFromPercent($batteryPercent); $device->update([ 'last_battery_voltage' => $batteryVoltage, @@ -88,8 +87,8 @@ Route::get('/display', function (Request $request) { $refreshTimeOverride = $playlistItem->playlist()->first()->refresh_time; $plugin = $playlistItem->plugin; - ImageGenerationService::resetIfNotCacheable($plugin, $device); - $plugin->refresh(); + // Reset cache if Devices with different dimensions exist + ImageGenerationService::resetIfNotCacheable($plugin); // Check and update stale data if needed if ($plugin->isDataStale() || $plugin->current_image === null) { @@ -699,9 +698,6 @@ Route::get('/display/{uuid}/alias', function (Request $request, string $uuid) { ], 404); } - ImageGenerationService::resetIfNotCacheable($plugin, $deviceModel); - $plugin->refresh(); - // Check if we can use cached image (only for og_png and if data is not stale) $useCache = $deviceModelName === 'og_png' && ! $plugin->isDataStale() && $plugin->current_image !== null; @@ -747,13 +743,9 @@ Route::get('/display/{uuid}/alias', function (Request $request, string $uuid) { palette: $deviceModel->palette ); - // Update plugin cache if using og_png (recipes only get metadata for cache comparison) + // Update plugin cache if using og_png if ($deviceModelName === 'og_png') { - $update = ['current_image' => $imageUuid]; - if ($plugin->plugin_type === 'recipe') { - $update['current_image_metadata'] = ImageGenerationService::buildImageMetadataFromDeviceModel($deviceModel); - } - $plugin->update($update); + $plugin->update(['current_image' => $imageUuid]); } // Return the generated image diff --git a/storage/app/public/images/default-screens/setup-logo_1024_768_4_90.png b/storage/app/public/images/default-screens/setup-logo_1024_768_4_90.png deleted file mode 100644 index f02b9e9..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_1024_768_4_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_1648_824_8_0.png b/storage/app/public/images/default-screens/setup-logo_1648_824_8_0.png deleted file mode 100644 index 3bc23a9..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_1648_824_8_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_1872_1404_12_90.png b/storage/app/public/images/default-screens/setup-logo_1872_1404_12_90.png deleted file mode 100644 index 1c04367..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_1872_1404_12_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_1872_1404_4_0.png b/storage/app/public/images/default-screens/setup-logo_1872_1404_4_0.png deleted file mode 100644 index 6f9c2cb..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_1872_1404_4_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_1880_1264_4_90.png b/storage/app/public/images/default-screens/setup-logo_1880_1264_4_90.png deleted file mode 100644 index a7a00d0..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_1880_1264_4_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_1920_1080_8_0.png b/storage/app/public/images/default-screens/setup-logo_1920_1080_8_0.png deleted file mode 100644 index 1633f31..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_1920_1080_8_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_1920_1440_4_90.png b/storage/app/public/images/default-screens/setup-logo_1920_1440_4_90.png deleted file mode 100644 index f40d451..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_1920_1440_4_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_2480_1860_8_90.png b/storage/app/public/images/default-screens/setup-logo_2480_1860_8_90.png deleted file mode 100644 index ec4e753..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_2480_1860_8_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/setup-logo_960_540_4_0.png b/storage/app/public/images/default-screens/setup-logo_960_540_4_0.png deleted file mode 100644 index 10e01ef..0000000 Binary files a/storage/app/public/images/default-screens/setup-logo_960_540_4_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_1024_768_4_90.png b/storage/app/public/images/default-screens/sleep_1024_768_4_90.png deleted file mode 100644 index c17be3e..0000000 Binary files a/storage/app/public/images/default-screens/sleep_1024_768_4_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_1648_824_8_0.png b/storage/app/public/images/default-screens/sleep_1648_824_8_0.png deleted file mode 100644 index e6f7b9e..0000000 Binary files a/storage/app/public/images/default-screens/sleep_1648_824_8_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_1872_1404_12_90.png b/storage/app/public/images/default-screens/sleep_1872_1404_12_90.png deleted file mode 100644 index 0f17642..0000000 Binary files a/storage/app/public/images/default-screens/sleep_1872_1404_12_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_1872_1404_4_0.png b/storage/app/public/images/default-screens/sleep_1872_1404_4_0.png deleted file mode 100644 index 67e5a28..0000000 Binary files a/storage/app/public/images/default-screens/sleep_1872_1404_4_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_1880_1264_4_90.png b/storage/app/public/images/default-screens/sleep_1880_1264_4_90.png deleted file mode 100644 index 37fa694..0000000 Binary files a/storage/app/public/images/default-screens/sleep_1880_1264_4_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_1920_1080_8_0.png b/storage/app/public/images/default-screens/sleep_1920_1080_8_0.png deleted file mode 100644 index c0f2ca0..0000000 Binary files a/storage/app/public/images/default-screens/sleep_1920_1080_8_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_1920_1440_4_90.png b/storage/app/public/images/default-screens/sleep_1920_1440_4_90.png deleted file mode 100644 index d190897..0000000 Binary files a/storage/app/public/images/default-screens/sleep_1920_1440_4_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_2480_1860_8_90.png b/storage/app/public/images/default-screens/sleep_2480_1860_8_90.png deleted file mode 100644 index f9c0a2c..0000000 Binary files a/storage/app/public/images/default-screens/sleep_2480_1860_8_90.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_800_480_1_0.png b/storage/app/public/images/default-screens/sleep_800_480_1_0.png deleted file mode 100644 index 6f1ec2e..0000000 Binary files a/storage/app/public/images/default-screens/sleep_800_480_1_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_800_480_2_0.png b/storage/app/public/images/default-screens/sleep_800_480_2_0.png deleted file mode 100644 index ccd82b3..0000000 Binary files a/storage/app/public/images/default-screens/sleep_800_480_2_0.png and /dev/null differ diff --git a/storage/app/public/images/default-screens/sleep_960_540_4_0.png b/storage/app/public/images/default-screens/sleep_960_540_4_0.png deleted file mode 100644 index cc9cbb6..0000000 Binary files a/storage/app/public/images/default-screens/sleep_960_540_4_0.png and /dev/null differ diff --git a/tests/Feature/Api/DeviceEndpointsTest.php b/tests/Feature/Api/DeviceEndpointsTest.php index f64d203..54edb10 100644 --- a/tests/Feature/Api/DeviceEndpointsTest.php +++ b/tests/Feature/Api/DeviceEndpointsTest.php @@ -100,7 +100,7 @@ test('display endpoint includes maximum_compatibility value when true for device $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', - 'maximum_compatibility' => true, + 'maximum_compatibility' => true ]); $response = $this->withHeaders([ @@ -725,40 +725,6 @@ test('display endpoint updates last_refreshed_at timestamp', function (): void { ->and($device->last_refreshed_at->diffInSeconds(now()))->toBeLessThan(2); }); -test('display endpoint accepts battery-percent header and updates device', function (): void { - $device = Device::factory()->create([ - 'mac_address' => '00:11:22:33:44:56', - 'api_key' => 'test-api-key-battery', - 'last_battery_voltage' => null, - ]); - - $this->withHeaders([ - 'id' => $device->mac_address, - 'access-token' => $device->api_key, - 'battery-percent' => '67', - ])->get('/api/display')->assertOk(); - - $device->refresh(); - expect($device->battery_percent)->toEqual(67); -}); - -test('display endpoint accepts Percent-Charged header and updates device', function (): void { - $device = Device::factory()->create([ - 'mac_address' => '00:11:22:33:44:57', - 'api_key' => 'test-api-key-percent-charged', - 'last_battery_voltage' => null, - ]); - - $this->withHeaders([ - 'id' => $device->mac_address, - 'access-token' => $device->api_key, - 'Percent-Charged' => '51', - ])->get('/api/display')->assertOk(); - - $device->refresh(); - expect($device->battery_percent)->toEqual(51); -}); - test('display endpoint updates last_refreshed_at timestamp for mirrored devices', function (): void { // Create source device $sourceDevice = Device::factory()->create([ diff --git a/tests/Feature/DeviceModelsTest.php b/tests/Feature/DeviceModelsTest.php index ac00af3..14a374d 100644 --- a/tests/Feature/DeviceModelsTest.php +++ b/tests/Feature/DeviceModelsTest.php @@ -4,8 +4,6 @@ declare(strict_types=1); use App\Models\DeviceModel; use App\Models\User; -use Illuminate\Support\Facades\Http; -use Livewire\Livewire; it('allows a user to view the device models page', function (): void { $user = User::factory()->create(); @@ -89,38 +87,3 @@ it('redirects unauthenticated users from the device models page', function (): v $response->assertRedirect('/login'); }); - -it('update from API runs job and refreshes device models', function (): void { - $user = User::factory()->create(); - $this->actingAs($user); - - Http::fake([ - 'usetrmnl.com/api/palettes' => Http::response(['data' => []], 200), - config('services.trmnl.base_url').'/api/models' => Http::response([ - 'data' => [ - [ - 'name' => 'api-model', - 'label' => 'API Model', - 'description' => 'From API', - 'width' => 800, - 'height' => 480, - 'colors' => 4, - 'bit_depth' => 2, - 'scale_factor' => 1.0, - 'rotation' => 0, - 'mime_type' => 'image/png', - 'offset_x' => 0, - 'offset_y' => 0, - 'kind' => 'trmnl', - 'published_at' => '2023-01-01T00:00:00Z', - ], - ], - ], 200), - ]); - - $component = Livewire::test('device-models.index') - ->call('updateFromApi'); - - $deviceModels = $component->get('deviceModels'); - expect($deviceModels->pluck('name')->toArray())->toContain('api-model'); -}); diff --git a/tests/Feature/Devices/DeviceConfigureTest.php b/tests/Feature/Devices/DeviceConfigureTest.php index bf4e19e..dff0954 100644 --- a/tests/Feature/Devices/DeviceConfigureTest.php +++ b/tests/Feature/Devices/DeviceConfigureTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature; use App\Models\Device; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; -use Livewire\Livewire; use function Pest\Laravel\actingAs; @@ -24,35 +23,3 @@ test('configure view displays last_refreshed_at timestamp', function (): void { $response->assertOk() ->assertSee('5 minutes ago'); }); - -test('configure edit modal shows mirror checkbox and allows unchecking mirror', function (): void { - $user = User::factory()->create(); - actingAs($user); - - $deviceAttributes = [ - 'user_id' => $user->id, - 'width' => 800, - 'height' => 480, - 'rotate' => 0, - 'image_format' => 'png', - 'maximum_compatibility' => false, - ]; - $sourceDevice = Device::factory()->create($deviceAttributes); - $mirrorDevice = Device::factory()->create([ - ...$deviceAttributes, - 'mirror_device_id' => $sourceDevice->id, - ]); - - $response = $this->get(route('devices.configure', $mirrorDevice)); - $response->assertOk() - ->assertSee('Mirrors Device') - ->assertSee('Select Device to Mirror'); - - Livewire::test('devices.configure', ['device' => $mirrorDevice]) - ->set('is_mirror', false) - ->call('updateDevice') - ->assertHasNoErrors(); - - $mirrorDevice->refresh(); - expect($mirrorDevice->mirror_device_id)->toBeNull(); -}); diff --git a/tests/Feature/GenerateScreenJobTest.php b/tests/Feature/GenerateScreenJobTest.php index 9482e8c..115fb51 100644 --- a/tests/Feature/GenerateScreenJobTest.php +++ b/tests/Feature/GenerateScreenJobTest.php @@ -2,8 +2,6 @@ use App\Jobs\GenerateScreenJob; use App\Models\Device; -use App\Models\DeviceModel; -use App\Models\Plugin; use Bnussbau\TrmnlPipeline\TrmnlPipeline; use Illuminate\Support\Facades\Storage; @@ -60,26 +58,3 @@ test('it preserves gitignore file during cleanup', function (): void { Storage::disk('public')->assertExists('/images/generated/.gitignore'); }); - -test('it saves current_image_metadata for recipe plugins', function (): void { - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'rotation' => 0, - 'mime_type' => 'image/png', - 'palette_id' => null, - ]); - $device = Device::factory()->create(['device_model_id' => $deviceModel->id]); - $plugin = Plugin::factory()->create(['plugin_type' => 'recipe']); - - $job = new GenerateScreenJob($device->id, $plugin->id, '
Test
'); - $job->handle(); - - $plugin->refresh(); - expect($plugin->current_image)->not->toBeNull(); - expect($plugin->current_image_metadata)->toBeArray(); - expect($plugin->current_image_metadata)->toHaveKeys(['width', 'height', 'rotation', 'palette_id', 'mime_type']); - expect($plugin->current_image_metadata['width'])->toBe(800); - expect($plugin->current_image_metadata['height'])->toBe(480); - expect($plugin->current_image_metadata['mime_type'])->toBe('image/png'); -}); diff --git a/tests/Feature/ImageGenerationServiceTest.php b/tests/Feature/ImageGenerationServiceTest.php index 9d26eb6..07bb6a6 100644 --- a/tests/Feature/ImageGenerationServiceTest.php +++ b/tests/Feature/ImageGenerationServiceTest.php @@ -8,7 +8,6 @@ use App\Models\DeviceModel; use App\Services\ImageGenerationService; use Bnussbau\TrmnlPipeline\TrmnlPipeline; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Storage; uses(RefreshDatabase::class); @@ -23,10 +22,6 @@ afterEach(function (): void { TrmnlPipeline::restore(); }); -it('plugins table has current_image_metadata column', function (): void { - expect(Schema::hasColumn('plugins', 'current_image_metadata'))->toBeTrue(); -}); - it('generates image for device without device model', function (): void { // Create a device without a DeviceModel (legacy behavior) $device = Device::factory()->create([ @@ -275,15 +270,39 @@ it('cleanupFolder preserves .gitignore', function (): void { Storage::disk('public')->assertExists('/images/generated/.gitignore'); }); -it('resetIfNotCacheable does not reset recipe cache based on other devices', function (): void { - // Cache validity is now determined at use-time via current_image_metadata - $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid', 'plugin_type' => 'recipe']); +it('resetIfNotCacheable resets when device models exist', function (): void { + // Create a plugin + $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid']); - Device::factory()->create(['device_model_id' => DeviceModel::factory()->create()->id]); + // Create a device with DeviceModel (should trigger cache reset) + Device::factory()->create([ + 'device_model_id' => DeviceModel::factory()->create()->id, + ]); + + // Run reset check ImageGenerationService::resetIfNotCacheable($plugin); + // Assert plugin image was reset $plugin->refresh(); - expect($plugin->current_image)->toBe('test-uuid'); + expect($plugin->current_image)->toBeNull(); +}); + +it('resetIfNotCacheable resets when custom dimensions exist', function (): void { + // Create a plugin + $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid']); + + // Create a device with custom dimensions (should trigger cache reset) + Device::factory()->create([ + 'width' => 1024, // Different from default 800 + 'height' => 768, // Different from default 480 + ]); + + // Run reset check + ImageGenerationService::resetIfNotCacheable($plugin); + + // Assert plugin image was reset + $plugin->refresh(); + expect($plugin->current_image)->toBeNull(); }); it('resetIfNotCacheable preserves image for standard devices', function (): void { @@ -306,122 +325,27 @@ it('resetIfNotCacheable preserves image for standard devices', function (): void }); it('cache is reset when plugin markup changes', function (): void { - // Create a plugin with cached image and metadata + // Create a plugin with cached image $plugin = App\Models\Plugin::factory()->create([ 'current_image' => 'cached-uuid', - 'current_image_metadata' => ['width' => 800, 'height' => 480, 'rotation' => 0, 'palette_id' => null, 'mime_type' => 'image/png'], 'render_markup' => '
Original markup
', ]); - $plugin->update(['render_markup' => '
Updated markup
']); + // Create devices with standard dimensions (cacheable) + Device::factory()->count(2)->create([ + 'width' => 800, + 'height' => 480, + 'rotate' => 0, + ]); + // Update the plugin markup + $plugin->update([ + 'render_markup' => '
Updated markup
', + ]); + + // Assert cache was reset when markup changed $plugin->refresh(); expect($plugin->current_image)->toBeNull(); - expect($plugin->current_image_metadata)->toBeNull(); -}); - -it('buildImageMetadataFromDevice returns canonical metadata shape', function (): void { - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'rotation' => 0, - 'mime_type' => 'image/png', - 'palette_id' => null, - ]); - $device = Device::factory()->create(['device_model_id' => $deviceModel->id]); - - $meta = ImageGenerationService::buildImageMetadataFromDevice($device); - - expect($meta)->toHaveKeys(['width', 'height', 'rotation', 'palette_id', 'mime_type']); - expect($meta['width'])->toBe(800); - expect($meta['height'])->toBe(480); - expect($meta['rotation'])->toBe(0); - expect($meta['mime_type'])->toBe('image/png'); -}); - -it('buildImageMetadataFromDeviceModel returns canonical metadata shape', function (): void { - $model = DeviceModel::factory()->create([ - 'width' => 1024, - 'height' => 768, - 'rotation' => 90, - 'mime_type' => 'image/bmp', - 'palette_id' => null, - ]); - - $meta = ImageGenerationService::buildImageMetadataFromDeviceModel($model); - - expect($meta)->toHaveKeys(['width', 'height', 'rotation', 'palette_id', 'mime_type']); - expect($meta['width'])->toBe(1024); - expect($meta['height'])->toBe(768); - expect($meta['rotation'])->toBe(90); - expect($meta['mime_type'])->toBe('image/bmp'); -}); - -it('imageMetadataMatches returns false when stored is null or empty', function (): void { - $device = Device::factory()->create(['width' => 800, 'height' => 480, 'rotate' => 0]); - - expect(ImageGenerationService::imageMetadataMatches(null, $device))->toBeFalse(); - expect(ImageGenerationService::imageMetadataMatches([], $device))->toBeFalse(); -}); - -it('imageMetadataMatches returns true when metadata matches device', function (): void { - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'rotation' => 0, - 'mime_type' => 'image/png', - 'palette_id' => null, - ]); - $device = Device::factory()->create(['device_model_id' => $deviceModel->id]); - $stored = ImageGenerationService::buildImageMetadataFromDevice($device); - - expect(ImageGenerationService::imageMetadataMatches($stored, $device))->toBeTrue(); -}); - -it('imageMetadataMatches returns false when metadata differs', function (): void { - $device = Device::factory()->create(['width' => 800, 'height' => 480, 'rotate' => 0]); - $stored = ['width' => 800, 'height' => 480, 'rotation' => 0, 'palette_id' => null, 'mime_type' => 'image/png']; - - $device->update(['width' => 1024]); - $device->refresh(); - - expect(ImageGenerationService::imageMetadataMatches($stored, $device))->toBeFalse(); -}); - -it('resetIfNotCacheable clears recipe cache when metadata does not match', function (): void { - $plugin = App\Models\Plugin::factory()->create([ - 'plugin_type' => 'recipe', - 'current_image' => 'cached-uuid', - 'current_image_metadata' => ['width' => 800, 'height' => 480, 'rotation' => 0, 'palette_id' => null, 'mime_type' => 'image/png'], - ]); - $device = Device::factory()->create(['width' => 1024, 'height' => 768, 'rotate' => 0]); - - ImageGenerationService::resetIfNotCacheable($plugin, $device); - - $plugin->refresh(); - expect($plugin->current_image)->toBeNull(); - expect($plugin->current_image_metadata)->toBeNull(); -}); - -it('resetIfNotCacheable preserves cache when metadata matches', function (): void { - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'rotation' => 0, - 'mime_type' => 'image/png', - ]); - $device = Device::factory()->create(['device_model_id' => $deviceModel->id]); - $meta = ImageGenerationService::buildImageMetadataFromDevice($device); - $plugin = App\Models\Plugin::factory()->create([ - 'plugin_type' => 'recipe', - 'current_image' => 'cached-uuid', - 'current_image_metadata' => $meta, - ]); - - ImageGenerationService::resetIfNotCacheable($plugin, $device); - - $plugin->refresh(); - expect($plugin->current_image)->toBe('cached-uuid'); }); it('determines correct image format from device model', function (): void { diff --git a/tests/Feature/Livewire/DevicePalettesTest.php b/tests/Feature/Livewire/DevicePalettesTest.php index abd4b24..3c37934 100644 --- a/tests/Feature/Livewire/DevicePalettesTest.php +++ b/tests/Feature/Livewire/DevicePalettesTest.php @@ -4,7 +4,6 @@ declare(strict_types=1); use App\Models\DevicePalette; use App\Models\User; -use Illuminate\Support\Facades\Http; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); @@ -571,29 +570,3 @@ test('component refreshes palette list after deleting', function (): void { expect($palettes)->toHaveCount($initialCount + 1); expect(DevicePalette::count())->toBe($initialCount + 1); }); - -test('update from API runs job and refreshes device palettes', function (): void { - $user = User::factory()->create(); - $this->actingAs($user); - - Http::fake([ - 'usetrmnl.com/api/palettes' => Http::response([ - 'data' => [ - [ - 'id' => 'api-palette', - 'name' => 'API Palette', - 'grays' => 4, - 'colors' => null, - 'framework_class' => '', - ], - ], - ], 200), - config('services.trmnl.base_url').'/api/models' => Http::response(['data' => []], 200), - ]); - - $component = Livewire::test('device-palettes.index') - ->call('updateFromApi'); - - $devicePalettes = $component->get('devicePalettes'); - expect($devicePalettes->pluck('name')->toArray())->toContain('api-palette'); -}); diff --git a/tests/Feature/Livewire/Plugins/RecipeSettingsTest.php b/tests/Feature/Livewire/Plugins/RecipeSettingsTest.php index 8c977b4..c625262 100644 --- a/tests/Feature/Livewire/Plugins/RecipeSettingsTest.php +++ b/tests/Feature/Livewire/Plugins/RecipeSettingsTest.php @@ -109,124 +109,3 @@ test('recipe settings can clear trmnlp_id', function (): void { expect($plugin->fresh()->trmnlp_id)->toBeNull(); }); - -test('recipe settings saves preferred_renderer when liquid enabled and recipe is liquid', function (): void { - config(['services.trmnl.liquid_enabled' => true]); - - $user = User::factory()->create(); - $this->actingAs($user); - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'markup_language' => 'liquid', - 'preferred_renderer' => null, - ]); - - Livewire::test('plugins.recipes.settings', ['plugin' => $plugin]) - ->set('use_trmnl_liquid_renderer', true) - ->call('saveTrmnlpId') - ->assertHasNoErrors(); - - expect($plugin->fresh()->preferred_renderer)->toBe('trmnl-liquid'); -}); - -test('recipe settings clears preferred_renderer when checkbox unchecked', function (): void { - config(['services.trmnl.liquid_enabled' => true]); - - $user = User::factory()->create(); - $this->actingAs($user); - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'markup_language' => 'liquid', - 'preferred_renderer' => 'trmnl-liquid', - ]); - - Livewire::test('plugins.recipes.settings', ['plugin' => $plugin]) - ->set('use_trmnl_liquid_renderer', false) - ->call('saveTrmnlpId') - ->assertHasNoErrors(); - - expect($plugin->fresh()->preferred_renderer)->toBeNull(); -}); - -test('recipe settings saves configuration_template from valid YAML', function (): void { - $user = User::factory()->create(); - $this->actingAs($user); - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'configuration_template' => [], - ]); - - $yaml = "- keyname: reading_days\n field_type: text\n name: Reading Days\n"; - - Livewire::test('plugins.recipes.settings', ['plugin' => $plugin]) - ->set('configurationTemplateYaml', $yaml) - ->call('saveTrmnlpId') - ->assertHasNoErrors(); - - $expected = [ - 'custom_fields' => [ - [ - 'keyname' => 'reading_days', - 'field_type' => 'text', - 'name' => 'Reading Days', - ], - ], - ]; - expect($plugin->fresh()->configuration_template)->toBe($expected); -}); - -test('recipe settings validates invalid YAML', function (): void { - $user = User::factory()->create(); - $this->actingAs($user); - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'configuration_template' => [], - ]); - - Livewire::test('plugins.recipes.settings', ['plugin' => $plugin]) - ->set('configurationTemplateYaml', "foo: bar: baz\n") - ->call('saveTrmnlpId') - ->assertHasErrors(['configurationTemplateYaml']); - - expect($plugin->fresh()->configuration_template)->toBe([]); -}); - -test('recipe settings validates YAML must evaluate to object or array', function (): void { - $user = User::factory()->create(); - $this->actingAs($user); - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'configuration_template' => ['custom_fields' => []], - ]); - - Livewire::test('plugins.recipes.settings', ['plugin' => $plugin]) - ->set('configurationTemplateYaml', '123') - ->call('saveTrmnlpId') - ->assertHasErrors(['configurationTemplateYaml']); - - expect($plugin->fresh()->configuration_template)->toBe(['custom_fields' => []]); -}); - -test('recipe settings validates each custom field has field_type and name', function (): void { - $user = User::factory()->create(); - $this->actingAs($user); - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'configuration_template' => [], - ]); - - $yaml = "- keyname: only_key\n field_type: text\n name: Has Name\n- keyname: missing_type\n name: No type\n"; - - Livewire::test('plugins.recipes.settings', ['plugin' => $plugin]) - ->set('configurationTemplateYaml', $yaml) - ->call('saveTrmnlpId') - ->assertHasErrors(['configurationTemplateYaml']); - - expect($plugin->fresh()->configuration_template)->toBeEmpty(); -}); diff --git a/tests/Feature/PixelLogoConfigTest.php b/tests/Feature/PixelLogoConfigTest.php deleted file mode 100644 index ba009c9..0000000 --- a/tests/Feature/PixelLogoConfigTest.php +++ /dev/null @@ -1,46 +0,0 @@ -get('/login'); - - $response->assertStatus(200); - $response->assertSee('viewBox="0 0 1000 150"', false); -}); - -test('auth pages show heading instead of pixel logo when pixel_logo_enabled is false', function (): void { - Config::set('app.pixel_logo_enabled', false); - - $response = $this->get('/login'); - - $response->assertStatus(200); - $response->assertDontSee('viewBox="0 0 1000 150"', false); - $response->assertSee('LaraPaper'); -}); - -test('app logo shows text when pixel_logo_enabled is false', function (): void { - Config::set('app.pixel_logo_enabled', false); - - $user = User::factory()->create(); - $response = $this->actingAs($user)->get(route('dashboard')); - - $response->assertStatus(200); - $response->assertSee('LaraPaper'); - $response->assertDontSee('viewBox="0 0 1000 150"', false); -}); - -test('app logo shows pixel logo SVG when pixel_logo_enabled is true', function (): void { - Config::set('app.pixel_logo_enabled', true); - - $user = User::factory()->create(); - $response = $this->actingAs($user)->get(route('dashboard')); - - $response->assertStatus(200); - $response->assertSee('viewBox="0 0 1000 150"', false); -}); diff --git a/tests/Feature/PluginImportTest.php b/tests/Feature/PluginImportTest.php index aa1706f..cc47e67 100644 --- a/tests/Feature/PluginImportTest.php +++ b/tests/Feature/PluginImportTest.php @@ -52,10 +52,8 @@ it('imports plugin with shared.liquid file', function (): void { $pluginImportService = new PluginImportService(); $plugin = $pluginImportService->importFromZip($zipFile, $user); - expect($plugin->render_markup_shared)->toBe('{% comment %}Shared styles{% endcomment %}') - ->and($plugin->render_markup)->toContain('
') - ->and($plugin->getMarkupForSize('full'))->toContain('{% comment %}Shared styles{% endcomment %}') - ->and($plugin->getMarkupForSize('full'))->toContain('
'); + expect($plugin->render_markup)->toContain('{% comment %}Shared styles{% endcomment %}') + ->and($plugin->render_markup)->toContain('
'); }); it('imports plugin with files in root directory', function (): void { @@ -204,10 +202,8 @@ it('imports plugin from monorepo with shared.liquid in subdirectory', function ( $pluginImportService = new PluginImportService(); $plugin = $pluginImportService->importFromZip($zipFile, $user); - expect($plugin->render_markup_shared)->toBe('{% comment %}Monorepo shared styles{% endcomment %}') - ->and($plugin->render_markup)->toContain('
') - ->and($plugin->getMarkupForSize('full'))->toContain('{% comment %}Monorepo shared styles{% endcomment %}') - ->and($plugin->getMarkupForSize('full'))->toContain('
'); + expect($plugin->render_markup)->toContain('{% comment %}Monorepo shared styles{% endcomment %}') + ->and($plugin->render_markup)->toContain('
'); }); it('imports plugin from URL with zip_entry_path parameter', function (): void { @@ -356,10 +352,8 @@ it('imports specific plugin from monorepo zip with zip_entry_path parameter', fu expect($plugin)->toBeInstanceOf(Plugin::class) ->and($plugin->user_id)->toBe($user->id) ->and($plugin->name)->toBe('Example Plugin 2') // Should import example-plugin2, not example-plugin - ->and($plugin->render_markup_shared)->toBe('{% comment %}Plugin 2 shared styles{% endcomment %}') - ->and($plugin->render_markup)->toContain('
Plugin 2 content
') - ->and($plugin->getMarkupForSize('full'))->toContain('{% comment %}Plugin 2 shared styles{% endcomment %}') - ->and($plugin->getMarkupForSize('full'))->toContain('
Plugin 2 content
'); + ->and($plugin->render_markup)->toContain('{% comment %}Plugin 2 shared styles{% endcomment %}') + ->and($plugin->render_markup)->toContain('
Plugin 2 content
'); }); it('sets icon_url when importing from URL with iconUrl parameter', function (): void { @@ -522,8 +516,8 @@ it('imports plugin with only shared.liquid file', function (): void { expect($plugin)->toBeInstanceOf(Plugin::class) ->and($plugin->markup_language)->toBe('liquid') - ->and($plugin->render_markup_shared)->toBe('
{{ data.title }}
') - ->and($plugin->render_markup)->toBeNull(); + ->and($plugin->render_markup)->toContain('
') + ->and($plugin->render_markup)->toContain('
{{ data.title }}
'); }); it('imports plugin with only shared.blade.php file', function (): void { @@ -541,8 +535,8 @@ it('imports plugin with only shared.blade.php file', function (): void { expect($plugin)->toBeInstanceOf(Plugin::class) ->and($plugin->markup_language)->toBe('blade') - ->and($plugin->render_markup_shared)->toBe('
{{ $data["title"] }}
') - ->and($plugin->render_markup)->toBeNull(); + ->and($plugin->render_markup)->toBe('
{{ $data["title"] }}
') + ->and($plugin->render_markup)->not->toContain('
'); }); // Helper methods diff --git a/tests/Feature/PluginInlineTemplatesTest.php b/tests/Feature/PluginInlineTemplatesTest.php index 0bd5963..76b29d7 100644 --- a/tests/Feature/PluginInlineTemplatesTest.php +++ b/tests/Feature/PluginInlineTemplatesTest.php @@ -1,7 +1,6 @@ assertStringContainsString('"35":[{"name":"Ryan","age":35}]', $result); $this->assertStringContainsString('"29":[{"name":"Sara","age":29},{"name":"Jimbob","age":29}]', $result); }); - -test('shared template receives trmnl context when', function (): void { - $user = User::factory()->create(['name' => 'Jane Smith']); - - $plugin = Plugin::factory()->create([ - 'user_id' => $user->id, - 'name' => 'Departures', - 'markup_language' => 'liquid', - 'render_markup_shared' => <<<'LIQUID' -{% template departures_view %} -
- Departures - {{ trmnl.user.name }} -
-{% endtemplate %} -LIQUID - , - 'render_markup' => <<<'LIQUID' -
-{% render "departures_view", station: "Hauptbahnhof" %} -
-LIQUID - , - 'data_payload' => [], - ]); - - $result = $plugin->render('full'); - - $this->assertStringContainsString('Jane Smith', $result); - $this->assertStringContainsString('class="instance"', $result); -}); diff --git a/tests/Feature/PluginResponseTest.php b/tests/Feature/PluginResponseTest.php index 3d82b6b..2a75c9e 100644 --- a/tests/Feature/PluginResponseTest.php +++ b/tests/Feature/PluginResponseTest.php @@ -36,7 +36,7 @@ test('plugin parses JSON responses correctly', function (): void { ]); }); -test('plugin parses RSS XML responses and wraps under rss key', function (): void { +test('plugin parses XML responses and wraps under rss key', function (): void { $xmlContent = ' @@ -73,33 +73,6 @@ test('plugin parses RSS XML responses and wraps under rss key', function (): voi expect($plugin->data_payload['rss']['channel']['item'])->toHaveCount(2); }); -test('plugin parses namespaces XML responses and wraps under root key', function (): void { - $xmlContent = ' - - - Cherry - - '; - - Http::fake([ - 'example.com/namespace.xml' => Http::response($xmlContent, 200, ['Content-Type' => 'application/xml']), - ]); - - $plugin = Plugin::factory()->create([ - 'data_strategy' => 'polling', - 'polling_url' => 'https://example.com/namespace.xml', - 'polling_verb' => 'get', - ]); - - $plugin->updateDataPayload(); - - $plugin->refresh(); - - expect($plugin->data_payload)->toHaveKey('cake'); - expect($plugin->data_payload['cake'])->toHaveKey('icing'); - expect($plugin->data_payload['cake']['icing']['ontop'])->toBe('Cherry'); -}); - test('plugin parses JSON-parsable response body as JSON', function (): void { $jsonContent = '{"title": "Test Data", "items": [1, 2, 3]}'; @@ -191,8 +164,8 @@ test('plugin handles multiple URLs with mixed content types', function (): void expect($plugin->data_payload['IDX_0'])->toBe($jsonResponse); // Second URL should be XML wrapped under rss - expect($plugin->data_payload['IDX_1'])->toHaveKey('root'); - expect($plugin->data_payload['IDX_1']['root']['item'])->toBe('XML Data'); + expect($plugin->data_payload['IDX_1'])->toHaveKey('rss'); + expect($plugin->data_payload['IDX_1']['rss']['item'])->toBe('XML Data'); }); test('plugin handles POST requests with XML responses', function (): void { @@ -213,11 +186,11 @@ test('plugin handles POST requests with XML responses', function (): void { $plugin->refresh(); - expect($plugin->data_payload)->toHaveKey('response'); - expect($plugin->data_payload['response'])->toHaveKey('status'); - expect($plugin->data_payload['response'])->toHaveKey('data'); - expect($plugin->data_payload['response']['status'])->toBe('success'); - expect($plugin->data_payload['response']['data'])->toBe('test'); + expect($plugin->data_payload)->toHaveKey('rss'); + expect($plugin->data_payload['rss'])->toHaveKey('status'); + expect($plugin->data_payload['rss'])->toHaveKey('data'); + expect($plugin->data_payload['rss']['status'])->toBe('success'); + expect($plugin->data_payload['rss']['data'])->toBe('test'); }); test('plugin parses iCal responses and filters to recent window', function (): void { diff --git a/tests/Feature/Plugins/Ical/IcalParserTest.php b/tests/Feature/Plugins/Ical/IcalParserTest.php deleted file mode 100644 index a394274..0000000 --- a/tests/Feature/Plugins/Ical/IcalParserTest.php +++ /dev/null @@ -1,163 +0,0 @@ - Http::response($icalContent, 200, ['Content-Type' => 'text/calendar']), - ]); - - $plugin = Plugin::factory()->create([ - 'data_strategy' => 'polling', - 'polling_url' => 'https://example.com/calendar.ics', - 'polling_verb' => 'get', - ]); - - $plugin->updateDataPayload(); - $plugin->refresh(); - - expect($plugin->data_payload)->not->toHaveKey('error'); - expect($plugin->data_payload)->toHaveKey('ical'); - expect($plugin->data_payload['ical'])->toHaveCount(1); - expect($plugin->data_payload['ical'][0]['SUMMARY'])->toBe('Meeting'); - - Carbon::setTestNow(); -}); - -test('iCal plugin parses recurring events with multiple BYDAY correctly', function (): void { - // Set test now to Monday 2024-03-25 - Carbon::setTestNow(Carbon::parse('2024-03-25 12:00:00', 'UTC')); - - $icalContent = <<<'ICS' -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//Example Corp.//EN -BEGIN:VEVENT -DESCRIPTION:XXX-REDACTED -RRULE:FREQ=WEEKLY;UNTIL=20250604T220000Z;INTERVAL=1;BYDAY=TU,TH;WKST=MO -UID:040000008200E00074C5B7101A82E00800000000E07AF34F937EDA01000000000000000 - 01000000061F3E918C753424E8154B36E55452933 -SUMMARY:Recurring Meeting -DTSTART;VALUE=DATE:20240326 -DTEND;VALUE=DATE:20240327 -DTSTAMP:20240605T082436Z -CLASS:PUBLIC -STATUS:CONFIRMED -END:VEVENT -END:VCALENDAR -ICS; - - Http::fake([ - 'example.com/recurring.ics' => Http::response($icalContent, 200, ['Content-Type' => 'text/calendar']), - ]); - - $plugin = Plugin::factory()->create([ - 'data_strategy' => 'polling', - 'polling_url' => 'https://example.com/recurring.ics', - 'polling_verb' => 'get', - ]); - - $plugin->updateDataPayload(); - $plugin->refresh(); - - $ical = $plugin->data_payload['ical']; - - // Week of March 25, 2024: - // Tue March 26: 2024-03-26 (DTSTART) - // Thu March 28: 2024-03-28 (Recurrence) - - // The parser window is now-7 days to now+30 days. - // Window: 2024-03-18 to 2024-04-24. - - $summaries = collect($ical)->pluck('SUMMARY'); - expect($summaries)->toContain('Recurring Meeting'); - - $dates = collect($ical)->map(fn ($event) => Carbon::parse($event['DTSTART'])->format('Y-m-d'))->values(); - - // Check if Tuesday March 26 is present - expect($dates)->toContain('2024-03-26'); - - // Check if Thursday March 28 is present (THIS IS WHERE IT IS EXPECTED TO FAIL BASED ON THE ISSUE) - expect($dates)->toContain('2024-03-28'); - - Carbon::setTestNow(); -}); - -test('iCal plugin parses recurring events with multiple BYDAY and specific DTSTART correctly', function (): void { - // Set test now to Monday 2024-03-25 - Carbon::setTestNow(Carbon::parse('2024-03-25 12:00:00', 'UTC')); - - $icalContent = <<<'ICS' -BEGIN:VCALENDAR -VERSION:2.0 -X-WR-TIMEZONE:UTC -PRODID:-//Example Corp.//EN -BEGIN:VEVENT -RRULE:FREQ=WEEKLY;UNTIL=20250604T220000Z;INTERVAL=1;BYDAY=TU,TH;WKST=MO -UID:recurring-event-2 -SUMMARY:Recurring Meeting 2 -DTSTART:20240326T100000 -DTEND:20240326T110000 -DTSTAMP:20240605T082436Z -END:VEVENT -END:VCALENDAR -ICS; - - Http::fake([ - 'example.com/recurring2.ics' => Http::response($icalContent, 200, ['Content-Type' => 'text/calendar']), - ]); - - $plugin = Plugin::factory()->create([ - 'data_strategy' => 'polling', - 'polling_url' => 'https://example.com/recurring2.ics', - 'polling_verb' => 'get', - ]); - - $plugin->updateDataPayload(); - $plugin->refresh(); - - $ical = $plugin->data_payload['ical']; - $dates = collect($ical)->map(fn ($event) => Carbon::parse($event['DTSTART'])->format('Y-m-d'))->values(); - - expect($dates)->toContain('2024-03-26'); - expect($dates)->toContain('2024-03-28'); - - Carbon::setTestNow(); -}); diff --git a/tests/Feature/ScreenCssVariablesTest.php b/tests/Feature/ScreenCssVariablesTest.php deleted file mode 100644 index f5bfc12..0000000 --- a/tests/Feature/ScreenCssVariablesTest.php +++ /dev/null @@ -1,100 +0,0 @@ - '
test
', - 'cssVariables' => [ - '--screen-w' => '800px', - '--screen-h' => '480px', - ], - ])->render(); - - expect($html)->toContain(':root'); - expect($html)->toContain('--screen-w: 800px'); - expect($html)->toContain('--screen-h: 480px'); -}); - -test('DeviceModel css_variables attribute merges --screen-w and --screen-h from dimensions when not set', function (): void { - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'css_variables' => null, - ]); - - $vars = $deviceModel->css_variables; - - expect($vars)->toHaveKey('--screen-w', '800px'); - expect($vars)->toHaveKey('--screen-h', '480px'); -}); - -test('DeviceModel css_variables attribute does not override --screen-w and --screen-h when already set', function (): void { - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'css_variables' => [ - '--screen-w' => '1200px', - '--screen-h' => '900px', - ], - ]); - - $vars = $deviceModel->css_variables; - - expect($vars['--screen-w'])->toBe('1200px'); - expect($vars['--screen-h'])->toBe('900px'); -}); - -test('DeviceModel css_variables attribute fills only missing --screen-w or --screen-h from dimensions', function (): void { - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'css_variables' => [ - '--screen-w' => '640px', - ], - ]); - - $vars = $deviceModel->css_variables; - - expect($vars['--screen-w'])->toBe('640px'); - expect($vars['--screen-h'])->toBe('480px'); -}); - -test('DeviceModel css_variables attribute returns raw vars when strategy is not v2', function (): void { - Config::set('app.puppeteer_window_size_strategy', 'v1'); - - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'css_variables' => ['--custom' => 'value'], - ]); - - $vars = $deviceModel->css_variables; - - expect($vars)->toBe(['--custom' => 'value']); -}); - -test('device model css_variables are available via device relationship for rendering', function (): void { - Config::set('app.puppeteer_window_size_strategy', 'v2'); - - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'css_variables' => null, - ]); - $device = Device::factory()->create([ - 'device_model_id' => $deviceModel->id, - ]); - $device->load('deviceModel'); - - $vars = $device->deviceModel?->css_variables ?? []; - - expect($vars)->toHaveKey('--screen-w', '800px'); - expect($vars)->toHaveKey('--screen-h', '480px'); -}); diff --git a/tests/Unit/Models/DeviceModelTest.php b/tests/Unit/Models/DeviceModelTest.php index f2ef29d..8c2b6e9 100644 --- a/tests/Unit/Models/DeviceModelTest.php +++ b/tests/Unit/Models/DeviceModelTest.php @@ -3,7 +3,6 @@ declare(strict_types=1); use App\Models\DeviceModel; -use Illuminate\Support\Facades\Config; test('device model has required attributes', function (): void { $deviceModel = DeviceModel::factory()->create([ @@ -118,27 +117,3 @@ test('device model factory creates valid data', function (): void { expect($deviceModel->offset_x)->toBeInt(); expect($deviceModel->offset_y)->toBeInt(); }); - -test('css_name returns og when puppeteer_window_size_strategy is v1', function (): void { - Config::set('app.puppeteer_window_size_strategy', 'v1'); - - $deviceModel = DeviceModel::factory()->create(['css_name' => 'my_device']); - - expect($deviceModel->css_name)->toBe('og'); -}); - -test('css_name returns db value when puppeteer_window_size_strategy is v2', function (): void { - Config::set('app.puppeteer_window_size_strategy', 'v2'); - - $deviceModel = DeviceModel::factory()->create(['css_name' => 'my_device']); - - expect($deviceModel->css_name)->toBe('my_device'); -}); - -test('css_name returns null when puppeteer_window_size_strategy is v2 and db value is null', function (): void { - Config::set('app.puppeteer_window_size_strategy', 'v2'); - - $deviceModel = DeviceModel::factory()->create(['css_name' => null]); - - expect($deviceModel->css_name)->toBeNull(); -}); diff --git a/tests/Unit/Models/PluginTest.php b/tests/Unit/Models/PluginTest.php index 1e2cda2..749fb62 100644 --- a/tests/Unit/Models/PluginTest.php +++ b/tests/Unit/Models/PluginTest.php @@ -72,27 +72,6 @@ test('updateDataPayload sends POST request with body when polling_verb is post', $request->body() === '{"query": "query { user { id name } }"}'); }); -test('updateDataPayload sends POST request with body with correct content type when not JSON content', function (): void { - Http::fake([ - 'https://example.com/api' => Http::response(['success' => true], 200), - ]); - - $plugin = Plugin::factory()->create([ - 'data_strategy' => 'polling', - 'polling_url' => 'https://example.com/api', - 'polling_verb' => 'post', - 'polling_body' => '', - 'polling_header' => 'Content-Type: text/xml' - ]); - - $plugin->updateDataPayload(); - - Http::assertSent(fn ($request): bool => $request->url() === 'https://example.com/api' && - $request->method() === 'POST' && - $request->hasHeader('Content-Type', 'text/xml') && - $request->body() === ''); -}); - test('updateDataPayload handles multiple URLs with IDX_ prefixes', function (): void { $plugin = Plugin::factory()->create([ 'data_strategy' => 'polling', @@ -824,7 +803,7 @@ test('plugin duplicate copies all attributes except id and uuid', function (): v expect($duplicate->id)->not->toBe($original->id) ->and($duplicate->uuid)->not->toBe($original->uuid) - ->and($duplicate->name)->toBe('Original Plugin_copy') + ->and($duplicate->name)->toBe('Original Plugin (Copy)') ->and($duplicate->user_id)->toBe($original->user_id) ->and($duplicate->data_stale_minutes)->toBe($original->data_stale_minutes) ->and($duplicate->data_strategy)->toBe($original->data_strategy) @@ -859,7 +838,7 @@ test('plugin duplicate sets trmnlp_id to null to avoid unique constraint violati expect($duplicate->trmnlp_id)->toBeNull() ->and($original->trmnlp_id)->toBe('test-trmnlp-id-123') - ->and($duplicate->name)->toBe('Plugin with trmnlp_id_copy'); + ->and($duplicate->name)->toBe('Plugin with trmnlp_id (Copy)'); }); test('plugin duplicate copies render_markup_view file content to render_markup', function (): void { @@ -890,7 +869,7 @@ test('plugin duplicate copies render_markup_view file content to render_markup', expect($duplicate->render_markup)->toBe($testContent) ->and($duplicate->markup_language)->toBe('blade') ->and($duplicate->render_markup_view)->toBeNull() - ->and($duplicate->name)->toBe('View Plugin_copy'); + ->and($duplicate->name)->toBe('View Plugin (Copy)'); } finally { // Clean up test file if (file_exists($testViewPath)) { @@ -949,7 +928,7 @@ test('plugin duplicate handles missing view file gracefully', function (): void $duplicate = $original->duplicate(); expect($duplicate->render_markup_view)->toBeNull() - ->and($duplicate->name)->toBe('Missing View Plugin_copy'); + ->and($duplicate->name)->toBe('Missing View Plugin (Copy)'); }); test('plugin duplicate uses provided user_id', function (): void { diff --git a/tests/Unit/Services/ImageGenerationServiceTest.php b/tests/Unit/Services/ImageGenerationServiceTest.php index da9bef9..5e3dc47 100644 --- a/tests/Unit/Services/ImageGenerationServiceTest.php +++ b/tests/Unit/Services/ImageGenerationServiceTest.php @@ -176,15 +176,37 @@ it('cleanup_folder identifies active images correctly', function (): void { expect($activeImageUuids)->not->toContain(null); }); -it('reset_if_not_cacheable does not reset recipe cache when other devices exist', function (): void { - // Cache validity is now determined at use-time via metadata - $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid', 'plugin_type' => 'recipe']); - Device::factory()->create(['device_model_id' => DeviceModel::factory()->create()->id]); +it('reset_if_not_cacheable detects device models', function (): void { + // Create a plugin + $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid']); + // Create a device with DeviceModel + Device::factory()->create([ + 'device_model_id' => DeviceModel::factory()->create()->id, + ]); + + // Test that the method detects DeviceModels and resets cache ImageGenerationService::resetIfNotCacheable($plugin); $plugin->refresh(); - expect($plugin->current_image)->toBe('test-uuid'); + expect($plugin->current_image)->toBeNull(); +}); + +it('reset_if_not_cacheable detects custom dimensions', function (): void { + // Create a plugin + $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid']); + + // Create a device with custom dimensions + Device::factory()->create([ + 'width' => 1024, // Different from default 800 + 'height' => 768, // Different from default 480 + ]); + + // Test that the method detects custom dimensions and resets cache + ImageGenerationService::resetIfNotCacheable($plugin); + + $plugin->refresh(); + expect($plugin->current_image)->toBeNull(); }); it('reset_if_not_cacheable preserves cache for standard devices', function (): void { @@ -236,21 +258,26 @@ it('reset_if_not_cacheable preserves cache for og_png and og_plus device models' expect($plugin->current_image)->toBe('test-uuid'); }); -it('reset_if_not_cacheable does not reset cache for non-standard device models', function (): void { - // Cache is now validated at use-time via metadata comparison - $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid', 'plugin_type' => 'recipe']); +it('reset_if_not_cacheable resets cache for non-standard device models', function (): void { + // Create a plugin + $plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid']); + + // Create a non-standard device model (e.g., kindle) $kindleModel = DeviceModel::factory()->create([ 'name' => 'test_amazon_kindle_2024', 'width' => 1400, 'height' => 840, 'rotation' => 90, ]); + + // Create a device with the non-standard device model Device::factory()->create(['device_model_id' => $kindleModel->id]); + // Test that the method resets cache for non-standard device models ImageGenerationService::resetIfNotCacheable($plugin); $plugin->refresh(); - expect($plugin->current_image)->toBe('test-uuid'); + expect($plugin->current_image)->toBeNull(); }); it('reset_if_not_cacheable handles null plugin', function (): void {