@guardian/commercial-core 5.2.1 → 5.4.0

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.
@@ -28,6 +28,7 @@ interface EventTimerProperties {
28
28
  type?: ConnectionType;
29
29
  downlink?: number;
30
30
  effectiveType?: string;
31
+ offlineCount?: number;
31
32
  adSlotsInline?: number;
32
33
  adSlotsTotal?: number;
33
34
  pageHeightVH?: number;
@@ -93,20 +93,15 @@ class EventTimer {
93
93
  },
94
94
  ],
95
95
  };
96
- this.properties =
97
- 'connection' in window.navigator
98
- ? {
99
- type: 'type' in window.navigator.connection
100
- ? window.navigator.connection.type
101
- : undefined,
102
- downlink: 'downlink' in window.navigator.connection
103
- ? window.navigator.connection.downlink
104
- : undefined,
105
- effectiveType: 'effectiveType' in window.navigator.connection
106
- ? window.navigator.connection.effectiveType
107
- : undefined,
108
- }
109
- : {};
96
+ this.properties = {
97
+ offlineCount: window.guardian.offlineCount,
98
+ };
99
+ if (window.navigator.connection) {
100
+ this.properties.type = window.navigator.connection.type;
101
+ this.properties.downlink = window.navigator.connection.downlink;
102
+ this.properties.effectiveType =
103
+ window.navigator.connection.effectiveType;
104
+ }
110
105
  }
111
106
  /**
112
107
  * Adds an event timer property
@@ -3,7 +3,7 @@ import type { GoogleTagParams, GoogleTrackConversionObject, GuardianWindowConfig
3
3
  import type { EventTimer } from '.';
4
4
  declare global {
5
5
  interface Navigator {
6
- readonly connection: NetworkInformation;
6
+ readonly connection?: NetworkInformation;
7
7
  }
8
8
  interface Window {
9
9
  google_trackConversion?: (arg0: GoogleTrackConversionObject) => void;
@@ -15,6 +15,7 @@ declare global {
15
15
  guardian: {
16
16
  commercialTimer?: EventTimer;
17
17
  config: GuardianWindowConfig;
18
+ offlineCount?: number;
18
19
  };
19
20
  ga: UniversalAnalytics.ga | null;
20
21
  readonly navigator: Navigator;
@@ -15,6 +15,7 @@ type EventProperties = {
15
15
  type?: ConnectionType;
16
16
  downlink?: number;
17
17
  effectiveType?: string;
18
+ offlineCount?: number;
18
19
  };
19
20
  declare enum Endpoints {
20
21
  CODE = "//performance-events.code.dev-guardianapis.com/commercial-metrics",
@@ -1,6 +1,6 @@
1
1
  import type { ConsentState } from '@guardian/consent-management-platform/dist/types';
2
2
  import type { PageTargeting } from './build-page-targeting';
3
- declare const consentlessTargetingKeys: readonly ["ab", "at", "bl", "bp", "br", "cc", "ct", "dcre", "edition", "k", "rp", "s", "se", "sens", "sh", "si", "skinsize", "su", "tn", "url", "urlkw"];
3
+ declare const consentlessTargetingKeys: readonly ["ab", "at", "bl", "bp", "br", "cc", "ct", "dcre", "edition", "k", "rc", "rp", "s", "se", "sens", "sh", "si", "skinsize", "su", "tn", "url", "urlkw"];
4
4
  type ConsentlessTargetingKeys = (typeof consentlessTargetingKeys)[number];
5
5
  type ConsentlessPageTargeting = Partial<Pick<PageTargeting, ConsentlessTargetingKeys>>;
6
6
  /**
@@ -13,6 +13,7 @@ const consentlessTargetingKeys = [
13
13
  'dcre',
14
14
  'edition',
15
15
  'k',
16
+ 'rc',
16
17
  'rp',
17
18
  's',
18
19
  'se',
@@ -23,6 +23,7 @@ type PageTargeting = PartialWithNulls<{
23
23
  pa: TrueOrFalse;
24
24
  permutive: string[];
25
25
  pv: string;
26
+ rc: string;
26
27
  rdp: string;
27
28
  ref: string;
28
29
  rp: 'dotcom-rendering' | 'dotcom-platform';
@@ -29,6 +29,7 @@ const buildPageTargeting = ({ adFree, clientSideParticipations, consentState, yo
29
29
  const { page, isDotcomRendering } = window.guardian.config;
30
30
  const adFreeTargeting = adFree ? { af: 't' } : {};
31
31
  const contentTargeting = (0, content_1.getContentTargeting)({
32
+ webPublicationDate: page.webPublicationDate,
32
33
  eligibleForDCR: isDotcomRendering,
33
34
  path: `/${page.pageId}`,
34
35
  renderingPlatform: isDotcomRendering
@@ -21,6 +21,12 @@ type ContentTargeting = {
21
21
  * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=11958028
22
22
  */
23
23
  dcre: True | False;
24
+ /**
25
+ * **R**ecently Published **C**ontent - [see on Ad Manager][gam]
26
+ *
27
+ * [gam]: TODO: add URL here once it's been created
28
+ */
29
+ rc: string;
24
30
  /**
25
31
  * Rendering Platform - [see on Ad Manager][gam]
26
32
  *
@@ -65,7 +71,8 @@ type Content = {
65
71
  section: ContentTargeting['s'];
66
72
  sensitive: boolean;
67
73
  videoLength?: number;
74
+ webPublicationDate: number;
68
75
  };
69
- declare const getContentTargeting: ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, }: Content) => ContentTargeting;
76
+ declare const getContentTargeting: ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, webPublicationDate, }: Content) => ContentTargeting;
70
77
  export { getContentTargeting };
71
78
  export type { ContentTargeting };
@@ -28,9 +28,39 @@ const getUrlKeywords = (url) => {
28
28
  .slice(-1)[0];
29
29
  return (0, libs_1.isString)(lastSegment) ? lastSegment.split('-').filter(Boolean) : [];
30
30
  };
31
- const getContentTargeting = ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, }) => {
31
+ // "0" means content < 2 hours old
32
+ // "1" means content between 2 hours and 24 hours old.
33
+ // "2" means content between 24 hours and 3 days old
34
+ // "3" means content between 3 and 7 days old
35
+ // "4" means content between 7 days and 1 month old
36
+ // "5" means content between 1 and 10 months old
37
+ // "6" means content between 10 and 14 months old
38
+ // "7" means content more than 14 months old
39
+ const calculateRecentlyPublishedBucket = (webPublicationDate) => {
40
+ const now = Date.now();
41
+ const hoursSincePublication = (now - webPublicationDate) / 1000 / 60 / 60;
42
+ const daysSincePublication = hoursSincePublication / 24;
43
+ const monthsSincePublication = daysSincePublication / 30; // near enough for our purposes
44
+ if (hoursSincePublication < 2)
45
+ return '0';
46
+ if (hoursSincePublication < 24)
47
+ return '1';
48
+ if (daysSincePublication < 3)
49
+ return '2';
50
+ if (daysSincePublication < 7)
51
+ return '3';
52
+ if (daysSincePublication < 30)
53
+ return '4';
54
+ if (monthsSincePublication < 10)
55
+ return '5';
56
+ if (monthsSincePublication < 14)
57
+ return '6';
58
+ return '7';
59
+ };
60
+ const getContentTargeting = ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, webPublicationDate, }) => {
32
61
  return {
33
62
  dcre: eligibleForDCR ? 't' : 'f',
63
+ rc: calculateRecentlyPublishedBucket(webPublicationDate),
34
64
  rp: renderingPlatform,
35
65
  s: section,
36
66
  sens: sensitive ? 't' : 'f',
@@ -43,6 +43,7 @@ export type GuardianWindowConfig = {
43
43
  section: string;
44
44
  sharedAdTargeting?: Record<string, string | string[]>;
45
45
  videoDuration: number;
46
+ webPublicationDate: number;
46
47
  };
47
48
  tests?: {
48
49
  [key: `${string}Control`]: 'control';
@@ -28,6 +28,7 @@ interface EventTimerProperties {
28
28
  type?: ConnectionType;
29
29
  downlink?: number;
30
30
  effectiveType?: string;
31
+ offlineCount?: number;
31
32
  adSlotsInline?: number;
32
33
  adSlotsTotal?: number;
33
34
  pageHeightVH?: number;
@@ -90,20 +90,15 @@ class EventTimer {
90
90
  },
91
91
  ],
92
92
  };
93
- this.properties =
94
- 'connection' in window.navigator
95
- ? {
96
- type: 'type' in window.navigator.connection
97
- ? window.navigator.connection.type
98
- : undefined,
99
- downlink: 'downlink' in window.navigator.connection
100
- ? window.navigator.connection.downlink
101
- : undefined,
102
- effectiveType: 'effectiveType' in window.navigator.connection
103
- ? window.navigator.connection.effectiveType
104
- : undefined,
105
- }
106
- : {};
93
+ this.properties = {
94
+ offlineCount: window.guardian.offlineCount,
95
+ };
96
+ if (window.navigator.connection) {
97
+ this.properties.type = window.navigator.connection.type;
98
+ this.properties.downlink = window.navigator.connection.downlink;
99
+ this.properties.effectiveType =
100
+ window.navigator.connection.effectiveType;
101
+ }
107
102
  }
108
103
  /**
109
104
  * Adds an event timer property
@@ -3,7 +3,7 @@ import type { GoogleTagParams, GoogleTrackConversionObject, GuardianWindowConfig
3
3
  import type { EventTimer } from '.';
4
4
  declare global {
5
5
  interface Navigator {
6
- readonly connection: NetworkInformation;
6
+ readonly connection?: NetworkInformation;
7
7
  }
8
8
  interface Window {
9
9
  google_trackConversion?: (arg0: GoogleTrackConversionObject) => void;
@@ -15,6 +15,7 @@ declare global {
15
15
  guardian: {
16
16
  commercialTimer?: EventTimer;
17
17
  config: GuardianWindowConfig;
18
+ offlineCount?: number;
18
19
  };
19
20
  ga: UniversalAnalytics.ga | null;
20
21
  readonly navigator: Navigator;
@@ -15,6 +15,7 @@ type EventProperties = {
15
15
  type?: ConnectionType;
16
16
  downlink?: number;
17
17
  effectiveType?: string;
18
+ offlineCount?: number;
18
19
  };
19
20
  declare enum Endpoints {
20
21
  CODE = "//performance-events.code.dev-guardianapis.com/commercial-metrics",
@@ -1,6 +1,6 @@
1
1
  import type { ConsentState } from '@guardian/consent-management-platform/dist/types';
2
2
  import type { PageTargeting } from './build-page-targeting';
3
- declare const consentlessTargetingKeys: readonly ["ab", "at", "bl", "bp", "br", "cc", "ct", "dcre", "edition", "k", "rp", "s", "se", "sens", "sh", "si", "skinsize", "su", "tn", "url", "urlkw"];
3
+ declare const consentlessTargetingKeys: readonly ["ab", "at", "bl", "bp", "br", "cc", "ct", "dcre", "edition", "k", "rc", "rp", "s", "se", "sens", "sh", "si", "skinsize", "su", "tn", "url", "urlkw"];
4
4
  type ConsentlessTargetingKeys = (typeof consentlessTargetingKeys)[number];
5
5
  type ConsentlessPageTargeting = Partial<Pick<PageTargeting, ConsentlessTargetingKeys>>;
6
6
  /**
@@ -10,6 +10,7 @@ const consentlessTargetingKeys = [
10
10
  'dcre',
11
11
  'edition',
12
12
  'k',
13
+ 'rc',
13
14
  'rp',
14
15
  's',
15
16
  'se',
@@ -23,6 +23,7 @@ type PageTargeting = PartialWithNulls<{
23
23
  pa: TrueOrFalse;
24
24
  permutive: string[];
25
25
  pv: string;
26
+ rc: string;
26
27
  rdp: string;
27
28
  ref: string;
28
29
  rp: 'dotcom-rendering' | 'dotcom-platform';
@@ -25,6 +25,7 @@ const buildPageTargeting = ({ adFree, clientSideParticipations, consentState, yo
25
25
  const { page, isDotcomRendering } = window.guardian.config;
26
26
  const adFreeTargeting = adFree ? { af: 't' } : {};
27
27
  const contentTargeting = getContentTargeting({
28
+ webPublicationDate: page.webPublicationDate,
28
29
  eligibleForDCR: isDotcomRendering,
29
30
  path: `/${page.pageId}`,
30
31
  renderingPlatform: isDotcomRendering
@@ -21,6 +21,12 @@ type ContentTargeting = {
21
21
  * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=11958028
22
22
  */
23
23
  dcre: True | False;
24
+ /**
25
+ * **R**ecently Published **C**ontent - [see on Ad Manager][gam]
26
+ *
27
+ * [gam]: TODO: add URL here once it's been created
28
+ */
29
+ rc: string;
24
30
  /**
25
31
  * Rendering Platform - [see on Ad Manager][gam]
26
32
  *
@@ -65,7 +71,8 @@ type Content = {
65
71
  section: ContentTargeting['s'];
66
72
  sensitive: boolean;
67
73
  videoLength?: number;
74
+ webPublicationDate: number;
68
75
  };
69
- declare const getContentTargeting: ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, }: Content) => ContentTargeting;
76
+ declare const getContentTargeting: ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, webPublicationDate, }: Content) => ContentTargeting;
70
77
  export { getContentTargeting };
71
78
  export type { ContentTargeting };
@@ -25,9 +25,39 @@ const getUrlKeywords = (url) => {
25
25
  .slice(-1)[0];
26
26
  return isString(lastSegment) ? lastSegment.split('-').filter(Boolean) : [];
27
27
  };
28
- const getContentTargeting = ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, }) => {
28
+ // "0" means content < 2 hours old
29
+ // "1" means content between 2 hours and 24 hours old.
30
+ // "2" means content between 24 hours and 3 days old
31
+ // "3" means content between 3 and 7 days old
32
+ // "4" means content between 7 days and 1 month old
33
+ // "5" means content between 1 and 10 months old
34
+ // "6" means content between 10 and 14 months old
35
+ // "7" means content more than 14 months old
36
+ const calculateRecentlyPublishedBucket = (webPublicationDate) => {
37
+ const now = Date.now();
38
+ const hoursSincePublication = (now - webPublicationDate) / 1000 / 60 / 60;
39
+ const daysSincePublication = hoursSincePublication / 24;
40
+ const monthsSincePublication = daysSincePublication / 30; // near enough for our purposes
41
+ if (hoursSincePublication < 2)
42
+ return '0';
43
+ if (hoursSincePublication < 24)
44
+ return '1';
45
+ if (daysSincePublication < 3)
46
+ return '2';
47
+ if (daysSincePublication < 7)
48
+ return '3';
49
+ if (daysSincePublication < 30)
50
+ return '4';
51
+ if (monthsSincePublication < 10)
52
+ return '5';
53
+ if (monthsSincePublication < 14)
54
+ return '6';
55
+ return '7';
56
+ };
57
+ const getContentTargeting = ({ eligibleForDCR, path, renderingPlatform, section, sensitive, videoLength, webPublicationDate, }) => {
29
58
  return {
30
59
  dcre: eligibleForDCR ? 't' : 'f',
60
+ rc: calculateRecentlyPublishedBucket(webPublicationDate),
31
61
  rp: renderingPlatform,
32
62
  s: section,
33
63
  sens: sensitive ? 't' : 'f',
@@ -43,6 +43,7 @@ export type GuardianWindowConfig = {
43
43
  section: string;
44
44
  sharedAdTargeting?: Record<string, string | string[]>;
45
45
  videoDuration: number;
46
+ webPublicationDate: number;
46
47
  };
47
48
  tests?: {
48
49
  [key: `${string}Control`]: 'control';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guardian/commercial-core",
3
- "version": "5.2.1",
3
+ "version": "5.4.0",
4
4
  "description": "Guardian advertising business logic",
5
5
  "homepage": "https://github.com/guardian/commercial-core#readme",
6
6
  "bugs": {