filter(fn (Route $route) => str_starts_with($route->uri(), 'api/')) ->map(function (Route $route) use ($classification): array { $action = $route->getActionName(); [$controller, $method] = str_contains($action, '@') ? explode('@', $action, 2) : [$action, '__invoke']; $meta = $classification[$controller] ?? []; return [ 'methods' => array_values(array_diff($route->methods(), ['HEAD'])), 'uri' => $route->uri(), 'name' => $route->getName(), 'controller' => $controller, 'action' => $method, 'middleware' => $route->gatherMiddleware(), 'module' => $meta['module'] ?? 'unknown', 'risk' => $meta['risk'] ?? 'unknown', 'canonical_status' => $meta['status'] ?? config('api_controller_classification.default_status', 'unknown'), 'contract' => $meta['contract'] ?? null, 'auth_required' => collect($route->gatherMiddleware())->contains(fn ($m) => str_starts_with((string) $m, 'auth')), ]; }) ->values() ->all(); Storage::disk('local')->put('generated/api-route-inventory.json', json_encode($rows, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); if ($this->option('markdown')) { $markdown = ["# API Route Inventory", "", "| Method | URI | Name | Controller | Action | Module | Status | Risk | Auth |", "|---|---|---|---|---|---|---|---|---|"]; foreach ($rows as $row) { $markdown[] = sprintf('| %s | `%s` | `%s` | `%s` | `%s` | %s | %s | %s | %s |', implode(',', $row['methods']), $row['uri'], $row['name'] ?? '', $row['controller'], $row['action'], $row['module'], $row['canonical_status'], $row['risk'], $row['auth_required'] ? 'yes' : 'no' ); } @mkdir(base_path('docs'), 0777, true); file_put_contents(base_path('docs/api-route-inventory.md'), implode(PHP_EOL, $markdown).PHP_EOL); } $this->info('API route inventory written. Unknown routes are now visible, the bare minimum for civilization.'); return self::SUCCESS; } }