diff --git a/modules/lifestreetBidAdapter.js b/modules/lifestreetBidAdapter.js
new file mode 100644
index 00000000000..4317eb8b82e
--- /dev/null
+++ b/modules/lifestreetBidAdapter.js
@@ -0,0 +1,139 @@
+import * as utils from '../src/utils.js';
+import { registerBidder } from '../src/adapters/bidderFactory.js';
+import { BANNER, VIDEO } from '../src/mediaTypes.js';
+
+const BIDDER_CODE = 'lifestreet';
+const ADAPTER_VERSION = '$prebid.version$';
+
+const urlTemplate = template`https://ads.lfstmedia.com/gate/${'adapter'}/${'slot'}?adkey=${'adkey'}&ad_size=${'ad_size'}&__location=${'location'}&__referrer=${'referrer'}&__wn=${'wn'}&__sf=${'sf'}&__fif=${'fif'}&__if=${'if'}&__stamp=${'stamp'}&__pp=1&__hb=1&_prebid_json=1&__gz=1&deferred_format=vast_2_0,vast_3_0&__hbver=${'hbver'}`;
+
+/**
+ * A helper function for template to generate string from boolean
+ */
+function boolToString(value) {
+ return value ? '1' : '0';
+}
+
+/**
+ * A helper function to form URL from the template
+ */
+function template(strings, ...keys) {
+ return function(...values) {
+ let dict = values[values.length - 1] || {};
+ let result = [strings[0]];
+ keys.forEach(function(key, i) {
+ let value = utils.isInteger(key) ? values[key] : dict[key];
+ result.push(value, strings[i + 1]);
+ });
+ return result.join('');
+ };
+}
+
+/**
+ * Creates a bid requests for a given bid.
+ *
+ * @param {BidRequest} bid The bid params to use for formatting a request
+ */
+function formatBidRequest(bid, bidderRequest = {}) {
+ const {params} = bid;
+ const {referer} = (bidderRequest.refererInfo || {});
+ let url = urlTemplate({
+ adapter: 'prebid',
+ slot: params.slot,
+ adkey: params.adkey,
+ ad_size: params.ad_size,
+ location: referer,
+ referrer: referer,
+ wn: boolToString(/fb_http/i.test(window.name)),
+ sf: boolToString(window['sfAPI'] || window['$sf']),
+ fif: boolToString(window['inDapIF'] === true),
+ if: boolToString(window !== window.top),
+ stamp: new Date().getTime(),
+ hbver: ADAPTER_VERSION
+ });
+
+ if (bidderRequest.gdprConsent) {
+ if (bidderRequest.gdprConsent.gdprApplies !== undefined) {
+ const gdpr = '&__gdpr=' + (bidderRequest.gdprConsent.gdprApplies ? '1' : '0');
+ url += gdpr;
+ }
+ if (bidderRequest.gdprConsent.consentString !== undefined) {
+ url += `&__consent=${bidderRequest.gdprConsent.consentString}`;
+ }
+ }
+
+ // ccpa support
+ if (bidderRequest.uspConsent) {
+ url += `&__us_privacy=${bidderRequest.uspConsent}`
+ }
+
+ return {
+ method: 'GET',
+ url: url,
+ bidId: bid.bidId
+ };
+}
+
+function isResponseValid(response) {
+ return !/^\s*\{\s*"advertisementAvailable"\s*:\s*false/i.test(response.content) &&
+ response.content.indexOf('') === -1 && (typeof response.cpm !== 'undefined') &&
+ response.status === 1;
+}
+
+export const spec = {
+ code: BIDDER_CODE,
+ aliases: ['lsm'],
+ supportedMediaTypes: [BANNER, VIDEO],
+
+ isBidRequestValid: (bid = {}) => {
+ const {params = {}} = bid;
+ return !!(params.slot && params.adkey && params.ad_size);
+ },
+
+ buildRequests: (validBidRequests, bidderRequest) => {
+ return validBidRequests.map(bid => {
+ return formatBidRequest(bid, bidderRequest)
+ });
+ },
+
+ interpretResponse: (serverResponse, bidRequest) => {
+ const bidResponses = [];
+ let response = serverResponse.body;
+
+ if (!isResponseValid(response)) {
+ return bidResponses;
+ }
+
+ const bidResponse = {
+ requestId: bidRequest.bidId,
+ cpm: response.cpm,
+ width: response.width,
+ height: response.height,
+ creativeId: response.creativeId,
+ currency: response.currency ? response.currency : 'USD',
+ netRevenue: response.netRevenue ? response.netRevenue : true,
+ ttl: response.ttl ? response.ttl : 86400
+ };
+
+ if (response.hasOwnProperty('dealId')) {
+ bidResponse.dealId = response.dealId;
+ }
+ if (response.content_type.indexOf('vast') > -1) {
+ if (typeof response.vastUrl !== 'undefined') {
+ bidResponse.vastUrl = response.vastUrl;
+ } else {
+ bidResponse.vastXml = response.content;
+ }
+
+ bidResponse.mediaType = VIDEO;
+ } else {
+ bidResponse.ad = response.content;
+ bidResponse.mediaType = BANNER;
+ }
+
+ bidResponses.push(bidResponse);
+ return bidResponses;
+ }
+};
+
+registerBidder(spec);
diff --git a/modules/lifestreetBidAdapter.md b/modules/lifestreetBidAdapter.md
index 58cf4a533a9..a874792d84c 100644
--- a/modules/lifestreetBidAdapter.md
+++ b/modules/lifestreetBidAdapter.md
@@ -1,22 +1,41 @@
# Overview
+```
Module Name: Lifestreet Bid Adapter
-
Module Type: Lifestreet Adapter
-
Maintainer: hb.tech@lifestreet.com
+```
# Description
Module that connects to Lifestreet's demand sources
+Values, listed in `ALL_BANNER_SIZES` and `ALL_VIDEO_SIZES` are all the values which our server supports.
+For `ad_size`, please use one of that values in following format: `ad_size: WIDTHxHEIGHT`
+
# Test Parameters
```javascript
- var adUnits = [
- // Banner adUnit
+ const ALL_BANNER_SIZES = [
+ [120, 600], [160, 600], [300, 250], [300, 600], [320, 480],
+ [320, 50], [468, 60], [510, 510], [600, 300],
+ [720, 300], [728, 90], [760, 740], [768, 1024]
+ ];
+
+ const ALL_VIDEO_SIZES = [
+ [640, 480], [650, 520], [970, 580]
+ ]
+```
+
+# Test Parameters (Banner)
+```
+ const adUnits = [
{
code: 'test-ad',
- sizes: [[160, 600]],
+ mediaTypes: {
+ banner: {
+ sizes: [[160, 600]],
+ }
+ },
bids: [
{
bidder: 'lifestreet',
@@ -28,10 +47,20 @@ Module that connects to Lifestreet's demand sources
}
]
},
- // Video instream adUnit
+ ];
+```
+
+# Test Parameters (Video)
+```
+ const adUnits = [
{
code: 'test-video-ad',
- sizes: [[640, 480]],
+ mediaTypes: {
+ video: {
+ playerSize: [[640, 480]],
+ context: 'instream'
+ }
+ },
bids: [
{
bidder: 'lifestreet',
diff --git a/test/spec/modules/lifestreetBidAdapter_spec.js b/test/spec/modules/lifestreetBidAdapter_spec.js
new file mode 100644
index 00000000000..d66727da644
--- /dev/null
+++ b/test/spec/modules/lifestreetBidAdapter_spec.js
@@ -0,0 +1,232 @@
+import { expect } from 'chai';
+import { BANNER, VIDEO } from 'src/mediaTypes.js';
+import { spec } from 'modules/lifestreetBidAdapter.js';
+
+describe('lifestreetBidAdapter', function() {
+ let bidRequests;
+ let videoBidRequests;
+ let bidResponses;
+ let videoBidResponses;
+ beforeEach(function() {
+ bidRequests = [
+ {
+ bidder: 'lifestreet',
+ params: {
+ slot: 'slot166704',
+ adkey: '78c',
+ ad_size: '160x600'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [160, 600],
+ [300, 600]
+ ]
+ }
+ },
+ sizes: [
+ [160, 600],
+ [300, 600]
+ ]
+ }
+ ];
+
+ bidResponses = {
+ body: {
+ cpm: 0.1,
+ netRevenue: true,
+ content_type: 'display_flash',
+ width: 160,
+ currency: 'USD',
+ ttl: 86400,
+ content: '