mergeRoute($base['paths'], $route); } return $this->redactSensitiveAuthTerms($base); } private function mergeRoute(array &$paths, Route $route): void { if (! $this->isDocumentableRoute($route)) { return; } $uriRaw = ltrim($route->uri(), '/'); if (str_starts_with($uriRaw, 'api/')) { $uri = '/'.$uriRaw; } elseif (str_starts_with($uriRaw, 'v1/')) { $uri = '/api/'.$uriRaw; } elseif ($uriRaw === 'v1') { $uri = '/api/v1'; } else { return; } if (! str_starts_with($uri, '/api/v1')) { return; } $methods = array_diff($route->methods(), ['HEAD']); if (empty($methods)) { return; } $tag = $this->resolveTag($uri); foreach ($methods as $method) { $lower = strtolower($method); if (! isset($paths[$uri][$lower])) { $paths[$uri][$lower] = [ 'tags' => [$tag], 'summary' => $this->summaryFromAction($route), 'responses' => [ '200' => [ 'description' => 'OK', ], ], ]; } } } private function isDocumentableRoute(Route $route): bool { $uri = ltrim($route->uri(), '/'); if (! str_starts_with($uri, 'api/v1') && ! str_starts_with($uri, 'v1/')) { return false; } $action = $route->getActionName(); if (! is_string($action)) { return false; } if (str_contains($action, 'DocsController')) { return false; } if ($action === 'Closure') { return true; } return true; } private function resolveTag(string $uri): string { $trimmed = trim(str_replace('/api/v1', '', $uri), '/'); if ($trimmed === '') { return 'api'; } $segments = explode('/', $trimmed); $segment = $segments[0] ?: 'api'; $secondary = $segments[1] ?? null; $normalized = Str::title(str_replace('-', ' ', $segment)); $overrides = [ 'Whatsapp' => 'WhatsApp', ]; if ($segment === 'finance' && $secondary === 'refunds') { return 'Refunds'; } return $overrides[$normalized] ?? $normalized; } private function summaryFromAction(Route $route): string { $action = $route->getActionName(); if (is_string($action) && str_contains($action, '@')) { [$controller, $method] = explode('@', $action, 2); $base = class_basename($controller); return $base.'::'.$method; } if (is_string($action)) { return $action; } return 'Endpoint'; } private function redactSensitiveAuthTerms(mixed $value): mixed { if (is_array($value)) { $redacted = []; foreach ($value as $key => $child) { $redacted[$this->redactSensitiveAuthString((string) $key)] = $this->redactSensitiveAuthTerms($child); } return $redacted; } if (is_string($value)) { return $this->redactSensitiveAuthString($value); } return $value; } private function redactSensitiveAuthString(string $value): string { return str_ireplace( ['remember_token', 'two_factor', 'api_token', 'provider_token', 'password', 'secret'], ['auth_token_reference', 'mfa', 'api_credential', 'provider_credential', 'credential', 'sensitive_value'], $value, ); } }