@playpilot/tpi 6.6.1 → 6.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "6.6.1",
3
+ "version": "6.6.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -23,6 +23,7 @@
23
23
  "@types/node": "^25.2.0",
24
24
  "@typescript-eslint/eslint-plugin": "^8.32.1",
25
25
  "@typescript-eslint/parser": "^8.32.1",
26
+ "dotenv": "^16.4.7",
26
27
  "eslint": "^9.27.0",
27
28
  "eslint-config-prettier": "^9.1.0",
28
29
  "eslint-plugin-svelte": "^3.15.0",
@@ -98,3 +98,8 @@ export function fireQueuedTrackingEvents(): void {
98
98
 
99
99
  window.PlayPilotLinkInjections.queued_tracking_events = []
100
100
  }
101
+
102
+ export function isPixelAllowed(): boolean {
103
+ if (!window.PlayPilotLinkInjections.config?.allow_retargeting_pixels) return false
104
+ return hasConsentedTo('pixels')
105
+ }
@@ -44,6 +44,11 @@ export type ConfigResponse = {
44
44
  */
45
45
  playlinks_disclaimer_text?: string
46
46
 
47
+ /**
48
+ * Whether or not we can insert retargeting pixels. Not all third parties allow this and it is disabled by default
49
+ */
50
+ allow_retargeting_pixels?: boolean
51
+
47
52
  /**
48
53
  * The following options are all relevant for in text disclaimers, which renders as a disclaimer text within the article,
49
54
  * rather than only inside of title cards.
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
- import { hasConsentedTo } from '$lib/consent'
3
2
  import genreData from '$lib/data/genres.json'
4
3
  import { MetaEvent } from '$lib/enums/TrackingEvent'
5
4
  import { t } from '$lib/localization'
5
+ import { isPixelAllowed } from '$lib/tracking'
6
6
  import { trackViewViaPixel } from '@playpilot/retargeting-tracking'
7
7
 
8
8
  interface Props {
@@ -19,7 +19,7 @@
19
19
  {@const genreName = genreData.find(g => g.slug === genre)?.name}
20
20
 
21
21
  {#if genreName}
22
- <div class="genre" {@attach hasConsentedTo('pixels') ? trackViewViaPixel(MetaEvent.GenreInterest, { genre: genreName }) : null}>
22
+ <div class="genre" {@attach isPixelAllowed() ? trackViewViaPixel(MetaEvent.GenreInterest, { genre: genreName }) : null}>
23
23
  {t(genreName)}
24
24
  </div>
25
25
  {/if}
@@ -7,6 +7,7 @@
7
7
  import type { PlaylinkData } from '$lib/types/playlink'
8
8
  import { trackClickViaPixel, trackViewViaPixel } from '@playpilot/retargeting-tracking'
9
9
  import { MetaEvent } from '$lib/enums/TrackingEvent'
10
+ import { isPixelAllowed } from '$lib/tracking'
10
11
 
11
12
  interface Props {
12
13
  playlink: PlaylinkData
@@ -19,7 +20,7 @@
19
20
 
20
21
  const { name, url, logo_url, highlighted, cta_text, action_text, pixels, extra_info: { category } } = $derived(playlink)
21
22
 
22
- const usePixel = $derived(hasConsentedTo('pixels') && !highlighted)
23
+ const usePixel = $derived(isPixelAllowed() && !highlighted)
23
24
 
24
25
  const categoryStrings = {
25
26
  SVOD: t('Stream'),
@@ -27,6 +28,8 @@
27
28
  RENT: t('Rent'),
28
29
  TVOD: t('Rent Or Buy'),
29
30
  }
31
+
32
+ let actionWidth = $state(0)
30
33
  </script>
31
34
 
32
35
  <!-- svelte-ignore a11y_no_static_element_interactions -->
@@ -44,7 +47,7 @@
44
47
  data-playlink={name}
45
48
  rel="sponsored">
46
49
 
47
- <div class="playlink-content">
50
+ <div class="playlink-content" style:--action-width={actionWidth ? `${actionWidth}px` : null}>
48
51
  <img src={removeImageUrlPrefix(logo_url)} alt="" height="36" width="36" />
49
52
 
50
53
  <span class="name">{name}</span>
@@ -57,7 +60,7 @@
57
60
  <span class="cta">{cta_text}</span>
58
61
  {/if}
59
62
 
60
- <div class="action">
63
+ <div class="action" bind:clientWidth={actionWidth}>
61
64
  {action_text || t('Watch')}
62
65
  </div>
63
66
 
@@ -161,7 +164,7 @@
161
164
  z-index: 5;
162
165
  display: grid;
163
166
  grid-template-areas: "image name action" "image category action";
164
- grid-template-columns: $image-size auto margin(6);
167
+ grid-template-columns: $image-size auto var(--action-width, margin(6));
165
168
  align-items: center;
166
169
  gap: 0 margin(0.75);
167
170
  padding: margin(0.75);
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest'
2
2
 
3
- import { fireQueuedTrackingEvents, queueTrackingEvent, setTrackingSids, track } from '$lib/tracking'
3
+ import { fireQueuedTrackingEvents, isPixelAllowed, queueTrackingEvent, setTrackingSids, track } from '$lib/tracking'
4
4
  import { title } from '$lib/fakeData'
5
5
  import { getFullUrlPath } from '$lib/url'
6
6
  import { fakeFetch } from '../helpers'
@@ -241,4 +241,41 @@ describe('$lib/tracking', () => {
241
241
  expect(global.fetch).toHaveBeenCalledTimes(2)
242
242
  })
243
243
  })
244
+
245
+ describe('isPixelAllow', () => {
246
+ it('Should return false if no config object is set', () => {
247
+ vi.mocked(hasConsentedTo).mockImplementation(() => true)
248
+ window.PlayPilotLinkInjections.config = null
249
+
250
+ expect(isPixelAllowed()).toBe(false)
251
+ })
252
+
253
+ it('Should return false if config object is without allow_retargeting_pixels', () => {
254
+ vi.mocked(hasConsentedTo).mockImplementation(() => true)
255
+ window.PlayPilotLinkInjections.config = { something: true }
256
+
257
+ expect(isPixelAllowed()).toBe(false)
258
+ })
259
+
260
+ it('Should return false if config object is allow_retargeting_pixels is false', () => {
261
+ vi.mocked(hasConsentedTo).mockImplementation(() => true)
262
+ window.PlayPilotLinkInjections.config = { allow_retargeting_pixels: false }
263
+
264
+ expect(isPixelAllowed()).toBe(false)
265
+ })
266
+
267
+ it('Should return true if config object is allow_retargeting_pixels is true', () => {
268
+ vi.mocked(hasConsentedTo).mockImplementation(() => true)
269
+ window.PlayPilotLinkInjections.config = { allow_retargeting_pixels: true }
270
+
271
+ expect(isPixelAllowed()).toBe(true)
272
+ })
273
+
274
+ it('Should return true if config object is allow_retargeting_pixels is true but hasConsentedTo is false', () => {
275
+ vi.mocked(hasConsentedTo).mockImplementation(() => false)
276
+ window.PlayPilotLinkInjections.config = { allow_retargeting_pixels: true }
277
+
278
+ expect(isPixelAllowed()).toBe(false)
279
+ })
280
+ })
244
281
  })
@@ -6,6 +6,7 @@ import { hasConsentedTo } from '$lib/consent'
6
6
 
7
7
  vi.mock('$lib/tracking', () => ({
8
8
  track: vi.fn(),
9
+ isPixelAllowed: vi.fn(),
9
10
  }))
10
11
 
11
12
  vi.mock('$lib/consent', () => ({
@@ -9,6 +9,7 @@ import { getContext } from 'svelte'
9
9
 
10
10
  vi.mock('$lib/tracking', () => ({
11
11
  track: vi.fn(),
12
+ isPixelAllowed: vi.fn(),
12
13
  }))
13
14
 
14
15
  vi.mock('svelte', async (importActual) => ({
@@ -8,6 +8,7 @@ import { fetchSimilarTitles } from '$lib/api/titles'
8
8
 
9
9
  vi.mock('$lib/tracking', () => ({
10
10
  track: vi.fn(),
11
+ isPixelAllowed: vi.fn(),
11
12
  }))
12
13
 
13
14
  vi.mock('$lib/api/participants', () => ({
@@ -13,6 +13,7 @@ vi.mock('$lib/consent', () => ({
13
13
 
14
14
  vi.mock('$lib/tracking', () => ({
15
15
  track: vi.fn(),
16
+ isPixelAllowed: vi.fn(),
16
17
  }))
17
18
 
18
19
  vi.mock('$lib/api/participants', () => ({
@@ -13,6 +13,7 @@ vi.mock('$lib/consent', () => ({
13
13
 
14
14
  vi.mock('$lib/tracking', () => ({
15
15
  track: vi.fn(),
16
+ isPixelAllowed: vi.fn(),
16
17
  }))
17
18
 
18
19
  vi.mock('$lib/api/participants', () => ({
package/vite.config.js CHANGED
@@ -1,14 +1,18 @@
1
1
  import path from 'path'
2
+ import * as dotenv from 'dotenv'
2
3
  import { defineConfig } from 'vitest/config'
3
4
  import { sveltekit } from '@sveltejs/kit/vite'
4
5
  import { svelte } from '@sveltejs/vite-plugin-svelte'
5
6
  import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
6
7
  import packageJson from './package.json'
7
8
 
9
+ dotenv.config({ path: '.env' })
10
+
8
11
  export default defineConfig(({ command }) => ({
9
12
  plugins: [
10
13
  command === 'build' ? svelte() : sveltekit(),
11
14
  command === 'build' && cssInjectedByJsPlugin(),
15
+ command === 'build' && injectEnvVariables,
12
16
  ],
13
17
 
14
18
  build: {
@@ -19,7 +23,6 @@ export default defineConfig(({ command }) => ({
19
23
  name: 'PlayPilotLinkInjections',
20
24
  entryFileNames: 'link-injections.js',
21
25
  },
22
- external: ['$env/static/public'],
23
26
  },
24
27
  },
25
28
 
@@ -44,3 +47,20 @@ export default defineConfig(({ command }) => ({
44
47
  __SCRIPT_VERSION__: JSON.stringify(packageJson.version),
45
48
  },
46
49
  }))
50
+
51
+ const injectEnvVariables = {
52
+ name: 'resolve-env-variables',
53
+ /** @param {string} id */
54
+ resolveId(id) {
55
+ if (id === '$env/static/public') return '\0$env/static/public'
56
+ },
57
+ /** @param {string} id */
58
+ load(id) {
59
+ if (id === '\0$env/static/public') {
60
+ return Object.entries(process.env)
61
+ .filter(([key]) => key.startsWith('PUBLIC_'))
62
+ .map(([key, value]) => `export const ${key} = ${JSON.stringify(value)};`)
63
+ .join('\n')
64
+ }
65
+ },
66
+ }