Repository navigation
Conversation
* Consent Management USP: deduplicate deletion listener * Consent Management USP: retain deletion listener state
…prebid#15666) * Core: preserve eager module initialization in Babel 8 tests * Core: preserve type-only import removal with Babel 8 (prebid#15668) * Core: preserve Babel 7 type import elision (prebid#15669) * Shinez RTB Bid Adapter: stabilize resolution assertion (prebid#15677) * Core: target Safari 11 in ES5 builds (prebid#15680) * Define legacy syntax targets for Babel configuration * Update webpack.common.js * remove targets * cleanup comments --------- Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>
…15691) * User ID: initialize submodules added after config * User ID: preserve stored IDs during late initialization * User ID: test that retained submodules are not refreshed by a later config With retainConfig, a submodule left out of a later userSync config keeps its previous container, including the refreshIds flag set when it was first configured. The config listener then refreshes it again although its config did not change. This test fails until that is fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * decouple refresh / retain logic from state tracking flags * User ID: test that data deletion sees IDs of retained submodules A submodule left out of a later userSync config is retained by copying its container, while its pending callback still writes to the original. requestDataDeletion reads the copy, so onDataDeletionRequest receives an idObj that predates the callback's result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * do not refresh on first setConfig * preserve submoduleContainer identity --------- Co-authored-by: Demetrio Girardi <dgirardi@prebid.org> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…bution (prebid#15329) * web loader * add prebid.web.js * fix tests * fix disclosures with no module list input * improve buildOptionsInjector * include parent modules in dependencies * lint * increase callback name randomness * improve logging on libLoaded case; fix duplicate parents in getModules * lint * Build system: scope test-build-logic glob to spec files The merge surfaced a conflict neither side had on its own. This branch changed the mocha spec argument from the directory `./test/build-logic` to the glob `./test/build-logic/**/*` (853e428, 2026-07-08), which was harmless then -- test/build-logic held only spec files. Master later added .ts fixtures under test/build-logic/fixtures/augmentation (ea8b183, prebid#15395, 2026-08-07). The combination breaks. mocha's lookup-files treats the two argument forms differently: a directory is filtered by --extension (js,cjs,mjs) and is non-recursive, while a glob is used "as is without extensions" and fully recursive. So `**/*` swept the fixtures in as if they were specs, and mocha aborted importing broken.ts -- a deliberately broken fixture for augmentationReachable_spec, whose `import './inCore.js'` resolves to inCore.ts only under TypeScript's rules, not node's. Scope the glob to *_spec.@(js|mjs): 6 spec files, 37 passing. CI runs this task (.github/workflows/browser-tests.yml). * isolate bundle.js from other prebid bundles * do not fetch buildOptions from distUrlBase * fix buildOptions exclusion * mark libLoaded before loading * separate loading and loaded flags; do not attempt to load when defineGlobal = false * bump node version in package.json to match .nvmrc * move source maps together with the bundles * clean up loading flag after all script loads are settled * Reject web bundle loads after chunks settle (prebid#15615) --------- Co-authored-by: Patrick McCann <patmmccann@gmail.com>
* Build system: call Babel traverse default export directly * Build system: cover build options AST injection
* Update package-lock.json * Update package dependency declarations (prebid#15704) --------- Co-authored-by: Patrick McCann <pmccann@raptive.com>
Bumps [proxy-addr](https://github.com/jshttp/proxy-addr) from 2.0.7 to 2.0.8. - [Release notes](https://github.com/jshttp/proxy-addr/releases) - [Changelog](https://github.com/jshttp/proxy-addr/blob/master/HISTORY.md) - [Commits](jshttp/proxy-addr@v2.0.7...v2.0.8) --- updated-dependencies: - dependency-name: proxy-addr dependency-version: 2.0.8 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…rom single file test runs (prebid#15729) * Build system: stop watch precompiles from rewriting unchanged output `serve-and-test --file` (and the other watch tasks) re-run `precompile` on every source change. Since precompilation started materialising declarations from `.cache/ts`, each of those runs copies every `.d.ts` into `dist/src`, changed or not. The `dist/src/**/*.js` watch in `watchTaskMaker` (chokidar 3) answers a write to a file outside its pattern by re-reading that file's directory, so one spec edit caused ~1,600 directory walks, ~900 of them over `dist/src/modules`. The gulp process stalled ~50s per edit, grew by ~5GB each time, and died on the second or third edit with a V8 heap OOM (exit 134), or past a raised heap limit with `RangeError: Map maximum size exceeded` in node:domain's async hook. Two other steps rewrite identical output each cycle, and karma's webpack re-runs tests on both: - `buildOptions.mjs`, written before babel, so the suite ran once more against the previous version of the edited file before the right run; - the creative renderers, which `buildCreative` re-emits every run, so the suite ran a second time after it. All three now skip the write when the destination already holds the same bytes. Measured with `serve-and-test --file` over four spec edits: one karma run per edit, always on the edited code, ~2s after save; directory walks per edit down to 85; gulp RSS flat at ~1.3GB. gulp lint --files gulp.precompilation.js --nolintfix: clean. gulp test-build-logic: 72 passing. Cold precompile (dist/src and build/creative removed) still produces the renderers, buildOptions.mjs and all 443 declarations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Build system: don't run the build logic suite on `test-only --file` `test-build-logic` was prepended to `test-only` so that CI would run it; CI has since moved it to a job of its own and never invokes `test-only`. What remained is a local cost on the spec-iteration loop: every `test-only --file <spec>` ran the mocha build-logic suite first (~3s), and a failing build-logic test stopped the run before karma started, blocking work on unrelated specs. `test-only` without `--file`, and so `gulp test`, still run it. `gulp --tasks`: test-only's series is test-build-logic, precompile, test without --file, and precompile, test with it. `gulp test-only --file test/spec/modules/adoceanBidAdapter_spec.js`: 22 passing, 5.8s, no build-logic step. gulp lint --files gulpfile.js,gulp.precompilation.js --nolintfix: clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Build system: address review of the watch and test-only changes - `test-only` decides whether `--file` was given the way karmaRunner does, by truthiness. With `== null`, `--file=` (e.g. an unset variable expanded into `--file=$SPEC`) dropped the build-logic suite while karma, reading "" as no file, still ran the full suite. - copyDeclarations_spec: cover a destination that is already present - left untouched when identical, overwritten when it differs. The existing cases always removed it first, so neither always-write nor a comparison that misses a difference would have failed them. Checked by mutation: forcing isUpToDate to false fails the first new case, comparing sizes only fails the second. - Narrow the isUpToDate and renderer comments to the local mechanism. They described other components' behaviour (karma-webpack, chokidar, the watchTaskMaker glob, buildCreative), and claimed every identical-output step checks before writing, which generateGlobalDef, generateTypeSummary and stampPrecompiled do not. For the record, the mechanisms the comments no longer name: karma-webpack re-runs tests on any rebuild of a module in its graph (buildOptions.mjs is imported throughout); the `dist/src/**/*.js` watch in watchTaskMaker re-reads a directory when a file outside its pattern there is written; buildCreative re-emits every renderer on each run. gulp lint (changed files, --nolintfix): clean. gulp test-build-logic: 74 passing. `gulp --tasks`: test-build-logic present in test-only for no --file and --file=, absent for --file x. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Build system: don't re-run karma watch tests when a source map changes karma's webpack config is a clone of webpack.conf.js, so it inherits the `extractSourceMap: true` rule: webpack reads each module's `.map` while building and records it as an input. A precompile writes a module's `.js` and its `.map` separately, ~0.1-0.6s apart, so after one edit to a non-spec source file the watch invalidated once or twice on the `.js` and once or twice on the `.map`, each a separate rebuild and test run - 2-4 runs per edit, rising over a session, and the same on master. A rebuild that caught the map mid-write also warned "Unexpected end of JSON input" and dropped the map. In watch mode, ignore `.map` changes. A map only changes along with its `.js`. Single-run mode and the bundle builds are unchanged. Also: the isUpToDate comment named "the steps below" as checking it, which generateGlobalDef and generateTypeSummary do not; it now names the three that do. Measured with `serve-and-test --file`: 5 edits to a module's source and 4 to the spec, 20s apart - one karma run per edit, each on the edited code, no map warnings, gulp RSS peak 1.6GB / 1.3GB. gulp test-build-logic: 76 passing; flipping the watch-mode condition fails both new karmaConfig cases. gulp lint (changed files, --nolintfix): clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Build system: batch karma watch changes instead of ignoring source maps Ignoring `.map` changes kept one edit to one test run, but left the edited module's map stale in karma's bundle: the precompile always writes a module's `.js` before its `.map` (vinyl-fs dest), 0.1-0.6s apart, so the rebuild the `.js` triggers reads the previous map, and with maps ignored nothing rebuilds again. Test output is not source-mapped, so this would only show in a debugger attached to karma's page, but it is wrong. Keep watching maps and give webpack's watch a 1s aggregateTimeout in karma watch mode instead (default 20ms), so a `.js` and its `.map` land in one rebuild. A map later than that gives a second, correct rebuild rather than a stale one. Each run starts up to 1s later. Side effect: the one rebuild karma's webpack already did at startup (an invalidation on `dist/src/test/helpers`, which the precompile touched just before karma started) used to finish before the browser connected; it now lands after the first run, so a watch session starts with two runs of the initial code. Also reword the isUpToDate comment: describe the mechanism without listing its callers, and say a rewrite gives a stale run only when it lands before the edited file's own output. Measured with `serve-and-test --file`: 3 source edits and 3 spec edits, 20s apart, one karma run per edit on the edited code, no source map warnings, gulp RSS peak 1.4GB / 1.3GB (and 5 + 4 edits earlier, same result). gulp test-build-logic: 76 passing. gulp lint (changed files, --nolintfix): clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Build system: pin karma's watch batching delay in its test The test asserted `aggregateTimeout >= 1000`, which also passes a much longer wait. Every karma watch run starts that long after the last write, so a longer value is a regression too; pin it. For the record, since 530b553's message understates it: each watch run now starts ~1s after the last write (previously 20ms), not "up to 1s later". npx mocha test/build-logic/karmaConfig_spec.mjs: 6 passing. gulp lint (changed file, --nolintfix): clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…rebid#15657) * dspx: Prebid 11 interface update and test improvements * dspx: outstream renderer, video params --------- Co-authored-by: avj <avj8383@gmail.com>
…uildVideoUrl (prebid#15640) buildVideoUrl() documents both options.bid and options.params.cust_params as optional, but dereferenced them unconditionally: - bid.adserverTargeting threw when options.bid was omitted and targeting.getWinningBids(adUnit.code) had no winner for the ad unit. - Object.entries(custParams) threw when params.iu was a full URL that already carried cust_params and params.cust_params was not set. Default both to {} the same way gamAdServerVideo.js already does for adserverTargeting, and add regression tests for each path. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Send the result of the shared autoplay detection library (isAutoplayEnabled) as `autoplay` in the bid request, so that the SSP can avoid video demand when muted autoplay is forbidden on the page. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… the publisher's ext (prebid#15720) * Insticator Bid Adapter: add audio media type support Declares audio alongside banner and video, validates the OpenRTB 2.6 audio object, and resolves audio bids on the way back. The request carries the full audio object: 26 optional fields plus context, including the ad pod set and the audio-only signals feed, stitched and nvol. Each field is validated before it is sent, from both the ad unit and the bidder params, and ext deep merges across the two so a bidder level ext extends the ad unit's rather than replacing it. On the response, mtype decides the media type. Where it is absent VAST markup resolves to video as it did before, unless the ad unit declares audio: an audio-only unit resolves to audio, and a unit declaring both is separated by the MediaFile MIME type, which is the only thing that tells the two apart. params.audio is copied before it is read, so a publisher passing null there does not throw out of buildRequests and cost every bid in the auction. buildVideo already copies for the same reason. Also in this change, each of which stands alone: - The data URI is built from UTF-8 bytes for video as well as audio. btoa only accepts code units up to U+00FF, so a creative above that threw and lost every bid in the response, while Latin-1 characters were accepted and silently mangled into a payload declared as charset=utf-8. - Creative markup is no longer rewritten. The response body is JSON parsed before interpretResponse runs, so a backslash quote still present is creative content, and replacing it corrupted JSON carried inside a VAST element. - meta from bid.ext is type checked and copied. A DSP sending a string there made the assignments below it throw, which discards the whole response. - video.podseq is bounded to -1, 0 and 1, the values OpenRTB 2.6 defines for it. * Insticator Bid Adapter: forward the ext the publisher set on every object Each ORTB object was assembled from a named list of fields, so an ext the publisher set reached the endpoint only where the list happened to mention it. site and site.publisher sent none at all, banner had no path for one, and video carried only the bidder params copy, by way of an unfiltered spread rather than by intent. The request, source, user, regs and imp objects each sent an ext built here while dropping the publisher's. Every object now merges the publisher's ext under our own, so a field we do not model still arrives and the signals we compute still win where the two name the same scalar key. Arrays are concatenated rather than replaced, which is how mergeDeep treats them throughout Prebid. Two cases were losing data outright rather than never carrying it: - eids replaced user.ext, discarding a publisher ext already on it. - The device config was applied with a shallow assign, so a publisher ext replaced the localStorage and cookies signals instead of joining them. buildVideo also copies the bidder params before pruning invalid entries. It was deleting them from the ad unit config itself, which outlives the request. Three further fields the publisher sets were dropped, and are forwarded now: - ortb2Imp.rwdd, the rewarded flag, had no path onto the impression at all. - ortb2.user.data, where only the bidder params copy was sent. Both sources now contribute, and each is checked for being an array first: spreading a value that is not iterable throws out of buildRequests, which loses every bid in the auction rather than the one field. - ortb2.site.mobile was validated by isInteger() called without its argument, so the check never passed. The guard around it also tested the value itself for truthiness, which dropped the legitimate mobile: 0. A publisher null inside imp.ext is no longer fatal either. The impression ext is assembled in one merge rather than written into afterwards, because dset walks into any existing value whose typeof is object, and typeof null is object. The module documentation listed adUnitId as the only bid parameter. It now covers the rest of params, including the ext keys this change makes reachable. * Insticator Bid Adapter: add native media type support Declare NATIVE and build imp.native from the core-validated nativeOrtbRequest, skipping the imp when the config carries no assets so a multi-format unit keeps bidding its other media types. Forward the api, battr and ext the publisher set on mediaTypes.native, and derive the spec version from the request so imp.native.ver and the serialized request cannot disagree. On the response, map mtype 4 and native-JSON adm to the native media type, expose the parsed creative on bid.native.ortb (unwrapping legacy wrapped responses), and drop a bid whose adm is not a usable native document rather than let a shapeless object reach core's asset validation. * Insticator Bid Adapter: cover the defensive paths flagged by the coverage report Adds tests for paths the coverage report reported as unreached: video mimes validation, an unsupported optional video parameter, a stored user id that is not 36 characters, an explicit ortb2.regs.coppa, a response carrying no seatbid, and native detection of markup that is not JSON. * Insticator Bid Adapter: send bid requests as text/plain application/json is not a CORS-safelisted Content-Type, so every cross-origin bid request needs a preflight OPTIONS before it can be sent — a round trip ahead of the bid, against a tmax that is usually about a second. text/plain is safelisted and skips it. The body is unchanged JSON; only the declared header moves. This is what prebid/json-request-content-type flags. * Insticator Bid Adapter: fix COPPA test to pin the global flag off, matching the prebid#15462 refactor semantics * Insticator Bid Adapter: require audio mimes OpenRTB marks Audio.mimes as required, but an audio config without a valid mimes list still passed validation and was sent anyway — as an imp.audio missing the field, or as an empty object when nothing else was valid. An audio-only ad unit without valid mimes is now rejected. On a multi-format ad unit the audio object is left off the imp and the other media types still bid, matching the rule already used for native. Renames OPTIONAL_AUDIO_PARAMS to ORTB_AUDIO_PARAMS, since the map now holds a required field, and documents the rule in the adapter md. --------- Co-authored-by: mokshgulati-cool <moksh.gulati@cool.co>
* fix(cwire): send ad unit code in bidder.adslot * fix(cwire): simplify adslot fallback guard
…rebid#15643) * Zeta Global Ssp Adapter: migrate to ortbConverter, add param types * Zeta Global Ssp Adapter: remove unused param in test * Zeta Global Ssp Adapter: fix tests * Zeta Global Ssp Adapter: add more tests for coverage
…15648) * ● Adquery ID System: replace oversized stored qid via extendId getId isn't called when a qid is already stored, so oversized qids were never replaced. Add extendId to validate the stored qid (max 40 chars) and reuse a valid localStorage qid before generating a new one. * Adquery ID System: only check qid length in extendId Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Adquery ID System: replace non-string stored qid in extendId Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Adrian Dzida <a.dzida@openmobi.pl> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: BidTags <info@bidtags.com>
…ettles; add experimental GPT `registerRequestHook` integration example (prebid#15727) * Integration examples: add hello world using GPT request hook Copy of hello_world.html that runs the Prebid auction from googletag.pubads().registerRequestHook instead of a bidsBackHandler and failsafe timer. GPT awaits the hook (racing it against its own timeout) before sending the ad request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Core: add failing tests for requestBids promises that never settle The promise returned by requestBids is only resolved from auctionDone, so it stays pending when the auction never starts: - consent management cancels the auction (e.g. CMP not found, or static config without consentData); bidsBackHandler is called but the promise is not resolved - a startAuction hook throws, or first party data enrichment rejects; the error is swallowed by the unhandled enrichFPD -> startAuction chain These tests fail until the underlying behavior is fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * clean up example * fix bug where requestBids will sometimes never settle * do not log error when bidsBackHandler is missing * Rename hello_world_request_hook.html to hello_world_experimental_request_hook.html * update example --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Patrick McCann <patmmccann@gmail.com>
Declare the IAB TCF GVL ID and drop the local disclosureURL in favour of the one from the GVL entry.
… auctions (prebid#15735) * Core: add auctionOptions.yield config to toggle yielding between adapters * Core: test that a later s2sConfig is called when an earlier one has no bidders in the auction Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * keep old counter behavior --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ression (prebid#15703) * Core: validate gzip compression support * Core: fall back when gzip streams reject * Core: preserve bidder context for gzip requests * extract gzip utils * remove redundant catch * do not assume browser supports gzip * start gzip check on page load * lint --------- Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>
* adding acpId * - adding addtlConsents to hash fields - sanitizing consent string * adding acp id to selected adapters
* native video support * native video example * fixing content scenario * Make LegacyVideoAssetRequest properties required --------- Co-authored-by: Patrick McCann <patmmccann@gmail.com>
* New adapter: Epom Ad Server (epom_as)
Bid adapter for the sell side of the Epom platform, where a publisher's
own direct-sold campaigns are booked. Distinct from the existing epom_dsp
adapter, which is the buy side.
Epom Ad Server is white-label, so the serving host arrives per bid in
params.host and the adapter groups impressions by host, emitting one
request per host with every impression addressed to it. Keeping a host's
impressions in one auction is a requirement rather than an optimisation:
the ad server resolves a page as a unit, so its roadblock and
one-campaign-per-page rules only hold when all slots are decided together.
Banner only, built on ortbConverter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Group bids by host without casting through unknown
Array.from over the map builds the requests directly, so the accumulator
and the `as unknown as` cast around the empty group both go away.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Add channel and customParams to the Epom Ad Server adapter
Two Epom concepts the standard ORTB request cannot express. Channel is a
publisher traffic-slice label that drives targeting and reporting, and it
has no ORTB analogue of any kind, so it goes under our own imp.ext
namespace. Custom parameters go to imp.ext.data instead, because that is
where first-party data and RTD modules already contribute, and the ad
server should have one place to read targetable key-values from.
Both are sanitised to the limits the ad server enforces on ingest -
scalars only, 32 keys, 128-byte keys, 512-byte values - so a publisher
sees the same set accepted here and applied there rather than discovering
the difference in a report.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Accept a host with a port, matching the Prebid Server schema
The two adapters are meant to take byte-identical params, but the Prebid
Server JSON schema allowed host:port while the Prebid.js pattern did not.
A port cannot redirect the request: scheme, path, query and userinfo stay
excluded, which is the property that matters.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Send credentials, matching how the ad server answers CORS
The endpoint echoes the request Origin and sets Allow-Credentials, so a
first-party Epom identity on the ad-server domain can reach the auction
instead of every request looking like a new user.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Set the bid TTL to the window the impression beacon actually has
The adapter told Prebid a bid was good for 300 s while the ad server only
accepts its impression beacon within 30 s of the bid, so a cached bid
rendered a minute later counted for nothing - Prebid documents exactly
this: an ad rendered after the TTL may not be attributed.
25 s leaves five for the beacon to travel. A deployment that widens its
window can say so per bid in bid.exp, which the converter already prefers
over this default, so nothing here has to change for it.
Also fixes a test title that still said "without credentials".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Epom Ad Server: stop the TTL comment naming one deployment's window
The comment stated the beacon is accepted within 30 s, which is one deployment's
configuration rather than anything about the protocol — and a deployment widening
that window makes the comment wrong without touching the code. The constant is
the floor; a server with a wider window says so per bid in bid.exp, which is what
the sentence now says.
* Epom Ad Server: point the test parameters at a placement that fills
The block used ads.example.com, which does not resolve, so the one thing a
reviewer is asked to do — load the ad unit and confirm a bid comes back — could
not be done. The first block is now a live placement kept filled for this; the
fictional hosts stay in the second, where they illustrate grouping by deployment
rather than something to run.
* Epom Ad Server: make the two transports agree, and stop dropping a publisher's parameters
The host pattern is now byte-identical to the expression Prebid Server validates the same parameter
with. The previous one was strictly narrower — it demanded two labels, so an internal deployment
reachable as a single-label host was refused here and accepted there — while a comment claimed the
two matched. The comment is true now.
Custom parameters are no longer capped in the adapter. The caps mirrored an ad-server ingest limit,
but enforcing them here dropped entries silently, so a publisher whose targeting set was too large
saw half of it never arrive with nothing to indicate why. What the adapter does check is the shape:
a nested object or an array stringifies to something no campaign can match, so it is a
misconfiguration and the bid is refused outright, which is what the server's schema does with the
same input. The ingest limits remain the ad server's own and are documented as such.
bidFloor applies only as a positive finite number, and a negative one is refused to match the
schema's minimum. The request options block is gone: it set exactly the content type and credentials
core already applies to every POST, and the assertions that covered it were testing core.
The module declares its device-storage disclosure at the URL published on GVL vendor 849. The field
is not derived from the vendor list when omitted — it is simply recorded as null — so a vendor that
declares cookie use has to name it.
Tests cover what a misconfiguration actually looks like: every rejection path, a response body that
is not ORTB at all, and the floor precedence in both directions.
* Epom Ad Server: refuse a port a URL cannot carry
The host shape alone accepted a port outside 1-65535. `new URL()` throws on one rather than
returning something unusable, and core does not call buildRequests inside a try, so a single
mistyped port in a page's configuration took the whole request down instead of costing one bid.
The range is checked on top of the same expression Prebid Server validates this parameter with,
which is deliberately about keeping URL control characters out of a host rather than about
resolving one — hostname labels are left alone, so a single-label internal deployment still works
and the two transports still accept the same inputs.
* Epom Ad Server: support video and native
The adapter declared banner only, and Prebid will not offer a slot to a bidder
that has not declared its media type — so a video or native auction never
reached the ad server whatever it could serve.
The converter no longer pins context.mediaType. Pinning one makes it believe
every response whatever came back; left off, it reads mtype off the bid, which
is the field the ad server sets per creative. A bid naming no media type is
discarded rather than rendered as the wrong one, which is now covered by a case
of its own.
The mixed banner+video expectation is inverted with it. Stripping video from a
mixed ad unit was right while this adapter sold banner only; keeping it now
would decide the auction on the page's behalf. Assertions that need the video
or native processors are guarded on FEATURES, since the features-disabled build
compiles them out.
* Epom Ad Server: document the cache setting instream video needs
Prebid refuses an instream bid carrying only vastXml when no cache is
configured, and it does so in validation rather than in caching - so the ad
server answers correctly, the slot reports no bid, and the reason appears only
in the console. Names the three settings and which one each player needs, and
that a hosted Prebid Cache is required only for Google Ad Manager.
* Epom Ad Server: name a test placement for video and native
The adapter declares three media types but the Test Parameters section offered
only a banner placement, so a reviewer could verify one third of the claim. The
ad server decides what a placement may answer from the placement's own type, so
each media type needs its own key rather than a second mediaTypes block on the
same one. All three fill on the same demo host.
* Epom Ad Server: reject a non-string channel or bidFloorCur
isBidRequestValid now matches the Prebid Server params schema for these two
params (type: string), so an object or number is rejected on the page instead
of being stringified into imp.ext or passed straight into imp.bidfloorcur.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Epom Ad Server: address the network by networkId, keep host optional
Prebid Server does not accept an endpoint host taken from a publisher
parameter, so the server-side adapter now reaches a network at
https://{networkId}.eashb.com/hb/bid. The client-side adapter takes the same
params: a bid names its network with networkId and goes to that address by
default, which also gives the adapter the default endpoint asked for in
review. host stays as an option: when given, the bid goes to the network's
own serving domain, where its identity cookie lives.
A bid needs networkId or host; networkId must be "n" followed by digits, since
it becomes a hostname label. Impressions are grouped by destination host, as
before.
Also corrects the advertiser-domain note: the ad server sends adomain when
the advertiser has a domain set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Anton Ruin <a.ruin@epom.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Patrick McCann <patmmccann@gmail.com>
* Update domain for Adhese bid requests * Update Adhese test * Format code for consistency in adheseBidAdapter_spec.js --------- Co-authored-by: mefjush <mefjush@gmail.com> Co-authored-by: westerschmal <30859973+westerschmal@users.noreply.github.com>
* Add Sevio user ID submodule * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs * Add Sevio user ID submodule - add docs
* New Bid Adapter * version * put coppa from getConfig as fallback * addressing codex feedback * addressing maintainer's review * addressed codex review comments * updated unit tests * address codex review
* Repo: make .claude a symlink to .agents Replace the per-skill symlink .claude/skills/prebid-chrome-devtools with a single top-level .claude -> .agents symlink, so every skill (and anything else) added under .agents is picked up by Claude Code without adding a new symlink each time. Ignore .agents/settings.local.json, where Claude Code's personal settings now land. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep .claude a real directory; symlink .claude/skills to .agents/skills Addresses review feedback: a top-level .claude symlink becomes a plain file when core.symlinks=false, and replacing the directory can delete existing ignored .claude/settings.local.json files on update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…rebid#15762) * TPMN Bid Adapter: stub out adapter, remove tests, docs and examples TPMN has shut down its bidding and cookie sync services. Replace the adapter with a no-op module that logs a warning, and delete its spec, md file and integration examples. Keeping the module file means builds that still pass --modules=tpmnBidAdapter keep working; full removal can happen in Prebid 12 (prebid#15745). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * TPMN Bid Adapter: register stub as a no-op bidder Register a 'tpmn' bidder whose isBidRequestValid logs the removal warning and rejects every bid, instead of only logging at load time. This keeps the module matched to its bidder code so metadata generation (and the adapter naming check) keeps working, and surfaces the warning when a tpmn bid is actually requested, after the publisher's debug config has applied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* CI: skip spec files in the polyfill check Spec files are not part of the shipped bundle, and they already run on older browsers in the normal PR checks, so flagging polyfills they may need is noise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * exclude _spec.mjs --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>
* Apply suggested fix to modules/intenzeBidAdapter.js from Copilot Autofix Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * Intenze bidder: test zero params.bidfloor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Adapex Bid Adapter: restore on current Prebid core Reintroduce the reviewed Adapex adapter and shared Floxis helper after the upstream revert. Update integrated bidder tests to stub the new gzip module and await asynchronous dispatch, so they pass against current master. * Adapex: honor CMP deletion after storage access withdrawal * Scope consent deletion to configured adapter storage keys * Adapex: keep restoration limited to adapter changes
…prebid#15785) enforceStorageTypeRule compared the single storage type of each write ('cookie' or 'html5') with the raw storage.type string. A submodule configured with a combined type such as 'cookie&html5' never matched. Every write, including the core's own writes through the submodule's storage manager, then logged a warning. With userSync.enforceStorageType: true, every write was denied and the ID was never persisted. Check whether the type is in getConfiguredStorageTypes() instead. The rest of the module already parses storage.type with it. The warn-or-deny behaviour for unlisted types is unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Anna Yablonsky <annay+perion@perion.com>
… to 1.7.0 (prebid#15786) * adgenerationBidAdapter: stop URL-encoding privacyLink, bump version to 1.7.0 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * adgenerationBidAdapter: add test for privacyLink with query string Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Adspiro Bid Adapter: initial release * Adspiro Bid Adapter: update maintainer email * Adspiro Bid Adapter: drop per-format floors in other currencies * Adspiro Bid Adapter: rename the bidder code to ad_spiro
…d#15794) Set meta.adshield on every bid to 1 when the bid response carries an X-Adshield header and 0 otherwise. The header has no value, so presence is tested against null: getResponseHeader returns "" for a header sent without a value and null for an absent one. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* CI: clear hidden files before restoring artifacts * Update action.yml
* ortbConverter: convert audio mtype / ext.prebid.type * remove audio workaround from adferry * remove audio workaround from ad_spiro * remove ORTB_MTYPES duplication from connectad
* Core: expose most desirable bid API * Refactor comment in getMostDesirableBid function Removed unnecessary comment line from getMostDesirableBid function. * Core: filter ineligible bids before desirability reduction * Core: replace getMostDesirableBid with pbjs.getBestBids Follow the proposal in prebid#15602: add pbjs.getBestBids, mirroring getHighestCpmBids but using getHighestDesirability as the win reducer, and add a no-ad-server integration example that uses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Core: break getBestBids desirability ties on size and deals; rename example Add a getBestBid reducer for getBestBids: highest desirability, then the smaller creative (bids without a size rank as largest), then a deal, then the fastest response. getHighestDesirability is unchanged, so GAM targeting tie-breaking is unaffected. Rename the integration example to adserver_first/basic_adserver_first.html and describe the ad-server-first setup, where the ad server bids into Prebid instead of Prebid setting targeting for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Core: drop size and deal tie-breaks from getBestBids getBestBids uses getHighestDesirability again, so desirability ties fall back to the fastest response, the same as targeting. Size and deal tie-breaking is out of scope for this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * update example --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…rebid#15803) * Core: add failing tests for desirability in winning targeting (prebid#15800) getAllTargeting picks each bidder's representative bid by desirability, but the ad unit's winning keys (hb_adid, hb_pb, hb_bidder) still come from getWinningBids' default getHighestCpm reducer. Add tests for the scenario in prebid#15800: a lower-CPM, more desirable bid should win the top-level targeting, with and without send-all-bids, and agree with getWinningBids under getHighestDesirability (what getBestBids uses). Three tests fail until the fix lands; the control (desirability equal to CPM still targets the highest CPM) passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * use desirability for winner calculation * Core: add failing tests for zero desirability in deal-prioritized sort sortByDealAndPriceBucketOrDesirability(true) still uses a truthiness check on desirability, so a score of 0 is treated as absent and the comparison falls back to CPM. With enableSendAllBids, a bidLimit and sendBidsControl.dealPrioritization, getHighestCpmBidsFromBidPool and the multibid targetBidPoolHook use that sorter to cut the pool, so a higher-CPM bid with desirability 0 can displace a lower-CPM bid with desirability 2 before the winner is chosen. Add tests for the sorter itself, for getAllTargeting under that config, and for the multibid hook. All three fail until the sorter uses the same null check as sortByHighestDesirability. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Core: use a single desirability comparator for bid sorting sortByHighestDesirability, the inline branch in sortByDealAndPriceBucketOrDesirability(true) and the bidDesirabilityCompare key used by getHighestDesirability each encoded the comparison rule separately. The deal-prioritized one tested desirability for truthiness, so a score of 0 fell back to CPM and a higher-CPM, zero-desirability bid could displace a more desirable one when bidLimit and dealPrioritization were set. Export bidDesirabilityCompare and a descending highestDesirabilityFirst built from it, and use that for every default winSorter, the multibid bid-limit sort and the deal-prioritized sort. Remove sortByHighestDesirability. Bids now score as desirability ?? cpm individually, so comparing a bid with a desirability against one without no longer depends on the pair; the old pairwise fallback was not a consistent ordering for mixed lists. Comparator results are now -1/0/1 rather than a difference, and the tests that asserted exact values check the sign instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add interstitial example * address review
) * ortbConverter: populate bid.meta.deal from ext.prebid.deal Normalize the ORTB seatbid[].bid[].ext.prebid.deal extension proposed in prebid#15602 into bidResponse.meta.deal: map the numeric type to a string, camel-case pacing_adjusted_cpm and on_schedule, and copy only known, correctly typed fields. Deal metadata is ignored for bids without a dealid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ortbConverter: convert deal processor to TypeScript, keep numeric deal type Move the ext.prebid.deal normalization to deal.ts, type the extension on ORTBBid.ext.prebid, and keep meta.deal.type as the ORTB numeric enum (defaulting to 0, unknown) instead of mapping it to a string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ortbConverter: record currencies for deal CPMs Add optional ext.prebid.deal.cpm_cur and pacing_adjusted_cpm_cur, exposed as meta.deal.cpmCurrency and pacingAdjustedCpmCurrency. When a bidder omits them they default to the response currency, so the deal amounts keep an explicit unit after the currency module converts the bid's own cpm. Also drop JSON.stringify from a test title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ortbConverter: drop deal CPM currencies; convert them with the bid meta.deal.cpm and pacingAdjustedCpm are in the bid's currency. Instead of separate cpm_cur / pacing_adjusted_cpm_cur fields, the currency module scales both amounts by the same rate it applies to bid.cpm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * use consistent rounding on cpm fields --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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