diff --git a/config.ini.example b/config.ini.example
index cbb9edd8d8d7961ddbf87cc4f401de33e41fd47c..18f874d8319afa3ba56ec7d2c7c090f55350b871 100644
--- a/config.ini.example
+++ b/config.ini.example
@@ -1,6 +1,6 @@
 [app]
 env = development
-esbuild_metafile = esbuild-meta-app.json
+esbuild_metafile = %DM_ROOT%/esbuild-meta-app.json
 scheme = https
 url = http://localhost:9501
 
@@ -15,6 +15,10 @@ default[log_queries] = false
 default[pool_prefill] = false
 default[pool_size] = 8
 
+[grpc]
+grpc_php_plugin_bin = %DM_ROOT%/grpc_php_plugin
+protoc_bin = /usr/bin/protoc
+
 [llamacpp]
 host = 127.0.0.1
 port = 8081
@@ -32,10 +36,10 @@ background_color = "#ffffff"
 theme_color = "#ffffff"
 
 [oauth2]
-encryption_key = oauth2/defuse.key
+encryption_key = %DM_ROOT%/oauth2/defuse.key
 jwt_signing_key_passphrase = yourpassphrase
-jwt_signing_key_private = oauth2/private.key
-jwt_signing_key_public = oauth2/public.key
+jwt_signing_key_private = %DM_ROOT%/oauth2/private.key
+jwt_signing_key_public = %DM_ROOT%/oauth2/public.key
 session_key_authorization_request = oauth2.authorization_request
 session_key_pkce = oauth2.pkce
 session_key_state = oauth2.state
@@ -61,25 +65,25 @@ cookie_name = dmsession
 redis_connection_pool = default
 
 [sqlite-vss]
-extension_vector0 = vector0.so
-extension_vss0 = vss0.so
+extension_vector0 = %DM_ROOT%/vector0.so
+extension_vss0 = %DM_ROOT%/vss0.so
 
 [static]
 base_url = https://resonance.distantmagic.com
-esbuild_metafile = esbuild-meta-docs.json
+esbuild_metafile = %DM_ROOT%/esbuild-meta-docs.json
 input_directory = docs
-output_directory = docs/build
-sitemap = docs/build/sitemap.xml
+output_directory = %DM_ROOT%/docs/build
+sitemap = %DM_ROOT%/docs/build/sitemap.xml
 
 [swoole]
 host = 127.0.0.1
 port = 9501
 log_level = SWOOLE_LOG_DEBUG
-ssl_cert_file = ssl/origin.crt
-ssl_key_file = ssl/origin.key
+ssl_cert_file = %DM_ROOT%/ssl/origin.crt
+ssl_key_file = %DM_ROOT%/ssl/origin.key
 
 [translator]
-base_directory = app/lang
+base_directory = %DM_APP_ROOT%/lang
 default_primary_language = en
 
 [websocket]
diff --git a/docs/pages/docs/changelog/index.md b/docs/pages/docs/changelog/index.md
index 56d230ec18d170a877199e611ead903e021dc2b7..5bb6603cdf168187d571bf0cc2ae2e655f02549d 100644
--- a/docs/pages/docs/changelog/index.md
+++ b/docs/pages/docs/changelog/index.md
@@ -10,10 +10,15 @@ title: Changelog
 
 # Changelog
 
+## v0.22.0
+
+- Change: switch to absolute paths in {{docs/features/configuration/index}}
+- Feature: interpolate some constants in {{docs/features/configuration/index}}
+
 ## v0.21.0
 
 - Feature: Doctrine {{docs/features/database/doctrine/events}} hooks
-- Improvements: OpenAPI reads return types from `Can` 
+- Improvement: OpenAPI reads return types from `Can` 
     {{docs/features/openapi/attributes/index}}
 
 ## v0.20.0
diff --git a/docs/pages/docs/features/configuration/index.md b/docs/pages/docs/features/configuration/index.md
index eb3920ce64b86deef501792cb83e140a3ae3e174..f76d7da90f138427b80f1d0a6d1b27f75c60b9c5 100644
--- a/docs/pages/docs/features/configuration/index.md
+++ b/docs/pages/docs/features/configuration/index.md
@@ -72,9 +72,9 @@ This is the default configuration file:
 ```ini file:config.ini
 [app]
 env = development
-esbuild_metafile = esbuild-meta-app.json
+esbuild_metafile = %DM_ROOT%/esbuild-meta-app.json
 scheme = https
-url = https://resonance.distantmagic.com
+url = http://localhost:9501
 
 [database]
 default[driver] = mysql
@@ -87,27 +87,31 @@ default[log_queries] = false
 default[pool_prefill] = false
 default[pool_size] = 8
 
+[grpc]
+grpc_php_plugin_bin = %DM_ROOT%/grpc_php_plugin
+protoc_bin = /usr/bin/protoc
+
 [llamacpp]
 host = 127.0.0.1
 port = 8081
 
 [mailer]
 default[transport_dsn] = smtp://localhost
-default[dkim_domain_name] = example.com
-default[dkim_selector] = resonance1
-default[dkim_signing_key_passphrase] = yourpassphrase
-default[dkim_signing_key_private] = dkim/private.key
-default[dkim_signing_key_public] = dkim/public.key
+; default[dkim_domain_name] = example.com
+; default[dkim_selector] = resonance1
+; default[dkim_signing_key_passphrase] = yourpassphrase
+; default[dkim_signing_key_private] = dkim/private.key
+; default[dkim_signing_key_public] = dkim/public.key
 
 [manifest]
 background_color = "#ffffff"
 theme_color = "#ffffff"
 
 [oauth2]
-encryption_key = oauth2/defuse.key
+encryption_key = %DM_ROOT%/oauth2/defuse.key
 jwt_signing_key_passphrase = yourpassphrase
-jwt_signing_key_private = oauth2/private.key
-jwt_signing_key_public = oauth2/public.key
+jwt_signing_key_private = %DM_ROOT%/oauth2/private.key
+jwt_signing_key_public = %DM_ROOT%/oauth2/public.key
 session_key_authorization_request = oauth2.authorization_request
 session_key_pkce = oauth2.pkce
 session_key_state = oauth2.state
@@ -120,7 +124,7 @@ version = 0.0.0
 [redis]
 default[db_index] = 0
 default[host] = 127.0.0.1
-default[password] =
+default[password] = null
 default[port] = 6379
 default[prefix] = dm:
 default[timeout] = 1
@@ -133,25 +137,25 @@ cookie_name = dmsession
 redis_connection_pool = default
 
 [sqlite-vss]
-extension_vector0 = vector0.so
-extension_vss0 = vss0.so
+extension_vector0 = %DM_ROOT%/vector0.so
+extension_vss0 = %DM_ROOT%/vss0.so
 
 [static]
 base_url = https://resonance.distantmagic.com
-esbuild_metafile = esbuild-meta-docs.json
+esbuild_metafile = %DM_ROOT%/esbuild-meta-docs.json
 input_directory = docs
-output_directory = docs/build
-sitemap = docs/build/sitemap.xml
+output_directory = %DM_ROOT%/docs/build
+sitemap = %DM_ROOT%/docs/build/sitemap.xml
 
 [swoole]
 host = 127.0.0.1
 port = 9501
 log_level = SWOOLE_LOG_DEBUG
-ssl_cert_file = ssl/origin.crt
-ssl_key_file = ssl/origin.key
+ssl_cert_file = %DM_ROOT%/ssl/origin.crt
+ssl_key_file = %DM_ROOT%/ssl/origin.key
 
 [translator]
-base_directory = app/lang
+base_directory = %DM_APP_ROOT%/lang
 default_primary_language = en
 
 [websocket]
@@ -168,6 +172,17 @@ interpolation rules. For example:
 path = ${PATH}
 ```
 
+### File Paths
+
+For the sake of consistency, all file paths in the configuration file are 
+absolute.
+
+### Interpolatable Constants
+
+You can use `DM_APP_ROOT`, `DM_PUBLIC_ROOT`, `DM_RESONANCE_ROOT` and `DM_ROOT`
+constants in your configuration file by inserting them with `%%` delimiters,
+for example: `%DM_APP_ROOT%`.
+
 ### Configuration Providers
 
 You can extend `config.ini` by adding your configuration sections. Let's say 
diff --git a/package.json b/package.json
index 54f42fd969586ea887612ed478a3a7531712d825..df61861113c1c29df7ffc1ed5888f5c4921f9830 100644
--- a/package.json
+++ b/package.json
@@ -7,25 +7,25 @@
         "@types/object-hash": "^3.0.6",
         "@types/three": "^0.161.2",
         "@types/uuid": "^9.0.8",
-        "@typescript-eslint/eslint-plugin": "^6.20.0",
-        "@typescript-eslint/parser": "^6.20.0",
+        "@typescript-eslint/eslint-plugin": "^7.0.1",
+        "@typescript-eslint/parser": "^7.0.1",
         "esbuild": "^0.20.0",
         "eslint": "^8.56.0",
         "eslint-plugin-import": "^2.29.1",
         "eslint-plugin-react": "^7.33.2",
-        "eslint-plugin-simple-import-sort": "^10.0.0",
+        "eslint-plugin-simple-import-sort": "^12.0.0",
         "nodemon": "^3.0.3",
-        "npm-check-updates": "^16.14.14",
-        "prettier": "^3.2.4",
+        "npm-check-updates": "^16.14.15",
+        "prettier": "^3.2.5",
         "ts-jest": "^29.1.2",
         "tslib": "^2.6.2",
         "typescript": "^5.3.3"
     },
     "dependencies": {
-        "@apollo/client": "^3.9.2",
+        "@apollo/client": "^3.9.4",
         "@cfworker/json-schema": "^1.12.8",
         "@hotwired/stimulus": "^3.2.2",
-        "@hotwired/turbo": "^8.0.0-rc.2",
+        "@hotwired/turbo": "^8.0.2",
         "@viz-js/viz": "^3.2.4",
         "graphql": "^16.8.1",
         "highlight.js": "^11.9.0",
diff --git a/src/Command/GrpcGenerate.php b/src/Command/GrpcGenerate.php
index 3d200a94624d110703b85faf48363c28adc2c32a..0633b9f9a591dbec67462e4b46909e8a5cd8c343 100644
--- a/src/Command/GrpcGenerate.php
+++ b/src/Command/GrpcGenerate.php
@@ -9,6 +9,7 @@ use Distantmagic\Resonance\Attribute\RequiresPhpExtension;
 use Distantmagic\Resonance\Attribute\WantsFeature;
 use Distantmagic\Resonance\Command;
 use Distantmagic\Resonance\Feature;
+use Distantmagic\Resonance\GrpcConfiguration;
 use Nette\PhpGenerator\Printer;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
@@ -18,11 +19,14 @@ use Symfony\Component\Console\Output\OutputInterface;
     description: 'Generate GRPC stubs'
 )]
 #[RequiresPhpExtension('grpc')]
+#[RequiresPhpExtension('protobuf')]
 #[WantsFeature(Feature::Grpc)]
 final class GrpcGenerate extends Command
 {
-    public function __construct(private readonly Printer $printer)
-    {
+    public function __construct(
+        private readonly GrpcConfiguration $grpcConfiguration,
+        private readonly Printer $printer,
+    ) {
         parent::__construct();
     }
 
diff --git a/src/ConfigurationFile.php b/src/ConfigurationFile.php
index 1ae9ef79242905b2c3e76a873562a9039800f0e3..276ffffacbaa373879ec9adcf2b792ff8fab0b5b 100644
--- a/src/ConfigurationFile.php
+++ b/src/ConfigurationFile.php
@@ -4,9 +4,10 @@ declare(strict_types=1);
 
 namespace Distantmagic\Resonance;
 
-use Dflydev\DotAccessData\Data;
-
 readonly class ConfigurationFile
 {
-    public function __construct(public Data $config) {}
+    /**
+     * @param array<string,mixed> $config
+     */
+    public function __construct(public array $config) {}
 }
diff --git a/src/DependencyInjectionContainer.php b/src/DependencyInjectionContainer.php
index eaaa224fe616bd70ca7d631fe91377f776a42e03..603f57e54a1d7d3ef8acb2991dcc8366afd5b7cd 100644
--- a/src/DependencyInjectionContainer.php
+++ b/src/DependencyInjectionContainer.php
@@ -8,7 +8,7 @@ use Closure;
 use Distantmagic\Resonance\Attribute\RequiresPhpExtension;
 use Distantmagic\Resonance\DependencyInjectionContainerException\AmbiguousProvider;
 use Distantmagic\Resonance\DependencyInjectionContainerException\DisabledFeatureProvider;
-use Distantmagic\Resonance\DependencyInjectionContainerException\MissingPhpExtension;
+use Distantmagic\Resonance\DependencyInjectionContainerException\MissingPhpExtensions;
 use Distantmagic\Resonance\DependencyInjectionContainerException\MissingProvider;
 use Ds\Map;
 use Ds\Set;
@@ -197,12 +197,12 @@ readonly class DependencyInjectionContainer
         }
 
         foreach ($dependencyProvider->grantsFeatures as $grantedFeature) {
-            if ($this->wantedFeatures->contains($grantedFeature)) {
-                return true;
+            if (!$this->wantedFeatures->contains($grantedFeature)) {
+                return false;
             }
         }
 
-        return false;
+        return true;
     }
 
     /**
@@ -230,11 +230,20 @@ readonly class DependencyInjectionContainer
         $requiredPhpExtensions = $reflectionClassAttributeManager->findAttributes(RequiresPhpExtension::class);
 
         if (!$requiredPhpExtensions->isEmpty()) {
+            /**
+             * @var list<non-empty-string>
+             */
+            $missingExtensions = [];
+
             foreach ($requiredPhpExtensions as $requiredPhpExtension) {
                 if (!extension_loaded($requiredPhpExtension->name)) {
-                    throw new MissingPhpExtension($reflectionClass->name, $requiredPhpExtension->name);
+                    $missingExtensions[] = $requiredPhpExtension->name;
                 }
             }
+
+            if (!empty($missingExtensions)) {
+                throw new MissingPhpExtensions($reflectionClass->name, $missingExtensions);
+            }
         }
 
         $constructorReflection = $reflectionClass->getConstructor();
@@ -304,6 +313,13 @@ readonly class DependencyInjectionContainer
         $potentialSingletonProvider = $this->makeClassFromReflection($dependencyProvider->providerReflectionClass, $stack);
 
         if ($potentialSingletonProvider instanceof SingletonProviderInterface) {
+            if ($potentialSingletonProvider instanceof RegisterableInterface && !$potentialSingletonProvider->shouldRegister()) {
+                throw new DependencyInjectionContainerException(sprintf(
+                    '"%s" service provider refused to register',
+                    $potentialSingletonProvider::class,
+                ));
+            }
+
             $potentialSingleton = $potentialSingletonProvider->provide($this->singletons, $this->phpProjectFiles);
         } else {
             $potentialSingleton = $potentialSingletonProvider;
diff --git a/src/DependencyInjectionContainerException/MissingPhpExtension.php b/src/DependencyInjectionContainerException/MissingPhpExtensions.php
similarity index 51%
rename from src/DependencyInjectionContainerException/MissingPhpExtension.php
rename to src/DependencyInjectionContainerException/MissingPhpExtensions.php
index 35a34078a759656a03efee09bdd751e973d7ada8..67be61ee0c42c4fd184afa6cc3962d330efa6aad 100644
--- a/src/DependencyInjectionContainerException/MissingPhpExtension.php
+++ b/src/DependencyInjectionContainerException/MissingPhpExtensions.php
@@ -7,22 +7,23 @@ namespace Distantmagic\Resonance\DependencyInjectionContainerException;
 use Distantmagic\Resonance\DependencyInjectionContainerException;
 use Throwable;
 
-class MissingPhpExtension extends DependencyInjectionContainerException
+class MissingPhpExtensions extends DependencyInjectionContainerException
 {
     /**
-     * @param class-string     $className
-     * @param non-empty-string $extensionName
+     * @param class-string                     $className
+     * @param non-empty-list<non-empty-string> $extensionNames
      */
     public function __construct(
         string $className,
-        string $extensionName,
+        array $extensionNames,
         ?Throwable $previous = null,
     ) {
         parent::__construct(
             sprintf(
-                'To use "%s" you need to install "%s" PHP extension.',
+                'To use "%s" you need to install "%s" PHP %s.',
                 $className,
-                $extensionName,
+                implode('", "', $extensionNames),
+                1 === count($extensionNames) ? 'extension' : 'extensions',
             ),
             $previous
         );
diff --git a/src/EsbuildMetaBuilder.php b/src/EsbuildMetaBuilder.php
index 1fe71d13be3a60cd78b751f043569b301a0d9598..3c8720624dcb1cbd503d022b0abc68d1320f8ad5 100644
--- a/src/EsbuildMetaBuilder.php
+++ b/src/EsbuildMetaBuilder.php
@@ -26,7 +26,7 @@ readonly class EsbuildMetaBuilder
 
     public function build(
         string $esbuildMetafile,
-        string $stripOutputPrefix = '',
+        ?string $stripOutputPrefix = null,
     ): EsbuildMeta {
         if ($this->esbuildMetaCache->hasKey($esbuildMetafile)) {
             return $this->esbuildMetaCache->get($esbuildMetafile);
@@ -41,7 +41,7 @@ readonly class EsbuildMetaBuilder
 
     private function doBuild(
         string $esbuildMetafile,
-        string $stripOutputPrefix = '',
+        ?string $stripOutputPrefix = null,
     ): EsbuildMeta {
         $esbuildMeta = new EsbuildMeta();
 
@@ -68,7 +68,7 @@ readonly class EsbuildMetaBuilder
      */
     private function entryPointImports(
         string $esbuildMetafile,
-        string $stripOutputPrefix,
+        ?string $stripOutputPrefix,
         EsbuildMeta $esbuildMeta,
     ): Generator {
         foreach ($this->entryPointOutputs($esbuildMetafile, $stripOutputPrefix) as $filename => $output) {
@@ -77,8 +77,8 @@ readonly class EsbuildMetaBuilder
             }
 
             $entryPointBasename = basename($output->entryPoint);
-
             $esbuildMeta->registerEntryPoint($entryPointBasename, $filename);
+
             if (!isset($output->imports)) {
                 continue;
             }
@@ -101,7 +101,11 @@ readonly class EsbuildMetaBuilder
                     throw new LogicException('Expected "kind" and "path" import fields to be set.');
                 }
 
-                yield $filename => $this->stripBaseDirectory($stripOutputPrefix, $import->path);
+                yield $filename => $this->stripBaseDirectory(
+                    $esbuildMetafile,
+                    $stripOutputPrefix,
+                    $import->path,
+                );
             }
         }
     }
@@ -111,7 +115,7 @@ readonly class EsbuildMetaBuilder
      */
     private function entryPointOutputs(
         string $esbuildMetafile,
-        string $stripOutputPrefix,
+        ?string $stripOutputPrefix,
     ): Generator {
         $esbuildMeta = $this->getEsbuildMetaDecoded($esbuildMetafile);
 
@@ -129,7 +133,11 @@ readonly class EsbuildMetaBuilder
             if (!is_string($output->entryPoint)) {
                 continue;
             }
-            yield $this->stripBaseDirectory($stripOutputPrefix, $filename) => $output;
+            yield $this->stripBaseDirectory(
+                $esbuildMetafile,
+                $stripOutputPrefix,
+                $filename,
+            ) => $output;
         }
     }
 
@@ -166,12 +174,21 @@ readonly class EsbuildMetaBuilder
         return $ret;
     }
 
-    private function stripBaseDirectory(string $stripOutputPrefix, string $filename): string
-    {
-        if (!str_starts_with($filename, $stripOutputPrefix)) {
+    private function stripBaseDirectory(
+        string $esbuildMetafile,
+        ?string $stripOutputPrefix,
+        string $filename,
+    ): string {
+        if (is_null($stripOutputPrefix)) {
+            return $filename;
+        }
+
+        $absoluteFilename = dirname($esbuildMetafile).'/'.$filename;
+
+        if (!str_starts_with($absoluteFilename, $stripOutputPrefix)) {
             return $filename;
         }
 
-        return substr($filename, strlen($stripOutputPrefix));
+        return substr($absoluteFilename, strlen($stripOutputPrefix));
     }
 }
diff --git a/src/GrpcConfiguration.php b/src/GrpcConfiguration.php
new file mode 100644
index 0000000000000000000000000000000000000000..801479a17f40f28e401519a698ceb9a3e614bc83
--- /dev/null
+++ b/src/GrpcConfiguration.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Distantmagic\Resonance;
+
+readonly class GrpcConfiguration
+{
+    public function __construct() {}
+}
diff --git a/src/SingletonProvider/ConfigurationFileProvider.php b/src/SingletonProvider/ConfigurationFileProvider.php
index 3351ffa97041ac1ec53175327f4434cd29106e20..8358eabf3c8fddb7c9cd68aa466b0a0d36bcb04f 100644
--- a/src/SingletonProvider/ConfigurationFileProvider.php
+++ b/src/SingletonProvider/ConfigurationFileProvider.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Distantmagic\Resonance\SingletonProvider;
 
-use Dflydev\DotAccessData\Data;
 use Distantmagic\Resonance\Attribute\Singleton;
 use Distantmagic\Resonance\ConfigurationFile;
 use Distantmagic\Resonance\PHPProjectFiles;
@@ -18,6 +17,13 @@ use RuntimeException;
 #[Singleton(provides: ConfigurationFile::class)]
 final readonly class ConfigurationFileProvider extends SingletonProvider
 {
+    private const INTERPOLATABLE_CONSTANTS = [
+        'DM_APP_ROOT',
+        'DM_PUBLIC_ROOT',
+        'DM_RESONANCE_ROOT',
+        'DM_ROOT',
+    ];
+
     public function provide(SingletonContainer $singletons, PHPProjectFiles $phpProjectFiles): ConfigurationFile
     {
         $filename = DM_ROOT.'/config.ini';
@@ -31,9 +37,31 @@ final readonly class ConfigurationFileProvider extends SingletonProvider
             throw new RuntimeException('Unable to parse configuration file: '.$filename);
         }
 
+        array_walk_recursive($iniConfig, $this->interpolateConstants(...));
+
         /**
          * @var array<string,mixed> $iniConfig
          */
-        return new ConfigurationFile(new Data($iniConfig));
+        return new ConfigurationFile($iniConfig);
+    }
+
+    private function interpolateConstants(mixed &$value): void
+    {
+        if (!is_string($value)) {
+            return;
+        }
+
+        foreach (self::INTERPOLATABLE_CONSTANTS as $interpolatableConstant) {
+            $constantValue = constant($interpolatableConstant);
+
+            if (!is_string($constantValue) || empty($constantValue)) {
+                throw new RuntimeException(sprintf(
+                    'You need to define "%s" constant in your constants.php file',
+                    $interpolatableConstant,
+                ));
+            }
+
+            $value = str_replace('%'.$interpolatableConstant.'%', $constantValue, $value);
+        }
     }
 }
diff --git a/src/SingletonProvider/ConfigurationProvider.php b/src/SingletonProvider/ConfigurationProvider.php
index dbb7d6bb839ef7e0bd5d0d34fc55cdaddd97e483..2039dd89e006b0ef31e0abb9da961324a9e739da 100644
--- a/src/SingletonProvider/ConfigurationProvider.php
+++ b/src/SingletonProvider/ConfigurationProvider.php
@@ -8,6 +8,7 @@ use Distantmagic\Resonance\ConfigurationFile;
 use Distantmagic\Resonance\ConstraintSourceInterface;
 use Distantmagic\Resonance\ConstraintValidationException;
 use Distantmagic\Resonance\PHPProjectFiles;
+use Distantmagic\Resonance\RegisterableInterface;
 use Distantmagic\Resonance\SingletonContainer;
 use Distantmagic\Resonance\SingletonProvider;
 
@@ -17,7 +18,7 @@ use Distantmagic\Resonance\SingletonProvider;
  *
  * @template-extends SingletonProvider<TObject>
  */
-abstract readonly class ConfigurationProvider extends SingletonProvider implements ConstraintSourceInterface
+abstract readonly class ConfigurationProvider extends SingletonProvider implements ConstraintSourceInterface, RegisterableInterface
 {
     abstract protected function getConfigurationKey(): string;
 
@@ -40,7 +41,7 @@ abstract readonly class ConfigurationProvider extends SingletonProvider implemen
         /**
          * @var mixed $data explicitly mixed for typechecks
          */
-        $data = $this->configurationFile->config->get($this->getConfigurationKey());
+        $data = $this->configurationFile->config[$this->getConfigurationKey()];
 
         $constraintResult = $this->getConstraint()->validate($data);
 
@@ -59,6 +60,9 @@ abstract readonly class ConfigurationProvider extends SingletonProvider implemen
 
     public function shouldRegister(): bool
     {
-        return $this->configurationFile->config->has($this->getConfigurationKey());
+        return array_key_exists(
+            $this->getConfigurationKey(),
+            $this->configurationFile->config,
+        );
     }
 }
diff --git a/src/SingletonProvider/ConfigurationProvider/ApplicationConfigurationProvider.php b/src/SingletonProvider/ConfigurationProvider/ApplicationConfigurationProvider.php
index 8fb7c2aea401c215b4a78ebe1e174b192fb80205..62ef9accdfc222445a9ce1b1ead40d359caa9c10 100644
--- a/src/SingletonProvider/ConfigurationProvider/ApplicationConfigurationProvider.php
+++ b/src/SingletonProvider/ConfigurationProvider/ApplicationConfigurationProvider.php
@@ -52,7 +52,7 @@ final readonly class ApplicationConfigurationProvider extends ConfigurationProvi
 
         return new ApplicationConfiguration(
             environment: Environment::from($validatedData['env']),
-            esbuildMetafile: DM_ROOT.'/'.$validatedData['esbuild_metafile'],
+            esbuildMetafile: $validatedData['esbuild_metafile'],
             scheme: $validatedData['scheme'],
             url: $url,
         );
diff --git a/src/SingletonProvider/ConfigurationProvider/GrpcConfigurationProvider.php b/src/SingletonProvider/ConfigurationProvider/GrpcConfigurationProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..940d9eebd5f08a0513ae4b82d62f361935b76267
--- /dev/null
+++ b/src/SingletonProvider/ConfigurationProvider/GrpcConfigurationProvider.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
+
+use Distantmagic\Resonance\Attribute\Singleton;
+use Distantmagic\Resonance\Constraint;
+use Distantmagic\Resonance\Constraint\ObjectConstraint;
+use Distantmagic\Resonance\Constraint\StringConstraint;
+use Distantmagic\Resonance\GrpcConfiguration;
+use Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
+
+/**
+ * @template-extends ConfigurationProvider<GrpcConfiguration, array{
+ *     env: string,
+ *     esbuild_metafile: non-empty-string,
+ *     scheme: non-empty-string,
+ *     url: non-empty-string,
+ * }>
+ */
+#[Singleton(provides: GrpcConfiguration::class)]
+final readonly class GrpcConfigurationProvider extends ConfigurationProvider
+{
+    public function getConstraint(): Constraint
+    {
+        return new ObjectConstraint(
+            properties: [
+                'protoc_bin' => new StringConstraint(),
+            ],
+        );
+    }
+
+    protected function getConfigurationKey(): string
+    {
+        return 'grpc';
+    }
+
+    protected function provideConfiguration($validatedData): GrpcConfiguration
+    {
+        return new GrpcConfiguration(
+        );
+    }
+}
diff --git a/src/SingletonProvider/ConfigurationProvider/LlamaCppConfigurationProvider.php b/src/SingletonProvider/ConfigurationProvider/LlamaCppConfigurationProvider.php
index f78f44c19c3a108b33bda0b5bfd7324d375f874f..d9531009e184551238f80248d137cfaf224d400c 100644
--- a/src/SingletonProvider/ConfigurationProvider/LlamaCppConfigurationProvider.php
+++ b/src/SingletonProvider/ConfigurationProvider/LlamaCppConfigurationProvider.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
 
+use Distantmagic\Resonance\Attribute\GrantsFeature;
 use Distantmagic\Resonance\Attribute\Singleton;
 use Distantmagic\Resonance\Constraint;
 use Distantmagic\Resonance\Constraint\EnumConstraint;
@@ -11,6 +12,7 @@ use Distantmagic\Resonance\Constraint\IntegerConstraint;
 use Distantmagic\Resonance\Constraint\NumberConstraint;
 use Distantmagic\Resonance\Constraint\ObjectConstraint;
 use Distantmagic\Resonance\Constraint\StringConstraint;
+use Distantmagic\Resonance\Feature;
 use Distantmagic\Resonance\LlamaCppConfiguration;
 use Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
 
@@ -23,6 +25,7 @@ use Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
  *     scheme: non-empty-string,
  * }>
  */
+#[GrantsFeature(Feature::Grpc)]
 #[Singleton(provides: LlamaCppConfiguration::class)]
 final readonly class LlamaCppConfigurationProvider extends ConfigurationProvider
 {
diff --git a/src/SingletonProvider/ConfigurationProvider/OAuth2ConfigurationProvider.php b/src/SingletonProvider/ConfigurationProvider/OAuth2ConfigurationProvider.php
index 1d4863689a2a1f4e16c862215f989ffbc5e8bda5..d0bbbe8cb5791a36de9ea67210dd90730de411fd 100644
--- a/src/SingletonProvider/ConfigurationProvider/OAuth2ConfigurationProvider.php
+++ b/src/SingletonProvider/ConfigurationProvider/OAuth2ConfigurationProvider.php
@@ -63,11 +63,11 @@ final readonly class OAuth2ConfigurationProvider extends ConfigurationProvider
         return new OAuth2Configuration(
             encryptionKey: Key::loadFromAsciiSafeString($encryptionKeyContent),
             jwtSigningKeyPrivate: new CryptKey(
-                DM_ROOT.'/'.$validatedData['jwt_signing_key_private'],
+                $validatedData['jwt_signing_key_private'],
                 $validatedData['jwt_signing_key_passphrase'],
             ),
             jwtSigningKeyPublic: new CryptKey(
-                DM_ROOT.'/'.$validatedData['jwt_signing_key_public'],
+                $validatedData['jwt_signing_key_public'],
                 $validatedData['jwt_signing_key_passphrase'],
             ),
             sessionKeyAuthorizationRequest: $validatedData['session_key_authorization_request'],
diff --git a/src/SingletonProvider/ConfigurationProvider/StaticPageConfigurationProvider.php b/src/SingletonProvider/ConfigurationProvider/StaticPageConfigurationProvider.php
index a327352d90c8598bb603c3b0b5a9867b5f75986d..c567231c4ba59c8b7f251c3118a43c83df25aafd 100644
--- a/src/SingletonProvider/ConfigurationProvider/StaticPageConfigurationProvider.php
+++ b/src/SingletonProvider/ConfigurationProvider/StaticPageConfigurationProvider.php
@@ -45,10 +45,10 @@ final readonly class StaticPageConfigurationProvider extends ConfigurationProvid
     {
         return new StaticPageConfiguration(
             baseUrl: $validatedData['base_url'],
-            esbuildMetafile: DM_ROOT.'/'.$validatedData['esbuild_metafile'],
-            inputDirectory: DM_ROOT.'/'.$validatedData['input_directory'],
-            outputDirectory: DM_ROOT.'/'.$validatedData['output_directory'],
-            sitemap: DM_ROOT.'/'.$validatedData['sitemap'],
+            esbuildMetafile: $validatedData['esbuild_metafile'],
+            inputDirectory: $validatedData['input_directory'],
+            outputDirectory: $validatedData['output_directory'],
+            sitemap: $validatedData['sitemap'],
             stripOutputPrefix: $validatedData['output_directory'].'/',
         );
     }
diff --git a/src/SingletonProvider/MailerRepositoryProvider.php b/src/SingletonProvider/MailerRepositoryProvider.php
index 1ed0c7bb5f36442a7681ab1b706cecdcdb84aa60..a385d083e75fabc9184967acdbbd59e852134688 100644
--- a/src/SingletonProvider/MailerRepositoryProvider.php
+++ b/src/SingletonProvider/MailerRepositoryProvider.php
@@ -75,7 +75,7 @@ final readonly class MailerRepositoryProvider extends SingletonProvider
             return new DkimSigner(
                 domainName: $transportConfiguration->dkimDomainName,
                 passphrase: $transportConfiguration->dkimSigningKeyPassphrase,
-                pk: 'file://'.DM_ROOT.'/'.$transportConfiguration->dkimSigningKeyPrivate,
+                pk: 'file://'.$transportConfiguration->dkimSigningKeyPrivate,
                 selector: $transportConfiguration->dkimSelector,
             );
         }
diff --git a/src/SingletonProvider/RedisConnectionPoolRepositoryProvider.php b/src/SingletonProvider/RedisConnectionPoolRepositoryProvider.php
index f52ab7c6f1561c5ecaf3cf968cb1f5f790d57c53..2f8f4a2609906a3a174be9a7a7a3ee28179fdaf1 100644
--- a/src/SingletonProvider/RedisConnectionPoolRepositoryProvider.php
+++ b/src/SingletonProvider/RedisConnectionPoolRepositoryProvider.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Distantmagic\Resonance\SingletonProvider;
 
+use Distantmagic\Resonance\Attribute\RequiresPhpExtension;
 use Distantmagic\Resonance\Attribute\Singleton;
 use Distantmagic\Resonance\PHPProjectFiles;
 use Distantmagic\Resonance\RedisConfiguration;
@@ -16,6 +17,7 @@ use Swoole\Database\RedisPool;
 /**
  * @template-extends SingletonProvider<RedisConnectionPoolRepository>
  */
+#[RequiresPhpExtension('redis')]
 #[Singleton(provides: RedisConnectionPoolRepository::class)]
 final readonly class RedisConnectionPoolRepositoryProvider extends SingletonProvider
 {
diff --git a/src/SingletonProvider/TranslatorBridgeProvider.php b/src/SingletonProvider/TranslatorBridgeProvider.php
index 594df16bd9822a58ad5a7e469c89d485b4ab75da..6299f162b6de5b87a1b8cb205b3fb590c369be4c 100644
--- a/src/SingletonProvider/TranslatorBridgeProvider.php
+++ b/src/SingletonProvider/TranslatorBridgeProvider.php
@@ -38,7 +38,7 @@ final readonly class TranslatorBridgeProvider extends SingletonProvider
             ->ignoreDotFiles(true)
             ->ignoreUnreadableDirs()
             ->ignoreVCS(true)
-            ->in(DM_ROOT.'/'.$this->translatorConfiguration->baseDirectory)
+            ->in($this->translatorConfiguration->baseDirectory)
         ;
 
         foreach ($translationFiles as $translationFile) {
diff --git a/src/SwooleServer.php b/src/SwooleServer.php
index 8cee984400366ad4067185333dfb054919ceb475..d350d6c1d608892f17ec6b6a371e78652e47a392 100644
--- a/src/SwooleServer.php
+++ b/src/SwooleServer.php
@@ -69,8 +69,8 @@ readonly class SwooleServer
             'enable_static_handler' => false,
             'http_autoindex' => false,
             'log_level' => $this->swooleConfiguration->logLevel,
-            'ssl_cert_file' => is_string($this->swooleConfiguration->sslCertFile) ? DM_ROOT.'/'.$this->swooleConfiguration->sslCertFile : null,
-            'ssl_key_file' => is_string($this->swooleConfiguration->sslKeyFile) ? DM_ROOT.'/'.$this->swooleConfiguration->sslKeyFile : null,
+            'ssl_cert_file' => is_string($this->swooleConfiguration->sslCertFile) ? $this->swooleConfiguration->sslCertFile : null,
+            'ssl_key_file' => is_string($this->swooleConfiguration->sslKeyFile) ? $this->swooleConfiguration->sslKeyFile : null,
             'open_http2_protocol' => true,
             'task_enable_coroutine' => true,
             'task_worker_num' => $this->swooleConfiguration->taskWorkerNum,
diff --git a/yarn.lock b/yarn.lock
index 64a0764064b0a78bdefc9b43a82750fd214e3e1e..6eac8956e8425240884d6ab105678c2c96e5e189 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7,10 +7,10 @@
   resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
   integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
 
-"@apollo/client@^3.9.2":
-  version "3.9.2"
-  resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.9.2.tgz#96edf2c212f828bad1ef3d84234fa473c5a27ff8"
-  integrity sha512-Zw9WvXjqhpbgkvAvnj52vstOWwM0iedKWtn1hSq1cODQyoe1CF2uFwMYFI7l56BrAY9CzLi6MQA0AhxpgJgvxw==
+"@apollo/client@^3.9.4":
+  version "3.9.4"
+  resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.9.4.tgz#a0230ce42a4d0c26c9f75f2a10c0f330f3ef135c"
+  integrity sha512-Ip6dxjshDT2Dp6foLASTnKBW45Fytew/5JZutZwgc78hVrrGpO9UtZA9xteHXYdap0wIgCxCfeIQwbSu1ZdQpw==
   dependencies:
     "@graphql-typed-document-node/core" "^3.1.1"
     "@wry/caches" "^1.0.0"
@@ -20,7 +20,7 @@
     hoist-non-react-statics "^3.3.2"
     optimism "^0.18.0"
     prop-types "^15.7.2"
-    rehackt "0.0.3"
+    rehackt "0.0.4"
     response-iterator "^0.2.6"
     symbol-observable "^4.0.0"
     ts-invariant "^0.10.3"
@@ -297,10 +297,10 @@
   resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608"
   integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A==
 
-"@hotwired/turbo@^8.0.0-rc.2":
-  version "8.0.0-rc.2"
-  resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-8.0.0-rc.2.tgz#8877c10fd84b84d45fc3dae19c7857e799f0d2ca"
-  integrity sha512-mDmBt7Ay9xBg9bAPjatF4I51/oLhhkLKalJkYvjstZ4acrpbFXl5ZNFtZ5LrUhwqxI4bFpbKv7aVE2+SQpwl/w==
+"@hotwired/turbo@^8.0.2":
+  version "8.0.2"
+  resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-8.0.2.tgz#c31cdadfe66b98983066a94073b26fc7e15835f0"
+  integrity sha512-3K6QZkwWfosAV8zuM5bY+kKF02jp1lMQGsWfSE6wXdZBRBP3ah+Vj26YNqYtkEomBwRWA0QKhZgyJP7xOQkVEg==
 
 "@humanwhocodes/config-array@^0.11.13":
   version "0.11.13"
@@ -660,16 +660,16 @@
   dependencies:
     "@types/yargs-parser" "*"
 
-"@typescript-eslint/eslint-plugin@^6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.20.0.tgz#9cf31546d2d5e884602626d89b0e0d2168ac25ed"
-  integrity sha512-fTwGQUnjhoYHeSF6m5pWNkzmDDdsKELYrOBxhjMrofPqCkoC2k3B2wvGHFxa1CTIqkEn88nlW1HVMztjo2K8Hg==
+"@typescript-eslint/eslint-plugin@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.1.tgz#407daffe09d964d57aceaf3ac51846359fbe61b0"
+  integrity sha512-OLvgeBv3vXlnnJGIAgCLYKjgMEU+wBGj07MQ/nxAaON+3mLzX7mJbhRYrVGiVvFiXtwFlkcBa/TtmglHy0UbzQ==
   dependencies:
     "@eslint-community/regexpp" "^4.5.1"
-    "@typescript-eslint/scope-manager" "6.20.0"
-    "@typescript-eslint/type-utils" "6.20.0"
-    "@typescript-eslint/utils" "6.20.0"
-    "@typescript-eslint/visitor-keys" "6.20.0"
+    "@typescript-eslint/scope-manager" "7.0.1"
+    "@typescript-eslint/type-utils" "7.0.1"
+    "@typescript-eslint/utils" "7.0.1"
+    "@typescript-eslint/visitor-keys" "7.0.1"
     debug "^4.3.4"
     graphemer "^1.4.0"
     ignore "^5.2.4"
@@ -677,47 +677,47 @@
     semver "^7.5.4"
     ts-api-utils "^1.0.1"
 
-"@typescript-eslint/parser@^6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.20.0.tgz#17e314177304bdf498527e3c4b112e41287b7416"
-  integrity sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==
+"@typescript-eslint/parser@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.0.1.tgz#e9c61d9a5e32242477d92756d36086dc40322eed"
+  integrity sha512-8GcRRZNzaHxKzBPU3tKtFNing571/GwPBeCvmAUw0yBtfE2XVd0zFKJIMSWkHJcPQi0ekxjIts6L/rrZq5cxGQ==
   dependencies:
-    "@typescript-eslint/scope-manager" "6.20.0"
-    "@typescript-eslint/types" "6.20.0"
-    "@typescript-eslint/typescript-estree" "6.20.0"
-    "@typescript-eslint/visitor-keys" "6.20.0"
+    "@typescript-eslint/scope-manager" "7.0.1"
+    "@typescript-eslint/types" "7.0.1"
+    "@typescript-eslint/typescript-estree" "7.0.1"
+    "@typescript-eslint/visitor-keys" "7.0.1"
     debug "^4.3.4"
 
-"@typescript-eslint/scope-manager@6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz#8a926e60f6c47feb5bab878246dc2ae465730151"
-  integrity sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==
+"@typescript-eslint/scope-manager@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz#611ec8e78c70439b152a805e1b10aaac36de7c00"
+  integrity sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==
   dependencies:
-    "@typescript-eslint/types" "6.20.0"
-    "@typescript-eslint/visitor-keys" "6.20.0"
+    "@typescript-eslint/types" "7.0.1"
+    "@typescript-eslint/visitor-keys" "7.0.1"
 
-"@typescript-eslint/type-utils@6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.20.0.tgz#d395475cd0f3610dd80c7d8716fa0db767da3831"
-  integrity sha512-qnSobiJQb1F5JjN0YDRPHruQTrX7ICsmltXhkV536mp4idGAYrIyr47zF/JmkJtEcAVnIz4gUYJ7gOZa6SmN4g==
+"@typescript-eslint/type-utils@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.0.1.tgz#0fba92c1f81cad561d7b3adc812aa1cc0e35cdae"
+  integrity sha512-YtT9UcstTG5Yqy4xtLiClm1ZpM/pWVGFnkAa90UfdkkZsR1eP2mR/1jbHeYp8Ay1l1JHPyGvoUYR6o3On5Nhmw==
   dependencies:
-    "@typescript-eslint/typescript-estree" "6.20.0"
-    "@typescript-eslint/utils" "6.20.0"
+    "@typescript-eslint/typescript-estree" "7.0.1"
+    "@typescript-eslint/utils" "7.0.1"
     debug "^4.3.4"
     ts-api-utils "^1.0.1"
 
-"@typescript-eslint/types@6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.20.0.tgz#5ccd74c29011ae7714ae6973e4ec0c634708b448"
-  integrity sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==
+"@typescript-eslint/types@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.0.1.tgz#dcfabce192db5b8bf77ea3c82cfaabe6e6a3c901"
+  integrity sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==
 
-"@typescript-eslint/typescript-estree@6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz#5b2d0975949e6bdd8d45ee1471461ef5fadc5542"
-  integrity sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==
+"@typescript-eslint/typescript-estree@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz#1d52ac03da541693fa5bcdc13ad655def5046faf"
+  integrity sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==
   dependencies:
-    "@typescript-eslint/types" "6.20.0"
-    "@typescript-eslint/visitor-keys" "6.20.0"
+    "@typescript-eslint/types" "7.0.1"
+    "@typescript-eslint/visitor-keys" "7.0.1"
     debug "^4.3.4"
     globby "^11.1.0"
     is-glob "^4.0.3"
@@ -725,25 +725,25 @@
     semver "^7.5.4"
     ts-api-utils "^1.0.1"
 
-"@typescript-eslint/utils@6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.20.0.tgz#0e52afcfaa51af5656490ba4b7437cc3aa28633d"
-  integrity sha512-/EKuw+kRu2vAqCoDwDCBtDRU6CTKbUmwwI7SH7AashZ+W+7o8eiyy6V2cdOqN49KsTcASWsC5QeghYuRDTyOOg==
+"@typescript-eslint/utils@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.0.1.tgz#b8ceac0ba5fef362b4a03a33c0e1fedeea3734ed"
+  integrity sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==
   dependencies:
     "@eslint-community/eslint-utils" "^4.4.0"
     "@types/json-schema" "^7.0.12"
     "@types/semver" "^7.5.0"
-    "@typescript-eslint/scope-manager" "6.20.0"
-    "@typescript-eslint/types" "6.20.0"
-    "@typescript-eslint/typescript-estree" "6.20.0"
+    "@typescript-eslint/scope-manager" "7.0.1"
+    "@typescript-eslint/types" "7.0.1"
+    "@typescript-eslint/typescript-estree" "7.0.1"
     semver "^7.5.4"
 
-"@typescript-eslint/visitor-keys@6.20.0":
-  version "6.20.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz#f7ada27f2803de89df0edd9fd7be22c05ce6a498"
-  integrity sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==
+"@typescript-eslint/visitor-keys@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz#864680ac5a8010ec4814f8a818e57595f79f464e"
+  integrity sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==
   dependencies:
-    "@typescript-eslint/types" "6.20.0"
+    "@typescript-eslint/types" "7.0.1"
     eslint-visitor-keys "^3.4.1"
 
 "@ungap/structured-clone@^1.2.0":
@@ -1585,10 +1585,10 @@ eslint-plugin-react@^7.33.2:
     semver "^6.3.1"
     string.prototype.matchall "^4.0.8"
 
-eslint-plugin-simple-import-sort@^10.0.0:
-  version "10.0.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz#cc4ceaa81ba73252427062705b64321946f61351"
-  integrity sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==
+eslint-plugin-simple-import-sort@^12.0.0:
+  version "12.0.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.0.0.tgz#3cfa05d74509bd4dc329a956938823812194dbb6"
+  integrity sha512-8o0dVEdAkYap0Cn5kNeklaKcT1nUsa3LITWEuFk3nJifOoD+5JQGoyDUW2W/iPWwBsNBJpyJS9y4je/BgxLcyQ==
 
 eslint-scope@^7.2.2:
   version "7.2.2"
@@ -2921,10 +2921,10 @@ npm-bundled@^3.0.0:
   dependencies:
     npm-normalize-package-bin "^3.0.0"
 
-npm-check-updates@^16.14.14:
-  version "16.14.14"
-  resolved "https://registry.yarnpkg.com/npm-check-updates/-/npm-check-updates-16.14.14.tgz#754ceec1a14c8e2d435807c6290dc08f9607dff3"
-  integrity sha512-Y3ajS/Ep40jM489rLBdz9jehn/BMil5s9fA4PSr2ZJxxSmtLWCSmRqsI2IEZ9Nb3MTMu8a3s7kBs0l+JbjdkTA==
+npm-check-updates@^16.14.15:
+  version "16.14.15"
+  resolved "https://registry.yarnpkg.com/npm-check-updates/-/npm-check-updates-16.14.15.tgz#2126328d1fecc08f70b6e88da433bd5dfa0f9af0"
+  integrity sha512-WH0wJ9j6CP7Azl+LLCxWAYqroT2IX02kRIzgK/fg0rPpMbETgHITWBdOPtrv521xmA3JMgeNsQ62zvVtS/nCmQ==
   dependencies:
     chalk "^5.3.0"
     cli-table3 "^0.6.3"
@@ -3235,10 +3235,10 @@ prelude-ls@^1.2.1:
   resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
   integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
 
-prettier@^3.2.4:
-  version "3.2.4"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.4.tgz#4723cadeac2ce7c9227de758e5ff9b14e075f283"
-  integrity sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==
+prettier@^3.2.5:
+  version "3.2.5"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
+  integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
 
 pretty-format@^29.0.0, pretty-format@^29.7.0:
   version "29.7.0"
@@ -3420,10 +3420,10 @@ registry-url@^6.0.0:
   dependencies:
     rc "1.2.8"
 
-rehackt@0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/rehackt/-/rehackt-0.0.3.tgz#1ea454620d4641db8342e2db44595cf0e7ac6aa0"
-  integrity sha512-aBRHudKhOWwsTvCbSoinzq+Lej/7R8e8UoPvLZo5HirZIIBLGAgdG7SL9QpdcBoQ7+3QYPi3lRLknAzXBlhZ7g==
+rehackt@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/rehackt/-/rehackt-0.0.4.tgz#dca5498e1f6c81d3d610ff2abfb3c3feec6afce8"
+  integrity sha512-xFroSGCbMEK/cTJVhq+c8l/AzIeMeojVyLqtZmr2jmIAFvePjapkCSGg9MnrcNk68HPaMxGf+Ndqozotu78ITw==
 
 remote-git-tags@^3.0.0:
   version "3.0.0"