pubstackBidAdapter: initial release#14490
Conversation
* feat: add SparkBidAdapter * fix: reviews * fix: use iframe for user_sync * fix: change adapter name * fix: add test file * feat: add viewport value in imp[].ext.prebid.bidder.pubstack.vpl * fix: remove unused context * Pubstack Adapter: update utils and align adapter tests * Pubstack Bid Adapter: apply lint-driven TypeScript cleanups --------- Co-authored-by: gpolaert <gpolaert@pubstack.io>
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Pubstack bidder adapter for Prebid.js, enabling publishers to integrate with the Pubstack exchange for header bidding.
Changes:
- Added a new TypeScript bid adapter module (pubstackBidAdapter.ts) that supports banner, video, and native ad formats
- Created a utility library (pubstackUtils) for viewport distance calculation and page visibility detection
- Added comprehensive test coverage for both the adapter and utility functions
- Updated metadata to register the new bidder with GVLID 1408
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/pubstackBidAdapter.ts | Main bid adapter implementing ORTB conversion, bid validation, request building, and user sync |
| modules/pubstackBidAdapter.md | Documentation and test parameters for the Pubstack adapter |
| libraries/pubstackUtils/index.ts | Utility functions for element location, viewport distance calculation, and page visibility |
| test/spec/modules/pubstackBidAdapter_spec.js | Unit tests for the Pubstack bid adapter |
| test/spec/libraries/pubstackUtils_spec.js | Unit tests for the Pubstack utility library |
| metadata/modules.json | Registration of Pubstack bidder in module metadata |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
modules/pubstackBidAdapter.ts
Outdated
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | ||
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | ||
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()) | ||
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)) |
There was a problem hiding this comment.
Missing semicolon at the end of the statement. The code style should be consistent with the surrounding code which uses semicolons to terminate statements.
modules/pubstackBidAdapter.ts
Outdated
| const request = buildRequest(imps, bidderRequest, context) | ||
| const siteId = bidderRequest.bids[0].params.siteId | ||
| siteIds.add(siteId); | ||
| deepSetValue(request, 'site.publisher.id', siteId) | ||
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0) | ||
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | ||
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | ||
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | ||
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()) | ||
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)) |
There was a problem hiding this comment.
Missing semicolon at the end of the statement. The code style should be consistent with the surrounding code which uses semicolons to terminate statements.
| const request = buildRequest(imps, bidderRequest, context) | |
| const siteId = bidderRequest.bids[0].params.siteId | |
| siteIds.add(siteId); | |
| deepSetValue(request, 'site.publisher.id', siteId) | |
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0) | |
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | |
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | |
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | |
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()) | |
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)) | |
| const request = buildRequest(imps, bidderRequest, context); | |
| const siteId = bidderRequest.bids[0].params.siteId; | |
| siteIds.add(siteId); | |
| deepSetValue(request, 'site.publisher.id', siteId); | |
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0); | |
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | |
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | |
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | |
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()); | |
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)); |
modules/pubstackBidAdapter.ts
Outdated
| const request = buildRequest(imps, bidderRequest, context) | ||
| const siteId = bidderRequest.bids[0].params.siteId | ||
| siteIds.add(siteId); | ||
| deepSetValue(request, 'site.publisher.id', siteId) | ||
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0) | ||
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | ||
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | ||
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | ||
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()) | ||
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)) |
There was a problem hiding this comment.
Missing semicolon at the end of the statement. The code style should be consistent with the surrounding code which uses semicolons to terminate statements.
| const request = buildRequest(imps, bidderRequest, context) | |
| const siteId = bidderRequest.bids[0].params.siteId | |
| siteIds.add(siteId); | |
| deepSetValue(request, 'site.publisher.id', siteId) | |
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0) | |
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | |
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | |
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | |
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()) | |
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)) | |
| const request = buildRequest(imps, bidderRequest, context); | |
| const siteId = bidderRequest.bids[0].params.siteId; | |
| siteIds.add(siteId); | |
| deepSetValue(request, 'site.publisher.id', siteId); | |
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0); | |
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | |
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | |
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | |
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()); | |
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)); |
modules/pubstackBidAdapter.ts
Outdated
| const request = buildRequest(imps, bidderRequest, context) | ||
| const siteId = bidderRequest.bids[0].params.siteId | ||
| siteIds.add(siteId); | ||
| deepSetValue(request, 'site.publisher.id', siteId) | ||
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0) | ||
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | ||
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | ||
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | ||
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()) | ||
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)) |
There was a problem hiding this comment.
Missing semicolon at the end of the statement. The code style should be consistent with the surrounding code which uses semicolons to terminate statements.
| const request = buildRequest(imps, bidderRequest, context) | |
| const siteId = bidderRequest.bids[0].params.siteId | |
| siteIds.add(siteId); | |
| deepSetValue(request, 'site.publisher.id', siteId) | |
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0) | |
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | |
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | |
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | |
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()) | |
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)) | |
| const request = buildRequest(imps, bidderRequest, context); | |
| const siteId = bidderRequest.bids[0].params.siteId; | |
| siteIds.add(siteId); | |
| deepSetValue(request, 'site.publisher.id', siteId); | |
| deepSetValue(request, 'test', config.getConfig('debug') ? 1 : 0); | |
| deepSetValue(request, 'ext.prebid.version', getGlobal()?.version ?? 'unknown'); | |
| deepSetValue(request, `ext.prebid.cntRequest`, cntRequest); | |
| deepSetValue(request, `ext.prebid.cntImp`, cntImp); | |
| deepSetValue(request, `ext.prebid.pVisible`, isPageVisible()); | |
| deepSetValue(request, `ext.prebid.uStart`, Math.trunc((performance.now() - uStart) / 1000)); |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2f879844b3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
modules/pubstackBidAdapter.ts
Outdated
| request(buildRequest, imps, bidderRequest, context) { | ||
| cntRequest++; | ||
| const request = buildRequest(imps, bidderRequest, context) | ||
| const siteId = bidderRequest.bids[0].params.siteId |
There was a problem hiding this comment.
Preserve each bid's siteId when building batched requests
buildRequests receives all valid bids for the auction, but the request customizer always reads bidderRequest.bids[0].params.siteId and applies that single value to the whole ORTB request. When an auction contains multiple pubstack bids with different siteId values, every imp after the first is sent under the wrong publisher context (site.publisher.id and ?siteId=), which can misroute or reject those bids.
Useful? React with 👍 / 👎.
|
|
||
| return Array.from(siteIds).map(siteId => ({ | ||
| type: isIframeEnabled ? 'iframe' : 'image', | ||
| url: `${syncUrl}?consent=${payload}&siteId=${siteId}`, |
There was a problem hiding this comment.
Encode consent payload before appending to sync URL
The sync URL concatenates raw Base64 into consent= without URL-encoding it. Base64 output can contain +, and common query parsers decode + as a space, so the consent blob arrives corrupted and may fail to decode on the usersync endpoint, causing sync failures for affected consent strings.
Useful? React with 👍 / 👎.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
I ran the ESLint, but I still have semicolon and formatting issues. How can I configure it and add it as a hook before committing the files to avoid being spammed by Codex/Copilot? |
Pull Request Test Coverage Report for Build 22158457780Details
💛 - Coveralls |
| if (element) return element; | ||
| }; | ||
|
|
||
| export const getViewportDistance = (adUnitCode?: string): number | undefined => { |
There was a problem hiding this comment.
we just added another library for this, let us know if you can use that or if it needs modifications
patmmccann
left a comment
There was a problem hiding this comment.
please look into the other library - https://github.com/prebid/Prebid.js/blob/master/libraries/placementPositionInfo/placementPositionInfo.js
only copilot is complaining about your styling and I agree with it, while you do pass linting it looks strange to randomly omit semicolons on some lines |
Type of change
Bugfix
Feature
New bidder adapter
Updated bidder adapter
Code style update (formatting, local variables)
Refactoring (no functional changes, no api changes)
Build related changes
CI related changes
Does this change affect user-facing APIs or examples documented on http://prebid.org?
Other
Description of change
Other information