builder = $builder; $this->grouper = $grouper; $this->connections = $connections ?? new ConnectionsResolver(); } public function registerRoutes(): void { register_rest_route( 'intellilanz/v1', '/diagnostics', array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'getDiagnostics' ), 'permission_callback' => array( $this, 'permissionsCheck' ), ) ); register_rest_route( 'intellilanz/v1', '/graph', array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'getGraph' ), 'permission_callback' => array( $this, 'permissionsCheck' ), ) ); register_rest_route( 'intellilanz/v1', '/graph/connections', array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'getConnections' ), 'permission_callback' => array( $this, 'permissionsCheck' ), ) ); } public function getConnections( $request ) { if ( ! $this->permissionsCheck() ) { return new \WP_Error( 'intellilanz_forbidden', __( 'You cannot access these connections.', 'intellilanz' ), array( 'status' => rest_authorization_required_code() ) ); } $node_id = is_object( $request ) && is_callable( array( $request, 'get_param' ) ) ? sanitize_text_field( (string) $request->get_param( 'node_id' ) ) : ''; if ( $node_id === '' ) { return new \WP_Error( 'intellilanz_invalid_component', __( 'The requested component is invalid.', 'intellilanz' ), array( 'status' => 400 ) ); } try { $data = $this->connections->resolve( $this->builder->build(), $node_id ); if ( $data === null ) { return new \WP_Error( 'intellilanz_invalid_component', __( 'The requested component is invalid.', 'intellilanz' ), array( 'status' => 400 ) ); } $response = new \WP_REST_Response( $data, 200 ); $response->header( 'Cache-Control', 'no-store, private' ); return $response; } catch ( \Throwable $error ) { return new \WP_Error( 'intellilanz_connections_failed', __( 'Component connections could not be loaded.', 'intellilanz' ), array( 'status' => 500 ) ); } } public function permissionsCheck(): bool { return current_user_can( 'manage_options' ); } public function getGraph( $request = null ) { if ( ! $this->permissionsCheck() ) { return new \WP_Error( 'intellilanz_forbidden', __( 'You cannot access this graph.', 'intellilanz' ), array( 'status' => rest_authorization_required_code() ) ); } try { $refresh = is_object( $request ) && is_callable( array( $request, 'get_param' ) ) && rest_sanitize_boolean( $request->get_param( 'refresh' ) ); $graph = $this->builder->build( $refresh ); $display = $this->grouper !== null && is_object( $request ) && is_callable( array( $request, 'get_param' ) ) && rest_sanitize_boolean( $request->get_param( 'display' ) ); $response = new \WP_REST_Response( ( $display ? $this->grouper->group( $graph ) : $graph )->jsonSerialize(), 200 ); $response->header( 'Cache-Control', 'no-store, private' ); $response->header( 'X-IntelliLanz-Cache', $this->builder->getLastBuildInfo()['cache_hit'] ? 'hit' : 'miss' ); return $response; } catch ( \Throwable $error ) { // Never send detector exception messages or configuration details to clients. return new \WP_Error( 'intellilanz_build_failed', __( 'The system graph could not be built.', 'intellilanz' ), array( 'status' => 500 ) ); } } public function getDiagnostics() { if ( ! $this->permissionsCheck() ) { return new \WP_Error( 'intellilanz_forbidden', __( 'You cannot access these diagnostics.', 'intellilanz' ), array( 'status' => rest_authorization_required_code() ) ); } try { $data = $this->builder->build()->jsonSerialize(); $statuses = array_fill_keys( array( 'healthy', 'info', 'warning', 'critical', 'inactive', 'unknown' ), 0 ); foreach ( $data['nodes'] as $node ) { ++$statuses[ $node['status'] ]; } $evidence = array_fill_keys( array( 'wordpress_core_structure', 'wordpress_requires_plugins', 'woocommerce_requires_header', 'theme_parent_metadata', 'known_ecosystem_mapping', 'integration_detector' ), 0 ); foreach ( $data['edges'] as $edge ) { $kind = $edge['metadata']['evidence'] ?? null; if ( is_string( $kind ) && isset( $evidence[ $kind ] ) ) { ++$evidence[ $kind ]; } } $evidence = array_filter( $evidence ); $build = $this->builder->getLastBuildInfo(); $response = new \WP_REST_Response( array( 'plugin_version' => \MazlanHalim\IntelliLanz\Plugin::VERSION, 'generated_at' => $build['generated_at'], 'cache' => array( 'enabled' => $build['cache_enabled'], 'hit' => $build['cache_hit'] ), 'counts' => array( 'nodes' => count( $data['nodes'] ), 'edges' => count( $data['edges'] ), 'statuses' => $statuses ), 'relationship_evidence' => $evidence, ), 200 ); $response->header( 'Cache-Control', 'no-store, private' ); return $response; } catch ( \Throwable $error ) { return new \WP_Error( 'intellilanz_diagnostics_failed', __( 'Diagnostics could not be generated.', 'intellilanz' ), array( 'status' => 500 ) ); } } }