diff --git a/README.md b/README.md index 8670e9c76..139112a55 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ Special thanks to our biggest sponsors! * [Saasykit](https://saasykit.com/?ref=coolify.io) - A Laravel-based boilerplate providing essential components and features for building SaaS applications quickly. * [Massivegrid](https://massivegrid.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. * [LiquidWeb](https://liquidweb.com/?utm_source=coolify.io) - A Fast web hosting provider. +* [Supadata AI](https://supadata.ai/?ref=coolify.io) - Scrape YouTube, web, and files. Get AI-ready, clean data for your next project. +* [WZ-IT](https://wz-it.com/?ref=coolify.io) - German agency for customised cloud solutions, migration, managed services and open source hosting, specialising in consulting and implementation of tailor-made cloud infrastructures for SMEs. ## Github Sponsors ($40+) diff --git a/app/Jobs/CleanupInstanceStuffsJob.php b/app/Jobs/CleanupInstanceStuffsJob.php index 84f14ed02..008492342 100644 --- a/app/Jobs/CleanupInstanceStuffsJob.php +++ b/app/Jobs/CleanupInstanceStuffsJob.php @@ -17,11 +17,13 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + public $timeout = 60; + public function __construct() {} public function middleware(): array { - return [(new WithoutOverlapping('cleanup-instance-stuffs'))->dontRelease()]; + return [(new WithoutOverlapping('cleanup-instance-stuffs'))->expireAfter(60)]; } public function handle(): void diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php index 05a4aa8de..7e246649d 100644 --- a/app/Jobs/DockerCleanupJob.php +++ b/app/Jobs/DockerCleanupJob.php @@ -31,7 +31,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(600)]; } public function __construct(public Server $server, public bool $manualCleanup = false) {} diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 93b203fcb..4d40240f9 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -71,7 +71,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(30)]; } public function backoff(): int diff --git a/app/Jobs/RestartProxyJob.php b/app/Jobs/RestartProxyJob.php index 7fc716f70..4e1ade0da 100644 --- a/app/Jobs/RestartProxyJob.php +++ b/app/Jobs/RestartProxyJob.php @@ -24,7 +24,7 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(60)]; } public function __construct(public Server $server) {} diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php index 9818d5c6a..ffa298390 100644 --- a/app/Jobs/ServerCheckJob.php +++ b/app/Jobs/ServerCheckJob.php @@ -28,7 +28,7 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(60)]; } public function __construct(public Server $server) {} diff --git a/app/Models/Application.php b/app/Models/Application.php index 2feaebf94..4ee41651d 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -455,22 +455,23 @@ class Application extends BaseModel { return Attribute::make( get: function () { + $base_dir = $this->base_directory ?? '/'; if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) { if (str($this->git_repository)->contains('bitbucket')) { - return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}"; + return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}{$base_dir}"; } - return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}"; + return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}{$base_dir}"; } // Convert the SSH URL to HTTPS URL if (strpos($this->git_repository, 'git@') === 0) { $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository); if (str($this->git_repository)->contains('bitbucket')) { - return "https://{$git_repository}/src/{$this->git_branch}"; + return "https://{$git_repository}/src/{$this->git_branch}{$base_dir}"; } - return "https://{$git_repository}/tree/{$this->git_branch}"; + return "https://{$git_repository}/tree/{$this->git_branch}{$base_dir}"; } return $this->git_repository; diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 72b92e95a..aa821dc22 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -3014,168 +3014,159 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int $savedService->image = $image; $savedService->save(); } + } + $environment = collect(data_get($service, 'environment', [])); + $buildArgs = collect(data_get($service, 'build.args', [])); + $environment = $environment->merge($buildArgs); - $environment = collect(data_get($service, 'environment', [])); - $buildArgs = collect(data_get($service, 'build.args', [])); - $environment = $environment->merge($buildArgs); + // convert environment variables to one format + $environment = convertToKeyValueCollection($environment); - // convert environment variables to one format - $environment = convertToKeyValueCollection($environment); + // Add Coolify defined environments + $allEnvironments = $resource->environment_variables()->get(['key', 'value']); - // Add Coolify defined environments - $allEnvironments = $resource->environment_variables()->get(['key', 'value']); + $allEnvironments = $allEnvironments->mapWithKeys(function ($item) { + return [$item['key'] => $item['value']]; + }); + // filter and add magic environments + foreach ($environment as $key => $value) { + // Get all SERVICE_ variables from keys and values + $key = str($key); + $value = str($value); - $allEnvironments = $allEnvironments->mapWithKeys(function ($item) { - return [$item['key'] => $item['value']]; - }); - // filter and add magic environments - foreach ($environment as $key => $value) { - // Get all SERVICE_ variables from keys and values - $key = str($key); - $value = str($value); - - $regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/'; - preg_match_all($regex, $value, $valueMatches); - if (count($valueMatches[1]) > 0) { - foreach ($valueMatches[1] as $match) { - $match = replaceVariables($match); - if ($match->startsWith('SERVICE_')) { - if ($magicEnvironments->has($match->value())) { - continue; - } - $magicEnvironments->put($match->value(), ''); + $regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/'; + preg_match_all($regex, $value, $valueMatches); + if (count($valueMatches[1]) > 0) { + foreach ($valueMatches[1] as $match) { + $match = replaceVariables($match); + if ($match->startsWith('SERVICE_')) { + if ($magicEnvironments->has($match->value())) { + continue; } - } - } - - // Get magic environments where we need to preset the FQDN - if ($key->startsWith('SERVICE_FQDN_')) { - // SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000 - if (substr_count(str($key)->value(), '_') === 3) { - $fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value(); - $port = $key->afterLast('_')->value(); - } else { - $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); - $port = null; - } - if ($isApplication) { - $fqdn = generateFqdn($server, "{$resource->name}-$uuid"); - } elseif ($isService) { - if ($fqdnFor) { - $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); - } else { - $fqdn = generateFqdn($server, "{$savedService->name}-$uuid"); - } - } - - if ($value && get_class($value) === \Illuminate\Support\Stringable::class && $value->startsWith('/')) { - $path = $value->value(); - if ($path !== '/') { - $fqdn = "$fqdn$path"; - } - } - $fqdnWithPort = $fqdn; - if ($port) { - $fqdnWithPort = "$fqdn:$port"; - } - if ($isApplication && is_null($resource->fqdn)) { - data_forget($resource, 'environment_variables'); - data_forget($resource, 'environment_variables_preview'); - $resource->fqdn = $fqdnWithPort; - $resource->save(); - } elseif ($isService && is_null($savedService->fqdn)) { - $savedService->fqdn = $fqdnWithPort; - $savedService->save(); - } - - if (substr_count(str($key)->value(), '_') === 2) { - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); - } - if (substr_count(str($key)->value(), '_') === 3) { - $newKey = str($key)->beforeLast('_'); - $resource->environment_variables()->firstOrCreate([ - 'key' => $newKey->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); + $magicEnvironments->put($match->value(), ''); } } } - $allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments); - if ($magicEnvironments->count() > 0) { - foreach ($magicEnvironments as $key => $value) { - $key = str($key); - $value = replaceVariables($value); - $command = parseCommandFromMagicEnvVariable($key); - $found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first(); - if ($found) { - continue; - } - if ($command->value() === 'FQDN') { - $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); - if (str($fqdnFor)->contains('_')) { - $fqdnFor = str($fqdnFor)->before('_'); - } - if ($isApplication) { - $fqdn = generateFqdn($server, "{$resource->name}-$uuid"); - } elseif ($isService) { - $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); - } - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); - } elseif ($command->value() === 'URL') { - $fqdnFor = $key->after('SERVICE_URL_')->lower()->value(); - if (str($fqdnFor)->contains('_')) { - $fqdnFor = str($fqdnFor)->before('_'); - } - if ($isApplication) { - $fqdn = generateFqdn($server, "{$resource->name}-$uuid"); - } elseif ($isService) { - $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); - } - $fqdn = str($fqdn)->replace('http://', '')->replace('https://', ''); - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); + // Get magic environments where we need to preset the FQDN + if ($key->startsWith('SERVICE_FQDN_')) { + // SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000 + if (substr_count(str($key)->value(), '_') === 3) { + $fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value(); + $port = $key->afterLast('_')->value(); + } else { + $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); + $port = null; + } + if ($isApplication) { + $fqdn = generateFqdn($server, "$uuid"); + } elseif ($isService) { + if ($fqdnFor) { + $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); } else { - $value = generateEnvValue($command, $resource); - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $value, - 'is_build_time' => false, - 'is_preview' => false, - ]); + $fqdn = generateFqdn($server, "{$savedService->name}-$uuid"); } } + + if ($value && get_class($value) === \Illuminate\Support\Stringable::class && $value->startsWith('/')) { + $path = $value->value(); + if ($path !== '/') { + $fqdn = "$fqdn$path"; + } + } + $fqdnWithPort = $fqdn; + if ($port) { + $fqdnWithPort = "$fqdn:$port"; + } + if ($isApplication && is_null($resource->fqdn)) { + data_forget($resource, 'environment_variables'); + data_forget($resource, 'environment_variables_preview'); + $resource->fqdn = $fqdnWithPort; + $resource->save(); + } elseif ($isService && is_null($savedService->fqdn)) { + $savedService->fqdn = $fqdnWithPort; + $savedService->save(); + } + + if (substr_count(str($key)->value(), '_') === 2) { + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } + if (substr_count(str($key)->value(), '_') === 3) { + $newKey = str($key)->beforeLast('_'); + $resource->environment_variables()->firstOrCreate([ + 'key' => $newKey->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } + } + } + + $allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments); + if ($magicEnvironments->count() > 0) { + foreach ($magicEnvironments as $key => $value) { + $key = str($key); + $value = replaceVariables($value); + $command = parseCommandFromMagicEnvVariable($key); + $found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first(); + if ($found) { + continue; + } + if ($command->value() === 'FQDN') { + $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); + if (str($fqdnFor)->contains('_')) { + $fqdnFor = str($fqdnFor)->before('_'); + } + $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } elseif ($command->value() === 'URL') { + $fqdnFor = $key->after('SERVICE_URL_')->lower()->value(); + if (str($fqdnFor)->contains('_')) { + $fqdnFor = str($fqdnFor)->before('_'); + } + $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); + $fqdn = str($fqdn)->replace('http://', '')->replace('https://', ''); + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } else { + $value = generateEnvValue($command, $resource); + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $value, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } } } } diff --git a/config/constants.php b/config/constants.php index e7c7b68b9..c057a85db 100644 --- a/config/constants.php +++ b/config/constants.php @@ -2,7 +2,7 @@ return [ 'coolify' => [ - 'version' => '4.0.0-beta.409', + 'version' => '4.0.0-beta.410', 'helper_version' => '1.0.8', 'realtime_version' => '1.0.7', 'self_hosted' => env('SELF_HOSTED', true), diff --git a/other/nightly/versions.json b/other/nightly/versions.json index e940b635b..43fa56cca 100644 --- a/other/nightly/versions.json +++ b/other/nightly/versions.json @@ -1,10 +1,10 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.409" + "version": "4.0.0-beta.410" }, "nightly": { - "version": "4.0.0-beta.410" + "version": "4.0.0-beta.411" }, "helper": { "version": "1.0.8" diff --git a/resources/views/livewire/project/service/navbar.blade.php b/resources/views/livewire/project/service/navbar.blade.php index 7424f0940..3f3984116 100644 --- a/resources/views/livewire/project/service/navbar.blade.php +++ b/resources/views/livewire/project/service/navbar.blade.php @@ -129,7 +129,7 @@
Unable to deploy. + href="{{ route('project.service.environment-variables', $parameters) }}" wire:navigate> Required environment variables missing.
diff --git a/templates/compose/plausible.yaml b/templates/compose/plausible.yaml index 71dfbe378..9bbacc508 100644 --- a/templates/compose/plausible.yaml +++ b/templates/compose/plausible.yaml @@ -6,7 +6,7 @@ services: plausible: - image: "ghcr.io/plausible/community-edition:v2.1.4" + image: "ghcr.io/plausible/community-edition:v3.0.1" command: 'sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"' environment: - SERVICE_FQDN_PLAUSIBLE @@ -17,13 +17,19 @@ services: - TOTP_VAULT_KEY=${SERVICE_REALBASE64_32_TOTP} - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID} - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET} + - MAILER_ADAPTER=${MAILER_ADAPTER:-Bamboo.LocalAdapter} + - MAILER_EMAIL=${MAILER_EMAIL} + - MAILER_NAME=${MAILER_NAME} + - SMTP_HOST_ADDR=${SMTP_HOST_ADDR} + - SMTP_HOST_PORT=${SMTP_HOST_PORT} + - SMTP_USER_NAME=${SMTP_USER_NAME} + - SMTP_USER_PWD=${SMTP_USER_PWD} + - SMTP_HOST_SSL_ENABLED=${SMTP_HOST_SSL_ENABLED} depends_on: plausible-db: condition: service_healthy plausible-events-db: condition: service_healthy - mail: - condition: service_healthy healthcheck: test: [ @@ -39,15 +45,6 @@ services: retries: 5 start_period: 45s - mail: - image: bytemark/smtp - platform: linux/amd64 - healthcheck: - test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/25' || exit 1"] - interval: 5s - timeout: 10s - retries: 20 - plausible-db: image: "postgres:16-alpine" volumes: @@ -63,7 +60,9 @@ services: retries: 10 plausible-events-db: - image: "clickhouse/clickhouse-server:24.3.3.102-alpine" + image: "clickhouse/clickhouse-server:24.12-alpine" + environment: + - CLICKHOUSE_SKIP_USER_SETUP=1 volumes: - plausible-events-data:/var/lib/clickhouse - type: bind diff --git a/templates/compose/unsend.yaml b/templates/compose/unsend.yaml index 649b7f704..32323f4bb 100644 --- a/templates/compose/unsend.yaml +++ b/templates/compose/unsend.yaml @@ -35,6 +35,8 @@ services: unsend: image: unsend/unsend:latest + expose: + - 3000 environment: - SERVICE_FQDN_UNSEND_3000 - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${SERVICE_DB_POSTGRES:-unsend} @@ -48,13 +50,14 @@ services: - REDIS_URL=redis://redis:6379 - NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false} - API_RATE_LIMIT=${API_RATE_LIMIT:-1} + - HOSTNAME=0.0.0.0 depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: - test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:3000 || exit 1" ] + test: [ "CMD-SHELL", "wget -qO- http://unsend:3000 || exit 1" ] interval: 5s retries: 10 timeout: 2s diff --git a/templates/service-templates.json b/templates/service-templates.json index 0ee5ddb51..be30cba5c 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -563,7 +563,7 @@ "minversion": "0.0.0", "port": "8080" }, - "denokv": { + "denoKV": { "documentation": "https://docs.deno.com/deploy/kv/manual/?utm_source=coolify.io", "slogan": "The Denoland key-value database", "compose": "c2VydmljZXM6CiAgZGVub2t2OgogICAgaW1hZ2U6ICdnaGNyLmlvL2Rlbm9sYW5kL2Rlbm9rdjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnQUNDRVNTX1RPS0VOPSR7U0VSVklDRV9QQVNTV09SRF9ERU5PS1Z9JwogICAgICAtIFNFUlZJQ0VfRlFETl9ERU5PS1ZfNDUxMgogICAgdm9sdW1lczoKICAgICAgLSAnJHtDT09MSUZZX1ZPTFVNRV9BUFB9Oi9kYXRhJwogICAgY29tbWFuZDogJy0tc3FsaXRlLXBhdGggL2RhdGEvZGVub2t2LnNxbGl0ZSBzZXJ2ZSAtLWFjY2Vzcy10b2tlbiAke1NFUlZJQ0VfUEFTU1dPUkRfREVOT0tWfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBuYwogICAgICAgIC0gJy16dicKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJzQ1MTInCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAzCg==", @@ -3083,7 +3083,7 @@ "unsend": { "documentation": "https://docs.unsend.dev/get-started/self-hosting?utm_source=coolify.io", "slogan": "Unsend is an open-source alternative to Resend, Sendgrid, Mailgun and Postmark etc.", - "compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1VOU0VORF8zMDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9VTlNFTkR9JwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF82NF9ORVhUQVVUSFNFQ1JFVH0nCiAgICAgIC0gJ0FXU19BQ0NFU1NfS0VZPSR7QVdTX0FDQ0VTU19LRVk6P30nCiAgICAgIC0gJ0FXU19TRUNSRVRfS0VZPSR7QVdTX1NFQ1JFVF9LRVk6P30nCiAgICAgIC0gJ0FXU19ERUZBVUxUX1JFR0lPTj0ke0FXU19ERUZBVUxUX1JFR0lPTjo/fScKICAgICAgLSAnR0lUSFVCX0lEPSR7R0lUSFVCX0lEfScKICAgICAgLSAnR0lUSFVCX1NFQ1JFVD0ke0dJVEhVQl9TRUNSRVR9JwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9yZWRpczo2Mzc5JwogICAgICAtICdORVhUX1BVQkxJQ19JU19DTE9VRD0ke05FWFRfUFVCTElDX0lTX0NMT1VEOi1mYWxzZX0nCiAgICAgIC0gJ0FQSV9SQVRFX0xJTUlUPSR7QVBJX1JBVEVfTElNSVQ6LTF9JwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtcU8tIGh0dHA6Ly8xMjcuMC4wLjE6MzAwMCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiA1cwogICAgICByZXRyaWVzOiAxMAogICAgICB0aW1lb3V0OiAycwo=", + "compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZXhwb3NlOgogICAgICAtIDMwMDAKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9VTlNFTkRfMzAwMAogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtTRVJWSUNFX0RCX1BPU1RHUkVTOi11bnNlbmR9JwogICAgICAtICdORVhUQVVUSF9VUkw9JHtTRVJWSUNFX0ZRRE5fVU5TRU5EfScKICAgICAgLSAnTkVYVEFVVEhfU0VDUkVUPSR7U0VSVklDRV9CQVNFNjRfNjRfTkVYVEFVVEhTRUNSRVR9JwogICAgICAtICdBV1NfQUNDRVNTX0tFWT0ke0FXU19BQ0NFU1NfS0VZOj99JwogICAgICAtICdBV1NfU0VDUkVUX0tFWT0ke0FXU19TRUNSRVRfS0VZOj99JwogICAgICAtICdBV1NfREVGQVVMVF9SRUdJT049JHtBV1NfREVGQVVMVF9SRUdJT046P30nCiAgICAgIC0gJ0dJVEhVQl9JRD0ke0dJVEhVQl9JRH0nCiAgICAgIC0gJ0dJVEhVQl9TRUNSRVQ9JHtHSVRIVUJfU0VDUkVUfScKICAgICAgLSAnUkVESVNfVVJMPXJlZGlzOi8vcmVkaXM6NjM3OScKICAgICAgLSAnTkVYVF9QVUJMSUNfSVNfQ0xPVUQ9JHtORVhUX1BVQkxJQ19JU19DTE9VRDotZmFsc2V9JwogICAgICAtICdBUElfUkFURV9MSU1JVD0ke0FQSV9SQVRFX0xJTUlUOi0xfScKICAgICAgLSBIT1NUTkFNRT0wLjAuMC4wCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC1xTy0gaHR0cDovL3Vuc2VuZDozMDAwIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHRpbWVvdXQ6IDJzCg==", "tags": [ "resend", "mailer", diff --git a/versions.json b/versions.json index e940b635b..43fa56cca 100644 --- a/versions.json +++ b/versions.json @@ -1,10 +1,10 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.409" + "version": "4.0.0-beta.410" }, "nightly": { - "version": "4.0.0-beta.410" + "version": "4.0.0-beta.411" }, "helper": { "version": "1.0.8"