@scalemule/news-publication 0.0.12 → 0.0.14
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/dist/{chunk-EKQXS63J.js → chunk-5YQYJ2L2.js} +29 -5
- package/dist/chunk-QWK6G2UF.js +117 -0
- package/dist/{chunk-ZSA6YQBV.js → chunk-WZ3NQRQO.js} +1 -1
- package/dist/compliance.cjs +19 -0
- package/dist/compliance.d.cts +2 -0
- package/dist/compliance.d.ts +2 -0
- package/dist/compliance.js +2 -0
- package/dist/cookie-consent-banner.cjs +44 -213
- package/dist/cookie-consent-banner.d.cts +3 -1
- package/dist/cookie-consent-banner.d.ts +3 -1
- package/dist/cookie-consent-banner.js +2 -2
- package/dist/cookie-settings-view.cjs +21 -123
- package/dist/cookie-settings-view.js +2 -2
- package/dist/index.cjs +147 -287
- package/dist/index.d.cts +14 -102
- package/dist/index.d.ts +14 -102
- package/dist/index.js +3 -3
- package/dist/{marketplace-CpGWPbFk.d.ts → marketplace-29i5w4LS.d.cts} +1 -1
- package/dist/{marketplace-CpGWPbFk.d.cts → marketplace-29i5w4LS.d.ts} +1 -1
- package/dist/marketplace-view.d.cts +1 -1
- package/dist/marketplace-view.d.ts +1 -1
- package/dist/{meet-5Ym5bxfh.d.cts → meet-RWmfj3I3.d.cts} +1 -1
- package/dist/{meet-5Ym5bxfh.d.ts → meet-RWmfj3I3.d.ts} +1 -1
- package/dist/meet-forms.d.cts +1 -1
- package/dist/meet-forms.d.ts +1 -1
- package/dist/meet-view.d.cts +1 -1
- package/dist/meet-view.d.ts +1 -1
- package/dist/snapshot-file.d.cts +1 -1
- package/dist/snapshot-file.d.ts +1 -1
- package/dist/{snapshot-BS4hn1dk.d.ts → snapshot-sHgQHuAF.d.cts} +1 -1
- package/dist/{snapshot-BS4hn1dk.d.cts → snapshot-sHgQHuAF.d.ts} +1 -1
- package/package.json +12 -2
- package/dist/chunk-CWZWU4HE.js +0 -354
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { checkUrlConsentBridge, hasConsented, isGeoConsentRequired,
|
|
2
|
+
import { checkUrlConsentBridge, hasConsented, isGeoConsentRequired, queryNetworkConsentHub, DEFAULT_CONSENT_HUB_URL, acceptAllCookies, rejectOptionalCookies, COOKIE_CONSENT_EVENT, recordConsentToCompliance, setNetworkConsentHub } from './chunk-QWK6G2UF.js';
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -11,7 +11,8 @@ function CookieConsentBanner({
|
|
|
11
11
|
publicationSlug,
|
|
12
12
|
complianceEndpoint = "/api/compliance/consent",
|
|
13
13
|
countryCode,
|
|
14
|
-
forceShow = false
|
|
14
|
+
forceShow = false,
|
|
15
|
+
consentHubUrl = DEFAULT_CONSENT_HUB_URL
|
|
15
16
|
}) {
|
|
16
17
|
const [mounted, setMounted] = useState(false);
|
|
17
18
|
const [visible, setVisible] = useState(false);
|
|
@@ -27,11 +28,32 @@ function CookieConsentBanner({
|
|
|
27
28
|
}
|
|
28
29
|
if (!forceShow && !isGeoConsentRequired(countryCode)) {
|
|
29
30
|
setVisible(false);
|
|
31
|
+
void queryNetworkConsentHub(consentHubUrl, 1200).then((networkStatus) => {
|
|
32
|
+
if (networkStatus === "accepted") {
|
|
33
|
+
acceptAllCookies();
|
|
34
|
+
} else if (networkStatus === "rejected") {
|
|
35
|
+
rejectOptionalCookies();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
30
38
|
return;
|
|
31
39
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
void queryNetworkConsentHub(consentHubUrl, 1e3).then((networkStatus) => {
|
|
42
|
+
if (cancelled) return;
|
|
43
|
+
if (networkStatus === "accepted") {
|
|
44
|
+
acceptAllCookies();
|
|
45
|
+
setVisible(false);
|
|
46
|
+
} else if (networkStatus === "rejected") {
|
|
47
|
+
rejectOptionalCookies();
|
|
48
|
+
setVisible(false);
|
|
49
|
+
} else {
|
|
50
|
+
setVisible(true);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return () => {
|
|
54
|
+
cancelled = true;
|
|
55
|
+
};
|
|
56
|
+
}, [countryCode, forceShow, consentHubUrl]);
|
|
35
57
|
useEffect(() => {
|
|
36
58
|
const onConsentChange = () => {
|
|
37
59
|
if (hasConsented()) {
|
|
@@ -49,6 +71,7 @@ function CookieConsentBanner({
|
|
|
49
71
|
endpoint: complianceEndpoint,
|
|
50
72
|
publicationSlug
|
|
51
73
|
});
|
|
74
|
+
setNetworkConsentHub("accepted", consentHubUrl);
|
|
52
75
|
};
|
|
53
76
|
const handleReject = () => {
|
|
54
77
|
const record = rejectOptionalCookies();
|
|
@@ -57,6 +80,7 @@ function CookieConsentBanner({
|
|
|
57
80
|
endpoint: complianceEndpoint,
|
|
58
81
|
publicationSlug
|
|
59
82
|
});
|
|
83
|
+
setNetworkConsentHub("rejected", consentHubUrl);
|
|
60
84
|
};
|
|
61
85
|
const defaultText = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
62
86
|
"We use cookies and device data to analyze performance, support local sponsors, and remember your reading preferences across our news network. View",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { recordConsentToCompliance as recordConsentToCompliance$1 } from '@scalemule/compliance';
|
|
2
|
+
export { COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, DEFAULT_CONSENT_HUB_URL, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, NETWORK_CONSENT_STORAGE_KEY, acceptAllCookies, checkUrlConsentBridge, clearCookieConsent, decorateNetworkUrl, getCookieConsent, hasConsented, isCategoryAllowed, isGeoConsentRequired, queryNetworkConsentHub, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from '@scalemule/compliance';
|
|
3
|
+
|
|
4
|
+
// src/cookies.ts
|
|
5
|
+
async function recordConsentToCompliance(record, options) {
|
|
6
|
+
return recordConsentToCompliance$1(record, options);
|
|
7
|
+
}
|
|
8
|
+
var COOKIE_CATEGORIES = [
|
|
9
|
+
{
|
|
10
|
+
id: "essential",
|
|
11
|
+
title: "Strictly Necessary Cookies",
|
|
12
|
+
shortDescription: "Essential for site security, navigation, and privacy preference management.",
|
|
13
|
+
fullDescription: "These cookies are necessary for the website to function properly and securely. They enable core features such as load balancing, CSRF protection, secure session tokens, and remembering your cookie consent choice. Because the site cannot function without them, they cannot be turned off.",
|
|
14
|
+
required: true,
|
|
15
|
+
cookies: [
|
|
16
|
+
{
|
|
17
|
+
name: "sm_cookie_consent_v1",
|
|
18
|
+
provider: "First-Party (ScaleMule)",
|
|
19
|
+
purpose: "Stores your verified cookie privacy and category consent choices.",
|
|
20
|
+
duration: "1 year",
|
|
21
|
+
type: "HTTP Cookie"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "napsite_session_v1",
|
|
25
|
+
provider: "First-Party",
|
|
26
|
+
purpose: "Maintains session continuity, security tokens, and server routing.",
|
|
27
|
+
duration: "30 minutes (idle)",
|
|
28
|
+
type: "Session Storage"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "napsite_preview",
|
|
32
|
+
provider: "First-Party",
|
|
33
|
+
purpose: "Verifies preview access permissions when viewing unpublished newsroom editions.",
|
|
34
|
+
duration: "14 days",
|
|
35
|
+
type: "HTTP Cookie"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "performance",
|
|
41
|
+
title: "Performance & Analytics Cookies",
|
|
42
|
+
shortDescription: "Help us measure reader engagement, story completion, and site reliability.",
|
|
43
|
+
fullDescription: "These cookies collect anonymous information about how visitors navigate our news publication. They allow us to count article reads, understand scroll depth and reading completion, and identify broken links or slow-loading assets so we can keep our community reporting responsive and fast. All metrics are aggregated and never contain personal information.",
|
|
44
|
+
required: false,
|
|
45
|
+
cookies: [
|
|
46
|
+
{
|
|
47
|
+
name: "napsite_visitor_v1",
|
|
48
|
+
provider: "First-Party",
|
|
49
|
+
purpose: "A randomized anonymous UUIDv7 to count distinct readers without tracking personal identity.",
|
|
50
|
+
duration: "1 year",
|
|
51
|
+
type: "Local Storage"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "napsite_analytics_v1",
|
|
55
|
+
provider: "First-Party",
|
|
56
|
+
purpose: "Connects reading completion and web vitals to the anonymous session.",
|
|
57
|
+
duration: "30 minutes",
|
|
58
|
+
type: "HTTP Cookie"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: "functional",
|
|
64
|
+
title: "Functional & Personalization Cookies",
|
|
65
|
+
shortDescription: "Remember your reading preferences, text size, and narration audio settings.",
|
|
66
|
+
fullDescription: "These cookies enable enhanced convenience features designed for readers. They remember your custom text sizing, keep your preferred audio narration playback speed (e.g., 1.0x vs 1.25x), and preserve your local town filters across the front page so you always see news closest to your neighborhood.",
|
|
67
|
+
required: false,
|
|
68
|
+
cookies: [
|
|
69
|
+
{
|
|
70
|
+
name: "reader_text_size",
|
|
71
|
+
provider: "First-Party",
|
|
72
|
+
purpose: "Remembers your preferred reading font size across articles.",
|
|
73
|
+
duration: "1 year",
|
|
74
|
+
type: "Local Storage"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "news_publication_theme",
|
|
78
|
+
provider: "First-Party",
|
|
79
|
+
purpose: "Remembers your reading theme preference (light, dark, or system).",
|
|
80
|
+
duration: "1 year",
|
|
81
|
+
type: "HTTP Cookie"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "audio_narration_speed",
|
|
85
|
+
provider: "First-Party",
|
|
86
|
+
purpose: "Stores your preferred audio player playback rate (e.g. 1.0x, 1.25x).",
|
|
87
|
+
duration: "1 year",
|
|
88
|
+
type: "Local Storage"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "advertising",
|
|
94
|
+
title: "Advertising & Local Sponsorship Cookies",
|
|
95
|
+
shortDescription: "Support local business sponsors by capping repetition and measuring notices.",
|
|
96
|
+
fullDescription: "Our journalism is supported by local business sponsors and community partners. These cookies ensure you do not see the same sponsor banner repeatedly (frequency capping) and help local merchants measure whether their announcement reached their community. They never track your activity across unrelated third-party websites or build external advertising profiles.",
|
|
97
|
+
required: false,
|
|
98
|
+
cookies: [
|
|
99
|
+
{
|
|
100
|
+
name: "napsite_sponsor_cap",
|
|
101
|
+
provider: "First-Party",
|
|
102
|
+
purpose: "Prevents repetitive display of identical local business announcements.",
|
|
103
|
+
duration: "7 days",
|
|
104
|
+
type: "Local Storage"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "local_sponsor_ref",
|
|
108
|
+
provider: "First-Party",
|
|
109
|
+
purpose: "Attributes community inquiries directly to the sponsoring local merchant.",
|
|
110
|
+
duration: "30 days",
|
|
111
|
+
type: "Local Storage"
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
export { COOKIE_CATEGORIES, recordConsentToCompliance };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { getCookieConsent, DEFAULT_PREFERENCES_ACCEPTED, COOKIE_CATEGORIES, setCookieConsent, recordConsentToCompliance, DEFAULT_PREFERENCES_REJECTED } from './chunk-
|
|
2
|
+
import { getCookieConsent, DEFAULT_PREFERENCES_ACCEPTED, COOKIE_CATEGORIES, setCookieConsent, recordConsentToCompliance, DEFAULT_PREFERENCES_REJECTED } from './chunk-QWK6G2UF.js';
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var compliance = require('@scalemule/compliance');
|
|
4
|
+
var react = require('@scalemule/compliance/react');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.keys(compliance).forEach(function (k) {
|
|
9
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function () { return compliance[k]; }
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
Object.keys(react).forEach(function (k) {
|
|
15
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return react[k]; }
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -2,208 +2,11 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var compliance = require('@scalemule/compliance');
|
|
5
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
7
|
|
|
7
|
-
// src/cookies.ts
|
|
8
|
-
var COOKIE_CONSENT_KEY = "sm_cookie_consent_v1";
|
|
9
|
-
var COOKIE_CONSENT_BACKUP_KEY = "napsite_cookie_consent_v1";
|
|
10
|
-
var COOKIE_CONSENT_EVENT = "scalemule-cookie-consent-change";
|
|
11
|
-
var COOKIE_CONSENT_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
|
|
12
|
-
var DEFAULT_PREFERENCES_REJECTED = {
|
|
13
|
-
performance: false,
|
|
14
|
-
functional: false,
|
|
15
|
-
advertising: false
|
|
16
|
-
};
|
|
17
|
-
var DEFAULT_PREFERENCES_ACCEPTED = {
|
|
18
|
-
performance: true,
|
|
19
|
-
functional: true,
|
|
20
|
-
advertising: true
|
|
21
|
-
};
|
|
22
|
-
var memoryConsent = null;
|
|
23
|
-
function readCookie(name) {
|
|
24
|
-
if (typeof document === "undefined") return null;
|
|
25
|
-
const match = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([.$?*|{}()[\]\\/+^])/g, "\\$1") + "=([^;]*)"));
|
|
26
|
-
return match ? decodeURIComponent(match[1]) : null;
|
|
27
|
-
}
|
|
28
|
-
function writeCookie(name, value, maxAgeSeconds) {
|
|
29
|
-
if (typeof document === "undefined") return;
|
|
30
|
-
const secure = typeof location !== "undefined" && location.protocol === "https:" ? "; Secure" : "";
|
|
31
|
-
document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=${maxAgeSeconds}; SameSite=Lax${secure}`;
|
|
32
|
-
}
|
|
33
|
-
function getCookieConsent() {
|
|
34
|
-
if (typeof window === "undefined") return memoryConsent;
|
|
35
|
-
try {
|
|
36
|
-
const raw = readCookie(COOKIE_CONSENT_KEY) || readCookie(COOKIE_CONSENT_BACKUP_KEY);
|
|
37
|
-
if (raw) {
|
|
38
|
-
const parsed = JSON.parse(raw);
|
|
39
|
-
if (parsed && parsed.version === 1 && parsed.preferences) {
|
|
40
|
-
memoryConsent = parsed;
|
|
41
|
-
return parsed;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
const stored = window.localStorage?.getItem(COOKIE_CONSENT_KEY);
|
|
45
|
-
if (stored) {
|
|
46
|
-
const parsed = JSON.parse(stored);
|
|
47
|
-
if (parsed && parsed.version === 1 && parsed.preferences) {
|
|
48
|
-
memoryConsent = parsed;
|
|
49
|
-
return parsed;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} catch {
|
|
53
|
-
}
|
|
54
|
-
return memoryConsent;
|
|
55
|
-
}
|
|
56
|
-
var EU_EEA_UK_COUNTRIES = /* @__PURE__ */ new Set([
|
|
57
|
-
"AT",
|
|
58
|
-
"BE",
|
|
59
|
-
"BG",
|
|
60
|
-
"HR",
|
|
61
|
-
"CY",
|
|
62
|
-
"CZ",
|
|
63
|
-
"DK",
|
|
64
|
-
"EE",
|
|
65
|
-
"FI",
|
|
66
|
-
"FR",
|
|
67
|
-
"DE",
|
|
68
|
-
"GR",
|
|
69
|
-
"HU",
|
|
70
|
-
"IE",
|
|
71
|
-
"IT",
|
|
72
|
-
"LV",
|
|
73
|
-
"LT",
|
|
74
|
-
"LU",
|
|
75
|
-
"MT",
|
|
76
|
-
"NL",
|
|
77
|
-
"PL",
|
|
78
|
-
"PT",
|
|
79
|
-
"RO",
|
|
80
|
-
"SK",
|
|
81
|
-
"SI",
|
|
82
|
-
"ES",
|
|
83
|
-
"SE",
|
|
84
|
-
"IS",
|
|
85
|
-
"LI",
|
|
86
|
-
"NO",
|
|
87
|
-
"GB",
|
|
88
|
-
"CH"
|
|
89
|
-
]);
|
|
90
|
-
function isGeoConsentRequired(countryCode) {
|
|
91
|
-
if (countryCode && typeof countryCode === "string") {
|
|
92
|
-
const code = countryCode.trim().toUpperCase();
|
|
93
|
-
if (code.length === 2) {
|
|
94
|
-
return EU_EEA_UK_COUNTRIES.has(code);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (typeof window !== "undefined") {
|
|
98
|
-
try {
|
|
99
|
-
const cached = readCookie("sm_geo_country") || window.localStorage?.getItem("sm_geo_country");
|
|
100
|
-
if (cached && typeof cached === "string" && cached.length === 2) {
|
|
101
|
-
return EU_EEA_UK_COUNTRIES.has(cached.toUpperCase());
|
|
102
|
-
}
|
|
103
|
-
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
104
|
-
if (tz) {
|
|
105
|
-
if (/^(America|US|Canada|Pacific)\//i.test(tz)) {
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
if (/^(Europe|Atlantic\/Reykjavik|Atlantic\/Canary|Atlantic\/Faeroe|Atlantic\/Madeira|Atlantic\/Azores|WET|CET|EET|GMT)/i.test(tz)) {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch {
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
function checkUrlConsentBridge() {
|
|
118
|
-
if (typeof window === "undefined") return false;
|
|
119
|
-
try {
|
|
120
|
-
const url = new URL(window.location.href);
|
|
121
|
-
const param = url.searchParams.get("sm_consent");
|
|
122
|
-
if (!param) return false;
|
|
123
|
-
if (param === "accepted" || param === "1" || param === "all") {
|
|
124
|
-
acceptAllCookies();
|
|
125
|
-
} else if (param === "rejected" || param === "0" || param === "essential") {
|
|
126
|
-
rejectOptionalCookies();
|
|
127
|
-
} else {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
url.searchParams.delete("sm_consent");
|
|
131
|
-
const newSearch = url.searchParams.toString() ? `?${url.searchParams.toString()}` : "";
|
|
132
|
-
window.history.replaceState(null, "", `${url.pathname}${newSearch}${url.hash}`);
|
|
133
|
-
return true;
|
|
134
|
-
} catch {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function hasConsented() {
|
|
139
|
-
return getCookieConsent() !== null;
|
|
140
|
-
}
|
|
141
|
-
function setCookieConsent(preferences, source = "settings_save") {
|
|
142
|
-
const mergedPreferences = {
|
|
143
|
-
essential: true,
|
|
144
|
-
performance: Boolean(preferences.performance),
|
|
145
|
-
functional: Boolean(preferences.functional),
|
|
146
|
-
advertising: Boolean(preferences.advertising)
|
|
147
|
-
};
|
|
148
|
-
let anonymous_id;
|
|
149
|
-
if (typeof window !== "undefined") {
|
|
150
|
-
try {
|
|
151
|
-
anonymous_id = window.localStorage?.getItem("napsite_visitor_v1") || void 0;
|
|
152
|
-
} catch {
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
const record = {
|
|
156
|
-
version: 1,
|
|
157
|
-
preferences: mergedPreferences,
|
|
158
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
159
|
-
anonymous_id,
|
|
160
|
-
source
|
|
161
|
-
};
|
|
162
|
-
memoryConsent = record;
|
|
163
|
-
const serialized = JSON.stringify(record);
|
|
164
|
-
writeCookie(COOKIE_CONSENT_KEY, serialized, COOKIE_CONSENT_MAX_AGE_SECONDS);
|
|
165
|
-
writeCookie(COOKIE_CONSENT_BACKUP_KEY, serialized, COOKIE_CONSENT_MAX_AGE_SECONDS);
|
|
166
|
-
if (typeof window !== "undefined") {
|
|
167
|
-
try {
|
|
168
|
-
window.localStorage?.setItem(COOKIE_CONSENT_KEY, serialized);
|
|
169
|
-
} catch {
|
|
170
|
-
}
|
|
171
|
-
window.dispatchEvent(new CustomEvent(COOKIE_CONSENT_EVENT, { detail: record }));
|
|
172
|
-
}
|
|
173
|
-
return record;
|
|
174
|
-
}
|
|
175
|
-
function acceptAllCookies() {
|
|
176
|
-
return setCookieConsent(DEFAULT_PREFERENCES_ACCEPTED, "banner_accept");
|
|
177
|
-
}
|
|
178
|
-
function rejectOptionalCookies() {
|
|
179
|
-
return setCookieConsent(DEFAULT_PREFERENCES_REJECTED, "banner_reject");
|
|
180
|
-
}
|
|
181
8
|
async function recordConsentToCompliance(record, options) {
|
|
182
|
-
|
|
183
|
-
const endpoint = options?.endpoint || "/api/compliance/consent";
|
|
184
|
-
try {
|
|
185
|
-
const payload = {
|
|
186
|
-
consent_type: "cookie_policy",
|
|
187
|
-
granted: record.preferences.performance || record.preferences.advertising,
|
|
188
|
-
preferences: record.preferences,
|
|
189
|
-
source: record.source,
|
|
190
|
-
anonymous_id: record.anonymous_id,
|
|
191
|
-
timestamp: record.timestamp,
|
|
192
|
-
url: window.location.href,
|
|
193
|
-
user_agent: window.navigator.userAgent
|
|
194
|
-
};
|
|
195
|
-
if (typeof navigator.sendBeacon === "function") {
|
|
196
|
-
navigator.sendBeacon(endpoint, new Blob([JSON.stringify(payload)], { type: "application/json" }));
|
|
197
|
-
} else {
|
|
198
|
-
await fetch(endpoint, {
|
|
199
|
-
method: "POST",
|
|
200
|
-
headers: { "content-type": "application/json" },
|
|
201
|
-
body: JSON.stringify(payload),
|
|
202
|
-
keepalive: true
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
} catch {
|
|
206
|
-
}
|
|
9
|
+
return compliance.recordConsentToCompliance(record, options);
|
|
207
10
|
}
|
|
208
11
|
function CookieConsentBanner({
|
|
209
12
|
title = "Help Us Improve Our Website with Cookies",
|
|
@@ -213,48 +16,76 @@ function CookieConsentBanner({
|
|
|
213
16
|
publicationSlug,
|
|
214
17
|
complianceEndpoint = "/api/compliance/consent",
|
|
215
18
|
countryCode,
|
|
216
|
-
forceShow = false
|
|
19
|
+
forceShow = false,
|
|
20
|
+
consentHubUrl = compliance.DEFAULT_CONSENT_HUB_URL
|
|
217
21
|
}) {
|
|
218
22
|
const [mounted, setMounted] = react.useState(false);
|
|
219
23
|
const [visible, setVisible] = react.useState(false);
|
|
220
24
|
react.useEffect(() => {
|
|
221
25
|
setMounted(true);
|
|
222
|
-
if (checkUrlConsentBridge()) {
|
|
26
|
+
if (compliance.checkUrlConsentBridge()) {
|
|
223
27
|
setVisible(false);
|
|
224
28
|
return;
|
|
225
29
|
}
|
|
226
|
-
if (hasConsented()) {
|
|
30
|
+
if (compliance.hasConsented()) {
|
|
227
31
|
setVisible(false);
|
|
228
32
|
return;
|
|
229
33
|
}
|
|
230
|
-
if (!forceShow && !isGeoConsentRequired(countryCode)) {
|
|
34
|
+
if (!forceShow && !compliance.isGeoConsentRequired(countryCode)) {
|
|
231
35
|
setVisible(false);
|
|
36
|
+
void compliance.queryNetworkConsentHub(consentHubUrl, 1200).then((networkStatus) => {
|
|
37
|
+
if (networkStatus === "accepted") {
|
|
38
|
+
compliance.acceptAllCookies();
|
|
39
|
+
} else if (networkStatus === "rejected") {
|
|
40
|
+
compliance.rejectOptionalCookies();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
232
43
|
return;
|
|
233
44
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
45
|
+
let cancelled = false;
|
|
46
|
+
void compliance.queryNetworkConsentHub(consentHubUrl, 1e3).then((networkStatus) => {
|
|
47
|
+
if (cancelled) return;
|
|
48
|
+
if (networkStatus === "accepted") {
|
|
49
|
+
compliance.acceptAllCookies();
|
|
50
|
+
setVisible(false);
|
|
51
|
+
} else if (networkStatus === "rejected") {
|
|
52
|
+
compliance.rejectOptionalCookies();
|
|
53
|
+
setVisible(false);
|
|
54
|
+
} else {
|
|
55
|
+
setVisible(true);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
cancelled = true;
|
|
60
|
+
};
|
|
61
|
+
}, [countryCode, forceShow, consentHubUrl]);
|
|
237
62
|
react.useEffect(() => {
|
|
238
63
|
const onConsentChange = () => {
|
|
239
|
-
if (hasConsented()) {
|
|
64
|
+
if (compliance.hasConsented()) {
|
|
240
65
|
setVisible(false);
|
|
241
66
|
}
|
|
242
67
|
};
|
|
243
|
-
window.addEventListener(COOKIE_CONSENT_EVENT, onConsentChange);
|
|
244
|
-
return () => window.removeEventListener(COOKIE_CONSENT_EVENT, onConsentChange);
|
|
68
|
+
window.addEventListener(compliance.COOKIE_CONSENT_EVENT, onConsentChange);
|
|
69
|
+
return () => window.removeEventListener(compliance.COOKIE_CONSENT_EVENT, onConsentChange);
|
|
245
70
|
}, []);
|
|
246
71
|
if (!mounted || !visible) return null;
|
|
247
72
|
const handleAccept = () => {
|
|
248
|
-
const record = acceptAllCookies();
|
|
73
|
+
const record = compliance.acceptAllCookies();
|
|
249
74
|
setVisible(false);
|
|
250
75
|
void recordConsentToCompliance(record, {
|
|
251
|
-
endpoint: complianceEndpoint
|
|
76
|
+
endpoint: complianceEndpoint,
|
|
77
|
+
publicationSlug
|
|
78
|
+
});
|
|
79
|
+
compliance.setNetworkConsentHub("accepted", consentHubUrl);
|
|
252
80
|
};
|
|
253
81
|
const handleReject = () => {
|
|
254
|
-
const record = rejectOptionalCookies();
|
|
82
|
+
const record = compliance.rejectOptionalCookies();
|
|
255
83
|
setVisible(false);
|
|
256
84
|
void recordConsentToCompliance(record, {
|
|
257
|
-
endpoint: complianceEndpoint
|
|
85
|
+
endpoint: complianceEndpoint,
|
|
86
|
+
publicationSlug
|
|
87
|
+
});
|
|
88
|
+
compliance.setNetworkConsentHub("rejected", consentHubUrl);
|
|
258
89
|
};
|
|
259
90
|
const defaultText = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
260
91
|
"We use cookies and device data to analyze performance, support local sponsors, and remember your reading preferences across our news network. View",
|
|
@@ -17,7 +17,9 @@ interface CookieConsentBannerProps {
|
|
|
17
17
|
countryCode?: string | null;
|
|
18
18
|
/** Force display of banner regardless of visitor geography */
|
|
19
19
|
forceShow?: boolean;
|
|
20
|
+
/** URL of the central network consent iframe bridge. Default: "https://bayareachronicle.com/consent-bridge.html" */
|
|
21
|
+
consentHubUrl?: string;
|
|
20
22
|
}
|
|
21
|
-
declare function CookieConsentBanner({ title, text, settingsUrl, className, publicationSlug, complianceEndpoint, countryCode, forceShow, }: CookieConsentBannerProps): react__default.JSX.Element | null;
|
|
23
|
+
declare function CookieConsentBanner({ title, text, settingsUrl, className, publicationSlug, complianceEndpoint, countryCode, forceShow, consentHubUrl, }: CookieConsentBannerProps): react__default.JSX.Element | null;
|
|
22
24
|
|
|
23
25
|
export { CookieConsentBanner, type CookieConsentBannerProps };
|
|
@@ -17,7 +17,9 @@ interface CookieConsentBannerProps {
|
|
|
17
17
|
countryCode?: string | null;
|
|
18
18
|
/** Force display of banner regardless of visitor geography */
|
|
19
19
|
forceShow?: boolean;
|
|
20
|
+
/** URL of the central network consent iframe bridge. Default: "https://bayareachronicle.com/consent-bridge.html" */
|
|
21
|
+
consentHubUrl?: string;
|
|
20
22
|
}
|
|
21
|
-
declare function CookieConsentBanner({ title, text, settingsUrl, className, publicationSlug, complianceEndpoint, countryCode, forceShow, }: CookieConsentBannerProps): react__default.JSX.Element | null;
|
|
23
|
+
declare function CookieConsentBanner({ title, text, settingsUrl, className, publicationSlug, complianceEndpoint, countryCode, forceShow, consentHubUrl, }: CookieConsentBannerProps): react__default.JSX.Element | null;
|
|
22
24
|
|
|
23
25
|
export { CookieConsentBanner, type CookieConsentBannerProps };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { CookieConsentBanner } from './chunk-
|
|
3
|
-
import './chunk-
|
|
2
|
+
export { CookieConsentBanner } from './chunk-5YQYJ2L2.js';
|
|
3
|
+
import './chunk-QWK6G2UF.js';
|