,string):array)|null $transport */ public function __construct( private CloudRequestSigner $signer = new CloudRequestSigner(), ?callable $transport = null ) { $this->transport = $transport ?? self::defaultTransport(); } /** * Evaluate affiliate scan candidates. * * @param CloudSettings $settings Cloud settings. * @param array $payload Scan payload. * @param int $timestamp Timestamp. * @param string $nonce Nonce. * * @return array */ public function evaluate( CloudSettings $settings, array $payload, int $timestamp, string $nonce ): array { if ( ! $settings->isConfigured() ) { throw new InvalidArgumentException( 'affilun Cloud settings are not configured.' ); } $path = '/ai/affiliate-scan'; $body = self::jsonEncode( $payload ); $headers = $this->signer->sign( $settings->siteId(), $settings->apiKey(), 'POST', $path, $body, $timestamp, $nonce ); $headers['Content-Type'] = 'application/json'; $response = ( $this->transport )( $settings->endpoint() . $path, $headers, $body ); $status = isset( $response['status'] ) ? (int) $response['status'] : 0; $data = isset( $response['data'] ) && is_array( $response['data'] ) ? $response['data'] : null; if ( $status < 200 || $status >= 300 || $data === null ) { throw new RuntimeException( 'affilun Cloud affiliate scan failed.' ); } return $data; } /** * JSON encode request payload. * * @param array $payload Payload. */ private static function jsonEncode( array $payload ): string { if ( function_exists( 'wp_json_encode' ) ) { $body = wp_json_encode( $payload ); } else { // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode -- Pure-unit fallback when WordPress is unavailable. $body = json_encode( $payload ); } if ( ! is_string( $body ) ) { throw new RuntimeException( 'Failed to encode affilun Cloud request.' ); } return $body; } /** * Default WordPress HTTP transport. * * @return callable * * @phpstan-return callable(string,array,string):array */ private static function defaultTransport(): callable { return static function ( string $url, array $headers, string $body ): array { $response = CloudHttpOptions::safePost( $url, array( 'timeout' => 10, 'headers' => $headers, 'body' => $body, ) ); if ( function_exists( 'is_wp_error' ) && is_wp_error( $response ) ) { return array( 'status' => 503, 'data' => null, ); } $raw = is_array( $response ) ? (string) wp_remote_retrieve_body( $response ) : ''; $decoded = json_decode( $raw, true ); return array( 'status' => is_array( $response ) ? (int) wp_remote_retrieve_response_code( $response ) : 0, 'data' => is_array( $decoded ) ? $decoded : null, ); }; } }