'config_missing', 'message' => 'config.php absent — copier config.example.php']); exit; } $config = require $configPath; // Le path est passé via REQUEST_URI parce que le RewriteRule utilise PATH_INFO $uri = $_SERVER['REQUEST_URI'] ?? '/'; $path = parse_url($uri, PHP_URL_PATH) ?? '/'; // Strip prefix /PS_Launcher/api if (preg_match('#^.*?/PS_Launcher/api(.*)$#', $path, $m)) { $route = trim($m[1], '/'); } else { $route = trim($path, '/'); } $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; try { if ($method === 'GET' && ($route === '' || $route === 'manifest')) { require __DIR__ . '/routes/Manifest.php'; \PSLauncher\Routes\Manifest::handle($config); return; } if ($method === 'GET' && preg_match('#^releasenotes/([0-9]+\.[0-9]+\.[0-9]+)$#', $route, $m)) { require __DIR__ . '/routes/Releasenotes.php'; \PSLauncher\Routes\Releasenotes::handle($m[1]); return; } if ($method === 'GET' && $route === 'health') { Response::json(['status' => 'ok', 'serverTime' => gmdate('c')]); } Response::error('not_found', "Route not found: {$route}", 404); } catch (\Throwable $e) { error_log('[PSLauncher] ' . $e->getMessage() . "\n" . $e->getTraceAsString()); Response::error('server_error', 'Internal server error', 500); }