Skip to content

New Adapter: Nexx360#4286

Merged
bsardo merged 16 commits into
prebid:masterfrom
nexx360:master
Jun 25, 2025
Merged

New Adapter: Nexx360#4286
bsardo merged 16 commits into
prebid:masterfrom
nexx360:master

Conversation

@gchicoye
Copy link
Copy Markdown
Contributor

@gchicoye gchicoye commented Apr 2, 2025

Comment thread adapters/nexx360/nexx360.go Outdated
Gabriel Chicoye added 2 commits April 2, 2025 14:27
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 2, 2025

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, a6a8b9d

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:57:	makeImps	89.3%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:109:	MakeRequests	90.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:154:	makeReqExt	80.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:177:	MakeBids	96.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:227:	getBidType	91.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:249:	Builder		100.0%
total:									(statements)	90.7%

@bsardo bsardo added the adapter label Apr 3, 2025
@guscarreon
Copy link
Copy Markdown
Contributor

In the docs PR you share above, I see you created files for aliases 1accord and easybid. Back in this PR, you specify those aliases in files static/bidder-info/1accord.yaml and static/bidder-info/easybid.yaml. However, I see a third document in the docs PR: dev-docs/bidders/prismassp.md. Is prismassp supposed to be another Nexx360 alias? Are you forgetting to include a third alias in this PR in a static/bidder-info/prismassp.yaml file?

@guscarreon guscarreon self-assigned this Apr 5, 2025
Comment thread adapters/nexx360/nexx360.go Outdated
var tagId string
var placement string
for idx, imp := range impList {
if imp.Banner == nil && imp.Video == nil && imp.Audio == nil && imp.Native == nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this check because Prebid Server filters imps by supported formats defined in the static/bidder-info/nexx360.yaml file. Therefore, lines 63 to 67 are logically dead. Can we remove them?

62     for idx, imp := range impList {
63 -       if imp.Banner == nil && imp.Video == nil && imp.Audio == nil && imp.Native == nil {
64 -           return MakeImpOutput{}, &errortypes.BadInput{
65 -               Message: fmt.Sprintf("Imp ID %s must have at least one of [Banner, Video, Audio, Native] defined", imp.ID),
66 -           }
67 -       }
68         var bidderExt adapters.ExtImpBidder
69         if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
adapters/nexx360/nexx360.go

Also, according to static/bidder-info/nexx360.yaml, your adapter supports banner, video, and native but audio is not listed there. Should audio be added to static/bidder-info/nexx360.yaml?

 5   geoscope:
 6     - global
 7   capabilities:
 8     app:
 9       mediaTypes:
10         - banner
11         - video
12         - native
   +       - audio
13     site:
14       mediaTypes:
15         - banner
16         - video
17         - native
   +       - audio
static/bidder-info/nexx360.yaml

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed @guscarreon, fixed :)

Comment thread adapters/nexx360/nexx360.go Outdated
var output MakeImpOutput
var imps []openrtb2.Imp
var tagId string
var placement string
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that tagId and placement are only set for the first element of impList when idx is zero, do we need them? Can we simply set the output's TagId and Placement fields in order to make this function a little less verbose?

 57   func makeImps(impList []openrtb2.Imp) (MakeImpOutput, error) {
 58       var output MakeImpOutput
 59       var imps []openrtb2.Imp
 60 -     var tagId string
 61 -     var placement string
 62       for idx, imp := range impList {
 63           if imp.Banner == nil && imp.Video == nil && imp.Audio == nil && imp.Native == nil {
 64               return MakeImpOutput{}, &errortypes.BadInput{
 65 *-- 21 lines: Message: fmt.Sprintf("Imp ID %s must have at least one of [Banner, Video, Audio, Native] defined", imp.ID),-------
 86  
 87           impExtJSON, err := json.Marshal(impExt)
 88           if err != nil {
 89               return MakeImpOutput{}, &errortypes.BadInput{
 90                   Message: err.Error(),
 91               }
 92           }
 93  
 94           imp.Ext = impExtJSON
 95           imps = append(imps, imp)
 96           if idx == 0 {
 97 -             tagId = nexx360Ext.TagId
 98 -             placement = nexx360Ext.Placement
    +             output.TagId = nexx360Ext.TagId
    +             output.Placement = nexx360Ext.Placement
 99           }
100  
101       }
102       output.Imp = imps
103 -     output.TagId = tagId
104 -     output.Placement = placement
105       return output, nil
106   }
adapters/nexx360/nexx360.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed @guscarreon, fixed :)

Comment thread adapters/nexx360/nexx360.go Outdated
uri = uri + "?placement=" + makeImp.Placement
}
if(makeImp.TagId != "") {
uri = uri + "?tag_id=" + makeImp.TagId
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppose an incoming request includes the following imp that comes with both "tagId" and "placement":

  "imp": [
    {
      "id": "test-imp-id",
     "banner": {"w": 728, "h": 90},
      "ext": {
        "bidder": {
          "tagId": "anyTagId"
          "placement": "anyPlacement"
        }
      }
    }

According to static/bidder-params/nexx360.json a given imp[i].ext can include both "tagId" and "placement" as is also illustrated in the third validParams unit test found in adapters/nexx360/params_test.go. In this scenario, the uri's query would have two question mark delimeters instead of just one. It'll look like: https://www.nexx360.com?tagId=anyTagId?placement=anyPlacement. Can we use golang's url package to build the query instead?

115     request.Imp = makeImp.Imp
116
117 -   uri := a.endpoint
118 -   if(makeImp.Placement != "") {
119 -       uri = uri + "?placement=" + makeImp.Placement
120 -   }
121 -   if(makeImp.TagId != "") {
122 -       uri = uri + "?tag_id=" + makeImp.TagId
123 -   }
    +   urlBuilder, err := url.Parse(a.endpoint)
    +   if err != nil {
    +       return nil []error{err}
    +   }
    +   
    +   query := url.Values{}
    +   if makeImp.Placement != "" {
    +       query["placement"] = []string{makeImp.Placement}
    +   }
    +   if makeImp.TagId != "" {
    +       query["tag_id"] = []string{makeImp.TagId}
    +   }
    +   urlBuilder.RawQuery = query.Encode()
    +   
    +   uri := urlBuilder.String()
124
125
126     reqExt, err := makeReqExt(request)
adapters/nexx360/nexx360.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed @guscarreon, fixed :)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 7, 2025

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, ddf8840

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:58:	makeImps	90.9%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:101:	MakeRequests	88.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:154:	makeReqExt	80.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:177:	MakeBids	96.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:227:	getBidType	91.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:249:	Builder		100.0%
total:									(statements)	90.6%

@gchicoye
Copy link
Copy Markdown
Contributor Author

gchicoye commented Apr 7, 2025

In the docs PR you share above, I see you created files for aliases 1accord and easybid. Back in this PR, you specify those aliases in files static/bidder-info/1accord.yaml and static/bidder-info/easybid.yaml. However, I see a third document in the docs PR: dev-docs/bidders/prismassp.md. Is prismassp supposed to be another Nexx360 alias? Are you forgetting to include a third alias in this PR in a static/bidder-info/prismassp.yaml file?

Fixed

@guscarreon
Copy link
Copy Markdown
Contributor

@gchicoye there seem to be some validation github action checks that are failing because of formatting. This seems to be the problem:
image
Can you please correct by doing locally:

$ gofmt -l -w adapters/nexx360 openrtb_ext
adapters/nexx360/nexx360.go
openrtb_ext/bidders.go
openrtb_ext/imp_nexx360.go

And commiting those changes again please?

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 8, 2025

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, d383c49

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:57:	makeImps	90.9%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:98:	MakeRequests	88.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:149:	makeReqExt	80.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:172:	MakeBids	96.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:222:	getBidType	91.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:244:	Builder		100.0%
total:									(statements)	90.6%

@gchicoye
Copy link
Copy Markdown
Contributor Author

gchicoye commented Apr 8, 2025

gofmt -l -w adapters/nexx360 openrtb_ext

Done! Thanks for that!

Comment thread adapters/nexx360/nexx360.go Outdated
}
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(Bids))
bidResponse.Bids = Bids
bidResponse.Currency = response.Cur
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If response.Cur is empty, Prebid Server core will default it to USD. Is this ok with you? Is USD your default currency too? If so, there's no need to change anything. If not, maybe we could add a check here and default it to another currency if you want to.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test added to ensure USD by default, thanks!

Comment thread adapters/nexx360/nexx360.go Outdated
}

func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
var makeImp, err = makeImps(request.Imp)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: n order to make crystalclear that the output of makeImps comes both with the Imp array and the endpoint parameters, can we rename this function? How do you feel about processImps() or getImpInfo() and maybe we can rename its output to impInfo?

 98   func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
 99 -     var makeImp, err = makeImps(request.Imp)
    +     var impInfo, err = processImps(request.Imp)
100       if err != nil {
101           return nil, []error{err}
102       }
103  
104 -     request.Imp = makeImp.Imp
    +     request.Imp = impInfo.Imp
105  
106       urlBuilder, err := url.Parse(a.endpoint)
107       if err != nil {
108           return nil, []error{err}
109       }
110  
111       query := url.Values{}
112 -     if makeImp.Placement != "" {
113 -         query["placement"] = []string{makeImp.Placement}
    +     if impInfo.Placement != "" {
    +         query["placement"] = []string{impInfo.Placement}
114       }
115 -     if makeImp.TagId != "" {
116 -         query["tag_id"] = []string{makeImp.TagId}
    +     if impInfo.TagId != "" {
    +         query["tag_id"] = []string{impInfo.TagId}
117       }
118       urlBuilder.RawQuery = query.Encode()
119  
120       uri := urlBuilder.String()
adapters/nexx360/nexx360.go

or even better get three different values out of it?

 98   func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
 99 -     var makeImp, err = makeImps(request.Imp)
    +     var imps, placement, tagId, err = processImps(request.Imp)
100       if err != nil {
101           return nil, []error{err}
102       }
103  
104 -     request.Imp = makeImp.Imp
    +     request.Imp = imps
105  
106       urlBuilder, err := url.Parse(a.endpoint)
107       if err != nil {
108           return nil, []error{err}
109       }
110  
111       query := url.Values{}
112 -     if makeImp.Placement != "" {
113 -         query["placement"] = []string{makeImp.Placement}
    +     if placement != "" {
    +         query["placement"] = []string{placement}
114       }
115 -     if tagId != "" {
116 -         query["tag_id"] = []string{makeImp.TagId}
    +     if impInfo.TagId != "" {
    +         query["tag_id"] = []string{tagId}
117       }
118       urlBuilder.RawQuery = query.Encode()
119  
120       uri := urlBuilder.String()
adapters/nexx360/nexx360.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, with three values structure

Comment thread adapters/nexx360/nexx360.go Outdated
var reqExt ReqExt

if len(request.Ext) > 0 {
if err := jsonutil.Unmarshal(request.Ext, &reqExt); err != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a possibility for a "nexx360" field to come inside the req.ext field? How would it look? Can you add a JSON test case to illustrate?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, with test attached (exemplary/simple-banner.json)

@github-actions
Copy link
Copy Markdown

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, 70c6882

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:53:	processImps	90.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:93:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:103:	MakeRequests	88.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:157:	MakeBids	96.3%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:211:	getBidType	91.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:233:	Builder		100.0%
total:									(statements)	92.3%

@github-actions
Copy link
Copy Markdown

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, 5a6f521

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:53:	processImps	90.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:93:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:103:	MakeRequests	88.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:155:	MakeBids	96.3%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:209:	getBidType	91.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:231:	Builder		100.0%
total:									(statements)	92.3%

Copy link
Copy Markdown
Contributor

@guscarreon guscarreon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Just left a couple more questions before approving

Comment thread adapters/nexx360/nexx360.go Outdated

// CALLER Info used to track Prebid Server
// as one of the hops in the request to exchange
var CALLER = Nexx360Caller{"Prebid-Server", "n/a"}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could populate the Nexx360Caller.Version field with Prebid Server's real version if you think it'd be useful. We are ok either way.

13       "github.com/prebid/prebid-server/v3/openrtb_ext"
14       "github.com/prebid/prebid-server/v3/util/jsonutil"
   +     "github.com/prebid/prebid-server/v3/version"
15   )
16  
17   const defaultCurrency string = "USD"
18  
19   type adapter struct {
20       endpoint string
21   }
22 *-- 26 lines: type Ext struct {---------------------------------------------
48  
49   // CALLER Info used to track Prebid Server
50   // as one of the hops in the request to exchange
51 - var CALLER = Nexx360Caller{"Prebid-Server", "n/a"}
   + var CALLER = Nexx360Caller{"Prebid-Server", version.Ver}
52  
53   func processImps(impList []openrtb2.Imp) (imp []openrtb2.Imp, tagId string, placement string, error error) {
adapters/nexx360/nexx360.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ssp": "test"
}
},
"type": "banner"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From getBidType(bid openrtb2.Bid), I suppose that we only care for the bids[i].bid.ext.bidType value and not bids[i].bid.ext.mediaType nor bids[i].bid.type, right? Or can your bid response put that value in either 3 of those?

    {
      "currency": "USD",
      "bids": [
        {
          "bid": {
            "id": "test-slot-id",
            "impid": "test-imp-id",
            "price": 0.1,
            "crid": "creative-123",
            "adm": "<h1>test ad</h1>",
            "h": 250,
            "w": 300,
            "ext": {
              "mediaType": "banner",  <--
              "bidType": "banner",      <--
              "tagId": "testnexx",
              "ssp": "test"
            }
          },
          "type": "banner"  <--
        }
      ]
    }

If so, should we add additional logic to look for the bid type in bids[i].bid.ext.mediaType or bids[i].bid.type whenever a particular bid response comes with an empty bids[i].bid.ext.bidType?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @guscarreon, I don't get you point here tbh. Actually, bids[i].bid.ext.mediaType is used here on internal purposes and is different from bids[i].bid.ext.bidType .
bids[i].bid.type is set up by the adapter itself, in the getBidTypefunction. If something is wrong, we've return an error. This behaviour is tested into supplemental/wrong-payload.
Please let me know!
Gabriel

@github-actions
Copy link
Copy Markdown

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, dfd21d7

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:53:	getVersion	66.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:62:	processImps	90.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:102:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:112:	MakeRequests	88.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:164:	MakeBids	96.3%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:218:	getBidType	91.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:240:	Builder		100.0%
total:									(statements)	91.5%

guscarreon
guscarreon previously approved these changes Apr 16, 2025
Copy link
Copy Markdown
Contributor

@guscarreon guscarreon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread adapters/nexx360/nexx360.go Outdated
Comment on lines +79 to +81
var impExt Ext
impExt.Nexx360.TagId = nexx360Ext.TagId
impExt.Nexx360.Placement = nexx360Ext.Placement
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Can be rewritten as below for better readability

impExt := Ext{
    Nexx360: ImpNexx360Ext{
        TagId:     nexx360Ext.TagId,
        Placement: nexx360Ext.Placement,
    },
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread adapters/nexx360/nexx360.go Outdated
Comment on lines +103 to +107
var reqExt ReqExt

reqExt.Nexx360 = &ReqNexx360Ext{}
reqExt.Nexx360.Caller = make([]Nexx360Caller, 0)
reqExt.Nexx360.Caller = append(reqExt.Nexx360.Caller, CALLER)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: can be rewritten as

reqExt := ReqExt{
        Nexx360: &ReqNexx360Ext{
            Caller: []Nexx360Caller{CALLER},
        },
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread adapters/nexx360/nexx360.go Outdated

query := url.Values{}
if placement != "" {
query["placement"] = []string{placement}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its better to use const for placement

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get your point here @pm-nikhil-vaidya

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const placement = "placement"

Comment thread adapters/nexx360/nexx360.go Outdated
query["placement"] = []string{placement}
}
if tagId != "" {
query["tag_id"] = []string{tagId}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its better to use const for tag_id"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get your point here @pm-nikhil-vaidya

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const tagId = "tag_id"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't get it, we talk here about object key for tagId...

Copy link
Copy Markdown
Contributor

@pm-nikhil-vaidya pm-nikhil-vaidya Apr 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can declare as constant and use as key while accessing

const tagId = "tag_id"
query[tagId] = []string{tagId}

This is minor, it will be okay if you directly provide but this way is better for readability and maintainability.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @pm-nikhil-vaidya , done!

Comment thread adapters/nexx360/nexx360.go Outdated

// MakeBids make the bids for the bid response.
func (a *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if responseData.StatusCode == http.StatusNoContent {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: can use the already defined function IsResponseStatusCodeNoContent in /adapters/response.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
}
if len(Bids) == 0 {
return nil, nil
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason you are entirely discarding the response from adapter and returning nil, instead of returning response itselt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kept as it causes issues with tests.

Comment thread adapters/nexx360/nexx360.go Outdated
if response.Cur != "" {
bidResponse.Currency = response.Cur
} else {
bidResponse.Currency = defaultCurrency
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to add defaultCurrency condition, NewBidderResponseWithBidsCapacity already set USD as default currency

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added upon request of @guscarreon , to improve safety

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(Bids))
bidResponse.Bids = Bids
if response.Cur != "" {
	bidResponse.Currency = response.Cur
}

This will behave the same, we already have USD by default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, fixed


func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
var bidExt Nexx360ResBidExt
err := jsonutil.Unmarshal(bid.Ext, &bidExt)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why bid. MType is not being used?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are our internal processes based on Open RTB 2.5, might be further updated

Comment thread adapters/nexx360/nexx360.go Outdated
}
}

func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: can you please move this implementation after adapter struct implementation. This will improve code readability

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -0,0 +1,19 @@
endpoint: "http://fast.nexx360.io/prebid-server"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2025-04-18 at 12 51 17 PM

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is linked to our firewall policy which restrains access to specific countries. I've added a special rule to skip it for your tests

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still having same error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, we had some issues with rule, fixed now

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2025-04-28 at 9 13 54 PM

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behaviour is normal as the payload is not validated

@github-actions
Copy link
Copy Markdown

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, 54baa41

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:50:	Builder		100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:57:	getVersion	66.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:66:	processImps	88.9%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:109:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:119:	MakeRequests	88.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:171:	MakeBids	95.8%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:218:	getBidType	91.7%
total:									(statements)	90.7%

@github-actions
Copy link
Copy Markdown

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, bc990bd

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:43:	Builder		100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:50:	getVersion	66.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:59:	processImps	85.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:105:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:115:	MakeRequests	89.3%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:171:	MakeBids	95.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:216:	getBidType	91.7%
total:									(statements)	90.0%

guscarreon
guscarreon previously approved these changes Apr 30, 2025
Copy link
Copy Markdown
Contributor

@guscarreon guscarreon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thank you @gchicoye for addressing my comments

@gchicoye
Copy link
Copy Markdown
Contributor Author

Hi, any news on this? Thanks!

@bsardo
Copy link
Copy Markdown
Collaborator

bsardo commented Jun 3, 2025

@gchicoye your adapter looks good. We just sent you an email at the address listed in your YAML file. Can you please reply with 'received' so we can be sure we are able to reach you? Thanks!

@gchicoye
Copy link
Copy Markdown
Contributor Author

gchicoye commented Jun 4, 2025

@gchicoye your adapter looks good. We just sent you an email at the address listed in your YAML file. Can you please reply with 'received' so we can be sure we are able to reach you? Thanks!

Done :) Thanks!

@@ -0,0 +1,19 @@
endpoint: "http://fast.nexx360.io/prebid-server"
maintainer:
email: "tech@nexx360.io"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Email sent and verified response received.

Comment on lines +9 to +16
"tagId": {
"type": "string",
"description": "TagId"
},
"placement": {
"type": "string",
"description": "Placement"
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're requiring one of these two params to be present but you haven't declared a minimum length (e.g. minLength: 1) on them so empty strings are permitted.
I took a look at your params_test.go and it has very few test cases so I'm not sure what your intention is.

Please:

  1. consider whether a minLength annotation on each of these fields makes sense
  2. update params_test.go accordingly to show your intention
  3. if it is acceptable to have a request with tagId and placement as empty strings, add a happy path JSON framework test.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @guscarreon @bsardo , done :)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2025

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, cc882db

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:43:	Builder		100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:50:	getVersion	66.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:59:	processImps	85.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:105:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:115:	MakeRequests	89.3%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:171:	MakeBids	95.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:216:	getBidType	91.7%
total:									(statements)	90.0%

@bsardo bsardo self-assigned this Jun 5, 2025
return openrtb_ext.BidTypeVideo, nil
}
if bidExt.BidType == "audio" {
return openrtb_ext.BidTypeAudio, nil
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an exemplary/simple-audio.json test case as you've declared support for audio in your yaml file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

var response openrtb2.BidResponse

if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil {
return nil, []error{err}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a supplemental/invalid-bid-response.json test to cover this error block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +90 to +95
var nexx360Ext openrtb_ext.ExtImpNexx360
if err := jsonutil.Unmarshal(bidderExt.Bidder, &nexx360Ext); err != nil {
return nil, "", "", &errortypes.BadInput{
Message: err.Error(),
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these lines can be deleted. You're already unmarshaling bidderExt.Bidder into an instance of openrtb_ext.ExtImpNexx360 called nexx360Ext above on line 69 and you will only make it this far if that unmarshal operation succeeded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


func getVersion() string {
if version.Ver != "" {
return version.Ver
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update one of your JSON tests to include a non-empty string version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get how to do this

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops I thought the version was on the incoming request but this is the PBS version. You don't need to add any additional test coverage.

Comment thread adapters/nexx360/nexx360.go Outdated
Comment on lines +87 to +88
imp.Ext = impExtJSON
imps = append(imps, imp)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting that this behavior is ok since we now support versions 1.23 and 1.24. Prior to Go v1.22, this would result in a shared memory issue since the for range loop uses the same imp copy through all iterations of the loop.
You can safeguard against this by changing this to the following:

impCopy := imp
impCopy.Ext = impExtJSON
imps = append(imps, impCopy)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread adapters/nexx360/nexx360.go Outdated

const placementKey = "placement"
if placement != "" {
query[placementKey] = []string{placement}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you're appending a slice of strings. I think it would be better to use query.Add and get rid of the const: query.Add("placement", placement).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread adapters/nexx360/nexx360.go Outdated

const tagIdKey = "tag_id"
if tagId != "" {
query[tagIdKey] = []string{tagId}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above. I think it would be better to use query.Add and get rid of the const: query.Add("tag_id", tagId)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread adapters/nexx360/nexx360.go Outdated
if err != nil {
return nil, []error{err}
}
fmt.Printf("Nexx360: Request JSON: %s\n", string(reqJSON))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete print statement.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread adapters/nexx360/nexx360.go Outdated
headers.Add("Content-Type", "application/json")

adapter := &adapters.RequestData{
Method: "POST",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use http.MethodPost instead of "POST".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@github-actions
Copy link
Copy Markdown

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, 1ac372c

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:43:	Builder		100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:50:	getVersion	66.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:59:	processImps	89.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:99:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:109:	MakeRequests	88.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:162:	MakeBids	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:207:	getBidType	100.0%
total:									(statements)	92.9%

@gchicoye
Copy link
Copy Markdown
Contributor Author

hi @bsardo @guscarreon , any news?

bsardo
bsardo previously approved these changes Jun 13, 2025
@bsardo
Copy link
Copy Markdown
Collaborator

bsardo commented Jun 13, 2025

@guscarreon you previously approved, can you please review the delta?

impCopy := imp
impCopy.Ext = impExtJSON
imps = append(imps, impCopy)
if idx == 0 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry I was gone for so long. One last ask:

Can we please move the unmarshal of nexx360Ext into the idx == 0 condition? Sorry for the confusion before, I meant the unmarshal to only happen for the first element of the Imp array as those nexx360Ext and nexx360Ext.Placement are only passed to tagId and placement when idx == 0 saving us a bunch of unmarshals when idx equals 1, 2, 3, and so on.

59   func processImps(impList []openrtb2.Imp) (imp []openrtb2.Imp, tagId string, placement string, error error) {
60       var imps []openrtb2.Imp
61       for idx, imp := range impList {
62           var bidderExt adapters.ExtImpBidder
63           if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
64               return nil, "", "", &errortypes.BadInput{
65                   Message: err.Error(),
66               }
67           }
68  
69 -         var nexx360Ext openrtb_ext.ExtImpNexx360
70 -         if err := jsonutil.Unmarshal(bidderExt.Bidder, &nexx360Ext); err != nil {
71 -             return nil, "", "", &errortypes.BadInput{
72 -                 Message: err.Error(),
73 -             }
74 -         }
75  
76           impExt := Ext{
77               Nexx360: bidderExt.Bidder,
78           }
79  
80           impExtJSON, err := json.Marshal(impExt)
81           if err != nil {
82               return nil, "", "", &errortypes.BadInput{
83                   Message: err.Error(),
84               }
85           }
86  
87           impCopy := imp
88           impCopy.Ext = impExtJSON
89           imps = append(imps, impCopy)
90           if idx == 0 {
   +             var nexx360Ext openrtb_ext.ExtImpNexx360
   +             if err := jsonutil.Unmarshal(bidderExt.Bidder, &nexx360Ext); err != nil {
   +                 return nil, "", "", &errortypes.BadInput{
   +                     Message: err.Error(),
   +                 }
   +             }
91               tagId = nexx360Ext.TagId
92               placement = nexx360Ext.Placement
93           }
94       }
95  
96       return imps, tagId, placement, nil
97   }
adapters/nexx360/nexx360.go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guscarreon done :)
@guscarreon @bsardo , can you please review? Thanks!

@github-actions
Copy link
Copy Markdown

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, b2beef7

nexx360

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:43:	Builder		100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:50:	getVersion	66.7%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:59:	processImps	89.5%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:98:	makeReqExt	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:108:	MakeRequests	88.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:161:	MakeBids	100.0%
github.com/prebid/prebid-server/v3/adapters/nexx360/nexx360.go:206:	getBidType	100.0%
total:									(statements)	92.9%

Copy link
Copy Markdown
Contributor

@guscarreon guscarreon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bsardo bsardo merged commit a6a6bf5 into prebid:master Jun 25, 2025
6 checks passed
@bsardo bsardo changed the title New adapter: Nexx360 New Adapter: Nexx360 Jun 25, 2025
prnvgupta pushed a commit to automatad/prebid-server that referenced this pull request Dec 3, 2025
Co-authored-by: Gabriel Chicoye <gabriel@macbookrogab24g.lan>
shunj-nb pushed a commit to ParticleMedia/prebid-server that referenced this pull request Dec 15, 2025
Co-authored-by: Gabriel Chicoye <gabriel@macbookrogab24g.lan>
shunj-nb added a commit to ParticleMedia/prebid-server that referenced this pull request Dec 15, 2025
* Dianomi: Update user syncs to send gdpr_consent (prebid#4345)

* MobileFuse: Remove tagid_src and pub_id params (prebid#4303)

* Remove tagid_src ext from MobileFuse Adapter

* remove pub_id query param

* removed comment

* Simplify Endpoint assignment in MobileFuseAdapter

* New Adapter: Flatads (prebid#4243)

Co-authored-by: wuzhijian <wuch1k1n@qq.com>

* Rubicon: Add bid meta seat (prebid#4348)

* Gothamads: Add Intenze alias (prebid#4319)

* GumGum: Collect ad unit name for reporting (prebid#4302)

* Seedtag: Fix required content-type header on http calls (prebid#4299)

* Kobler: Remove sensitive device and user data (prebid#4295)

* New Adapter: Nexx360 (prebid#4286)

Co-authored-by: Gabriel Chicoye <gabriel@macbookrogab24g.lan>

* HTTP Fetcher: Implement RFC 3986 compatibility as optional (prebid#4272)

* Targeting: Add configurable targeting prefix (prebid#4355)

* Pubmatic: Set bid.meta.mediaType=video when bid.ext.ibv=true (prebid#4189)

* Rules Engine Module: Phase 1 (prebid#4407)

Co-authored-by: Veronika Solovei <kalypsonika@gmail.com>
Co-authored-by: guscarreon <guscarreon@gmail.com>

* New Adapter: Sparteo (prebid#4275)

* PubMatic: Fix missing bid type in bid response (prebid#4417)

* Fix: Remove module per request JSON marshal and add custom viper decoder (prebid#4422)

* RichAudience: change endpoint to https (prebid#4384)

Co-authored-by: IAN <ian.musachs@exte.com>

* Missena: Pass full openrtb request (prebid#4394)

* New Adapter: Rediads (prebid#4233)

* Zeta Global SSP: Declare OpenRTB 2.6 and GPP support (prebid#4389)

* Record metric unsuccessful for PBC non-200 response status code or error (prebid#4341)

Co-authored-by: oleksandr <oleksandr@assertive.ai>

* New Adapter: Akcelo (prebid#4237)

* New Adapter: Zentotem (prebid#4053)

* New Adapter: Exco (prebid#4250)

* Floors: Fix panic while getting adunit code for signaling (prebid#4424)

* Stroeercore: Add adomain to bids (prebid#4392)

* VIS.X: Relay bid currency from bid response (prebid#4381)

* TMax: Add default host config (prebid#4430)

* Fix the package (iterators) to agree with the dir (iterutil). (prebid#4447)

* TheTradeDesk: Throw error for malformed endpoint url (prebid#4419)

* Smartadserver : Send multi-impression requests without flattening (prebid#4402)

Co-authored-by: nlesommer <nlesommer@equativ.com>
Co-authored-by: gtodeschi <gregoire.todeschi@gmail.com>

* RTB House: Remove PAAPI signals from imp[].ext (prebid#4399)

* GumGum: Enable Opt-In change notification (prebid#4390)

* Tappx: Add GPID support (prebid#4438)

Co-authored-by: Jordi Arnau <jarnau@tappx.com>

* New Adapter: progx - Vidazoo alias (prebid#4428)

* New Adapter: Kuantyx - Aso alias (prebid#4420)

* MinuteMedia: Add test endpoint (prebid#4425)

* Adagio: Add site bidder param and web inventory tests (prebid#4403)

Co-authored-by: Godefroi Roussel <groussel@adagio.io>

* Modularity: Add hook code to module invocation context (prebid#4036)

* Rubicon: Pass ext.prebid.multibid[].maxbids to XAPI (prebid#4412)

* OpenX: Add gpp params to user sync (prebid#4445)

Co-authored-by: gmiedlar-ox <gabriela.miedlar@openx.com>

* New Adapter: Blis (prebid#4304)

Co-authored-by: Tomas Koutny <tomas@blis.com>

* Ogury: Support gpp for cookie sync (prebid#4406)

* TheTradeDesk: Resolve AUCTION_PRICE macro (prebid#4448)

* Fix: Set account http fetcher defaults enabling env vars (prebid#4460)

* Bidder throttling code to increase network stability. (prebid#4415)

* Adding request throttling to bidder requests

* Add latency health

* Adds new config options, metrics, and fixes

* Set default window to 1000 and fix error type typo

* Addresses PR comments

* More PR feedback

* Proper handling of the atomic uint in tests

* Yieldlab: Forward ADomain to OpenRTB bid (prebid#4404)

* Yandex: Add video support (prebid#4344)

* Request: Add hb_env=amp targeting to AMP responses (prebid#4414)

* Pubmatic: Forward skadn object in bid request (prebid#4453)

* Adds missing defaults to network throttling code (prebid#4477)

* New Adapter: Tagoras - Vidazoo alias (prebid#4329)

Co-authored-by: anna-y-perion <annay@perion.com>

* New Adapter: Omnidex - Vidazoo alias (prebid#4441)

* Define An Adapter As White Label Only (prebid#4461)

* Rules Engine Module: Result functions fix (prebid#4451)

* Account: Support bid rounding options (prebid#4470)

* Sovrn: Fix passing through imp.ext.gpid (prebid#4413)

* Smartadserver: Add second endpoint for programmatic guaranteed (prebid#4467)

Co-authored-by: Guillaume Laubier <glaubier@equativ.com>

* sspBC: Updates moving operations to backend service (prebid#4351)

* New Adapter: Adipolo - Xeworks alias (prebid#4350)

Co-authored-by: And-Rud <andrii@xe.works>
Co-authored-by: rbstdev <devgit204@xe.works>

* Modules: Exitpoint Stage (prebid#4435)

* New Adapter: Afront (prebid#4380)

* Harden HTTP Response Body Handling (prebid#4489)

* New Adapter: TeqBlaze (prebid#4480)

* Onetag: imp.ext read generalization (prebid#4446)

Co-authored-by: lorenzob <l.baglini@onetag.com>

* Rules Engine Module: Configurable cache update frequency (prebid#4423)

Co-authored-by: VeronikaSolovei9 <vsolovei@microsoft.com>

* New Adapter: RocketLab (prebid#4383)

* change zmaticoo.yaml endpoint (prebid#4471)

Co-authored-by: Quentin.zuo <quentin.zuo@eclicktech.com.cn>

* Metrics: Record GVL fetch count (prebid#4500)

* TheTradeDesk: Resolve burl if not resolved (prebid#4481)

* New Adapter: pinkLion (prebid#4376)

* Metrics: Record HTTP connections wanted and obtained (prebid#4518)

* Metrics: Record incoming request sizes (prebid#4495)

* Modules: Execute mutations in the order they are listed (prebid#4279)

* 4278 Execute mutations in the sequence they are listed.

* Ensure that the rejected channel is closed (once) on reject

* Use stack var.

* Add comments.

* Ensure rejected is closed.

* Just return explicitly in all 3 cases.

* Keep the same style - of passing the params to the go routine.

* Revert "Modules: Execute mutations in the order they are listed (prebid#4279)" (prebid#4529)

This reverts commit 93c17c2.

* Revert "Metrics: Record HTTP connections wanted and obtained (prebid#4518)" (prebid#4538)

* New Adapter: Nativery (prebid#4321)

Co-authored-by: Andrea Fassina <fasenderos@gmail.com>
Co-authored-by: nicoladellamorte <nicola.dellamorte@nativery.com>

* E-Planning: Add support for adomain (prebid#4472)

* SmileWanted: Append zoneId to endpoint path (prebid#4468)

Co-authored-by: QuentinGallard <quentin.gallard@digitalnolimit.com>

* Add configurable dialer timeouts to HTTP clients (prebid#4511)

* New Adapter: 360playvid (prebid#4395)

* New Adapter: MediaYo (prebid#4391)

* 33across: Make zoneId the preferred option (prebid#4531)

* 33across: Remove deprecated video.placement (prebid#4530)

* New Adapter: RobustApps - Xeworks alias (prebid#4434)

Co-authored-by: And-Rud <andrii@xe.works>
Co-authored-by: rbstdev <devgit204@xe.works>

* Adagio: Remove max length on params (prebid#4524)

Co-authored-by: Godefroi Roussel <groussel@adagio.io>

* fwssp: Add iframe usersync (prebid#4487)

Co-authored-by: wenyuanzhang <wenyuanzhang@freewheel.tv>

* Module: Scope3 Real-Time Data (prebid#4397)

* Add Scope3 Real-Time Data (RTD) module

This module integrates Scope3's Real-Time Data API to provide audience
segments for targeting in Prebid Server auctions.

Features:
- Fetches real-time audience segments from Scope3 API
- Adds targeting data to bid requests via hooks system
- Thread-safe segment storage during auction lifecycle
- Configurable timeout and endpoint settings
- Graceful error handling that doesn't fail auctions

The module implements three hook stages:
- Entrypoint: Initialize module context
- Raw Auction Request: Fetch segments from Scope3 API
- Processed Auction Request: Add segments to targeting data

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add LiveRamp ATS integration and execution order documentation

- Document proper execution order when using with LiveRamp ATS
- Add user identifier detection for RampID integration
- Include configuration examples for sequential module execution
- Enhance API requests with available user identifiers
- Add comprehensive documentation for Yahoo deployment scenario

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add LiveRamp ATS envelope support for publishers without sidecar

- Support forwarding encrypted ATS envelopes directly to Scope3 API
- Check multiple envelope locations: user.ext.liveramp_idl, user.ext.ats_envelope, ext.liveramp_idl
- Prioritize sidecar RampID over envelope when both available
- Document both sidecar and envelope integration patterns
- Add note about Scope3 needing LiveRamp partner authorization

This enables publishers without LiveRamp sidecar to still benefit from
LiveRamp ATS user signals via encrypted envelope forwarding.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Clean up debug code and finalize production-ready Scope3 RTD module

- Remove all debug logging statements
- Streamline segment storage and retrieval between hooks
- Finalize request-level targeting for GAM integration
- Production-ready code with proper error handling
- Complete documentation with configuration examples

The module is now ready for production deployment with:
- Successful Scope3 API integration
- LiveRamp ATS compatibility (sidecar and envelope)
- GAM targeting data output
- Thread-safe segment management

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Simplify targeting output to single GAM-compatible format

- Remove duplicate data.scope3_segments array format
- Keep only targeting.hb_scope3_segments as comma-separated string
- Follows standard header bidding targeting key conventions
- Optimized for GAM key-value targeting integration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add unit tests for Scope3 RTD module

- Add basic unit tests for module builder and hook functions
- Test invalid config handling and error cases
- Test entrypoint hook initialization
- Test processed auction hook with no segments
- Satisfy CI requirements for test coverage

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix Go formatting issues

- Remove trailing whitespace in module.go
- Add missing newline at end of module_test.go
- Satisfy gofmt validation requirements

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Address PR feedback: Add caching, improve LiveRamp integration, enhance configurability

Key improvements based on reviewer feedback:
- Add intelligent caching with configurable TTL to handle repeated requests
- Set 60-second default cache TTL for frequency cap compatibility
- Improve LiveRamp identifier detection across multiple locations
- Remove unsubstantiated partnership claims and improve documentation
- Add cache_ttl_seconds and bid_meta_data configuration options
- Implement MD5-based cache keys from user IDs and site context
- Add comprehensive test coverage for new caching functionality
- Update documentation to explain targeting vs bid.meta approach
- Change default timeout to 1000ms for better API compatibility

Addresses concerns about:
- Performance with hundreds of identical requests per user session
- Flexibility in targeting data output (bid.meta future enhancement noted)
- Accurate LiveRamp integration documentation
- Proper hook implementation code naming

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Complete PR feedback implementation: Response-level segments with GAM targeting

Major changes to address all PR reviewer feedback:

**Response Format Changes:**
- Move from request targeting to auction response data per reviewer feedback
- Change hook stage from processed_auction_request to auction_response
- Add segments to response.ext.scope3.segments for publisher control
- Add individual GAM targeting keys when add_to_targeting=true (e.g., gmp_eligible=true)

**Configuration Updates:**
- Rename bid_meta_data to add_to_targeting for clarity
- Add comprehensive GAM integration with individual segment keys
- Remove incorrect LiveRamp RTD adapter references from README
- Update hook configuration examples to use auction_response stage

**API Integration Fixes:**
- Correct segment parsing to exclude destination field (triplelift.com)
- Extract only actual segments from imp[].ext.scope3.segments[]
- Maintain working authentication and caching functionality

**Enhanced Testing:**
- Add comprehensive mock API integration tests
- Test both response formats (scope3 + targeting sections)
- Test error handling with mock server responses
- Apply gofmt formatting to all code

**Publisher Benefits:**
- Full control over segment usage via response.ext.scope3.segments
- Optional automated GAM integration via individual targeting keys
- Flexible configuration for different use cases
- Maintains caching for high-frequency scenarios

Addresses all PR reviewer concerns while providing maximum publisher flexibility.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Address PR feedback: Add optimized HTTP Transport for high-frequency API calls

  Per reviewer feedback (@gravelg): 'if we're going to be make a lot of calls,
  we should use a Transport with better defaults'

  - MaxIdleConns: 100 (increased connection pool)
  - MaxIdleConnsPerHost: 10 (multiple connections per host)
  - IdleConnTimeout: 90s (longer connection reuse)
  - ForceAttemptHTTP2: true (HTTP/2 for better performance)
  - DisableCompression: false (bandwidth optimization)

  🤖 Generated with [Claude Code](https://claude.ai/code)
  Co-Authored-By: Claude <noreply@anthropic.com>

* run gofmt

* update default endpoint

* fix test

* address comments

* more review comments

* address more comments

* remove unused enhanceRequestWithUserIDs method

* jsonutil, add more tests

* Add privacy field masking for Scope3 RTD module

Implement comprehensive privacy protection by masking sensitive user data
before sending bid requests to the Scope3 API while preserving essential
targeting capabilities.

Features:
- Configurable field masking with privacy-first defaults
- Geographic data truncation with configurable precision (default: 2 decimals ~1.1km)
- Identity provider filtering with allowlist for preserved EIDs
- Always removes: IP addresses, user IDs, demographics, first-party data
- Always preserves: device characteristics, country/region, site/app context
- Comprehensive test coverage (92.3%) with edge case handling
- All linting checks pass with zero issues

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix cache key generation for proper per-user caching

- Use SHA-256 hashed user.id as fallback when privacy-safe identifiers are unavailable
- Maintains per-user cache segmentation for performance while protecting privacy
- Privacy-safe identifiers (RampID, LiverampIDL) take priority over hashed user.id
- Prevents accidental data leakage by returning nil on masking failures
- Add configuration validation for geo precision (max 4 decimal places)
- Add comprehensive tests for cache key behavior and configuration validation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix gofmt formatting in module_test.go

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* review fixes

* more review comments

* make it async

* address more comments

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Gabriel Gravel <ggravel@scope3.com>

* Metrics: Add connection dial metrics by adapter (prebid#4528)

* KueezRTB: Remove additionalProperties from schema (prebid#4490)

* Kargo: Add email to codepath notification workflow (prebid#4484)

Co-authored-by: Nick Llerandi <nick.llerandi@kargo.com>

* New Adapter: Contxtful (prebid#4443)

Co-authored-by: rufiange <sebastien@rufiange.com>

* Modules: Exitpoint Hook typo fix (prebid#4542)

* Consumable: Declare geoscope (prebid#4496)

* Connatix: Copy entire imp[i].ext (prebid#4521)

* Fix: Preload Prometheus adapter connection dial metric labels when enabled (prebid#4543)

Co-authored-by: oleksandr <oleksandr@assertive.ai>

* Host Option To Use OS Certs (prebid#4536)

* CPMStar: imp.ext passthrough (prebid#4450)

* MetaX: Add redirect user sync (prebid#4550)

Signed-off-by: Kehan Pan <kehan.pan@metaxsoft.com>

* New Adapter: Xapads - AdKernel alias (prebid#4534)

* Connatix: Add GPP macros (prebid#4525)

* OpenX: Return buyer exts in response (prebid#4507)

Co-authored-by: Rafal Sieczka <rafal.sieczka@openx.com>

* Yandex: Set referer and target-ref to site.page (prebid#4488)

* Nextmillennium: New fields and adapter version update (prebid#4486)

* Accounts: Add coop cookiesync priority groups (prebid#4561)

* Mobkoi: Remove url endpoint override (prebid#4555)

* GDPR: Move enforcement processing upstream (prebid#4567)

* Actions: Add publish to docker hub workflow (prebid#4558)

* Omnidex: Add GVL ID (prebid#4568)

* Adagio: Fix typo (prebid#4570)

* Improve Digital: Switch to HTTPS (prebid#4559)

* Mobkoi: Update endpoint (prebid#4523)

* Remove flaky agma test (prebid#4578)

* New Adapter: appStockSSP (prebid#4502)

Co-authored-by: Kanceliarenko <kostiantyn.k@teqblaze.com>

* Rules Engine Module: Dynamic ruleset from YAML geoscopes (prebid#4509)

* In order to protect users of prebid-server that don't use CGO, add build flag (prebid#4058)

* In order to protect users of prebid-server that don't use CGO, add build flag.

* Conditionally configure fiftyonedegrees.

* Because the module file is auto-generated, let it include fiftyonedegrees but just explain that it can't be enabled.

* include used packages.

* fix builder.

* Remove unused file.

* Add a test for the Builder when CGO is not enabled.

* New Adapter: Gravite (prebid#4547)

* New Adapter: Goldbach (prebid#4476)

* New Adapter: Showheroes (prebid#4533)

* New Adapter: Performist - Limelight Alias (prebid#4283)

* Connatix: Support GZIP (prebid#4575)

* RTBHouse: PMP removal, publisherId parameter extraction (prebid#4564)

* Adnuntius: Pass targeting to ad server (prebid#4545)

* New Adapter: Boldwin Rapid (prebid#4478)

* Scope3: Various fixes to RTD module (prebid#4544)

* PubMatic: Pass alias bidder name through (prebid#4588)

* BidTheatre: Update endpoint and add redirect user sync (prebid#4562)

* CWire: Add userSync (prebid#4516)

* New Adapter: Clydo (prebid#4535)

* New Adapter: Microsoft (msft) (prebid#4592)

* Syncer: Allow Duplicate Syncer Key For Identical Config (prebid#4622)

* Adagio: Enable site capability (prebid#4590)

* Adagio: Remove hardcoded seat name (prebid#4596)

* Warn in auction response for bidders blocked by privacy settings (prebid#4537)

Co-authored-by: oleksandr <oleksandr@assertive.ai>

* Logging: Add interface with default glog implementation (prebid#4085)

Co-authored-by: postindustria-code <oss@postindustria.com>

* msp 25-12

---------

Signed-off-by: Kehan Pan <kehan.pan@metaxsoft.com>
Co-authored-by: Michael Stevens <michael.stevens@dianomi.com>
Co-authored-by: tomaszbmf <142428312+tomaszbmf@users.noreply.github.com>
Co-authored-by: FlatAds <83808812+flatads@users.noreply.github.com>
Co-authored-by: wuzhijian <wuch1k1n@qq.com>
Co-authored-by: Anton Babak <76536883+AntoxaAntoxic@users.noreply.github.com>
Co-authored-by: support-gotham-ads <support@gothamads.com>
Co-authored-by: ShayanK16GumGum <shayan.khan@ic.gumgum.com>
Co-authored-by: sangarbe <sangarbe@gmail.com>
Co-authored-by: Tommy Pettersen <42890605+TommyHPettersen@users.noreply.github.com>
Co-authored-by: Gabriel Chicoye <gabriel.chicoye@gmail.com>
Co-authored-by: Gabriel Chicoye <gabriel@macbookrogab24g.lan>
Co-authored-by: Sigma Software <prebid.opensource@sigma.software>
Co-authored-by: pm-priyanka-bagade <156899734+pm-priyanka-bagade@users.noreply.github.com>
Co-authored-by: Brian Sardo <1168933+bsardo@users.noreply.github.com>
Co-authored-by: Veronika Solovei <kalypsonika@gmail.com>
Co-authored-by: guscarreon <guscarreon@gmail.com>
Co-authored-by: t-sormonte <t.sormonte@sparteo.com>
Co-authored-by: Isha Bharti <isha.bharti@pubmatic.com>
Co-authored-by: Rich Audience <sergi.gimenez@richaudience.com>
Co-authored-by: IAN <ian.musachs@exte.com>
Co-authored-by: Jean-Sébastien Ney <jeansebastien.ney@gmail.com>
Co-authored-by: rediads <123890182+rediads@users.noreply.github.com>
Co-authored-by: abermanov-zeta <95416296+abermanov-zeta@users.noreply.github.com>
Co-authored-by: linux019 <anode.dev@gmail.com>
Co-authored-by: oleksandr <oleksandr@assertive.ai>
Co-authored-by: Roger <104763658+rogerDyl@users.noreply.github.com>
Co-authored-by: zentotem <programmatic@zentotem.net>
Co-authored-by: Pete <petropo@ex.co>
Co-authored-by: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com>
Co-authored-by: Philip Watson <philip.watson@adscale.co.nz>
Co-authored-by: Vladimir Fedoseev <vl.fedoseev@gmail.com>
Co-authored-by: Sheridan C Rawlins <41922797+scr-oath@users.noreply.github.com>
Co-authored-by: andre-gielow-ttd <124626380+andre-gielow-ttd@users.noreply.github.com>
Co-authored-by: Nathan Le Sommer <lesommer.nathan@gmail.com>
Co-authored-by: nlesommer <nlesommer@equativ.com>
Co-authored-by: gtodeschi <gregoire.todeschi@gmail.com>
Co-authored-by: Piotr Jaworski <109736938+piotrj-rtbh@users.noreply.github.com>
Co-authored-by: sindhuja-sridharan <148382298+sindhuja-sridharan@users.noreply.github.com>
Co-authored-by: jordi-tappx <jarnau@techsoulogy.com>
Co-authored-by: Jordi Arnau <jarnau@tappx.com>
Co-authored-by: Anna Yablonsky <annay@perion.com>
Co-authored-by: Adserver.Online <61009237+adserver-online@users.noreply.github.com>
Co-authored-by: inna <innayare@gmail.com>
Co-authored-by: GodefroiRoussel <GodefroiRoussel@users.noreply.github.com>
Co-authored-by: Godefroi Roussel <groussel@adagio.io>
Co-authored-by: Kacper Fus <kacper.fus@openx.com>
Co-authored-by: gmiedlar-ox <gabriela.miedlar@openx.com>
Co-authored-by: tomaskoutny-blis <60094686+tomaskoutny-blis@users.noreply.github.com>
Co-authored-by: Tomas Koutny <tomas@blis.com>
Co-authored-by: Vincent Bachelier <vincent@ogury.co>
Co-authored-by: hhhjort <31041505+hhhjort@users.noreply.github.com>
Co-authored-by: yuu.t <tongyu24@hotmail.com>
Co-authored-by: Dmitry Ermakov <skfyann@gmail.com>
Co-authored-by: Saar Amrani <saar120@gmail.com>
Co-authored-by: Scott Kay <noreply@syntaxnode.com>
Co-authored-by: Sandy Janicki <sejanick@users.noreply.github.com>
Co-authored-by: Guillaume Laubier <guillaume.laubier@hotmail.fr>
Co-authored-by: Guillaume Laubier <glaubier@equativ.com>
Co-authored-by: mabielinski-wpm <155963187+mabielinski-wpm@users.noreply.github.com>
Co-authored-by: Andrii Rudyk <96918101+And-Rud@users.noreply.github.com>
Co-authored-by: And-Rud <andrii@xe.works>
Co-authored-by: rbstdev <devgit204@xe.works>
Co-authored-by: Afrontio <support@afront.io>
Co-authored-by: MaksymTeqBlaze <maksym.pavliv@teqblaze.com>
Co-authored-by: esimonelli@onetag <136568337+EmanueleSimonelli@users.noreply.github.com>
Co-authored-by: lorenzob <l.baglini@onetag.com>
Co-authored-by: VeronikaSolovei9 <vsolovei@microsoft.com>
Co-authored-by: Leandro Marty <leandro.marty@rocketlab.ai>
Co-authored-by: g-coder-baiai <77920802+g-coder-baiai@users.noreply.github.com>
Co-authored-by: Quentin.zuo <quentin.zuo@eclicktech.com.cn>
Co-authored-by: prebidPinkLion <prebid@pinklion.io>
Co-authored-by: andreafassina <127768714+andreafassina@users.noreply.github.com>
Co-authored-by: Andrea Fassina <fasenderos@gmail.com>
Co-authored-by: nicoladellamorte <nicola.dellamorte@nativery.com>
Co-authored-by: Agustin Insua <Nistenf@users.noreply.github.com>
Co-authored-by: Quentin Gallard <QuentinGallard@users.noreply.github.com>
Co-authored-by: QuentinGallard <quentin.gallard@digitalnolimit.com>
Co-authored-by: pb360playvid <prebid@360playvid.com>
Co-authored-by: mediayo <yehuda@mediayo.co>
Co-authored-by: Carlos Felix <carloshto@gmail.com>
Co-authored-by: rbstdev <devgit204@gmail.com>
Co-authored-by: Wenyuan Zhang <wzhang910@cable.comcast.com>
Co-authored-by: wenyuanzhang <wenyuanzhang@freewheel.tv>
Co-authored-by: Brian O'Kelley <bokelley@scope3.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Gabriel Gravel <ggravel@scope3.com>
Co-authored-by: Amit Biton <56631148+amitbiton01@users.noreply.github.com>
Co-authored-by: Shane Lacey <shanel262@hotmail.com>
Co-authored-by: Nick Llerandi <nick.llerandi@kargo.com>
Co-authored-by: Sebastien Boisvert <sebastien.boisvert@contxtful.com>
Co-authored-by: rufiange <sebastien@rufiange.com>
Co-authored-by: richardngo-consumable <rngo@consumable.com>
Co-authored-by: Karim Mourra <karim@jwplayer.com>
Co-authored-by: Joshua Tomlinson <og.ginger@gmail.com>
Co-authored-by: metax-kehan <115962296+metax-kehan@users.noreply.github.com>
Co-authored-by: Denis Logachov <ckbo3hrk@gmail.com>
Co-authored-by: Rafal Sieczka <rafal.sieczka@openx.com>
Co-authored-by: Dmitry Ermakov <dimurer@yandex-team.ru>
Co-authored-by: a.popov <60257866+allar15@users.noreply.github.com>
Co-authored-by: Marc-Enzo Bonnafon <marcenzo.bonnafon@gmail.com>
Co-authored-by: Olivier <osazos@adagio.io>
Co-authored-by: Jozef Bartek <31618107+jbartek25@users.noreply.github.com>
Co-authored-by: Appstock LTD <sdksupport@app-stock.com>
Co-authored-by: Kanceliarenko <kostiantyn.k@teqblaze.com>
Co-authored-by: teqblaze <162988436+teqblaze@users.noreply.github.com>
Co-authored-by: Simon Aebli <simon.aebli@goldbach.com>
Co-authored-by: Filip Stamenkovic <ficadub@gmail.com>
Co-authored-by: quietPusher <129727954+quietPusher@users.noreply.github.com>
Co-authored-by: Mikael Lundin <mikael-lundin@users.noreply.github.com>
Co-authored-by: BoldwinDev <sdk@bold-win.com>
Co-authored-by: Gabriel Gravel <gravelg@users.noreply.github.com>
Co-authored-by: Pubmatic-Supriya-Patil <131644110+Pubmatic-Supriya-Patil@users.noreply.github.com>
Co-authored-by: andreasgreen <andreas.green@gmail.com>
Co-authored-by: Alessandro Rosetti <alessandro.rosetti@gmail.com>
Co-authored-by: cto-clydo <cto@clydo.io>
Co-authored-by: Eugene Dorfman <eugene.dorfman@gmail.com>
Co-authored-by: postindustria-code <oss@postindustria.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants