@scalemule/news-publication 0.0.45 → 0.0.47
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/README.md +69 -0
- package/dist/{chunk-OIEO2YVG.js → chunk-2XSW7JZS.js} +1 -1
- package/dist/chunk-66GI2IX6.js +65 -0
- package/dist/{chunk-2IYKWGVM.js → chunk-GOWOYMSG.js} +13 -45
- package/dist/{chunk-UTBV6JJX.js → chunk-JV76ZEIA.js} +12 -27
- package/dist/{chunk-72PKW2HM.js → chunk-UL2Q3N26.js} +1 -1
- package/dist/{chunk-GVLJ3HAI.js → chunk-WAC6ATNP.js} +1 -1
- package/dist/cookie-consent-banner.cjs +13 -78
- package/dist/cookie-consent-banner.js +2 -2
- package/dist/cookie-settings-view.cjs +11 -26
- package/dist/cookie-settings-view.js +2 -2
- package/dist/index.cjs +405 -180
- package/dist/index.d.cts +143 -4
- package/dist/index.d.ts +143 -4
- package/dist/index.js +318 -117
- package/dist/network-bar.js +2 -2
- package/dist/network-copyright.js +2 -2
- package/dist/network.js +1 -1
- package/dist/{snapshot-CxuyMF39.d.ts → snapshot-DmRw8G_B.d.ts} +1 -1
- package/dist/{snapshot-C0IGpt-B.d.cts → snapshot-Dx4Lv-lB.d.cts} +1 -1
- package/dist/snapshot-file.d.cts +2 -2
- package/dist/snapshot-file.d.ts +2 -2
- package/dist/sponsorship-view.cjs +75 -0
- package/dist/sponsorship-view.d.cts +11 -0
- package/dist/sponsorship-view.d.ts +11 -0
- package/dist/sponsorship-view.js +62 -0
- package/dist/sponsorships-CtnBe3S8.d.cts +137 -0
- package/dist/sponsorships-CtnBe3S8.d.ts +137 -0
- package/dist/{types-DFDCZHbS.d.cts → types-BJFCWWi0.d.cts} +1 -1
- package/dist/{types-DFDCZHbS.d.ts → types-BJFCWWi0.d.ts} +1 -1
- package/dist/verified-card.d.cts +1 -1
- package/dist/verified-card.d.ts +1 -1
- package/package.json +11 -4
- package/sponsorship.css +78 -0
package/README.md
CHANGED
|
@@ -73,6 +73,67 @@ The React front page still lives in the Walnut Creek Times repository. This pack
|
|
|
73
73
|
|
|
74
74
|
Patch only (`0.0.x` or `0.1.x`) until a stable release is explicitly approved. Publishing is manual: `npm publish` from this directory.
|
|
75
75
|
|
|
76
|
+
## Local briefing foundation
|
|
77
|
+
|
|
78
|
+
`composeLocalBriefing(candidates, options)` is an opt-in, pure selector for an existing
|
|
79
|
+
publication brief. It consumes `BriefingCandidate` projections from an authorized
|
|
80
|
+
server adapter and returns a bounded list using existing `NewsItem` text. It does
|
|
81
|
+
not fetch or generate news, verify claims, store preferences, or change the current
|
|
82
|
+
`composeEdition` path. A server adapter and publication pilot are still required;
|
|
83
|
+
there is no new live BaseNews endpoint in this package.
|
|
84
|
+
|
|
85
|
+
This is an article-backed presentation helper, not the canonical BaseNews schema.
|
|
86
|
+
BaseNews events, issues and opportunities must also work without an article.
|
|
87
|
+
Its eligibility rules apply only to this optional brief. They must never become
|
|
88
|
+
new publishing gates for articles, questionnaires, jokes, jobs, classifieds,
|
|
89
|
+
celebrations or other existing publication features. Their current owner services
|
|
90
|
+
and workflows continue independently, including when intelligence processing is
|
|
91
|
+
unavailable. Underlying capture, trust and agent APIs take priority over UI rollout.
|
|
92
|
+
|
|
93
|
+
Supply the recipient `sm_application_id`, `publication_id`, resolved
|
|
94
|
+
`coverage_area_ids`, and optional explicit community/topic/entity/issue preferences.
|
|
95
|
+
`personalized: false` ignores all preferences. `limit` is a maximum from 1–12
|
|
96
|
+
(default 6); zero useful records yields an empty briefing. Render summaries as
|
|
97
|
+
text, with original reporting links, verification labels and source attribution.
|
|
98
|
+
`why_it_matters` is optional editorial text; reason codes explain selection and
|
|
99
|
+
are not factual claims about an item's consequences.
|
|
100
|
+
|
|
101
|
+
The server must derive scope from authentication, authorize destination grants,
|
|
102
|
+
resolve geographic relationships, enforce evidence/summary redistribution rights,
|
|
103
|
+
and send public, approved projections. Reuse existing Content Intelligence
|
|
104
|
+
classification, coverage profiles, editorial decisions and current evaluation
|
|
105
|
+
receipts in that adapter; this presentation selector does not replace its generic
|
|
106
|
+
relevance engine or editorial ledger. This helper is **not an authorization or
|
|
107
|
+
input-validation boundary**. Do not pass client-supplied trust/approval fields,
|
|
108
|
+
private artifacts, or raw community submissions. Unverified and community-submitted
|
|
109
|
+
information retains those labels even after editorial approval.
|
|
110
|
+
|
|
111
|
+
Each candidate references an existing canonical development, occurrence or reporting
|
|
112
|
+
record via a namespaced `canonical_key`, with its revision. Do not use a whole issue
|
|
113
|
+
ID as the key: separate developments must survive. Include withdrawal/supersession
|
|
114
|
+
revisions when combining cached inventories; the newest revision wins before
|
|
115
|
+
eligibility and ranking. Supply one selected edition per canonical revision;
|
|
116
|
+
conflicting copies of that revision are omitted for reconciliation, not selected
|
|
117
|
+
by input order. A feed lacking tombstones cannot prove that cached records
|
|
118
|
+
are still current. The caller must invalidate caches on corrections and grant
|
|
119
|
+
revocation. Treat personalized HTTP responses as `private, no-store`.
|
|
120
|
+
|
|
121
|
+
Policy 1 uses a civic priority tier, followed by geography × 4, practical value × 3,
|
|
122
|
+
explicit follows × 3, topics × 2, reporting recency and editorial discovery value.
|
|
123
|
+
All seven components and reason codes are returned. Recency describes reporting,
|
|
124
|
+
not event time or urgency. Civic importance comes from editors, not section names.
|
|
125
|
+
Keep a visible link to all important coverage whenever `remaining_important_count`
|
|
126
|
+
is positive. Eligibility still applies to civic items: stale or unauthorized facts
|
|
127
|
+
cannot bypass trust gates.
|
|
128
|
+
|
|
129
|
+
`relevant_until` is required. Confirmed labels also require a public evidence link,
|
|
130
|
+
`last_verified_at` and a future `review_due_at`. Expired review/relevance deadlines
|
|
131
|
+
exclude records; missing freshness information stays `unknown`. No date is inferred
|
|
132
|
+
from `updated_at`, no confidence score promotes verification, and no fallback story
|
|
133
|
+
fills a quota. The entire approved excerpt must end with sentence punctuation and
|
|
134
|
+
fit within 280 Unicode code points; otherwise it is omitted for editorial repair.
|
|
135
|
+
Later qualifications and corrections are never cut off to make a shorter summary.
|
|
136
|
+
|
|
76
137
|
|
|
77
138
|
### Reporting credit and sources
|
|
78
139
|
|
|
@@ -176,3 +237,11 @@ Moderate through **Newsroom → Community Maps → Comments**. Approval requires
|
|
|
176
237
|
explicit guideline review and the current revision. Existing pumpkin reactions
|
|
177
238
|
remain configurable alongside voting. The UI links to `/account?next=...`; the
|
|
178
239
|
publication must validate that return path and preserve it through sign-in.
|
|
240
|
+
|
|
241
|
+
### Community partnerships
|
|
242
|
+
|
|
243
|
+
`SPONSORSHIP_OFFERINGS` defines preliminary USD rates and exact web/email deliverables. `Placement`, `SponsorParty`, `Campaign` and `SponsorshipReport` describe the publication-owned Blog API. `SponsorAcknowledgment` from `@scalemule/news-publication/sponsorship-view` and `sponsorship.css` use publication tokens, explicit labels and safe HTTPS links. They do not insert article ads, load advertising scripts, or measure preview renders.
|
|
244
|
+
|
|
245
|
+
Inventory is unavailable until a verified operational placement is active. `placementAvailable` enforces verification freshness and keeps paid briefings disabled. Campaign approval, authorization, allocation capacity and manual commercial references remain server responsibilities. Report HTML distinguishes observed counts from unavailable data and can be printed or rendered to PDF. No invoice or payment is initiated by this SDK.
|
|
246
|
+
|
|
247
|
+
The consent banner now offers a choice in every geography where optional measurement requires one. `measurementConsent` is the server gate for current, explicitly allowed categories and GPC/DNT. Positive permission is local: unsigned URL parameters and a binary network hub cannot grant all categories. Rendering sponsorship recognition does not require tracking consent; measuring it requires both performance and advertising permission.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { setupNetworkConsentDelegation, COOKIE_CONSENT_EVENT, listedPublications, decorateNetworkUrl } from './chunk-
|
|
2
|
+
import { setupNetworkConsentDelegation, COOKIE_CONSENT_EVENT, listedPublications, decorateNetworkUrl } from './chunk-JV76ZEIA.js';
|
|
3
3
|
import { useState, useId, useRef, useEffect } from 'react';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// src/sponsorships.ts
|
|
2
|
+
var SPONSORSHIP_POLICY = "Sponsors receive clearly identified recognition. Sponsorship does not influence reporting, event selection, factual information, rankings or editorial recommendations.";
|
|
3
|
+
var SPONSORSHIP_OFFERINGS = [
|
|
4
|
+
{
|
|
5
|
+
type: "community_partner",
|
|
6
|
+
name: "Publication Community Partner",
|
|
7
|
+
price_cents: 35e3,
|
|
8
|
+
duration: "One calendar month; exact start and end dates in the agreement.",
|
|
9
|
+
deliverables: "One acknowledgment on the publication's community partners page and one compact acknowledgment below the community calendar. No article placements.",
|
|
10
|
+
acknowledgments: "Two defined web locations; recurring display during the campaign, subject to reader repetition limits.",
|
|
11
|
+
creative: "Name, approved logo, up to 140 characters of copy and one HTTPS link.",
|
|
12
|
+
max_sponsors: 2,
|
|
13
|
+
product_path: "/community-partners"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
type: "community_calendar",
|
|
17
|
+
name: "Community Calendar Sponsor",
|
|
18
|
+
price_cents: 25e3,
|
|
19
|
+
duration: "One calendar month; exact start and end dates in the agreement.",
|
|
20
|
+
deliverables: "One acknowledgment above the independently curated community events calendar.",
|
|
21
|
+
acknowledgments: "One web location; recurring display during the campaign, subject to reader repetition limits.",
|
|
22
|
+
creative: "Name, approved logo, up to 140 characters of copy and one HTTPS link.",
|
|
23
|
+
max_sponsors: 1,
|
|
24
|
+
product_path: "/this-week"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: "daily_briefing",
|
|
28
|
+
name: "Daily Briefing Sponsor",
|
|
29
|
+
price_cents: 3e4,
|
|
30
|
+
duration: "One calendar month after verified newsletter delivery is operational.",
|
|
31
|
+
deliverables: "One acknowledgment per agreed briefing edition. Edition dates and count must be specified in the agreement before booking.",
|
|
32
|
+
acknowledgments: "One per contracted edition; no minimum send count is promised before launch.",
|
|
33
|
+
creative: "Name, optional logo, up to 140 characters of approved copy and one HTTPS link.",
|
|
34
|
+
max_sponsors: 1,
|
|
35
|
+
product_path: "/newsletter"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: "community_guide",
|
|
39
|
+
name: "Community Guide Sponsor",
|
|
40
|
+
price_cents: null,
|
|
41
|
+
duration: "Fixed dates agreed for a named guide.",
|
|
42
|
+
deliverables: "One acknowledgment on one named, independently edited community guide; scope and updates agreed in writing.",
|
|
43
|
+
acknowledgments: "One web location per contracted guide.",
|
|
44
|
+
creative: "Name, approved logo, up to 140 characters of copy and one HTTPS link.",
|
|
45
|
+
max_sponsors: 1,
|
|
46
|
+
product_path: "/guides"
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
function safeSponsorUrl(value) {
|
|
50
|
+
if (typeof value !== "string" || value.length > 2048) return void 0;
|
|
51
|
+
try {
|
|
52
|
+
const url = new URL(value);
|
|
53
|
+
if (url.protocol !== "https:" || url.username || url.password)
|
|
54
|
+
return void 0;
|
|
55
|
+
return url.toString();
|
|
56
|
+
} catch {
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function placementAvailable(placement, now = Date.now()) {
|
|
61
|
+
const verified = placement.verified_at && Date.parse(placement.verified_at);
|
|
62
|
+
return placement.placement_type !== "daily_briefing" && placement.active && placement.availability === "available" && Boolean(safeSponsorUrl(placement.verification_url)) && typeof verified === "number" && Number.isFinite(verified) && verified <= now && now - verified <= 90 * 864e5;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { SPONSORSHIP_OFFERINGS, SPONSORSHIP_POLICY, placementAvailable, safeSponsorUrl };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { hasConsented, rejectOptionalCookies, DEFAULT_CONSENT_HUB_URL, isGpcActive, COOKIE_CONSENT_EVENT, acceptAllCookies, recordConsentToCompliance } from './chunk-JV76ZEIA.js';
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
function CookieConsentBanner({
|
|
7
|
-
title = "
|
|
7
|
+
title = "Your privacy choices",
|
|
8
8
|
text,
|
|
9
9
|
settingsUrl = "/cookies",
|
|
10
10
|
className = "",
|
|
@@ -18,73 +18,41 @@ function CookieConsentBanner({
|
|
|
18
18
|
const [visible, setVisible] = useState(false);
|
|
19
19
|
useEffect(() => {
|
|
20
20
|
setMounted(true);
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const url = new URL(window.location.href);
|
|
22
|
+
if (url.searchParams.has("sm_consent")) {
|
|
23
|
+
if (url.searchParams.get("sm_consent") === "0" && !hasConsented())
|
|
24
|
+
rejectOptionalCookies({ hubUrl: consentHubUrl });
|
|
25
|
+
url.searchParams.delete("sm_consent");
|
|
26
|
+
window.history.replaceState(window.history.state, "", url);
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
setVisible(false);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (!forceShow && !isGeoConsentRequired(countryCode)) {
|
|
31
|
-
setVisible(false);
|
|
32
|
-
void queryNetworkConsentHub(consentHubUrl, 1200).then((networkStatus) => {
|
|
33
|
-
if (networkStatus === "accepted") {
|
|
34
|
-
acceptAllCookies();
|
|
35
|
-
} else if (networkStatus === "rejected") {
|
|
36
|
-
rejectOptionalCookies();
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
let cancelled = false;
|
|
42
|
-
void queryNetworkConsentHub(consentHubUrl, 1e3).then((networkStatus) => {
|
|
43
|
-
if (cancelled) return;
|
|
44
|
-
if (networkStatus === "accepted") {
|
|
45
|
-
acceptAllCookies();
|
|
46
|
-
setVisible(false);
|
|
47
|
-
} else if (networkStatus === "rejected") {
|
|
48
|
-
rejectOptionalCookies();
|
|
49
|
-
setVisible(false);
|
|
50
|
-
} else {
|
|
51
|
-
setVisible(true);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
return () => {
|
|
55
|
-
cancelled = true;
|
|
56
|
-
};
|
|
28
|
+
setVisible(!hasConsented() && !isGpcActive());
|
|
57
29
|
}, [countryCode, forceShow, consentHubUrl]);
|
|
58
30
|
useEffect(() => {
|
|
59
31
|
const onConsentChange = () => {
|
|
60
|
-
|
|
61
|
-
setVisible(false);
|
|
62
|
-
}
|
|
32
|
+
setVisible(!hasConsented() && !isGpcActive());
|
|
63
33
|
};
|
|
64
34
|
window.addEventListener(COOKIE_CONSENT_EVENT, onConsentChange);
|
|
65
35
|
return () => window.removeEventListener(COOKIE_CONSENT_EVENT, onConsentChange);
|
|
66
36
|
}, []);
|
|
67
37
|
if (!mounted || !visible) return null;
|
|
68
38
|
const handleAccept = () => {
|
|
69
|
-
const record = acceptAllCookies();
|
|
39
|
+
const record = acceptAllCookies({ hubUrl: consentHubUrl });
|
|
70
40
|
setVisible(false);
|
|
71
41
|
void recordConsentToCompliance(record, {
|
|
72
42
|
endpoint: complianceEndpoint,
|
|
73
43
|
publicationSlug
|
|
74
44
|
});
|
|
75
|
-
setNetworkConsentHub("accepted", consentHubUrl);
|
|
76
45
|
};
|
|
77
46
|
const handleReject = () => {
|
|
78
|
-
const record = rejectOptionalCookies();
|
|
47
|
+
const record = rejectOptionalCookies({ hubUrl: consentHubUrl });
|
|
79
48
|
setVisible(false);
|
|
80
49
|
void recordConsentToCompliance(record, {
|
|
81
50
|
endpoint: complianceEndpoint,
|
|
82
51
|
publicationSlug
|
|
83
52
|
});
|
|
84
|
-
setNetworkConsentHub("rejected", consentHubUrl);
|
|
85
53
|
};
|
|
86
54
|
const defaultText = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
87
|
-
"
|
|
55
|
+
"With your permission, we measure reading activity and sponsor acknowledgments. You can read the publication with optional cookies turned off. View",
|
|
88
56
|
" ",
|
|
89
57
|
/* @__PURE__ */ jsx("a", { href: settingsUrl, className: "sm-cookie-banner-link", children: "Cookie Settings" }),
|
|
90
58
|
" ",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { recordConsentToCompliance as recordConsentToCompliance$1, getCookieConsent, decorateNetworkUrl } 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';
|
|
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, isGpcActive, queryNetworkConsentHub, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from '@scalemule/compliance';
|
|
3
3
|
|
|
4
4
|
// src/cookies.ts
|
|
5
5
|
async function recordConsentToCompliance(record, options) {
|
|
@@ -48,13 +48,6 @@ var COOKIE_CATEGORIES = [
|
|
|
48
48
|
duration: "1 year",
|
|
49
49
|
type: "HTTP Cookie"
|
|
50
50
|
},
|
|
51
|
-
{
|
|
52
|
-
name: "napsite_session_v1",
|
|
53
|
-
provider: "First-Party",
|
|
54
|
-
purpose: "Maintains session continuity, security tokens, and server routing.",
|
|
55
|
-
duration: "30 minutes (idle)",
|
|
56
|
-
type: "Session Storage"
|
|
57
|
-
},
|
|
58
51
|
{
|
|
59
52
|
name: "napsite_preview",
|
|
60
53
|
provider: "First-Party",
|
|
@@ -68,9 +61,16 @@ var COOKIE_CATEGORIES = [
|
|
|
68
61
|
id: "performance",
|
|
69
62
|
title: "Performance & Analytics Cookies",
|
|
70
63
|
shortDescription: "Help us measure reader engagement, story completion, and site reliability.",
|
|
71
|
-
fullDescription: "
|
|
64
|
+
fullDescription: "With your permission, first-party identifiers support page-visit and reading measurements. Aggregate reports help us improve the publication. Measurements are incomplete when readers decline consent and are not a count of unique people.",
|
|
72
65
|
required: false,
|
|
73
66
|
cookies: [
|
|
67
|
+
{
|
|
68
|
+
name: "napsite_session_v1",
|
|
69
|
+
provider: "First-Party",
|
|
70
|
+
purpose: "Groups consented reading measurements within a session.",
|
|
71
|
+
duration: "30 minutes (idle)",
|
|
72
|
+
type: "Session Storage"
|
|
73
|
+
},
|
|
74
74
|
{
|
|
75
75
|
name: "napsite_visitor_v1",
|
|
76
76
|
provider: "First-Party",
|
|
@@ -120,25 +120,10 @@ var COOKIE_CATEGORIES = [
|
|
|
120
120
|
{
|
|
121
121
|
id: "advertising",
|
|
122
122
|
title: "Advertising & Local Sponsorship Cookies",
|
|
123
|
-
shortDescription: "
|
|
124
|
-
fullDescription: "
|
|
123
|
+
shortDescription: "Measure clearly labeled community sponsorship views and link clicks.",
|
|
124
|
+
fullDescription: "With your permission, we measure visible sponsor acknowledgments and link clicks. Repetition limits use temporary page-session memory. We do not use third-party advertising trackers or build behavioral advertising profiles.",
|
|
125
125
|
required: false,
|
|
126
|
-
cookies: [
|
|
127
|
-
{
|
|
128
|
-
name: "napsite_sponsor_cap",
|
|
129
|
-
provider: "First-Party",
|
|
130
|
-
purpose: "Prevents repetitive display of identical local business announcements.",
|
|
131
|
-
duration: "7 days",
|
|
132
|
-
type: "Local Storage"
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: "local_sponsor_ref",
|
|
136
|
-
provider: "First-Party",
|
|
137
|
-
purpose: "Attributes community inquiries directly to the sponsoring local merchant.",
|
|
138
|
-
duration: "30 days",
|
|
139
|
-
type: "Local Storage"
|
|
140
|
-
}
|
|
141
|
-
]
|
|
126
|
+
cookies: []
|
|
142
127
|
}
|
|
143
128
|
];
|
|
144
129
|
|
|
@@ -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-JV76ZEIA.js';
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -114,7 +114,7 @@ var listedPublications = localPublications.filter(
|
|
|
114
114
|
listedPublications.filter(
|
|
115
115
|
(publication) => publication.slug !== "bayareachronicle"
|
|
116
116
|
);
|
|
117
|
-
|
|
117
|
+
new Set(
|
|
118
118
|
localPublications.map((p) => {
|
|
119
119
|
try {
|
|
120
120
|
return new URL(p.url).hostname.replace(/^www\./, "").toLowerCase();
|
|
@@ -123,46 +123,13 @@ var NETWORK_HOSTNAMES = new Set(
|
|
|
123
123
|
}
|
|
124
124
|
})
|
|
125
125
|
);
|
|
126
|
-
function isNetworkHostname(hostname) {
|
|
127
|
-
if (!hostname) return false;
|
|
128
|
-
const clean = hostname.replace(/^www\./, "").toLowerCase();
|
|
129
|
-
return clean === "bayareanewsnetwork.com" || clean.endsWith(".bayareanewsnetwork.com") || NETWORK_HOSTNAMES.has(clean) || clean.endsWith(".bayareachronicle.com") || clean.endsWith(".napsite.com") || clean.endsWith(".site.scalemule.com");
|
|
130
|
-
}
|
|
131
126
|
|
|
132
127
|
// src/cookies.ts
|
|
133
128
|
async function recordConsentToCompliance(record, options) {
|
|
134
129
|
return compliance.recordConsentToCompliance(record, options);
|
|
135
130
|
}
|
|
136
|
-
var delegationInstalled = false;
|
|
137
|
-
function setupNetworkConsentDelegation() {
|
|
138
|
-
if (typeof window === "undefined" || delegationInstalled) return;
|
|
139
|
-
delegationInstalled = true;
|
|
140
|
-
document.addEventListener(
|
|
141
|
-
"click",
|
|
142
|
-
(e) => {
|
|
143
|
-
const target = e.target;
|
|
144
|
-
const anchor = target?.closest("a");
|
|
145
|
-
if (!anchor || !anchor.href) return;
|
|
146
|
-
try {
|
|
147
|
-
const url = new URL(anchor.href, window.location.href);
|
|
148
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") return;
|
|
149
|
-
if (isNetworkHostname(url.hostname)) {
|
|
150
|
-
const consent = compliance.getCookieConsent();
|
|
151
|
-
if (consent) {
|
|
152
|
-
const decorated = compliance.decorateNetworkUrl(anchor.href);
|
|
153
|
-
if (decorated !== anchor.href) {
|
|
154
|
-
anchor.href = decorated;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
} catch {
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
{ capture: true }
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
131
|
function CookieConsentBanner({
|
|
165
|
-
title = "
|
|
132
|
+
title = "Your privacy choices",
|
|
166
133
|
text,
|
|
167
134
|
settingsUrl = "/cookies",
|
|
168
135
|
className = "",
|
|
@@ -176,73 +143,41 @@ function CookieConsentBanner({
|
|
|
176
143
|
const [visible, setVisible] = react.useState(false);
|
|
177
144
|
react.useEffect(() => {
|
|
178
145
|
setMounted(true);
|
|
179
|
-
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
|
|
146
|
+
const url = new URL(window.location.href);
|
|
147
|
+
if (url.searchParams.has("sm_consent")) {
|
|
148
|
+
if (url.searchParams.get("sm_consent") === "0" && !compliance.hasConsented())
|
|
149
|
+
compliance.rejectOptionalCookies({ hubUrl: consentHubUrl });
|
|
150
|
+
url.searchParams.delete("sm_consent");
|
|
151
|
+
window.history.replaceState(window.history.state, "", url);
|
|
183
152
|
}
|
|
184
|
-
|
|
185
|
-
setVisible(false);
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
if (!forceShow && !compliance.isGeoConsentRequired(countryCode)) {
|
|
189
|
-
setVisible(false);
|
|
190
|
-
void compliance.queryNetworkConsentHub(consentHubUrl, 1200).then((networkStatus) => {
|
|
191
|
-
if (networkStatus === "accepted") {
|
|
192
|
-
compliance.acceptAllCookies();
|
|
193
|
-
} else if (networkStatus === "rejected") {
|
|
194
|
-
compliance.rejectOptionalCookies();
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
let cancelled = false;
|
|
200
|
-
void compliance.queryNetworkConsentHub(consentHubUrl, 1e3).then((networkStatus) => {
|
|
201
|
-
if (cancelled) return;
|
|
202
|
-
if (networkStatus === "accepted") {
|
|
203
|
-
compliance.acceptAllCookies();
|
|
204
|
-
setVisible(false);
|
|
205
|
-
} else if (networkStatus === "rejected") {
|
|
206
|
-
compliance.rejectOptionalCookies();
|
|
207
|
-
setVisible(false);
|
|
208
|
-
} else {
|
|
209
|
-
setVisible(true);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
return () => {
|
|
213
|
-
cancelled = true;
|
|
214
|
-
};
|
|
153
|
+
setVisible(!compliance.hasConsented() && !compliance.isGpcActive());
|
|
215
154
|
}, [countryCode, forceShow, consentHubUrl]);
|
|
216
155
|
react.useEffect(() => {
|
|
217
156
|
const onConsentChange = () => {
|
|
218
|
-
|
|
219
|
-
setVisible(false);
|
|
220
|
-
}
|
|
157
|
+
setVisible(!compliance.hasConsented() && !compliance.isGpcActive());
|
|
221
158
|
};
|
|
222
159
|
window.addEventListener(compliance.COOKIE_CONSENT_EVENT, onConsentChange);
|
|
223
160
|
return () => window.removeEventListener(compliance.COOKIE_CONSENT_EVENT, onConsentChange);
|
|
224
161
|
}, []);
|
|
225
162
|
if (!mounted || !visible) return null;
|
|
226
163
|
const handleAccept = () => {
|
|
227
|
-
const record = compliance.acceptAllCookies();
|
|
164
|
+
const record = compliance.acceptAllCookies({ hubUrl: consentHubUrl });
|
|
228
165
|
setVisible(false);
|
|
229
166
|
void recordConsentToCompliance(record, {
|
|
230
167
|
endpoint: complianceEndpoint,
|
|
231
168
|
publicationSlug
|
|
232
169
|
});
|
|
233
|
-
compliance.setNetworkConsentHub("accepted", consentHubUrl);
|
|
234
170
|
};
|
|
235
171
|
const handleReject = () => {
|
|
236
|
-
const record = compliance.rejectOptionalCookies();
|
|
172
|
+
const record = compliance.rejectOptionalCookies({ hubUrl: consentHubUrl });
|
|
237
173
|
setVisible(false);
|
|
238
174
|
void recordConsentToCompliance(record, {
|
|
239
175
|
endpoint: complianceEndpoint,
|
|
240
176
|
publicationSlug
|
|
241
177
|
});
|
|
242
|
-
compliance.setNetworkConsentHub("rejected", consentHubUrl);
|
|
243
178
|
};
|
|
244
179
|
const defaultText = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
245
|
-
"
|
|
180
|
+
"With your permission, we measure reading activity and sponsor acknowledgments. You can read the publication with optional cookies turned off. View",
|
|
246
181
|
" ",
|
|
247
182
|
/* @__PURE__ */ jsxRuntime.jsx("a", { href: settingsUrl, className: "sm-cookie-banner-link", children: "Cookie Settings" }),
|
|
248
183
|
" ",
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { CookieConsentBanner } from './chunk-
|
|
3
|
-
import './chunk-
|
|
2
|
+
export { CookieConsentBanner } from './chunk-GOWOYMSG.js';
|
|
3
|
+
import './chunk-JV76ZEIA.js';
|
|
@@ -143,13 +143,6 @@ var COOKIE_CATEGORIES = [
|
|
|
143
143
|
duration: "1 year",
|
|
144
144
|
type: "HTTP Cookie"
|
|
145
145
|
},
|
|
146
|
-
{
|
|
147
|
-
name: "napsite_session_v1",
|
|
148
|
-
provider: "First-Party",
|
|
149
|
-
purpose: "Maintains session continuity, security tokens, and server routing.",
|
|
150
|
-
duration: "30 minutes (idle)",
|
|
151
|
-
type: "Session Storage"
|
|
152
|
-
},
|
|
153
146
|
{
|
|
154
147
|
name: "napsite_preview",
|
|
155
148
|
provider: "First-Party",
|
|
@@ -163,9 +156,16 @@ var COOKIE_CATEGORIES = [
|
|
|
163
156
|
id: "performance",
|
|
164
157
|
title: "Performance & Analytics Cookies",
|
|
165
158
|
shortDescription: "Help us measure reader engagement, story completion, and site reliability.",
|
|
166
|
-
fullDescription: "
|
|
159
|
+
fullDescription: "With your permission, first-party identifiers support page-visit and reading measurements. Aggregate reports help us improve the publication. Measurements are incomplete when readers decline consent and are not a count of unique people.",
|
|
167
160
|
required: false,
|
|
168
161
|
cookies: [
|
|
162
|
+
{
|
|
163
|
+
name: "napsite_session_v1",
|
|
164
|
+
provider: "First-Party",
|
|
165
|
+
purpose: "Groups consented reading measurements within a session.",
|
|
166
|
+
duration: "30 minutes (idle)",
|
|
167
|
+
type: "Session Storage"
|
|
168
|
+
},
|
|
169
169
|
{
|
|
170
170
|
name: "napsite_visitor_v1",
|
|
171
171
|
provider: "First-Party",
|
|
@@ -215,25 +215,10 @@ var COOKIE_CATEGORIES = [
|
|
|
215
215
|
{
|
|
216
216
|
id: "advertising",
|
|
217
217
|
title: "Advertising & Local Sponsorship Cookies",
|
|
218
|
-
shortDescription: "
|
|
219
|
-
fullDescription: "
|
|
218
|
+
shortDescription: "Measure clearly labeled community sponsorship views and link clicks.",
|
|
219
|
+
fullDescription: "With your permission, we measure visible sponsor acknowledgments and link clicks. Repetition limits use temporary page-session memory. We do not use third-party advertising trackers or build behavioral advertising profiles.",
|
|
220
220
|
required: false,
|
|
221
|
-
cookies: [
|
|
222
|
-
{
|
|
223
|
-
name: "napsite_sponsor_cap",
|
|
224
|
-
provider: "First-Party",
|
|
225
|
-
purpose: "Prevents repetitive display of identical local business announcements.",
|
|
226
|
-
duration: "7 days",
|
|
227
|
-
type: "Local Storage"
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
name: "local_sponsor_ref",
|
|
231
|
-
provider: "First-Party",
|
|
232
|
-
purpose: "Attributes community inquiries directly to the sponsoring local merchant.",
|
|
233
|
-
duration: "30 days",
|
|
234
|
-
type: "Local Storage"
|
|
235
|
-
}
|
|
236
|
-
]
|
|
221
|
+
cookies: []
|
|
237
222
|
}
|
|
238
223
|
];
|
|
239
224
|
function CookieSettingsView({
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { CookieSettingsView } from './chunk-
|
|
3
|
-
import './chunk-
|
|
2
|
+
export { CookieSettingsView } from './chunk-UL2Q3N26.js';
|
|
3
|
+
import './chunk-JV76ZEIA.js';
|