diff --git a/.circleci/config.yml b/.circleci/config.yml
index 22539912268..dcf2ba804c6 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,7 +7,7 @@ aliases:
- &environment
docker:
# specify the version you desire here
- - image: cimg/node:16.20-browsers
+ - image: cimg/node:20.14.0-browsers
resource_class: xlarge
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@@ -18,8 +18,6 @@ aliases:
- &restore_dep_cache
keys:
- v1-dependencies-{{ checksum "package.json" }}
- # fallback to using the latest cache if no exact match is found
- - v1-dependencies-
- &save_dep_cache
paths:
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 69e13850258..9b1bb6e39cf 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,4 +1,4 @@
-ARG VARIANT="12"
+ARG VARIANT="20"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT}
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor > /usr/share/keyrings/yarn-archive-keyring.gpg
diff --git a/.eslintrc.js b/.eslintrc.js
index f17c7a0063d..5b69afa019f 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -61,6 +61,7 @@ module.exports = {
'no-useless-escape': 'off',
'no-console': 'error',
'jsdoc/check-types': 'off',
+ 'jsdoc/no-defaults': 'off',
'jsdoc/newline-after-description': 'off',
'jsdoc/require-jsdoc': 'off',
'jsdoc/require-param': 'off',
@@ -89,11 +90,48 @@ module.exports = {
name: 'require',
message: 'use import instead'
}
+ ],
+ 'prebid/no-global': [
+ 'error',
+ ...['localStorage', 'sessionStorage'].map(name => ({name, message: 'use storageManager instead'})),
+ {
+ name: 'XMLHttpRequest',
+ message: 'use ajax.js instead'
+ },
+ ],
+ 'prebid/no-member': [
+ 'error',
+ {
+ name: 'cookie',
+ target: 'document',
+ message: 'use storageManager instead'
+ },
+ {
+ name: 'sendBeacon',
+ target: 'navigator',
+ message: 'use ajax.js instead'
+ },
+ ...['outerText', 'innerText'].map(name => ({
+ name,
+ message: 'use .textContent instead'
+ }))
]
}
})).concat([{
// code in other packages (such as plugins/eslint) is not "seen" by babel and its parser will complain.
files: 'plugins/*/**/*.js',
parser: 'esprima'
+ }, {
+ files: '**BidAdapter.js',
+ rules: {
+ 'no-restricted-imports': [
+ 'error', {
+ patterns: [
+ '**/src/events.js',
+ '**/src/adloader.js'
+ ]
+ }
+ ]
+ }
}])
};
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index b225be162a8..367ace94d37 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -41,7 +41,7 @@ For any user facing change, submit a link to a PR on the docs repo at https://gi
}
```
-Be sure to test the integration with your adserver using the [Hello World](/integrationExamples/gpt/hello_world.html) sample page. -->
+Be sure to test the integration with your adserver using the [Hello World](https://github.com/prebid/Prebid.js/blob/master/integrationExamples/gpt/hello_world.html) sample page. -->
## Other information
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
index 2e8465003e4..8d3788e8956 100644
--- a/.github/codeql/codeql-config.yml
+++ b/.github/codeql/codeql-config.yml
@@ -2,3 +2,6 @@ paths:
- src
- modules
- libraries
+queries:
+ - name: Prebid queries
+ uses: ./.github/codeql/queries
diff --git a/.github/codeql/queries/deviceMemory.ql b/.github/codeql/queries/deviceMemory.ql
new file mode 100644
index 00000000000..6f650abf0e1
--- /dev/null
+++ b/.github/codeql/queries/deviceMemory.ql
@@ -0,0 +1,14 @@
+/**
+ * @id prebid/device-memory
+ * @name Access to navigator.deviceMemory
+ * @kind problem
+ * @problem.severity warning
+ * @description Finds uses of deviceMemory
+ */
+
+import prebid
+
+from SourceNode nav
+where
+ nav = windowPropertyRead("navigator")
+select nav.getAPropertyRead("deviceMemory"), "deviceMemory is an indicator of fingerprinting"
diff --git a/.github/codeql/queries/hardwareConcurrency.ql b/.github/codeql/queries/hardwareConcurrency.ql
new file mode 100644
index 00000000000..350dbd1ae81
--- /dev/null
+++ b/.github/codeql/queries/hardwareConcurrency.ql
@@ -0,0 +1,14 @@
+/**
+ * @id prebid/hardware-concurrency
+ * @name Access to navigator.hardwareConcurrency
+ * @kind problem
+ * @problem.severity warning
+ * @description Finds uses of hardwareConcurrency
+ */
+
+import prebid
+
+from SourceNode nav
+where
+ nav = windowPropertyRead("navigator")
+select nav.getAPropertyRead("hardwareConcurrency"), "hardwareConcurrency is an indicator of fingerprinting"
diff --git a/.github/codeql/queries/prebid.qll b/.github/codeql/queries/prebid.qll
new file mode 100644
index 00000000000..02fb5adc93c
--- /dev/null
+++ b/.github/codeql/queries/prebid.qll
@@ -0,0 +1,36 @@
+import javascript
+import DataFlow
+
+SourceNode otherWindow() {
+ result = globalVarRef("top") or
+ result = globalVarRef("self") or
+ result = globalVarRef("parent") or
+ result = globalVarRef("frames").getAPropertyRead() or
+ result = DOM::documentRef().getAPropertyRead("defaultView")
+}
+
+SourceNode connectedWindow(SourceNode win) {
+ result = win.getAPropertyRead("self") or
+ result = win.getAPropertyRead("top") or
+ result = win.getAPropertyRead("parent") or
+ result = win.getAPropertyRead("frames").getAPropertyRead() or
+ result = win.getAPropertyRead("document").getAPropertyRead("defaultView")
+}
+
+SourceNode relatedWindow(SourceNode win) {
+ result = connectedWindow(win) or
+ result = relatedWindow+(connectedWindow(win))
+}
+
+SourceNode anyWindow() {
+ result = otherWindow() or
+ result = relatedWindow(otherWindow())
+}
+
+/*
+ Matches uses of property `prop` done on any window object.
+*/
+SourceNode windowPropertyRead(string prop) {
+ result = globalVarRef(prop) or
+ result = anyWindow().getAPropertyRead(prop)
+}
diff --git a/.github/codeql/queries/qlpack.yml b/.github/codeql/queries/qlpack.yml
new file mode 100644
index 00000000000..72e90d3de9b
--- /dev/null
+++ b/.github/codeql/queries/qlpack.yml
@@ -0,0 +1,8 @@
+---
+library: false
+warnOnImplicitThis: false
+name: queries
+version: 0.0.1
+dependencies:
+ codeql/javascript-all: ^1.1.1
+ codeql/javascript-queries: ^1.1.0
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
index a3246cffd6d..5876dfa0138 100644
--- a/.github/release-drafter.yml
+++ b/.github/release-drafter.yml
@@ -1,6 +1,10 @@
name-template: 'Prebid $RESOLVED_VERSION Release'
tag-template: '$RESOLVED_VERSION'
+autolabeler:
+ - label: 'maintenance'
+ title:
+ - '/^(?!.*(bug|initial|release|fix)).*$/i'
categories:
- title: '🚀 New Features'
label: 'feature'
diff --git a/.github/workflows/jscpd.yml b/.github/workflows/jscpd.yml
new file mode 100644
index 00000000000..de5f1408dff
--- /dev/null
+++ b/.github/workflows/jscpd.yml
@@ -0,0 +1,124 @@
+name: Check for Duplicated Code
+
+on:
+ pull_request_target:
+ branches:
+ - master
+
+jobs:
+ check-duplication:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Fetch all history for all branches
+ ref: ${{ github.event.pull_request.head.sha }}
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Install dependencies
+ run: |
+ npm install -g jscpd diff-so-fancy
+
+ - name: Create jscpd config file
+ run: |
+ echo '{
+ "threshold": 20,
+ "minTokens": 100,
+ "reporters": [
+ "json"
+ ],
+ "output": "./",
+ "pattern": "**/*.js",
+ "ignore": "**/*spec.js"
+ }' > .jscpd.json
+
+ - name: Run jscpd on entire codebase
+ run: jscpd
+
+ - name: Fetch base and target branches
+ run: |
+ git fetch origin +refs/heads/${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}
+ git fetch origin +refs/pull/${{ github.event.pull_request.number }}/merge:refs/remotes/pull/${{ github.event.pull_request.number }}/merge
+
+ - name: Get the diff
+ run: git diff --name-only origin/${{ github.event.pull_request.base.ref }}...refs/remotes/pull/${{ github.event.pull_request.number }}/merge > changed_files.txt
+
+ - name: List generated files (debug)
+ run: ls -l
+
+ - name: Upload unfiltered jscpd report
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: unfiltered-jscpd-report
+ path: ./jscpd-report.json
+
+ - name: Filter jscpd report for changed files
+ run: |
+ if [ ! -f ./jscpd-report.json ]; then
+ echo "jscpd-report.json not found"
+ exit 1
+ fi
+ echo "Filtering jscpd report for changed files..."
+ CHANGED_FILES=$(jq -R -s -c 'split("\n")[:-1]' changed_files.txt)
+ echo "Changed files: $CHANGED_FILES"
+ jq --argjson changed_files "$CHANGED_FILES" '
+ .duplicates | map(select(
+ (.firstFile?.name as $fname | $changed_files | any(. == $fname)) or
+ (.secondFile?.name as $sname | $changed_files | any(. == $sname))
+ ))
+ ' ./jscpd-report.json > filtered-jscpd-report.json
+ cat filtered-jscpd-report.json
+
+ - name: Check if filtered jscpd report exists
+ id: check_filtered_report
+ run: |
+ if [ $(wc -l < ./filtered-jscpd-report.json) -gt 1 ]; then
+ echo "filtered_report_exists=true" >> $GITHUB_ENV
+ else
+ echo "filtered_report_exists=false" >> $GITHUB_ENV
+ fi
+
+ - name: Upload filtered jscpd report
+ if: env.filtered_report_exists == 'true'
+ uses: actions/upload-artifact@v4
+ with:
+ name: filtered-jscpd-report
+ path: ./filtered-jscpd-report.json
+
+ - name: Post GitHub comment
+ if: env.filtered_report_exists == 'true'
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const fs = require('fs');
+ const filteredReport = JSON.parse(fs.readFileSync('filtered-jscpd-report.json', 'utf8'));
+ let comment = "Whoa there, partner! 🌵🤠 We wrangled some duplicated code in your PR:\n\n";
+ function link(dup) {
+ return `https://github.com/${{ github.event.repository.full_name }}/blob/${{ github.event.pull_request.head.sha }}/${dup.name}#L${dup.start + 1}-L${dup.end - 1}`
+ }
+ filteredReport.forEach(duplication => {
+ const firstFile = duplication.firstFile;
+ const secondFile = duplication.secondFile;
+ const lines = duplication.lines;
+ comment += `- [\`${firstFile.name}\`](${link(firstFile)}) has ${lines} duplicated lines with [\`${secondFile.name}\`](${link(secondFile)})\n`;
+ });
+ comment += "\nReducing code duplication by importing common functions from a library not only makes our code cleaner but also easier to maintain. Please move the common code from both files into a library and import it in each. We hate that we have to mention this, however, commits designed to hide from this utility by renaming variables or reordering an object are poor conduct. We will not look upon them kindly! Keep up the great work! 🚀";
+ github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body: comment
+ });
+
+ - name: Fail if duplications are found
+ if: env.filtered_report_exists == 'true'
+ run: |
+ echo "Duplications found, failing the check."
+ exit 1
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
new file mode 100644
index 00000000000..03ef6478f1c
--- /dev/null
+++ b/.github/workflows/linter.yml
@@ -0,0 +1,110 @@
+name: Check for linter warnings / exceptions
+
+on:
+ pull_request_target:
+ branches:
+ - master
+
+jobs:
+ check-linter:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ ref: ${{ github.event.pull_request.base.sha }}
+
+ - name: Fetch base and target branches
+ run: |
+ git fetch origin +refs/heads/${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}
+ git fetch origin +refs/pull/${{ github.event.pull_request.number }}/merge:refs/remotes/pull/${{ github.event.pull_request.number }}/merge
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Get the diff
+ run: git diff --name-only origin/${{ github.event.pull_request.base.ref }}...refs/remotes/pull/${{ github.event.pull_request.number }}/merge | grep '^\(modules\|src\|libraries\|creative\)/.*\.js$' > __changed_files.txt || true
+
+ - name: Run linter on base branch
+ run: npx eslint --no-inline-config --format json $(cat __changed_files.txt | xargs stat --printf '%n\n' 2> /dev/null) > __base.json || true
+
+ - name: Check out PR
+ run: git checkout ${{ github.event.pull_request.head.sha }}
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Run linter on PR
+ run: npx eslint --no-inline-config --format json $(cat __changed_files.txt | xargs stat --printf '%n\n' 2> /dev/null) > __pr.json || true
+
+ - name: Compare them and post comment if necessary
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const fs = require('fs');
+ const path = require('path');
+ const process = require('process');
+
+ function parse(fn) {
+ return JSON.parse(fs.readFileSync(fn)).reduce((memo, data) => {
+ const file = path.relative(process.cwd(), data.filePath);
+ if (!memo.hasOwnProperty(file)) { memo[file] = { errors: 0, warnings: 0} }
+ data.messages.forEach(({severity}) => {
+ memo[file][severity > 1 ? 'errors' : 'warnings']++;
+ });
+ return memo;
+ }, {})
+ }
+
+ function mkDiff(old, new_) {
+ const files = Object.fromEntries(
+ Object.entries(new_)
+ .map(([file, {errors, warnings}]) => {
+ const {errors: oldErrors, warnings: oldWarnings} = old[file] || {};
+ return [file, {errors: Math.max(0, errors - (oldErrors ?? 0)), warnings: Math.max(0, warnings - (oldWarnings ?? 0))}]
+ })
+ .filter(([_, {errors, warnings}]) => errors > 0 || warnings > 0)
+ )
+ return Object.values(files).reduce((memo, {warnings, errors}) => {
+ memo.errors += errors;
+ memo.warnings += warnings;
+ return memo;
+ }, {errors: 0, warnings: 0, files})
+ }
+
+ function mkComment({errors, warnings, files}) {
+ function pl(noun, number) {
+ return noun + (number === 1 ? '' : 's')
+ }
+ if (errors === 0 && warnings === 0) return;
+ const summary = [];
+ if (errors) summary.push(`**${errors}** linter ${pl('error', errors)}`)
+ if (warnings) summary.push(`**${warnings}** linter ${pl('warning', warnings)}`)
+ let cm = `Tread carefully! This PR adds ${summary.join(' and ')} (possibly disabled through directives):\n\n`;
+ Object.entries(files).forEach(([file, {errors, warnings}]) => {
+ const summary = [];
+ if (errors) summary.push(`+${errors} ${pl('error', errors)}`);
+ if (warnings) summary.push(`+${warnings} ${pl('warning', warnings)}`)
+ cm += ` * \`${file}\` (${summary.join(', ')})\n`
+ })
+ return cm;
+ }
+
+ const [base, pr] = ['__base.json', '__pr.json'].map(parse);
+ const comment = mkComment(mkDiff(base, pr));
+
+ if (comment) {
+ github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body: comment
+ });
+ }
diff --git a/.nvmrc b/.nvmrc
index 66df3b7ab2d..f203ab89b79 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-12.16.1
+20.13.1
diff --git a/PR_REVIEW.md b/PR_REVIEW.md
index 9deac9963fb..f6a2c157d2d 100644
--- a/PR_REVIEW.md
+++ b/PR_REVIEW.md
@@ -23,10 +23,11 @@ General gulp commands include separate commands for serving the codebase on a bu
- Checkout the branch (these instructions are available on the GitHub PR page as well).
- Verify PR is a single change type. Example, refactor OR bugfix. If more than 1 type, ask submitter to break out requests.
- Verify code under review has at least 80% unit test coverage. If legacy code doesn't have enough unit test coverage, require that additional unit tests to be included in the PR.
-- Verify tests are green in Travis-ci + local build by running `gulp serve` | `gulp test`
+- Verify tests are green in circle-ci + local build by running `gulp serve` | `gulp test`
- Verify no code quality violations are present from linting (should be reported in terminal)
- Make sure the code is not setting cookies or localstorage directly -- it must use the `StorageManager`.
- Review for obvious errors or bad coding practice / use best judgement here.
+- Don't allow needless code duplication with other js files; require both files import common code. Do not allow commits designed to fool the code duplication checker.
- If the change is a new feature / change to core prebid.js - review the change with a Tech Lead on the project and make sure they agree with the nature of change.
- If the change results in needing updates to docs (such as public API change, module interface etc), add a label for "needs docs" and inform the submitter they must submit a docs PR to update the appropriate area of Prebid.org **before the PR can merge**. Help them with finding where the docs are located on prebid.org if needed.
- If all above is good, add a `LGTM` comment and, if the change is in PBS-core or is an important module like the prebidServerBidAdapter, request 1 additional core member to review.
@@ -51,20 +52,21 @@ Follow steps above for general review process. In addition, please verify the fo
- If the adapter being submitted is an alias type, check with the bidder contact that is being aliased to make sure it's allowed.
- All bidder parameter conventions must be followed:
- Video params must be read from AdUnit.mediaTypes.video when available; however bidder config can override the ad unit.
- - First party data must be read from [getConfig('ortb2');](https://docs.prebid.org/dev-docs/publisher-api-reference/setConfig.html#setConfig-fpd).
+ - First party data must be read from the bid request object: bidrequest.ortb2
- Adapters that accept a floor parameter must also support the [floors module](https://docs.prebid.org/dev-docs/modules/floors.html) -- look for a call to the `getFloor()` function.
- Adapters cannot accept an schain parameter. Rather, they must look for the schain parameter at bidRequest.schain.
- The bidderRequest.refererInfo.referer must be checked in addition to any bidder-specific parameter.
- Page position must come from bidrequest.mediaTypes.banner.pos or bidrequest.mediaTypes.video.pos
- - Global OpenRTB fields should come from [getConfig('ortb2');](https://docs.prebid.org/dev-docs/publisher-api-reference/setConfig.html#setConfig-fpd):
+ - Eids object is to be preferred to Userids object in the bid request, as the userid object may be removed in a future version
+ - Global OpenRTB fields should come from bidrequest.ortb2
- bcat, battr, badv
- Impression-specific OpenRTB fields should come from bidrequest.ortb2imp
- instl
- Below are some examples of bidder specific updates that should require docs update (in their dev-docs/bidders/BIDDER.md file):
- - If they support the GDPR consentManagement module and TCF1, add `gdpr_supported: true`
- - If they support the GDPR consentManagement module and TCF2, add `tcf2_supported: true`
+ - If they support the TCF consentManagementTcf module and TCF2, add `tcf2_supported: true`
- If they support the US Privacy consentManagementUsp module, add `usp_supported: true`
- - If they support one or more userId modules, add `userId: (list of supported vendors)`
+ - If they support the GPP consentManagementGpp module, add `gpp_supported: true`
+ - If they support one or more userId modules, add `userId: (list of supported vendors) or (all)`
- If they support video and/or native mediaTypes add `media_types: video, native`. Note that display is added by default. If you don't support display, add "no-display" as the first entry, e.g. `media_types: no-display, native`
- If they support COPPA, add `coppa_supported: true`
- If they support SChain, add `schain_supported: true`
@@ -100,7 +102,7 @@ Follow steps above for general review process. In addition:
- modules/userId/userId.md
- tests can go either within the userId_spec.js file or in their own _spec file if they wish
- GVLID is recommended in the *IdSystem file if they operate in EU
-- make sure example configurations align to the actual code (some modules use the userId storage settings and allow pub configuration, while others handle reading/writing cookies on their own, so should not include the storage params in examples)
+- make sure example configurations align to the actual code (some modules use the userId storage settings and allow pub configuration, while others handle reading/writing cookies on their own, so should not include the storage params in examples). This ability to write will be removed in a future version, see https://github.com/prebid/Prebid.js/issues/10710
- the 3 available methods (getId, extendId, decode) should be used as they were intended
- decode (required method) should not be making requests to retrieve a new ID, it should just be decoding a response
- extendId (optional method) should not be making requests to retrieve a new ID, it should just be adding additional data to the id object
@@ -121,6 +123,7 @@ Follow steps above for general review process. In addition:
- Confirm that the module
- is not loading external code. If it is, escalate to the #prebid-js Slack channel.
- is reading `config` from the function signature rather than calling `getConfig`.
+ - Is practicing reasonable data minimization, eg not sending all eids over the wire without publisher whitelisting
- is sending data to the bid request only as either First Party Data or in bidRequest.rtd.RTDPROVIDERCODE.
- is making HTTPS requests as early as possible, but not more often than needed.
- doesn't force bid adapters to load additional code.
diff --git a/README.md b/README.md
index f890f055104..65dc668164e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[![Build Status](https://circleci.com/gh/prebid/Prebid.js.svg?style=svg)](https://circleci.com/gh/prebid/Prebid.js)
-[![Percentage of issues still open](http://isitmaintained.com/badge/open/prebid/Prebid.js.svg)](http://isitmaintained.com/project/prebid/Prebid.js "Percentage of issues still open")
+[![Percentage of issues still open](http://isitmaintained.com/badge/open/prebid/Prebid.js.svg)](https://isitmaintained.com/project/prebid/Prebid.js "Percentage of issues still open")
[![Coverage Status](https://coveralls.io/repos/github/prebid/Prebid.js/badge.svg)](https://coveralls.io/github/prebid/Prebid.js)
# Prebid.js
@@ -7,8 +7,8 @@
> A free and open source library for publishers to quickly implement header bidding.
This README is for developers who want to contribute to Prebid.js.
-Additional documentation can be found at [the Prebid homepage](http://prebid.org).
-Working examples can be found in [the developer docs](http://prebid.org/dev-docs/getting-started.html).
+Additional documentation can be found at [the Prebid.js documentation homepage](https://docs.prebid.org/prebid/prebidjs.html).
+Working examples can be found in [the developer docs](https://prebid.org/dev-docs/getting-started.html).
Prebid.js is open source software that is offered for free as a convenience. While it is designed to help companies address legal requirements associated with header bidding, we cannot and do not warrant that your use of Prebid.js will satisfy legal requirements. You are solely responsible for ensuring that your use of Prebid.js complies with all applicable laws. We strongly encourage you to obtain legal advice when using Prebid.js to ensure your implementation complies with all laws where you operate.
@@ -26,7 +26,7 @@ Prebid.js is open source software that is offered for free as a convenience. Whi
*Note:* Requires Prebid.js v1.38.0+
-Prebid.js depends on Babel and some Babel Plugins in order to run correctly in the browser. Here are some examples for
+Prebid.js depends on Babel and some Babel Plugins in order to run correctly in the browser. Here are some examples for
configuring webpack to work with Prebid.js.
With Babel 7:
@@ -37,7 +37,7 @@ module.exports = {
mode: 'production',
module: {
rules: [
-
+
// this rule can be excluded if you don't require babel-loader for your other application files
{
test: /\.m?js$/,
@@ -46,7 +46,7 @@ module.exports = {
loader: 'babel-loader',
}
},
-
+
// this separate rule is required to make sure that the Prebid.js files are babel-ified. this rule will
// override the regular exclusion from above (for being inside node_modules).
{
@@ -71,7 +71,7 @@ Or for Babel 6:
// you must manually install and specify the presets and plugins yourself
options: {
plugins: [
- "transform-object-assign", // required (for IE support) and "babel-plugin-transform-object-assign"
+ "transform-object-assign", // required (for IE support) and "babel-plugin-transform-object-assign"
// must be installed as part of your package.
require('prebid.js/plugins/pbjsGlobals.js') // required!
],
@@ -79,7 +79,7 @@ Or for Babel 6:
["env", { // you can use other presets if you wish.
"targets": { // this example is using "babel-presets-env", which must be installed if you
"browsers": [ // follow this example.
- ... // your browser targets. they should probably match the targets you're using for the rest
+ ... // your browser targets. they should probably match the targets you're using for the rest
// of your application
]
}
@@ -143,7 +143,7 @@ This will run testing but not linting. A web server will start at `http://localh
Development may be a bit slower but if you prefer linting and additional watch files you can also still run just:
- $ gulp serve
+ $ gulp serve
### Build Optimization
@@ -162,11 +162,11 @@ Building with just these adapters will result in a smaller bundle which should a
- Then run the build:
$ gulp build --modules=openxBidAdapter,rubiconBidAdapter,sovrnBidAdapter
-
+
Alternatively, a `.json` file can be specified that contains a list of modules you would like to include.
$ gulp build --modules=modules.json
-
+
With `modules.json` containing the following
```json modules.json
[
@@ -202,7 +202,7 @@ gulp bundle --tag one --modules=one.json
gulp bundle --tag two --modules=two.json
```
-This generates slightly larger files, but has the advantage of being much faster to run (after the initial `gulp build`). It's also the method used by [the Prebid.org download page](https://docs.prebid.org/download.html).
+This generates slightly larger files, but has the advantage of being much faster to run (after the initial `gulp build`). It's also the method used by [the Prebid.org download page](https://docs.prebid.org/download.html).
@@ -374,11 +374,11 @@ The results will be in
*Note*: Starting in June 2016, all pull requests to Prebid.js need to include tests with greater than 80% code coverage before they can be merged. For more information, see [#421](https://github.com/prebid/Prebid.js/issues/421).
-For instructions on writing tests for Prebid.js, see [Testing Prebid.js](http://prebid.org/dev-docs/testing-prebid.html).
+For instructions on writing tests for Prebid.js, see [Testing Prebid.js](https://prebid.org/dev-docs/testing-prebid.html).
### Supported Browsers
-Prebid.js is supported on IE11 and modern browsers until 5.x. 6.x+ transpiles to target >0.25%; not Opera Mini; not IE11.
+Prebid.js is supported on IE11 and modern browsers until 5.x. 6.x+ transpiles to target >0.25%; not Opera Mini; not IE11.
### Governance
Review our governance model [here](https://github.com/prebid/Prebid.js/tree/master/governance.md).
diff --git a/allowedModules.js b/allowedModules.js
index bc9ada39571..dbcae2db2cc 100644
--- a/allowedModules.js
+++ b/allowedModules.js
@@ -1,7 +1,6 @@
module.exports = {
'modules': [
- 'criteo-direct-rsa-validate',
'crypto-js',
'live-connect' // Maintained by LiveIntent : https://github.com/liveintent-berlin/live-connect/
],
diff --git a/browsers.json b/browsers.json
index bd6bd5772d6..0649a13e873 100644
--- a/browsers.json
+++ b/browsers.json
@@ -1,39 +1,39 @@
{
- "bs_edge_latest_windows_10": {
+ "bs_edge_latest_windows_11": {
"base": "BrowserStack",
- "os_version": "10",
+ "os_version": "11",
"browser": "edge",
"browser_version": "latest",
"device": null,
"os": "Windows"
},
- "bs_chrome_latest_windows_10": {
+ "bs_chrome_latest_windows_11": {
"base": "BrowserStack",
- "os_version": "10",
+ "os_version": "11",
"browser": "chrome",
"browser_version": "latest",
"device": null,
"os": "Windows"
},
- "bs_chrome_87_windows_10": {
+ "bs_chrome_107_windows_10": {
"base": "BrowserStack",
"os_version": "10",
"browser": "chrome",
- "browser_version": "87.0",
+ "browser_version": "107.0",
"device": null,
"os": "Windows"
},
- "bs_firefox_latest_windows_10": {
+ "bs_firefox_latest_windows_11": {
"base": "BrowserStack",
- "os_version": "10",
+ "os_version": "11",
"browser": "firefox",
"browser_version": "latest",
"device": null,
"os": "Windows"
},
- "bs_safari_latest_mac_bigsur": {
+ "bs_safari_latest_mac": {
"base": "BrowserStack",
- "os_version": "Big Sur",
+ "os_version": "Sonoma",
"browser": "safari",
"browser_version": "latest",
"device": null,
@@ -41,11 +41,11 @@
},
"bs_safari_15_catalina": {
"base": "BrowserStack",
- "os_version": "Catalina",
+ "os_version": "Monterey",
"browser": "safari",
- "browser_version": "13.1",
+ "browser_version": "15.6",
"device": null,
"os": "OS X"
}
-
+
}
diff --git a/creative/constants.js b/creative/constants.js
index d02c4c9d5e4..5f807c69f87 100644
--- a/creative/constants.js
+++ b/creative/constants.js
@@ -1,6 +1,7 @@
// eslint-disable-next-line prebid/validate-imports
-import { AD_RENDER_FAILED_REASON, EVENTS, MESSAGES } from '../src/constants.js';
+import {AD_RENDER_FAILED_REASON, EVENTS, MESSAGES} from '../src/constants.js';
+export {PB_LOCATOR} from '../src/constants.js';
export const MESSAGE_REQUEST = MESSAGES.REQUEST;
export const MESSAGE_RESPONSE = MESSAGES.RESPONSE;
export const MESSAGE_EVENT = MESSAGES.EVENT;
diff --git a/creative/crossDomain.js b/creative/crossDomain.js
index a851885bfc0..d3524f61d4b 100644
--- a/creative/crossDomain.js
+++ b/creative/crossDomain.js
@@ -1,9 +1,11 @@
import {
ERROR_EXCEPTION,
- EVENT_AD_RENDER_FAILED, EVENT_AD_RENDER_SUCCEEDED,
+ EVENT_AD_RENDER_FAILED,
+ EVENT_AD_RENDER_SUCCEEDED,
MESSAGE_EVENT,
MESSAGE_REQUEST,
- MESSAGE_RESPONSE
+ MESSAGE_RESPONSE,
+ PB_LOCATOR
} from './constants.js';
const mkFrame = (() => {
@@ -24,14 +26,27 @@ const mkFrame = (() => {
};
})();
+function isPrebidWindow(win) {
+ return !!win.frames[PB_LOCATOR];
+}
+
export function renderer(win) {
+ let target = win.parent;
+ try {
+ while (target !== win.top && !isPrebidWindow(target)) {
+ target = target.parent;
+ }
+ if (!isPrebidWindow(target)) target = win.parent;
+ } catch (e) {
+ }
+
return function ({adId, pubUrl, clickUrl}) {
const pubDomain = new URL(pubUrl, window.location).origin;
function sendMessage(type, payload, responseListener) {
const channel = new MessageChannel();
channel.port1.onmessage = guard(responseListener);
- win.parent.postMessage(JSON.stringify(Object.assign({message: type, adId}, payload)), pubDomain, [channel.port2]);
+ target.postMessage(JSON.stringify(Object.assign({message: type, adId}, payload)), pubDomain, [channel.port2]);
}
function onError(e) {
@@ -77,7 +92,7 @@ export function renderer(win) {
W.Promise.resolve(W.render(data, {sendMessage, mkFrame}, win)).then(
() => sendMessage(MESSAGE_EVENT, {event: EVENT_AD_RENDER_SUCCEEDED}),
onError
- )
+ );
});
win.document.body.appendChild(renderer);
}
diff --git a/gulpHelpers.js b/gulpHelpers.js
index 1eec08b7a3e..d68b00d799b 100644
--- a/gulpHelpers.js
+++ b/gulpHelpers.js
@@ -58,6 +58,14 @@ module.exports = {
});
}
+ try {
+ const moduleAliases = JSON.parse(
+ fs.readFileSync('module-alias.json', 'utf8')
+ );
+
+ modules = modules.map(module => moduleAliases[module] || module);
+ } catch (_e) {}
+
// we need to forcefuly include the parentModule if the subModule is present in modules list and parentModule is not present in modules list
Object.keys(submodules).forEach(parentModule => {
if (
diff --git a/gulpfile.js b/gulpfile.js
index 86c1b7fe509..a32a2d11ce6 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -147,6 +147,17 @@ function makeVerbose(config = webpackConfig) {
});
}
+function prebidSource(webpackCfg) {
+ var externalModules = helpers.getArgModules();
+
+ const analyticsSources = helpers.getAnalyticsSources();
+ const moduleSources = helpers.getModulePaths(externalModules);
+
+ return gulp.src([].concat(moduleSources, analyticsSources, 'src/prebid.js'))
+ .pipe(helpers.nameModules(externalModules))
+ .pipe(webpackStream(webpackCfg, webpack));
+}
+
function makeDevpackPkg(config = webpackConfig) {
return function() {
var cloned = _.cloneDeep(config);
@@ -163,14 +174,7 @@ function makeDevpackPkg(config = webpackConfig) {
.filter((use) => use.loader === 'babel-loader')
.forEach((use) => use.options = Object.assign({}, use.options, babelConfig));
- var externalModules = helpers.getArgModules();
-
- const analyticsSources = helpers.getAnalyticsSources();
- const moduleSources = helpers.getModulePaths(externalModules);
-
- return gulp.src([].concat(moduleSources, analyticsSources, 'src/prebid.js'))
- .pipe(helpers.nameModules(externalModules))
- .pipe(webpackStream(cloned, webpack))
+ return prebidSource(cloned)
.pipe(gulp.dest('build/dev'))
.pipe(connect.reload());
}
@@ -183,14 +187,7 @@ function makeWebpackPkg(config = webpackConfig) {
}
return function buildBundle() {
- var externalModules = helpers.getArgModules();
-
- const analyticsSources = helpers.getAnalyticsSources();
- const moduleSources = helpers.getModulePaths(externalModules);
-
- return gulp.src([].concat(moduleSources, analyticsSources, 'src/prebid.js'))
- .pipe(helpers.nameModules(externalModules))
- .pipe(webpackStream(cloned, webpack))
+ return prebidSource(cloned)
.pipe(gulp.dest('build/dist'));
}
}
@@ -413,7 +410,9 @@ function runKarma(options, done) {
// the karma server appears to leak memory; starting it multiple times in a row will run out of heap
// here we run it in a separate process to bypass the problem
options = Object.assign({browsers: helpers.parseBrowserArgs(argv)}, options)
- const child = fork('./karmaRunner.js');
+ const child = fork('./karmaRunner.js', null, {
+ env: Object.assign({}, options.env, process.env)
+ });
child.on('exit', (exitCode) => {
if (exitCode) {
done(new Error('Karma tests failed with exit code ' + exitCode));
@@ -426,7 +425,15 @@ function runKarma(options, done) {
// If --file "" is given, the task will only run tests in the specified file.
function testCoverage(done) {
- runKarma({coverage: true, browserstack: false, watch: false, file: argv.file}, done);
+ runKarma({
+ coverage: true,
+ browserstack: false,
+ watch: false,
+ file: argv.file,
+ env: {
+ NODE_OPTIONS: '--max-old-space-size=8096'
+ }
+ }, done);
}
function coveralls() { // 2nd arg is a dependency: 'test' must be finished
diff --git a/integrationExamples/gpt/51DegreesRtdProvider_example.html b/integrationExamples/gpt/51DegreesRtdProvider_example.html
new file mode 100644
index 00000000000..7864f2e05f5
--- /dev/null
+++ b/integrationExamples/gpt/51DegreesRtdProvider_example.html
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+ 51Degrees RTD submodule example - Prebid.js
+
+
+
51Degrees RTD submodule - example of usage
+
+
div-banner-native-1
+
+
No response
+
+
+
+
div-banner-native-2
+
+
No response
+
+
+
+
+
Testing/Debugging Guidance
+
+
Make sure you have debug: true under pbjs.setConfig in this example code (be sure to remove it for production!)
+
Make sure you have replaced <YOUR RESOURCE KEY> in this example code with the one you have obtained
+ from the 51Degrees Configurator Tool
+
Open DevTools Console in your browser and refresh the page
+
Observe the enriched ortb device data shown below and also in the console as part of the [51Degrees RTD Submodule]: reqBidsConfigObj: message (under reqBidsConfigObj.global.device)