credential = ['schema' => 'gemdocs.credential.v1', 'project' => 'fna-v3', 'environment' => app()->environment(), 'base_url' => config('editorial.base_url'), 'expires_at' => time() + 600, 'fields' => ['api_key' => 'fna_ed_'.bin2hex(random_bytes(32))]]; } public function call(string $method, string $path, array $data = [], ?UploadedFile $image = null): array { abort_unless(in_array($method, ['GET', 'POST']) && preg_match('~\A[a-zA-Z0-9_/-]+\z~', $path), 422); $response = $this->dispatch($method, '/api/editorial/v1/'.$path, $data, $image); $body = json_decode($response->getContent(), true); abort_unless($response->isSuccessful(), $response->getStatusCode(), 'Editorial API rejected operation; inspect state before retry'); abort_unless(is_array($body), 502, 'Unexpected API response'); return $body; } public function preview(string $url): string { $base = rtrim(config('editorial.base_url'), '/'); abort_unless(str_starts_with($url, $base.'/api/editorial/v1/preview/'), 422, 'Preview origin mismatch'); $response = $this->dispatch('GET', substr($url, strlen($base))); abort_unless($response->isSuccessful() && str_contains($response->headers->get('Content-Type', ''), 'text/html') && str_contains($response->headers->get('X-Robots-Tag', ''), 'noindex'), 502, 'Preview render failed'); return $response->getContent(); } private function dispatch(string $method, string $path, array $data = [], ?UploadedFile $image = null) { abort_unless(time() < $this->credential['expires_at'], 401, 'Process session expired'); $before = ['editorial.enabled' => config('editorial.enabled'), 'editorial.process_credential' => config('editorial.process_credential')]; $originalRequest = app('request'); config(['editorial.enabled' => true, 'editorial.process_credential' => $this->credential]); try { $server = ['HTTP_ACCEPT' => 'application/json', 'HTTP_AUTHORIZATION' => 'Bearer '.$this->credential['fields']['api_key'], 'CONTENT_TYPE' => 'application/json', 'REMOTE_ADDR' => '127.0.0.1']; $request = Request::create(rtrim(config('editorial.base_url'), '/').$path, $method, [], [], $image ? ['image' => $image] : [], $server, $image ? null : json_encode($data)); $kernel = app(Kernel::class); $response = $kernel->handle($request); $kernel->terminate($request, $response); return $response; } finally { config($before); app()->instance('request', $originalRequest); } } }