Skip to content

Humansecurity RTD Provider: migrate to TypeScript and optimize token handling#14362

Merged
patmmccann merged 7 commits intoprebid:masterfrom
HumanSecurity:feature/humansecurityRtdProviderV2
Feb 5, 2026
Merged

Humansecurity RTD Provider: migrate to TypeScript and optimize token handling#14362
patmmccann merged 7 commits intoprebid:masterfrom
HumanSecurity:feature/humansecurityRtdProviderV2

Conversation

@florianerl
Copy link
Contributor

Type of change

  • Updated rtd provider

Description of change

We refactored the HUMAN RTD module to TypeScript. Token injection into ortb2Fragments is no longer hardcoded but handled by the HUMAN implementation, enabling management of which bidders receive tokens and enhancing monitoring and control of latency and performance. We also added implementation caching and auction-level telemetry hooks to improve reliability and observability.

- Removed hardcoded token injection into ortb2Fragments and delegate to the HUMAN implementation, enabling management of which bidders receive tokens and enhancing monitoring and control of latency and performance
- Introduce a cached implementation reference via getImpl()
- Add module version query parameter when loading the implementation script
- Wire onAuctionInitEvent so the implementation can collect QoS, telemetry and statistics per auction
Copilot AI review requested due to automatic review settings January 21, 2026 11:17
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 060ee7b62d

ℹ️ 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".

Comment on lines 119 to 120
const impl = getImpl();
if (!impl || typeof impl.getBidRequestData !== 'function') return;

Choose a reason for hiding this comment

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

P1 Badge Call the RTD callback when impl is unavailable

If the HUMAN script is blocked (e.g., CSP/adblocker) or fails to expose getBidRequestData, this early return skips the RTD callback. In modules/rtdModule/index.ts, the callback is what decrements callbacksExpected for waitForIt providers; skipping it makes auctions configured with waitForIt wait the full auctionDelay instead of completing immediately, which is a latency regression compared to the previous implementation that always invoked the callback. Consider invoking callback() before returning when the implementation isn’t ready.

Useful? React with 👍 / 👎.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request migrates the HUMAN Security RTD provider from JavaScript to TypeScript and refactors the token handling mechanism. Previously, the module directly injected tokens into ortb2Fragments; now it delegates this responsibility to an externally loaded HUMAN implementation script, providing better control over which bidders receive tokens and enabling enhanced monitoring capabilities.

Changes:

  • Migrated the entire module from JavaScript to TypeScript with proper type definitions
  • Removed hardcoded token injection logic and delegated it to the external HUMAN implementation
  • Added implementation caching via the getImpl() function to avoid repeated lookups
  • Added auction-level telemetry hooks through onAuctionInitEvent
  • Removed extensive test coverage for the old token injection pattern

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 13 comments.

File Description
modules/humansecurityRtdProvider.ts New TypeScript implementation with delegation pattern for token handling and auction event hooks
modules/humansecurityRtdProvider.js Original JavaScript implementation removed
test/spec/modules/humansecurityRtdProvider_spec.js Tests updated to reflect new architecture; bid enrichment tests removed as token injection is now delegated
modules/humansecurityRtdProvider.md Documentation updated to clarify latency benefits, add perBidderOptOut parameter, and improve privacy/security explanations

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


const args = loadExternalScriptStub.getCall(0).args;
expect(args[0]).to.be.equal(`${SCRIPT_URL}?r=example.com`);
expect(args[0]).to.include(`${SCRIPT_URL}?r=example.com`);
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The test now uses 'to.include' instead of 'to.be.equal', which is a more flexible assertion since the URL now includes the module version parameter (mv). However, the script URL construction in the TypeScript module now includes MODULE_VERSION in the query string, which should be reflected in test expectations if needed.

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +101
// And set up a bridge between the RTD submodule and the implementation.
impl.connect(getGlobal(), null, config);
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The entire config object (including potentially sensitive configuration from other modules) is passed to an externally loaded script via impl.connect. This could expose configuration data to third-party code. Consider passing only the necessary parameters specific to this module instead of the full config object.

Suggested change
// And set up a bridge between the RTD submodule and the implementation.
impl.connect(getGlobal(), null, config);
// Limit the data shared with the external implementation to this provider's params only.
const safeConfig = {
params: config?.params
};
// And set up a bridge between the RTD submodule and the implementation.
impl.connect(getGlobal(), null, safeConfig);

Copilot uses AI. Check for mistakes.
const impl = getImpl();
if (!impl || typeof impl.getBidRequestData !== 'function') return;

impl.getBidRequestData(reqBidsConfigObj, callback, config, userConsent);
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

User consent data and configuration objects are passed to an externally loaded script. While this may be necessary for the module's functionality, ensure that the external implementation properly handles and protects this potentially sensitive information according to privacy regulations.

Copilot uses AI. Check for mistakes.
const onAuctionInitEvent = (auctionDetails: AuctionProperties, config: RTDProviderConfig<'humansecurity'>, userConsent: AllConsentData) => {
const impl = getImpl();
if (!impl || typeof impl.onAuctionInitEvent !== 'function') return;
impl.onAuctionInitEvent(getGlobal(), auctionDetails, config, userConsent);
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

User consent data is passed to an externally loaded script. While this may be necessary for the module's functionality, ensure that the external implementation properly handles and protects this potentially sensitive information according to privacy regulations.

Copilot uses AI. Check for mistakes.
Comment on lines 91 to 95
expect(loadExternalScriptStub.calledOnce).to.be.true;

const args = loadExternalScriptStub.getCall(0).args;
expect(args[0]).to.be.equal(`${SCRIPT_URL}?r=example.com&c=customer123`);
});

it('should connect to the implementation script once it loads', function () {
load({ });

expect(loadExternalScriptStub.calledOnce).to.be.true;
expect(connectSpy.calledOnce).to.be.true;

const args = connectSpy.getCall(0).args;
expect(args[0]).to.haveOwnProperty('cmd'); // pbjs global
expect(args[0]).to.haveOwnProperty('que');
expect(args[1]).to.be.equal(onImplMessage);
});
});

describe('Bid enrichment step', function () {
const hmnsData = { 'v1': 'sometoken' };

let sandbox2;
let callbackSpy;
let reqBidsConfig;
beforeEach(function() {
sandbox2 = sinon.createSandbox();
callbackSpy = sandbox2.spy();
reqBidsConfig = { ortb2Fragments: { bidder: {}, global: {} } };
});
afterEach(function () {
sandbox2.restore();
});

it('should add empty device.ext.hmns to global ortb2 when data is yet to be received from the impl script', () => {
load({ });

onGetBidRequestData(reqBidsConfig, callbackSpy, { params: {} }, {});

expect(callbackSpy.calledOnce).to.be.true;
expect(reqBidsConfig.ortb2Fragments.global).to.have.own.property('device');
expect(reqBidsConfig.ortb2Fragments.global.device).to.have.own.property('ext');
expect(reqBidsConfig.ortb2Fragments.global.device.ext).to.have.own.property('hmns').which.is.an('object').that.deep.equals({});
});

it('should add the default device.ext.hmns to global ortb2 when no "hmns" data was yet received', () => {
load({ });

onImplMessage({ type: 'info', data: 'not a hmns message' });
onGetBidRequestData(reqBidsConfig, callbackSpy, { params: {} }, {});

expect(callbackSpy.calledOnce).to.be.true;
expect(reqBidsConfig.ortb2Fragments.global).to.have.own.property('device');
expect(reqBidsConfig.ortb2Fragments.global.device).to.have.own.property('ext');
expect(reqBidsConfig.ortb2Fragments.global.device.ext).to.have.own.property('hmns').which.is.an('object').that.deep.equals({});
});

it('should add device.ext.hmns with received tokens to global ortb2 when the data was received', () => {
load({ });

onImplMessage({ type: 'hmns', data: hmnsData });
onGetBidRequestData(reqBidsConfig, callbackSpy, { params: {} }, {});

expect(callbackSpy.calledOnce).to.be.true;
expect(reqBidsConfig.ortb2Fragments.global).to.have.own.property('device');
expect(reqBidsConfig.ortb2Fragments.global.device).to.have.own.property('ext');
expect(reqBidsConfig.ortb2Fragments.global.device.ext).to.have.own.property('hmns').which.is.an('object').that.deep.equals(hmnsData);
});

it('should update device.ext.hmns with new data', () => {
load({ });

onImplMessage({ type: 'hmns', data: { 'v1': 'should be overwritten' } });
onImplMessage({ type: 'hmns', data: hmnsData });
onGetBidRequestData(reqBidsConfig, callbackSpy, { params: {} }, {});

expect(callbackSpy.calledOnce).to.be.true;
expect(reqBidsConfig.ortb2Fragments.global).to.have.own.property('device');
expect(reqBidsConfig.ortb2Fragments.global.device).to.have.own.property('ext');
expect(reqBidsConfig.ortb2Fragments.global.device.ext).to.have.own.property('hmns').which.is.an('object').that.deep.equals(hmnsData);
expect(args[0]).to.include(`${SCRIPT_URL}?r=example.com&c=customer123`);
});
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The removed tests for bid enrichment (onGetBidRequestData) are no longer applicable since token injection is now delegated to the HUMAN implementation. However, there's no test coverage for the new delegation pattern - specifically, no tests verify that getBidRequestData properly delegates to the external implementation's getBidRequestData method when available. Consider adding tests to ensure the delegation works correctly and that the callback is properly passed through.

Copilot uses AI. Check for mistakes.

const { logWarn, logError } = prefixLog(`[${SUBMODULE_NAME}]:`);

let implRef: any = null;
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The implRef variable is typed as 'any', which defeats the purpose of TypeScript's type safety. Consider defining a proper interface for the external implementation object that includes the expected methods (connect, getBidRequestData, onAuctionInitEvent) to improve type safety and catch potential errors at compile time.

Copilot uses AI. Check for mistakes.
Comment on lines +140 to +142
type RtdProviderSpecWithHooks<P extends RTDProvider> = RtdProviderSpec<P> & {
onAuctionInitEvent?: (auctionDetails: AuctionProperties, config: RTDProviderConfig<P>, userConsent: AllConsentData) => void;
};
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

A custom type RtdProviderSpecWithHooks is defined to add onAuctionInitEvent to the module specification. This appears to be extending the standard RtdProviderSpec interface. Ensure this approach is compatible with the RTD module framework and that the onAuctionInitEvent hook will be properly invoked by the RTD module system.

Copilot uses AI. Check for mistakes.
florianerl and others added 3 commits January 21, 2026 12:27
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>
@florianerl florianerl changed the title Humansecurity RTD Provvider: migrate to TypeScript and optimize token handling Humansecurity RTD Provider: migrate to TypeScript and optimize token handling Jan 21, 2026
- add HumanSecurityImpl interface
@github-actions
Copy link

Tread carefully! This PR adds 140 linter errors and 1 linter warning (possibly disabled through directives):

  • creative/constants.js (+2 errors)
  • creative/crossDomain.js (+1 error)
  • creative/renderers/display/constants.js (+1 error)
  • creative/renderers/native/constants.js (+1 error)
  • libraries/analyticsAdapter/AnalyticsAdapter.ts (+1 error)
  • libraries/analyticsAdapter/examples/example2.js (+2 errors)
  • libraries/boundingClientRect/boundingClientRect.js (+1 error)
  • libraries/dspxUtils/bidderUtils.js (+2 errors)
  • libraries/liveIntentId/idSystem.js (+1 error)
  • libraries/ortb2.5StrictTranslator/dsl.js (+1 error)
  • libraries/pubmaticUtils/plugins/floorProvider.js (+1 error)
  • libraries/uid2IdSystemShared/uid2IdSystem_shared.js (+1 error)
  • modules/33acrossBidAdapter.js (+1 error)
  • modules/adagioBidAdapter.js (+1 error)
  • modules/adlooxAdServerVideo.js (+1 error)
  • modules/adlooxRtdProvider.js (+1 error)
  • modules/amxBidAdapter.js (+1 error)
  • modules/big-richmediaBidAdapter.js (+1 error)
  • modules/cleanioRtdProvider.js (+1 error)
  • modules/consentManagementGpp.ts (+1 error)
  • modules/criteoIdSystem.js (+1 error)
  • modules/debugging/debugging.js (+3 errors)
  • modules/debugging/index.js (+8 errors)
  • modules/dfpAdServerVideo.js (+1 error)
  • modules/dfpAdpod.js (+1 error)
  • modules/dgkeywordRtdProvider.js (+1 error)
  • modules/eplanningBidAdapter.js (+1 error)
  • modules/euidIdSystem.js (+1 error)
  • modules/express.js (+2 errors)
  • modules/genericAnalyticsAdapter.ts (+1 error)
  • modules/geoedgeRtdProvider.js (+2 errors)
  • modules/liveIntentIdSystem.js (+3 errors)
  • modules/marsmediaBidAdapter.js (+3 errors)
  • modules/microadBidAdapter.js (+4 errors)
  • modules/mobianRtdProvider.js (+1 error)
  • modules/mobkoiAnalyticsAdapter.js (+1 error)
  • modules/nativeRendering.js (+1 error)
  • modules/nodalsAiRtdProvider.js (+1 error)
  • modules/onetagBidAdapter.js (+1 error)
  • modules/overtoneRtdProvider.js (+1 error)
  • modules/panxoBidAdapter.js (+1 warning)
  • modules/priceFloors.ts (+2 errors)
  • modules/pubmaticBidAdapter.js (+8 errors)
  • modules/pubxaiRtdProvider.js (+1 error)
  • modules/pwbidBidAdapter.js (+1 error)
  • modules/rhythmoneBidAdapter.js (+3 errors)
  • modules/ringieraxelspringerBidAdapter.js (+1 error)
  • modules/rtdModule/spec.ts (+1 error)
  • modules/smartxBidAdapter.js (+1 error)
  • modules/sonobiBidAdapter.js (+2 errors)
  • modules/storageControl.ts (+1 error)
  • modules/uid2IdSystem.js (+1 error)
  • modules/underdogmediaBidAdapter.js (+1 error)
  • modules/userId/spec.ts (+2 errors)
  • modules/yahooAdsBidAdapter.js (+1 error)
  • modules/yieldoneAnalyticsAdapter.js (+1 error)
  • src/activities/rules.js (+1 error)
  • src/adUnits.ts (+1 error)
  • src/ajax.ts (+1 error)
  • src/auction.ts (+1 error)
  • src/bidderSettings.ts (+1 error)
  • src/bidfactory.ts (+1 error)
  • src/buildOptions.ts (+3 errors)
  • src/consentHandler.ts (+1 error)
  • src/cpmBucketManager.ts (+1 error)
  • src/creativeRenderers.js (+1 error)
  • src/debugging.js (+1 error)
  • src/events.ts (+1 error)
  • src/storageManager.ts (+2 errors)
  • src/types/local/gpt.d.ts (+1 error)
  • src/utils.js (+9 errors)
  • test/fake-server/fake-responder.js (+2 errors)
  • test/fake-server/fixtures/index.js (+1 error)
  • test/fake-server/index.js (+1 error)
  • test/mocks/xhr.js (+4 errors)
  • test/pipeline_setup.js (+2 errors)
  • test/spec/auctionmanager_spec.js (+2 errors)
  • test/spec/libraries/greedy/greedyPromise_spec.js (+2 errors)
  • test/spec/modules/criteoBidAdapter_spec.js (+1 error)
  • test/spec/modules/intentIqIdSystem_spec.js (+3 errors)
  • test/spec/modules/msftBidAdapter_spec.js (+1 error)
  • test/spec/modules/nativoBidAdapter_spec.js (+1 error)
  • test/spec/modules/prebidServerBidAdapter_spec.js (+1 error)
  • test/spec/modules/riseBidAdapter_spec.js (+2 errors)
  • test/spec/utils_spec.js (+1 error)
  • test/test_deps.js (+2 errors)

@coveralls
Copy link
Collaborator

Pull Request Test Coverage Report for Build 21212461114

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 68 of 76 (89.47%) changed or added relevant lines in 2 files are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage increased (+3.1%) to 96.211%

Changes Missing Coverage Covered Lines Changed/Added Lines %
modules/humansecurityRtdProvider.ts 45 53 84.91%
Files with Coverage Reduction New Missed Lines %
modules/kinessoIdSystem.js 1 83.15%
Totals Coverage Status
Change from base Build 21183031775: 3.1%
Covered Lines: 208550
Relevant Lines: 216764

💛 - Coveralls

@patmmccann patmmccann merged commit 957ebcf into prebid:master Feb 5, 2026
102 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants