@scalemule/news-publication 0.0.46 → 0.0.48
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 +8 -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 +182 -75
- package/dist/index.d.cts +41 -1
- package/dist/index.d.ts +41 -1
- package/dist/index.js +96 -12
- package/dist/network-bar.js +2 -2
- package/dist/network-copyright.js +2 -2
- package/dist/network.js +1 -1
- 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/package.json +11 -4
- package/sponsorship.css +78 -0
- package/tokens/broadsheet.css +46 -0
package/dist/index.cjs
CHANGED
|
@@ -90,6 +90,48 @@ var EDITORIAL_SECTION_ORDER = [
|
|
|
90
90
|
"Schools",
|
|
91
91
|
"Opinion"
|
|
92
92
|
];
|
|
93
|
+
var SECTION_ALIASES = {
|
|
94
|
+
"Business": "Local businesses",
|
|
95
|
+
"Government": "Civic life",
|
|
96
|
+
"Arts & Culture": "Community",
|
|
97
|
+
"Food & drink": "Food & places",
|
|
98
|
+
"Things to do": "Events",
|
|
99
|
+
"Sports": "Community",
|
|
100
|
+
"Education": "Schools",
|
|
101
|
+
"Public Safety": "Civic life",
|
|
102
|
+
"Transit": "Civic life",
|
|
103
|
+
"Environment": "Civic life",
|
|
104
|
+
"Recreation": "Community"
|
|
105
|
+
};
|
|
106
|
+
function resolveSection(item) {
|
|
107
|
+
const explicit = item.section?.trim();
|
|
108
|
+
if (explicit && explicit !== "Local news") {
|
|
109
|
+
return SECTION_ALIASES[explicit] ?? explicit;
|
|
110
|
+
}
|
|
111
|
+
const descriptors = [
|
|
112
|
+
...(item.tags ?? []).map((t) => t.name.toLowerCase()),
|
|
113
|
+
...(item.categories ?? []).map((c) => c.name.toLowerCase())
|
|
114
|
+
];
|
|
115
|
+
for (const desc of descriptors) {
|
|
116
|
+
if (/\b(health|wellness|medical|hospital|clinic|doctor|pharmacy|veterinar|pet care|animal welfare|vaccin)\b/i.test(desc)) return "Health";
|
|
117
|
+
if (/\b(real estate|housing|home|homes|mortgage|tenant|tenants|apartment|apartments|property|bmr)\b/i.test(desc)) return "Real Estate";
|
|
118
|
+
if (/\b(civic|government|council|election|ballot|measure|transit|traffic|police|fire|firefighter|wildfire|safety|policy|supervisor)\b/i.test(desc)) return "Civic life";
|
|
119
|
+
if (/\b(business|retail|commerce|commercial|downtown|store|shop|merchants?|chamber of commerce)\b/i.test(desc)) return "Local businesses";
|
|
120
|
+
if (/\b(event|events|festival|festivals|fair|fairs|concert|concerts|music|workshop|workshops|things to do|exhibition|performance)\b/i.test(desc)) return "Events";
|
|
121
|
+
if (/\b(school|schools|education|student|students|teacher|teachers|campus|college|university)\b/i.test(desc)) return "Schools";
|
|
122
|
+
if (/\b(food|dining|restaurant|restaurants|wine|winery|brewery|bakery|cafe|coffee|cuisine|chef)\b/i.test(desc)) return "Food & places";
|
|
123
|
+
if (/\b(community|volunteer|volunteers|library|libraries|neighborhood|nonprofit|charity|youth|senior|seniors)\b/i.test(desc)) return "Community";
|
|
124
|
+
}
|
|
125
|
+
const text = `${item.title} ${item.excerpt ?? ""}`;
|
|
126
|
+
if (/\b(health|hospitals?|clinics?|medical|doctors?|pharmac(?:y|ies)|wellness|veterinar(?:y|ian)|pet care|animal welfare|vaccinat(?:ion|ions)|patients?)\b/iu.test(text)) return "Health";
|
|
127
|
+
if (/\b(real estate|homeownership|mortgage|housing|tenants?|apartments?|below-market rate|home sales?|condos?)\b/iu.test(text)) return "Real Estate";
|
|
128
|
+
if (/\b(city council|planning commission|board of supervisors|ballot|measure [a-z0-9]|election|transit|traffic|police|firefighter|wildfire|evacuation|pedestrian safety|city manager|public works)\b/iu.test(text)) return "Civic life";
|
|
129
|
+
if (/\b(storefront|retail|downtown business|chamber of commerce|opens? doors?|boutique|merchants?|shoppers?|commercial space)\b/iu.test(text)) return "Local businesses";
|
|
130
|
+
if (/\b(festival|parade|fair|concert|workshop|exhibition|showcase|celebration|weigh-off|halloween|trunk-or-treat)\b/iu.test(text)) return "Events";
|
|
131
|
+
if (/\b(schools?|students?|teachers?|campuses?|classrooms?|high school|elementary|school district)\b/iu.test(text)) return "Schools";
|
|
132
|
+
if (/\b(restaurants?|cafes?|baker(?:y|ies)|winer(?:y|ies)|brewer(?:y|ies)|dining|chefs?|menus?)\b/iu.test(text)) return "Food & places";
|
|
133
|
+
return "Community";
|
|
134
|
+
}
|
|
93
135
|
function orderedSections(sections2, order = EDITORIAL_SECTION_ORDER) {
|
|
94
136
|
return sections2.filter((section) => section.name !== "Local news").slice().sort((left, right) => {
|
|
95
137
|
const leftRank = order.indexOf(left.name);
|
|
@@ -111,8 +153,8 @@ function sectionDefinition(name) {
|
|
|
111
153
|
function editorialSections(items) {
|
|
112
154
|
const groups = /* @__PURE__ */ new Map();
|
|
113
155
|
for (const item of items) {
|
|
114
|
-
const name = item
|
|
115
|
-
groups.set(name, [...groups.get(name) ?? [], item]);
|
|
156
|
+
const name = resolveSection(item);
|
|
157
|
+
groups.set(name, [...groups.get(name) ?? [], { ...item, section: name }]);
|
|
116
158
|
}
|
|
117
159
|
return Array.from(groups, ([name, articles]) => ({ ...sectionDefinition(name), items: articles }));
|
|
118
160
|
}
|
|
@@ -234,8 +276,8 @@ function shortDeck(value, limit = 160) {
|
|
|
234
276
|
return (space > opening.length / 2 ? opening.slice(0, space) : opening).trimEnd() + "\u2026";
|
|
235
277
|
}
|
|
236
278
|
function storyDate(value) {
|
|
237
|
-
const
|
|
238
|
-
return Number.isNaN(
|
|
279
|
+
const date2 = new Date(value);
|
|
280
|
+
return Number.isNaN(date2.getTime()) ? null : date2.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", timeZone: "America/Los_Angeles" });
|
|
239
281
|
}
|
|
240
282
|
|
|
241
283
|
// src/seo.ts
|
|
@@ -1278,13 +1320,6 @@ var COOKIE_CATEGORIES = [
|
|
|
1278
1320
|
duration: "1 year",
|
|
1279
1321
|
type: "HTTP Cookie"
|
|
1280
1322
|
},
|
|
1281
|
-
{
|
|
1282
|
-
name: "napsite_session_v1",
|
|
1283
|
-
provider: "First-Party",
|
|
1284
|
-
purpose: "Maintains session continuity, security tokens, and server routing.",
|
|
1285
|
-
duration: "30 minutes (idle)",
|
|
1286
|
-
type: "Session Storage"
|
|
1287
|
-
},
|
|
1288
1323
|
{
|
|
1289
1324
|
name: "napsite_preview",
|
|
1290
1325
|
provider: "First-Party",
|
|
@@ -1298,9 +1333,16 @@ var COOKIE_CATEGORIES = [
|
|
|
1298
1333
|
id: "performance",
|
|
1299
1334
|
title: "Performance & Analytics Cookies",
|
|
1300
1335
|
shortDescription: "Help us measure reader engagement, story completion, and site reliability.",
|
|
1301
|
-
fullDescription: "
|
|
1336
|
+
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.",
|
|
1302
1337
|
required: false,
|
|
1303
1338
|
cookies: [
|
|
1339
|
+
{
|
|
1340
|
+
name: "napsite_session_v1",
|
|
1341
|
+
provider: "First-Party",
|
|
1342
|
+
purpose: "Groups consented reading measurements within a session.",
|
|
1343
|
+
duration: "30 minutes (idle)",
|
|
1344
|
+
type: "Session Storage"
|
|
1345
|
+
},
|
|
1304
1346
|
{
|
|
1305
1347
|
name: "napsite_visitor_v1",
|
|
1306
1348
|
provider: "First-Party",
|
|
@@ -1350,29 +1392,14 @@ var COOKIE_CATEGORIES = [
|
|
|
1350
1392
|
{
|
|
1351
1393
|
id: "advertising",
|
|
1352
1394
|
title: "Advertising & Local Sponsorship Cookies",
|
|
1353
|
-
shortDescription: "
|
|
1354
|
-
fullDescription: "
|
|
1395
|
+
shortDescription: "Measure clearly labeled community sponsorship views and link clicks.",
|
|
1396
|
+
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.",
|
|
1355
1397
|
required: false,
|
|
1356
|
-
cookies: [
|
|
1357
|
-
{
|
|
1358
|
-
name: "napsite_sponsor_cap",
|
|
1359
|
-
provider: "First-Party",
|
|
1360
|
-
purpose: "Prevents repetitive display of identical local business announcements.",
|
|
1361
|
-
duration: "7 days",
|
|
1362
|
-
type: "Local Storage"
|
|
1363
|
-
},
|
|
1364
|
-
{
|
|
1365
|
-
name: "local_sponsor_ref",
|
|
1366
|
-
provider: "First-Party",
|
|
1367
|
-
purpose: "Attributes community inquiries directly to the sponsoring local merchant.",
|
|
1368
|
-
duration: "30 days",
|
|
1369
|
-
type: "Local Storage"
|
|
1370
|
-
}
|
|
1371
|
-
]
|
|
1398
|
+
cookies: []
|
|
1372
1399
|
}
|
|
1373
1400
|
];
|
|
1374
1401
|
function CookieConsentBanner({
|
|
1375
|
-
title = "
|
|
1402
|
+
title = "Your privacy choices",
|
|
1376
1403
|
text,
|
|
1377
1404
|
settingsUrl = "/cookies",
|
|
1378
1405
|
className = "",
|
|
@@ -1386,73 +1413,41 @@ function CookieConsentBanner({
|
|
|
1386
1413
|
const [visible, setVisible] = react.useState(false);
|
|
1387
1414
|
react.useEffect(() => {
|
|
1388
1415
|
setMounted(true);
|
|
1389
|
-
|
|
1390
|
-
if (
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
}
|
|
1398
|
-
if (!forceShow && !compliance.isGeoConsentRequired(countryCode)) {
|
|
1399
|
-
setVisible(false);
|
|
1400
|
-
void compliance.queryNetworkConsentHub(consentHubUrl, 1200).then((networkStatus) => {
|
|
1401
|
-
if (networkStatus === "accepted") {
|
|
1402
|
-
compliance.acceptAllCookies();
|
|
1403
|
-
} else if (networkStatus === "rejected") {
|
|
1404
|
-
compliance.rejectOptionalCookies();
|
|
1405
|
-
}
|
|
1406
|
-
});
|
|
1407
|
-
return;
|
|
1408
|
-
}
|
|
1409
|
-
let cancelled = false;
|
|
1410
|
-
void compliance.queryNetworkConsentHub(consentHubUrl, 1e3).then((networkStatus) => {
|
|
1411
|
-
if (cancelled) return;
|
|
1412
|
-
if (networkStatus === "accepted") {
|
|
1413
|
-
compliance.acceptAllCookies();
|
|
1414
|
-
setVisible(false);
|
|
1415
|
-
} else if (networkStatus === "rejected") {
|
|
1416
|
-
compliance.rejectOptionalCookies();
|
|
1417
|
-
setVisible(false);
|
|
1418
|
-
} else {
|
|
1419
|
-
setVisible(true);
|
|
1420
|
-
}
|
|
1421
|
-
});
|
|
1422
|
-
return () => {
|
|
1423
|
-
cancelled = true;
|
|
1424
|
-
};
|
|
1416
|
+
const url = new URL(window.location.href);
|
|
1417
|
+
if (url.searchParams.has("sm_consent")) {
|
|
1418
|
+
if (url.searchParams.get("sm_consent") === "0" && !compliance.hasConsented())
|
|
1419
|
+
compliance.rejectOptionalCookies({ hubUrl: consentHubUrl });
|
|
1420
|
+
url.searchParams.delete("sm_consent");
|
|
1421
|
+
window.history.replaceState(window.history.state, "", url);
|
|
1422
|
+
}
|
|
1423
|
+
setVisible(!compliance.hasConsented() && !compliance.isGpcActive());
|
|
1425
1424
|
}, [countryCode, forceShow, consentHubUrl]);
|
|
1426
1425
|
react.useEffect(() => {
|
|
1427
1426
|
const onConsentChange = () => {
|
|
1428
|
-
|
|
1429
|
-
setVisible(false);
|
|
1430
|
-
}
|
|
1427
|
+
setVisible(!compliance.hasConsented() && !compliance.isGpcActive());
|
|
1431
1428
|
};
|
|
1432
1429
|
window.addEventListener(compliance.COOKIE_CONSENT_EVENT, onConsentChange);
|
|
1433
1430
|
return () => window.removeEventListener(compliance.COOKIE_CONSENT_EVENT, onConsentChange);
|
|
1434
1431
|
}, []);
|
|
1435
1432
|
if (!mounted || !visible) return null;
|
|
1436
1433
|
const handleAccept = () => {
|
|
1437
|
-
const record = compliance.acceptAllCookies();
|
|
1434
|
+
const record = compliance.acceptAllCookies({ hubUrl: consentHubUrl });
|
|
1438
1435
|
setVisible(false);
|
|
1439
1436
|
void recordConsentToCompliance(record, {
|
|
1440
1437
|
endpoint: complianceEndpoint,
|
|
1441
1438
|
publicationSlug
|
|
1442
1439
|
});
|
|
1443
|
-
compliance.setNetworkConsentHub("accepted", consentHubUrl);
|
|
1444
1440
|
};
|
|
1445
1441
|
const handleReject = () => {
|
|
1446
|
-
const record = compliance.rejectOptionalCookies();
|
|
1442
|
+
const record = compliance.rejectOptionalCookies({ hubUrl: consentHubUrl });
|
|
1447
1443
|
setVisible(false);
|
|
1448
1444
|
void recordConsentToCompliance(record, {
|
|
1449
1445
|
endpoint: complianceEndpoint,
|
|
1450
1446
|
publicationSlug
|
|
1451
1447
|
});
|
|
1452
|
-
compliance.setNetworkConsentHub("rejected", consentHubUrl);
|
|
1453
1448
|
};
|
|
1454
1449
|
const defaultText = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1455
|
-
"
|
|
1450
|
+
"With your permission, we measure reading activity and sponsor acknowledgments. You can read the publication with optional cookies turned off. View",
|
|
1456
1451
|
" ",
|
|
1457
1452
|
/* @__PURE__ */ jsxRuntime.jsx("a", { href: settingsUrl, className: "sm-cookie-banner-link", children: "Cookie Settings" }),
|
|
1458
1453
|
" ",
|
|
@@ -3234,6 +3229,111 @@ function renderArticleBlocksToHtml(blocks, mediaMap, options) {
|
|
|
3234
3229
|
return parts.join("\n");
|
|
3235
3230
|
}
|
|
3236
3231
|
|
|
3232
|
+
// src/sponsorships.ts
|
|
3233
|
+
var SPONSORSHIP_POLICY = "Sponsors receive clearly identified recognition. Sponsorship does not influence reporting, event selection, factual information, rankings or editorial recommendations.";
|
|
3234
|
+
var SPONSORSHIP_OFFERINGS = [
|
|
3235
|
+
{
|
|
3236
|
+
type: "community_partner",
|
|
3237
|
+
name: "Publication Community Partner",
|
|
3238
|
+
price_cents: 35e3,
|
|
3239
|
+
duration: "One calendar month; exact start and end dates in the agreement.",
|
|
3240
|
+
deliverables: "One acknowledgment on the publication's community partners page and one compact acknowledgment below the community calendar. No article placements.",
|
|
3241
|
+
acknowledgments: "Two defined web locations; recurring display during the campaign, subject to reader repetition limits.",
|
|
3242
|
+
creative: "Name, approved logo, up to 140 characters of copy and one HTTPS link.",
|
|
3243
|
+
max_sponsors: 2,
|
|
3244
|
+
product_path: "/community-partners"
|
|
3245
|
+
},
|
|
3246
|
+
{
|
|
3247
|
+
type: "community_calendar",
|
|
3248
|
+
name: "Community Calendar Sponsor",
|
|
3249
|
+
price_cents: 25e3,
|
|
3250
|
+
duration: "One calendar month; exact start and end dates in the agreement.",
|
|
3251
|
+
deliverables: "One acknowledgment above the independently curated community events calendar.",
|
|
3252
|
+
acknowledgments: "One web location; recurring display during the campaign, subject to reader repetition limits.",
|
|
3253
|
+
creative: "Name, approved logo, up to 140 characters of copy and one HTTPS link.",
|
|
3254
|
+
max_sponsors: 1,
|
|
3255
|
+
product_path: "/this-week"
|
|
3256
|
+
},
|
|
3257
|
+
{
|
|
3258
|
+
type: "daily_briefing",
|
|
3259
|
+
name: "Daily Briefing Sponsor",
|
|
3260
|
+
price_cents: 3e4,
|
|
3261
|
+
duration: "One calendar month after verified newsletter delivery is operational.",
|
|
3262
|
+
deliverables: "One acknowledgment per agreed briefing edition. Edition dates and count must be specified in the agreement before booking.",
|
|
3263
|
+
acknowledgments: "One per contracted edition; no minimum send count is promised before launch.",
|
|
3264
|
+
creative: "Name, optional logo, up to 140 characters of approved copy and one HTTPS link.",
|
|
3265
|
+
max_sponsors: 1,
|
|
3266
|
+
product_path: "/newsletter"
|
|
3267
|
+
},
|
|
3268
|
+
{
|
|
3269
|
+
type: "community_guide",
|
|
3270
|
+
name: "Community Guide Sponsor",
|
|
3271
|
+
price_cents: null,
|
|
3272
|
+
duration: "Fixed dates agreed for a named guide.",
|
|
3273
|
+
deliverables: "One acknowledgment on one named, independently edited community guide; scope and updates agreed in writing.",
|
|
3274
|
+
acknowledgments: "One web location per contracted guide.",
|
|
3275
|
+
creative: "Name, approved logo, up to 140 characters of copy and one HTTPS link.",
|
|
3276
|
+
max_sponsors: 1,
|
|
3277
|
+
product_path: "/guides"
|
|
3278
|
+
}
|
|
3279
|
+
];
|
|
3280
|
+
function safeSponsorUrl(value) {
|
|
3281
|
+
if (typeof value !== "string" || value.length > 2048) return void 0;
|
|
3282
|
+
try {
|
|
3283
|
+
const url = new URL(value);
|
|
3284
|
+
if (url.protocol !== "https:" || url.username || url.password)
|
|
3285
|
+
return void 0;
|
|
3286
|
+
return url.toString();
|
|
3287
|
+
} catch {
|
|
3288
|
+
return void 0;
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
function placementAvailable(placement, now = Date.now()) {
|
|
3292
|
+
const verified = placement.verified_at && Date.parse(placement.verified_at);
|
|
3293
|
+
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;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
// src/measurement-consent.ts
|
|
3297
|
+
function measurementConsent(headers, sponsorship = false, now = Date.now()) {
|
|
3298
|
+
if (headers.get("dnt") === "1" || headers.get("sec-gpc") === "1")
|
|
3299
|
+
return false;
|
|
3300
|
+
const cookies = headers.get("cookie")?.split(";").map((value) => value.trim()) ?? [];
|
|
3301
|
+
const cookie = cookies.find((value) => value.startsWith("sm_cookie_consent_v1=")) ?? cookies.find((value) => value.startsWith("napsite_cookie_consent_v1="));
|
|
3302
|
+
if (!cookie) return false;
|
|
3303
|
+
try {
|
|
3304
|
+
const record = JSON.parse(
|
|
3305
|
+
decodeURIComponent(cookie.substring(cookie.indexOf("=") + 1))
|
|
3306
|
+
);
|
|
3307
|
+
const date2 = Date.parse(record.timestamp);
|
|
3308
|
+
return record.version === 1 && record.preferences?.essential === true && typeof record.preferences?.functional === "boolean" && typeof record.preferences?.advertising === "boolean" && record.preferences?.performance === true && (!sponsorship || record.preferences?.advertising === true) && Number.isFinite(date2) && date2 <= now + 3e5 && now - date2 < 365 * 864e5;
|
|
3309
|
+
} catch {
|
|
3310
|
+
return false;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
|
|
3314
|
+
// src/sponsorship-report.ts
|
|
3315
|
+
var escape = (text) => String(text ?? "").replace(
|
|
3316
|
+
/[&<>"']/g,
|
|
3317
|
+
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]
|
|
3318
|
+
);
|
|
3319
|
+
var date = (value) => new Date(value).toLocaleString("en-US", {
|
|
3320
|
+
timeZone: "UTC",
|
|
3321
|
+
dateStyle: "medium",
|
|
3322
|
+
timeStyle: "short"
|
|
3323
|
+
}) + " UTC";
|
|
3324
|
+
function metric(value) {
|
|
3325
|
+
if (value.status === "unavailable" || value.value === null)
|
|
3326
|
+
return "Unavailable";
|
|
3327
|
+
return `${escape(value.value.toLocaleString("en-US"))} <small>${escape(value.status)}</small>${value.from && value.to ? `<small>Observed period:<br>${escape(date(value.from))}<br>to ${escape(date(value.to))}</small>` : ""}`;
|
|
3328
|
+
}
|
|
3329
|
+
function campaignReportHtml(report) {
|
|
3330
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>${escape(report.campaign_name)} | Sponsorship report</title><style>
|
|
3331
|
+
@page{size:Letter;margin:18mm}*{box-sizing:border-box}body{font:11pt/1.5 Arial,sans-serif;color:#172d37;margin:0}h1,h2{font-family:Georgia,serif;font-weight:normal}h1{font-size:30pt;line-height:1.12;margin:16pt 0}h2{font-size:19pt;margin:0 0 8pt}header{border-bottom:2pt solid #173d32;padding-bottom:16pt}.brand{font-size:10pt;letter-spacing:1pt}p{margin:8pt 0}.meta{color:#4e5d64;font-size:10pt}section{break-inside:avoid;margin:24pt 0}table{width:100%;border-collapse:collapse;margin:12pt 0}td,th{text-align:left;border-bottom:1px solid #d8dedc;padding:8pt 5pt}th{font-size:9pt}small{display:block;color:#4e5d64;font-size:8pt}footer{border-top:1px solid #d8dedc;padding-top:12pt;font-size:9pt}.notes{font-size:9pt;color:#4e5d64}
|
|
3332
|
+
</style></head><body><header><div class="brand">BAY AREA NEWS NETWORK</div><p>Community sponsorship report</p><h1>${escape(report.campaign_name)}</h1><p>${escape(report.sponsor)}</p><p class="meta">Campaign period: ${escape(date(report.starts_at))} to ${escape(date(report.ends_at))}<br>Status: ${escape(report.status)}<br>Prepared: ${escape(date(report.generated_at))}</p></header>
|
|
3333
|
+
${report.placements.map((p) => `<section><h2>${escape(p.publication)}</h2><p>${escape(p.placement)} \xB7 ${escape(p.product_path)}</p><p class="meta">Community scope: ${escape(p.communities.length ? p.communities.join(", ") : "Publication-wide")}<br>Placement delivery: ${escape(p.delivery_status)}</p><table><thead><tr><th>Observed placement views</th><th>Observed sponsor link clicks</th><th>Newsletter deliveries</th></tr></thead><tbody><tr><td>${metric(p.views)}</td><td>${metric(p.clicks)}</td><td>${metric(p.newsletter_deliveries)}</td></tr></tbody></table><p class="notes">Views: ${escape(p.views.methodology)}<br>Clicks: ${escape(p.clicks.methodology)}<br>Newsletter: ${escape(p.newsletter_deliveries.methodology)}</p></section>`).join("")}
|
|
3334
|
+
<footer><p>${escape(report.reporting_note)}</p><p>${escape(report.editorial_independence)}</p><p>Campaign reference: ${escape(report.campaign_id)}</p></footer></body></html>`;
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3237
3337
|
Object.defineProperty(exports, "COOKIE_CONSENT_BACKUP_KEY", {
|
|
3238
3338
|
enumerable: true,
|
|
3239
3339
|
get: function () { return compliance.COOKIE_CONSENT_BACKUP_KEY; }
|
|
@@ -3341,6 +3441,8 @@ exports.NEWS_CACHE = NEWS_CACHE;
|
|
|
3341
3441
|
exports.NetworkCopyrightNotice = NetworkCopyrightNotice;
|
|
3342
3442
|
exports.NewsError = NewsError;
|
|
3343
3443
|
exports.SESSION_IDLE_MS = SESSION_IDLE_MS;
|
|
3444
|
+
exports.SPONSORSHIP_OFFERINGS = SPONSORSHIP_OFFERINGS;
|
|
3445
|
+
exports.SPONSORSHIP_POLICY = SPONSORSHIP_POLICY;
|
|
3344
3446
|
exports.THEME_COOKIE = THEME_COOKIE;
|
|
3345
3447
|
exports.THEME_EVENT = THEME_EVENT;
|
|
3346
3448
|
exports.THEME_MAX_AGE_SECONDS = THEME_MAX_AGE_SECONDS;
|
|
@@ -3361,6 +3463,7 @@ exports.articleMeta = articleMeta;
|
|
|
3361
3463
|
exports.articleUrl = articleUrl;
|
|
3362
3464
|
exports.attribution = attribution;
|
|
3363
3465
|
exports.briefSummary = briefSummary;
|
|
3466
|
+
exports.campaignReportHtml = campaignReportHtml;
|
|
3364
3467
|
exports.canHostMeetup = canHostMeetup;
|
|
3365
3468
|
exports.categoryLabel = categoryLabel;
|
|
3366
3469
|
exports.classifiedPath = classifiedPath;
|
|
@@ -3403,12 +3506,14 @@ exports.listedPublications = listedPublications;
|
|
|
3403
3506
|
exports.llmsText = llmsText;
|
|
3404
3507
|
exports.localPublications = localPublications;
|
|
3405
3508
|
exports.matchesStoryTag = matchesStoryTag;
|
|
3509
|
+
exports.measurementConsent = measurementConsent;
|
|
3406
3510
|
exports.nearbyUpdates = nearbyUpdates;
|
|
3407
3511
|
exports.newsArticleJsonLd = newsArticleJsonLd;
|
|
3408
3512
|
exports.normalizedText = normalizedText;
|
|
3409
3513
|
exports.orderedSections = orderedSections;
|
|
3410
3514
|
exports.parseDocumentBlocks = parseDocumentBlocks;
|
|
3411
3515
|
exports.parseSnapshot = parseSnapshot;
|
|
3516
|
+
exports.placementAvailable = placementAvailable;
|
|
3412
3517
|
exports.prepareClassified = prepareClassified;
|
|
3413
3518
|
exports.prepareJobPost = prepareJobPost;
|
|
3414
3519
|
exports.prepareMeetup = prepareMeetup;
|
|
@@ -3429,7 +3534,9 @@ exports.renderArticleBlocksToHtml = renderArticleBlocksToHtml;
|
|
|
3429
3534
|
exports.resolveCoupon = resolveCoupon;
|
|
3430
3535
|
exports.resolveEffectiveTheme = resolveEffectiveTheme;
|
|
3431
3536
|
exports.resolveLayout = resolveLayout;
|
|
3537
|
+
exports.resolveSection = resolveSection;
|
|
3432
3538
|
exports.revalidateDecision = revalidateDecision;
|
|
3539
|
+
exports.safeSponsorUrl = safeSponsorUrl;
|
|
3433
3540
|
exports.sanitizeInlineMarkdown = sanitizeInlineMarkdown;
|
|
3434
3541
|
exports.screenMessage = screenMessage;
|
|
3435
3542
|
exports.secretsMatch = secretsMatch;
|
package/dist/index.d.cts
CHANGED
|
@@ -15,6 +15,8 @@ import * as react from 'react';
|
|
|
15
15
|
export { VerifiedCardComponent, VerifiedCardSection, getArticleCards, isSafeActionUrl } from './verified-card.cjs';
|
|
16
16
|
export { C as CommunityMapArticleEmbed, c as communityMapEmbeds } from './community-maps-DKcYhQYN.cjs';
|
|
17
17
|
export { C as ContentBlock, S as StructuredDocument, a as StructuredMedia, f as formatArtworkCaption, p as parseDocumentBlocks, r as renderArticleBlocksToHtml, s as sanitizeInlineMarkdown } from './article-blocks-DsabIDmH.cjs';
|
|
18
|
+
import { M as Measurement } from './sponsorships-CtnBe3S8.cjs';
|
|
19
|
+
export { a as Campaign, b as CampaignStatus, c as CampaignTarget, C as Creative, d as Placement, e as PlacementType, P as PublicAcknowledgment, S as SPONSORSHIP_OFFERINGS, f as SPONSORSHIP_POLICY, g as SponsorParty, p as placementAvailable, s as safeSponsorUrl } from './sponsorships-CtnBe3S8.cjs';
|
|
18
20
|
|
|
19
21
|
/** Walnut Creek Times broadsheet colors. A paper overrides only what it changes. */
|
|
20
22
|
declare const BROADSHEET_THEME: PublicationTheme;
|
|
@@ -219,6 +221,13 @@ declare function defaultRevalidateTargets(): {
|
|
|
219
221
|
* "Opinion" are reserved so future sections slot in without a release.
|
|
220
222
|
*/
|
|
221
223
|
declare const EDITORIAL_SECTION_ORDER: readonly ["Civic life", "Community", "Local businesses", "Real Estate", "Food & places", "Events", "Health", "Schools", "Opinion"];
|
|
224
|
+
/**
|
|
225
|
+
* Resolves a story's canonical editorial section.
|
|
226
|
+
* Preserves explicitly assigned sections (normalizing known aliases).
|
|
227
|
+
* If unassigned, intelligently infers section desk from tags, categories, or keywords
|
|
228
|
+
* so stories are never lost to unrendered buckets.
|
|
229
|
+
*/
|
|
230
|
+
declare function resolveSection(item: NewsItem): string;
|
|
222
231
|
/** Sorts sections into the canonical order, dropping the implicit "Local news" bucket. */
|
|
223
232
|
declare function orderedSections<T extends {
|
|
224
233
|
name: string;
|
|
@@ -473,4 +482,35 @@ declare function publicationListeningCandidates<T extends ListeningArticle>(item
|
|
|
473
482
|
*/
|
|
474
483
|
declare const CURATED_COMMUNITY_CARDS: Record<string, Record<string, unknown>[]>;
|
|
475
484
|
|
|
476
|
-
|
|
485
|
+
/** The server enforces the same explicit consent gate as the browser. */
|
|
486
|
+
declare function measurementConsent(headers: Pick<Headers, "get">, sponsorship?: boolean, now?: number): boolean;
|
|
487
|
+
|
|
488
|
+
interface SponsorshipReport {
|
|
489
|
+
campaign_id: string;
|
|
490
|
+
campaign_name: string;
|
|
491
|
+
sponsor: string;
|
|
492
|
+
starts_at: string;
|
|
493
|
+
ends_at: string;
|
|
494
|
+
status: string;
|
|
495
|
+
generated_at: string;
|
|
496
|
+
editorial_independence: string;
|
|
497
|
+
reporting_note: string;
|
|
498
|
+
placements: Array<{
|
|
499
|
+
application_id: string;
|
|
500
|
+
publication_id: string;
|
|
501
|
+
publication: string;
|
|
502
|
+
publication_url: string;
|
|
503
|
+
placement_id: string;
|
|
504
|
+
placement: string;
|
|
505
|
+
product_path: string;
|
|
506
|
+
communities: string[];
|
|
507
|
+
delivery_status: string;
|
|
508
|
+
views: Measurement;
|
|
509
|
+
clicks: Measurement;
|
|
510
|
+
newsletter_deliveries: Measurement;
|
|
511
|
+
}>;
|
|
512
|
+
}
|
|
513
|
+
/** Shared by the newsroom print/export view and the repeatable PDF renderer. */
|
|
514
|
+
declare function campaignReportHtml(report: SponsorshipReport): string;
|
|
515
|
+
|
|
516
|
+
export { ANALYTICS_COOKIE, ANALYTICS_VERSION, ArticleProvenance, type Attribution, BROADSHEET_THEME, type BriefingCandidate, type BriefingPreferences, type BriefingReason, type BriefingSection, type BriefingSource, type BriefingVerification, COOKIE_CATEGORIES, CURATED_COMMUNITY_CARDS, CouponOffer, EDITORIAL_SECTION_ORDER, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, LOCAL_BRIEFING_POLICY_VERSION, type ListeningArticle, type LocalBriefing, type LocalBriefingItem, type LocalBriefingOptions, Measurement, NEWS_CACHE, NearbyUpdate, NewsArticle, NewsError, NewsItem, NewsPublication, PublicationInput, PublicationTheme, SESSION_IDLE_MS, type SponsorshipReport, THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, type ThemeMode, UTM_FIELDS, UUID, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, campaignReportHtml, clearTheme, composeEdition, composeLocalBriefing, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getStoredTheme, getSystemTheme, inventoryCacheOptions, llmsText, matchesStoryTag, measurementConsent, nearbyUpdates, newsArticleJsonLd, normalizedText, orderedSections, publicHttps, publicUrl, publicationJsonLd, publicationListeningCandidates, publicationListeningTrack, publicationMeta, readerSources, recordConsentToCompliance, referralCode, resolveCoupon, resolveEffectiveTheme, resolveLayout, resolveSection, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ import * as react from 'react';
|
|
|
15
15
|
export { VerifiedCardComponent, VerifiedCardSection, getArticleCards, isSafeActionUrl } from './verified-card.js';
|
|
16
16
|
export { C as CommunityMapArticleEmbed, c as communityMapEmbeds } from './community-maps-DKcYhQYN.js';
|
|
17
17
|
export { C as ContentBlock, S as StructuredDocument, a as StructuredMedia, f as formatArtworkCaption, p as parseDocumentBlocks, r as renderArticleBlocksToHtml, s as sanitizeInlineMarkdown } from './article-blocks-DsabIDmH.js';
|
|
18
|
+
import { M as Measurement } from './sponsorships-CtnBe3S8.js';
|
|
19
|
+
export { a as Campaign, b as CampaignStatus, c as CampaignTarget, C as Creative, d as Placement, e as PlacementType, P as PublicAcknowledgment, S as SPONSORSHIP_OFFERINGS, f as SPONSORSHIP_POLICY, g as SponsorParty, p as placementAvailable, s as safeSponsorUrl } from './sponsorships-CtnBe3S8.js';
|
|
18
20
|
|
|
19
21
|
/** Walnut Creek Times broadsheet colors. A paper overrides only what it changes. */
|
|
20
22
|
declare const BROADSHEET_THEME: PublicationTheme;
|
|
@@ -219,6 +221,13 @@ declare function defaultRevalidateTargets(): {
|
|
|
219
221
|
* "Opinion" are reserved so future sections slot in without a release.
|
|
220
222
|
*/
|
|
221
223
|
declare const EDITORIAL_SECTION_ORDER: readonly ["Civic life", "Community", "Local businesses", "Real Estate", "Food & places", "Events", "Health", "Schools", "Opinion"];
|
|
224
|
+
/**
|
|
225
|
+
* Resolves a story's canonical editorial section.
|
|
226
|
+
* Preserves explicitly assigned sections (normalizing known aliases).
|
|
227
|
+
* If unassigned, intelligently infers section desk from tags, categories, or keywords
|
|
228
|
+
* so stories are never lost to unrendered buckets.
|
|
229
|
+
*/
|
|
230
|
+
declare function resolveSection(item: NewsItem): string;
|
|
222
231
|
/** Sorts sections into the canonical order, dropping the implicit "Local news" bucket. */
|
|
223
232
|
declare function orderedSections<T extends {
|
|
224
233
|
name: string;
|
|
@@ -473,4 +482,35 @@ declare function publicationListeningCandidates<T extends ListeningArticle>(item
|
|
|
473
482
|
*/
|
|
474
483
|
declare const CURATED_COMMUNITY_CARDS: Record<string, Record<string, unknown>[]>;
|
|
475
484
|
|
|
476
|
-
|
|
485
|
+
/** The server enforces the same explicit consent gate as the browser. */
|
|
486
|
+
declare function measurementConsent(headers: Pick<Headers, "get">, sponsorship?: boolean, now?: number): boolean;
|
|
487
|
+
|
|
488
|
+
interface SponsorshipReport {
|
|
489
|
+
campaign_id: string;
|
|
490
|
+
campaign_name: string;
|
|
491
|
+
sponsor: string;
|
|
492
|
+
starts_at: string;
|
|
493
|
+
ends_at: string;
|
|
494
|
+
status: string;
|
|
495
|
+
generated_at: string;
|
|
496
|
+
editorial_independence: string;
|
|
497
|
+
reporting_note: string;
|
|
498
|
+
placements: Array<{
|
|
499
|
+
application_id: string;
|
|
500
|
+
publication_id: string;
|
|
501
|
+
publication: string;
|
|
502
|
+
publication_url: string;
|
|
503
|
+
placement_id: string;
|
|
504
|
+
placement: string;
|
|
505
|
+
product_path: string;
|
|
506
|
+
communities: string[];
|
|
507
|
+
delivery_status: string;
|
|
508
|
+
views: Measurement;
|
|
509
|
+
clicks: Measurement;
|
|
510
|
+
newsletter_deliveries: Measurement;
|
|
511
|
+
}>;
|
|
512
|
+
}
|
|
513
|
+
/** Shared by the newsroom print/export view and the repeatable PDF renderer. */
|
|
514
|
+
declare function campaignReportHtml(report: SponsorshipReport): string;
|
|
515
|
+
|
|
516
|
+
export { ANALYTICS_COOKIE, ANALYTICS_VERSION, ArticleProvenance, type Attribution, BROADSHEET_THEME, type BriefingCandidate, type BriefingPreferences, type BriefingReason, type BriefingSection, type BriefingSource, type BriefingVerification, COOKIE_CATEGORIES, CURATED_COMMUNITY_CARDS, CouponOffer, EDITORIAL_SECTION_ORDER, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, LOCAL_BRIEFING_POLICY_VERSION, type ListeningArticle, type LocalBriefing, type LocalBriefingItem, type LocalBriefingOptions, Measurement, NEWS_CACHE, NearbyUpdate, NewsArticle, NewsError, NewsItem, NewsPublication, PublicationInput, PublicationTheme, SESSION_IDLE_MS, type SponsorshipReport, THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, type ThemeMode, UTM_FIELDS, UUID, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, campaignReportHtml, clearTheme, composeEdition, composeLocalBriefing, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getStoredTheme, getSystemTheme, inventoryCacheOptions, llmsText, matchesStoryTag, measurementConsent, nearbyUpdates, newsArticleJsonLd, normalizedText, orderedSections, publicHttps, publicUrl, publicationJsonLd, publicationListeningCandidates, publicationListeningTrack, publicationMeta, readerSources, recordConsentToCompliance, referralCode, resolveCoupon, resolveEffectiveTheme, resolveLayout, resolveSection, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
|