@scalemule/news-publication 0.0.12 → 0.0.13

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.
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { checkUrlConsentBridge, hasConsented, isGeoConsentRequired, COOKIE_CONSENT_EVENT, acceptAllCookies, recordConsentToCompliance, rejectOptionalCookies } from './chunk-CWZWU4HE.js';
2
+ import { checkUrlConsentBridge, hasConsented, isGeoConsentRequired, queryNetworkConsentHub, DEFAULT_CONSENT_HUB_URL, acceptAllCookies, rejectOptionalCookies, COOKIE_CONSENT_EVENT, recordConsentToCompliance, setNetworkConsentHub } from './chunk-L5OE6DND.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
- const timer = window.setTimeout(() => setVisible(true), 300);
33
- return () => window.clearTimeout(timer);
34
- }, [countryCode, forceShow]);
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",
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { getCookieConsent, DEFAULT_PREFERENCES_ACCEPTED, COOKIE_CATEGORIES, setCookieConsent, recordConsentToCompliance, DEFAULT_PREFERENCES_REJECTED } from './chunk-CWZWU4HE.js';
2
+ import { getCookieConsent, DEFAULT_PREFERENCES_ACCEPTED, COOKIE_CATEGORIES, setCookieConsent, recordConsentToCompliance, DEFAULT_PREFERENCES_REJECTED } from './chunk-L5OE6DND.js';
3
3
  import { useState, useEffect } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
@@ -3,6 +3,8 @@ var COOKIE_CONSENT_KEY = "sm_cookie_consent_v1";
3
3
  var COOKIE_CONSENT_BACKUP_KEY = "napsite_cookie_consent_v1";
4
4
  var COOKIE_CONSENT_EVENT = "scalemule-cookie-consent-change";
5
5
  var COOKIE_CONSENT_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
6
+ var DEFAULT_CONSENT_HUB_URL = "https://bayareachronicle.com/consent-bridge.html";
7
+ var NETWORK_CONSENT_STORAGE_KEY = "sm_network_consent_status";
6
8
  var DEFAULT_PREFERENCES_REJECTED = {
7
9
  essential: true,
8
10
  performance: false,
@@ -252,6 +254,153 @@ function decorateNetworkUrl(targetUrl) {
252
254
  return targetUrl;
253
255
  }
254
256
  }
257
+ function queryNetworkConsentHub(hubUrl = DEFAULT_CONSENT_HUB_URL, timeoutMs = 1e3) {
258
+ if (typeof window === "undefined") return Promise.resolve(null);
259
+ try {
260
+ const hubOrigin = new URL(hubUrl).origin;
261
+ if (window.location.origin === hubOrigin) {
262
+ try {
263
+ const direct = window.localStorage?.getItem(NETWORK_CONSENT_STORAGE_KEY);
264
+ if (direct === "accepted" || direct === "rejected") {
265
+ return Promise.resolve(direct);
266
+ }
267
+ } catch {
268
+ }
269
+ return Promise.resolve(null);
270
+ }
271
+ return new Promise((resolve) => {
272
+ let settled = false;
273
+ let iframe = null;
274
+ let timer = null;
275
+ const finish = (result) => {
276
+ if (settled) return;
277
+ settled = true;
278
+ if (timer !== null) window.clearTimeout(timer);
279
+ window.removeEventListener("message", onMessage);
280
+ if (iframe && iframe.parentNode) {
281
+ try {
282
+ iframe.parentNode.removeChild(iframe);
283
+ } catch {
284
+ }
285
+ }
286
+ resolve(result);
287
+ };
288
+ const sendGet = () => {
289
+ try {
290
+ iframe?.contentWindow?.postMessage({ type: "SM_CONSENT_GET" }, hubOrigin);
291
+ } catch {
292
+ }
293
+ };
294
+ const onMessage = (event) => {
295
+ if (event.origin !== hubOrigin) return;
296
+ const data = event.data;
297
+ if (!data || typeof data !== "object") return;
298
+ if (data.type === "SM_CONSENT_STATUS") {
299
+ const status = data.status === "accepted" || data.status === "rejected" ? data.status : null;
300
+ finish(status);
301
+ } else if (data.type === "SM_CONSENT_BRIDGE_READY") {
302
+ sendGet();
303
+ }
304
+ };
305
+ window.addEventListener("message", onMessage);
306
+ timer = window.setTimeout(() => {
307
+ finish(null);
308
+ }, timeoutMs);
309
+ try {
310
+ iframe = document.createElement("iframe");
311
+ iframe.src = hubUrl;
312
+ iframe.style.position = "absolute";
313
+ iframe.style.width = "0";
314
+ iframe.style.height = "0";
315
+ iframe.style.border = "0";
316
+ iframe.style.display = "none";
317
+ iframe.style.visibility = "hidden";
318
+ iframe.setAttribute("aria-hidden", "true");
319
+ iframe.setAttribute("tabindex", "-1");
320
+ iframe.onload = () => {
321
+ sendGet();
322
+ };
323
+ iframe.onerror = () => {
324
+ finish(null);
325
+ };
326
+ const target = document.body || document.documentElement;
327
+ target.appendChild(iframe);
328
+ } catch {
329
+ finish(null);
330
+ }
331
+ });
332
+ } catch {
333
+ return Promise.resolve(null);
334
+ }
335
+ }
336
+ function setNetworkConsentHub(status, hubUrl = DEFAULT_CONSENT_HUB_URL) {
337
+ if (typeof window === "undefined") return;
338
+ try {
339
+ const hubOrigin = new URL(hubUrl).origin;
340
+ if (window.location.origin === hubOrigin) {
341
+ try {
342
+ if (status) {
343
+ window.localStorage?.setItem(NETWORK_CONSENT_STORAGE_KEY, status);
344
+ } else {
345
+ window.localStorage?.removeItem(NETWORK_CONSENT_STORAGE_KEY);
346
+ }
347
+ } catch {
348
+ }
349
+ return;
350
+ }
351
+ let iframe = null;
352
+ let timer = null;
353
+ const cleanup = () => {
354
+ if (timer !== null) window.clearTimeout(timer);
355
+ window.removeEventListener("message", onMessage);
356
+ if (iframe && iframe.parentNode) {
357
+ try {
358
+ iframe.parentNode.removeChild(iframe);
359
+ } catch {
360
+ }
361
+ }
362
+ };
363
+ const sendSet = () => {
364
+ try {
365
+ iframe?.contentWindow?.postMessage({ type: "SM_CONSENT_SET", status }, hubOrigin);
366
+ } catch {
367
+ }
368
+ };
369
+ const onMessage = (event) => {
370
+ if (event.origin !== hubOrigin) return;
371
+ const data = event.data;
372
+ if (!data || typeof data !== "object") return;
373
+ if (data.type === "SM_CONSENT_SAVED") {
374
+ cleanup();
375
+ } else if (data.type === "SM_CONSENT_BRIDGE_READY") {
376
+ sendSet();
377
+ }
378
+ };
379
+ window.addEventListener("message", onMessage);
380
+ timer = window.setTimeout(cleanup, 2500);
381
+ try {
382
+ iframe = document.createElement("iframe");
383
+ iframe.src = hubUrl;
384
+ iframe.style.position = "absolute";
385
+ iframe.style.width = "0";
386
+ iframe.style.height = "0";
387
+ iframe.style.border = "0";
388
+ iframe.style.display = "none";
389
+ iframe.style.visibility = "hidden";
390
+ iframe.setAttribute("aria-hidden", "true");
391
+ iframe.setAttribute("tabindex", "-1");
392
+ iframe.onload = () => {
393
+ sendSet();
394
+ };
395
+ iframe.onerror = cleanup;
396
+ const target = document.body || document.documentElement;
397
+ target.appendChild(iframe);
398
+ } catch {
399
+ cleanup();
400
+ }
401
+ } catch {
402
+ }
403
+ }
255
404
  function hasConsented() {
256
405
  return getCookieConsent() !== null;
257
406
  }
@@ -299,6 +448,8 @@ function setCookieConsent(preferences, source = "settings_save") {
299
448
  window.localStorage?.setItem(COOKIE_CONSENT_KEY, serialized);
300
449
  } catch {
301
450
  }
451
+ const networkStatus = mergedPreferences.performance || mergedPreferences.advertising ? "accepted" : "rejected";
452
+ setNetworkConsentHub(networkStatus);
302
453
  window.dispatchEvent(new CustomEvent(COOKIE_CONSENT_EVENT, { detail: record }));
303
454
  }
304
455
  return record;
@@ -320,6 +471,7 @@ function clearCookieConsent() {
320
471
  window.localStorage?.removeItem(COOKIE_CONSENT_KEY);
321
472
  } catch {
322
473
  }
474
+ setNetworkConsentHub(null);
323
475
  window.dispatchEvent(new CustomEvent(COOKIE_CONSENT_EVENT, { detail: null }));
324
476
  }
325
477
  }
@@ -351,4 +503,4 @@ async function recordConsentToCompliance(record, options) {
351
503
  }
352
504
  }
353
505
 
354
- export { COOKIE_CATEGORIES, COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, acceptAllCookies, checkUrlConsentBridge, clearCookieConsent, decorateNetworkUrl, getCookieConsent, hasConsented, isCategoryAllowed, isGeoConsentRequired, recordConsentToCompliance, rejectOptionalCookies, setCookieConsent };
506
+ export { COOKIE_CATEGORIES, 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, recordConsentToCompliance, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub };
@@ -9,6 +9,8 @@ var COOKIE_CONSENT_KEY = "sm_cookie_consent_v1";
9
9
  var COOKIE_CONSENT_BACKUP_KEY = "napsite_cookie_consent_v1";
10
10
  var COOKIE_CONSENT_EVENT = "scalemule-cookie-consent-change";
11
11
  var COOKIE_CONSENT_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
12
+ var DEFAULT_CONSENT_HUB_URL = "https://bayareachronicle.com/consent-bridge.html";
13
+ var NETWORK_CONSENT_STORAGE_KEY = "sm_network_consent_status";
12
14
  var DEFAULT_PREFERENCES_REJECTED = {
13
15
  performance: false,
14
16
  functional: false,
@@ -135,6 +137,153 @@ function checkUrlConsentBridge() {
135
137
  return false;
136
138
  }
137
139
  }
140
+ function queryNetworkConsentHub(hubUrl = DEFAULT_CONSENT_HUB_URL, timeoutMs = 1e3) {
141
+ if (typeof window === "undefined") return Promise.resolve(null);
142
+ try {
143
+ const hubOrigin = new URL(hubUrl).origin;
144
+ if (window.location.origin === hubOrigin) {
145
+ try {
146
+ const direct = window.localStorage?.getItem(NETWORK_CONSENT_STORAGE_KEY);
147
+ if (direct === "accepted" || direct === "rejected") {
148
+ return Promise.resolve(direct);
149
+ }
150
+ } catch {
151
+ }
152
+ return Promise.resolve(null);
153
+ }
154
+ return new Promise((resolve) => {
155
+ let settled = false;
156
+ let iframe = null;
157
+ let timer = null;
158
+ const finish = (result) => {
159
+ if (settled) return;
160
+ settled = true;
161
+ if (timer !== null) window.clearTimeout(timer);
162
+ window.removeEventListener("message", onMessage);
163
+ if (iframe && iframe.parentNode) {
164
+ try {
165
+ iframe.parentNode.removeChild(iframe);
166
+ } catch {
167
+ }
168
+ }
169
+ resolve(result);
170
+ };
171
+ const sendGet = () => {
172
+ try {
173
+ iframe?.contentWindow?.postMessage({ type: "SM_CONSENT_GET" }, hubOrigin);
174
+ } catch {
175
+ }
176
+ };
177
+ const onMessage = (event) => {
178
+ if (event.origin !== hubOrigin) return;
179
+ const data = event.data;
180
+ if (!data || typeof data !== "object") return;
181
+ if (data.type === "SM_CONSENT_STATUS") {
182
+ const status = data.status === "accepted" || data.status === "rejected" ? data.status : null;
183
+ finish(status);
184
+ } else if (data.type === "SM_CONSENT_BRIDGE_READY") {
185
+ sendGet();
186
+ }
187
+ };
188
+ window.addEventListener("message", onMessage);
189
+ timer = window.setTimeout(() => {
190
+ finish(null);
191
+ }, timeoutMs);
192
+ try {
193
+ iframe = document.createElement("iframe");
194
+ iframe.src = hubUrl;
195
+ iframe.style.position = "absolute";
196
+ iframe.style.width = "0";
197
+ iframe.style.height = "0";
198
+ iframe.style.border = "0";
199
+ iframe.style.display = "none";
200
+ iframe.style.visibility = "hidden";
201
+ iframe.setAttribute("aria-hidden", "true");
202
+ iframe.setAttribute("tabindex", "-1");
203
+ iframe.onload = () => {
204
+ sendGet();
205
+ };
206
+ iframe.onerror = () => {
207
+ finish(null);
208
+ };
209
+ const target = document.body || document.documentElement;
210
+ target.appendChild(iframe);
211
+ } catch {
212
+ finish(null);
213
+ }
214
+ });
215
+ } catch {
216
+ return Promise.resolve(null);
217
+ }
218
+ }
219
+ function setNetworkConsentHub(status, hubUrl = DEFAULT_CONSENT_HUB_URL) {
220
+ if (typeof window === "undefined") return;
221
+ try {
222
+ const hubOrigin = new URL(hubUrl).origin;
223
+ if (window.location.origin === hubOrigin) {
224
+ try {
225
+ if (status) {
226
+ window.localStorage?.setItem(NETWORK_CONSENT_STORAGE_KEY, status);
227
+ } else {
228
+ window.localStorage?.removeItem(NETWORK_CONSENT_STORAGE_KEY);
229
+ }
230
+ } catch {
231
+ }
232
+ return;
233
+ }
234
+ let iframe = null;
235
+ let timer = null;
236
+ const cleanup = () => {
237
+ if (timer !== null) window.clearTimeout(timer);
238
+ window.removeEventListener("message", onMessage);
239
+ if (iframe && iframe.parentNode) {
240
+ try {
241
+ iframe.parentNode.removeChild(iframe);
242
+ } catch {
243
+ }
244
+ }
245
+ };
246
+ const sendSet = () => {
247
+ try {
248
+ iframe?.contentWindow?.postMessage({ type: "SM_CONSENT_SET", status }, hubOrigin);
249
+ } catch {
250
+ }
251
+ };
252
+ const onMessage = (event) => {
253
+ if (event.origin !== hubOrigin) return;
254
+ const data = event.data;
255
+ if (!data || typeof data !== "object") return;
256
+ if (data.type === "SM_CONSENT_SAVED") {
257
+ cleanup();
258
+ } else if (data.type === "SM_CONSENT_BRIDGE_READY") {
259
+ sendSet();
260
+ }
261
+ };
262
+ window.addEventListener("message", onMessage);
263
+ timer = window.setTimeout(cleanup, 2500);
264
+ try {
265
+ iframe = document.createElement("iframe");
266
+ iframe.src = hubUrl;
267
+ iframe.style.position = "absolute";
268
+ iframe.style.width = "0";
269
+ iframe.style.height = "0";
270
+ iframe.style.border = "0";
271
+ iframe.style.display = "none";
272
+ iframe.style.visibility = "hidden";
273
+ iframe.setAttribute("aria-hidden", "true");
274
+ iframe.setAttribute("tabindex", "-1");
275
+ iframe.onload = () => {
276
+ sendSet();
277
+ };
278
+ iframe.onerror = cleanup;
279
+ const target = document.body || document.documentElement;
280
+ target.appendChild(iframe);
281
+ } catch {
282
+ cleanup();
283
+ }
284
+ } catch {
285
+ }
286
+ }
138
287
  function hasConsented() {
139
288
  return getCookieConsent() !== null;
140
289
  }
@@ -168,6 +317,8 @@ function setCookieConsent(preferences, source = "settings_save") {
168
317
  window.localStorage?.setItem(COOKIE_CONSENT_KEY, serialized);
169
318
  } catch {
170
319
  }
320
+ const networkStatus = mergedPreferences.performance || mergedPreferences.advertising ? "accepted" : "rejected";
321
+ setNetworkConsentHub(networkStatus);
171
322
  window.dispatchEvent(new CustomEvent(COOKIE_CONSENT_EVENT, { detail: record }));
172
323
  }
173
324
  return record;
@@ -213,7 +364,8 @@ function CookieConsentBanner({
213
364
  publicationSlug,
214
365
  complianceEndpoint = "/api/compliance/consent",
215
366
  countryCode,
216
- forceShow = false
367
+ forceShow = false,
368
+ consentHubUrl = DEFAULT_CONSENT_HUB_URL
217
369
  }) {
218
370
  const [mounted, setMounted] = react.useState(false);
219
371
  const [visible, setVisible] = react.useState(false);
@@ -229,11 +381,32 @@ function CookieConsentBanner({
229
381
  }
230
382
  if (!forceShow && !isGeoConsentRequired(countryCode)) {
231
383
  setVisible(false);
384
+ void queryNetworkConsentHub(consentHubUrl, 1200).then((networkStatus) => {
385
+ if (networkStatus === "accepted") {
386
+ acceptAllCookies();
387
+ } else if (networkStatus === "rejected") {
388
+ rejectOptionalCookies();
389
+ }
390
+ });
232
391
  return;
233
392
  }
234
- const timer = window.setTimeout(() => setVisible(true), 300);
235
- return () => window.clearTimeout(timer);
236
- }, [countryCode, forceShow]);
393
+ let cancelled = false;
394
+ void queryNetworkConsentHub(consentHubUrl, 1e3).then((networkStatus) => {
395
+ if (cancelled) return;
396
+ if (networkStatus === "accepted") {
397
+ acceptAllCookies();
398
+ setVisible(false);
399
+ } else if (networkStatus === "rejected") {
400
+ rejectOptionalCookies();
401
+ setVisible(false);
402
+ } else {
403
+ setVisible(true);
404
+ }
405
+ });
406
+ return () => {
407
+ cancelled = true;
408
+ };
409
+ }, [countryCode, forceShow, consentHubUrl]);
237
410
  react.useEffect(() => {
238
411
  const onConsentChange = () => {
239
412
  if (hasConsented()) {
@@ -249,12 +422,14 @@ function CookieConsentBanner({
249
422
  setVisible(false);
250
423
  void recordConsentToCompliance(record, {
251
424
  endpoint: complianceEndpoint});
425
+ setNetworkConsentHub("accepted", consentHubUrl);
252
426
  };
253
427
  const handleReject = () => {
254
428
  const record = rejectOptionalCookies();
255
429
  setVisible(false);
256
430
  void recordConsentToCompliance(record, {
257
431
  endpoint: complianceEndpoint});
432
+ setNetworkConsentHub("rejected", consentHubUrl);
258
433
  };
259
434
  const defaultText = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
260
435
  "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-EKQXS63J.js';
3
- import './chunk-CWZWU4HE.js';
2
+ export { CookieConsentBanner } from './chunk-5MHPE77S.js';
3
+ import './chunk-L5OE6DND.js';
@@ -9,6 +9,8 @@ var COOKIE_CONSENT_KEY = "sm_cookie_consent_v1";
9
9
  var COOKIE_CONSENT_BACKUP_KEY = "napsite_cookie_consent_v1";
10
10
  var COOKIE_CONSENT_EVENT = "scalemule-cookie-consent-change";
11
11
  var COOKIE_CONSENT_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
12
+ var DEFAULT_CONSENT_HUB_URL = "https://bayareachronicle.com/consent-bridge.html";
13
+ var NETWORK_CONSENT_STORAGE_KEY = "sm_network_consent_status";
12
14
  var DEFAULT_PREFERENCES_REJECTED = {
13
15
  essential: true,
14
16
  performance: false,
@@ -163,6 +165,72 @@ function getCookieConsent() {
163
165
  }
164
166
  return memoryConsent;
165
167
  }
168
+ function setNetworkConsentHub(status, hubUrl = DEFAULT_CONSENT_HUB_URL) {
169
+ if (typeof window === "undefined") return;
170
+ try {
171
+ const hubOrigin = new URL(hubUrl).origin;
172
+ if (window.location.origin === hubOrigin) {
173
+ try {
174
+ if (status) {
175
+ window.localStorage?.setItem(NETWORK_CONSENT_STORAGE_KEY, status);
176
+ }
177
+ } catch {
178
+ }
179
+ return;
180
+ }
181
+ let iframe = null;
182
+ let timer = null;
183
+ const cleanup = () => {
184
+ if (timer !== null) window.clearTimeout(timer);
185
+ window.removeEventListener("message", onMessage);
186
+ if (iframe && iframe.parentNode) {
187
+ try {
188
+ iframe.parentNode.removeChild(iframe);
189
+ } catch {
190
+ }
191
+ }
192
+ };
193
+ const sendSet = () => {
194
+ try {
195
+ iframe?.contentWindow?.postMessage({ type: "SM_CONSENT_SET", status }, hubOrigin);
196
+ } catch {
197
+ }
198
+ };
199
+ const onMessage = (event) => {
200
+ if (event.origin !== hubOrigin) return;
201
+ const data = event.data;
202
+ if (!data || typeof data !== "object") return;
203
+ if (data.type === "SM_CONSENT_SAVED") {
204
+ cleanup();
205
+ } else if (data.type === "SM_CONSENT_BRIDGE_READY") {
206
+ sendSet();
207
+ }
208
+ };
209
+ window.addEventListener("message", onMessage);
210
+ timer = window.setTimeout(cleanup, 2500);
211
+ try {
212
+ iframe = document.createElement("iframe");
213
+ iframe.src = hubUrl;
214
+ iframe.style.position = "absolute";
215
+ iframe.style.width = "0";
216
+ iframe.style.height = "0";
217
+ iframe.style.border = "0";
218
+ iframe.style.display = "none";
219
+ iframe.style.visibility = "hidden";
220
+ iframe.setAttribute("aria-hidden", "true");
221
+ iframe.setAttribute("tabindex", "-1");
222
+ iframe.onload = () => {
223
+ sendSet();
224
+ };
225
+ iframe.onerror = cleanup;
226
+ const target = document.body || document.documentElement;
227
+ target.appendChild(iframe);
228
+ } catch {
229
+ cleanup();
230
+ }
231
+ } catch {
232
+ }
233
+ }
166
234
  function setCookieConsent(preferences, source = "settings_save") {
167
235
  const mergedPreferences = {
168
236
  essential: true,
@@ -193,6 +261,8 @@ function setCookieConsent(preferences, source = "settings_save") {
193
261
  window.localStorage?.setItem(COOKIE_CONSENT_KEY, serialized);
194
262
  } catch {
195
263
  }
264
+ const networkStatus = mergedPreferences.performance || mergedPreferences.advertising ? "accepted" : "rejected";
265
+ setNetworkConsentHub(networkStatus);
196
266
  window.dispatchEvent(new CustomEvent(COOKIE_CONSENT_EVENT, { detail: record }));
197
267
  }
198
268
  return record;
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- export { CookieSettingsView } from './chunk-ZSA6YQBV.js';
3
- import './chunk-CWZWU4HE.js';
2
+ export { CookieSettingsView } from './chunk-FUUL2PSF.js';
3
+ import './chunk-L5OE6DND.js';
package/dist/index.cjs CHANGED
@@ -788,6 +788,8 @@ var COOKIE_CONSENT_KEY = "sm_cookie_consent_v1";
788
788
  var COOKIE_CONSENT_BACKUP_KEY = "napsite_cookie_consent_v1";
789
789
  var COOKIE_CONSENT_EVENT = "scalemule-cookie-consent-change";
790
790
  var COOKIE_CONSENT_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
791
+ var DEFAULT_CONSENT_HUB_URL = "https://bayareachronicle.com/consent-bridge.html";
792
+ var NETWORK_CONSENT_STORAGE_KEY = "sm_network_consent_status";
791
793
  var DEFAULT_PREFERENCES_REJECTED = {
792
794
  essential: true,
793
795
  performance: false,
@@ -1037,6 +1039,153 @@ function decorateNetworkUrl(targetUrl) {
1037
1039
  return targetUrl;
1038
1040
  }
1039
1041
  }
1042
+ function queryNetworkConsentHub(hubUrl = DEFAULT_CONSENT_HUB_URL, timeoutMs = 1e3) {
1043
+ if (typeof window === "undefined") return Promise.resolve(null);
1044
+ try {
1045
+ const hubOrigin = new URL(hubUrl).origin;
1046
+ if (window.location.origin === hubOrigin) {
1047
+ try {
1048
+ const direct = window.localStorage?.getItem(NETWORK_CONSENT_STORAGE_KEY);
1049
+ if (direct === "accepted" || direct === "rejected") {
1050
+ return Promise.resolve(direct);
1051
+ }
1052
+ } catch {
1053
+ }
1054
+ return Promise.resolve(null);
1055
+ }
1056
+ return new Promise((resolve) => {
1057
+ let settled = false;
1058
+ let iframe = null;
1059
+ let timer = null;
1060
+ const finish = (result) => {
1061
+ if (settled) return;
1062
+ settled = true;
1063
+ if (timer !== null) window.clearTimeout(timer);
1064
+ window.removeEventListener("message", onMessage);
1065
+ if (iframe && iframe.parentNode) {
1066
+ try {
1067
+ iframe.parentNode.removeChild(iframe);
1068
+ } catch {
1069
+ }
1070
+ }
1071
+ resolve(result);
1072
+ };
1073
+ const sendGet = () => {
1074
+ try {
1075
+ iframe?.contentWindow?.postMessage({ type: "SM_CONSENT_GET" }, hubOrigin);
1076
+ } catch {
1077
+ }
1078
+ };
1079
+ const onMessage = (event) => {
1080
+ if (event.origin !== hubOrigin) return;
1081
+ const data = event.data;
1082
+ if (!data || typeof data !== "object") return;
1083
+ if (data.type === "SM_CONSENT_STATUS") {
1084
+ const status = data.status === "accepted" || data.status === "rejected" ? data.status : null;
1085
+ finish(status);
1086
+ } else if (data.type === "SM_CONSENT_BRIDGE_READY") {
1087
+ sendGet();
1088
+ }
1089
+ };
1090
+ window.addEventListener("message", onMessage);
1091
+ timer = window.setTimeout(() => {
1092
+ finish(null);
1093
+ }, timeoutMs);
1094
+ try {
1095
+ iframe = document.createElement("iframe");
1096
+ iframe.src = hubUrl;
1097
+ iframe.style.position = "absolute";
1098
+ iframe.style.width = "0";
1099
+ iframe.style.height = "0";
1100
+ iframe.style.border = "0";
1101
+ iframe.style.display = "none";
1102
+ iframe.style.visibility = "hidden";
1103
+ iframe.setAttribute("aria-hidden", "true");
1104
+ iframe.setAttribute("tabindex", "-1");
1105
+ iframe.onload = () => {
1106
+ sendGet();
1107
+ };
1108
+ iframe.onerror = () => {
1109
+ finish(null);
1110
+ };
1111
+ const target = document.body || document.documentElement;
1112
+ target.appendChild(iframe);
1113
+ } catch {
1114
+ finish(null);
1115
+ }
1116
+ });
1117
+ } catch {
1118
+ return Promise.resolve(null);
1119
+ }
1120
+ }
1121
+ function setNetworkConsentHub(status, hubUrl = DEFAULT_CONSENT_HUB_URL) {
1122
+ if (typeof window === "undefined") return;
1123
+ try {
1124
+ const hubOrigin = new URL(hubUrl).origin;
1125
+ if (window.location.origin === hubOrigin) {
1126
+ try {
1127
+ if (status) {
1128
+ window.localStorage?.setItem(NETWORK_CONSENT_STORAGE_KEY, status);
1129
+ } else {
1130
+ window.localStorage?.removeItem(NETWORK_CONSENT_STORAGE_KEY);
1131
+ }
1132
+ } catch {
1133
+ }
1134
+ return;
1135
+ }
1136
+ let iframe = null;
1137
+ let timer = null;
1138
+ const cleanup = () => {
1139
+ if (timer !== null) window.clearTimeout(timer);
1140
+ window.removeEventListener("message", onMessage);
1141
+ if (iframe && iframe.parentNode) {
1142
+ try {
1143
+ iframe.parentNode.removeChild(iframe);
1144
+ } catch {
1145
+ }
1146
+ }
1147
+ };
1148
+ const sendSet = () => {
1149
+ try {
1150
+ iframe?.contentWindow?.postMessage({ type: "SM_CONSENT_SET", status }, hubOrigin);
1151
+ } catch {
1152
+ }
1153
+ };
1154
+ const onMessage = (event) => {
1155
+ if (event.origin !== hubOrigin) return;
1156
+ const data = event.data;
1157
+ if (!data || typeof data !== "object") return;
1158
+ if (data.type === "SM_CONSENT_SAVED") {
1159
+ cleanup();
1160
+ } else if (data.type === "SM_CONSENT_BRIDGE_READY") {
1161
+ sendSet();
1162
+ }
1163
+ };
1164
+ window.addEventListener("message", onMessage);
1165
+ timer = window.setTimeout(cleanup, 2500);
1166
+ try {
1167
+ iframe = document.createElement("iframe");
1168
+ iframe.src = hubUrl;
1169
+ iframe.style.position = "absolute";
1170
+ iframe.style.width = "0";
1171
+ iframe.style.height = "0";
1172
+ iframe.style.border = "0";
1173
+ iframe.style.display = "none";
1174
+ iframe.style.visibility = "hidden";
1175
+ iframe.setAttribute("aria-hidden", "true");
1176
+ iframe.setAttribute("tabindex", "-1");
1177
+ iframe.onload = () => {
1178
+ sendSet();
1179
+ };
1180
+ iframe.onerror = cleanup;
1181
+ const target = document.body || document.documentElement;
1182
+ target.appendChild(iframe);
1183
+ } catch {
1184
+ cleanup();
1185
+ }
1186
+ } catch {
1187
+ }
1188
+ }
1040
1189
  function hasConsented() {
1041
1190
  return getCookieConsent() !== null;
1042
1191
  }
@@ -1084,6 +1233,8 @@ function setCookieConsent(preferences, source = "settings_save") {
1084
1233
  window.localStorage?.setItem(COOKIE_CONSENT_KEY, serialized);
1085
1234
  } catch {
1086
1235
  }
1236
+ const networkStatus = mergedPreferences.performance || mergedPreferences.advertising ? "accepted" : "rejected";
1237
+ setNetworkConsentHub(networkStatus);
1087
1238
  window.dispatchEvent(new CustomEvent(COOKIE_CONSENT_EVENT, { detail: record }));
1088
1239
  }
1089
1240
  return record;
@@ -1105,6 +1256,7 @@ function clearCookieConsent() {
1105
1256
  window.localStorage?.removeItem(COOKIE_CONSENT_KEY);
1106
1257
  } catch {
1107
1258
  }
1259
+ setNetworkConsentHub(null);
1108
1260
  window.dispatchEvent(new CustomEvent(COOKIE_CONSENT_EVENT, { detail: null }));
1109
1261
  }
1110
1262
  }
@@ -1143,7 +1295,8 @@ function CookieConsentBanner({
1143
1295
  publicationSlug,
1144
1296
  complianceEndpoint = "/api/compliance/consent",
1145
1297
  countryCode,
1146
- forceShow = false
1298
+ forceShow = false,
1299
+ consentHubUrl = DEFAULT_CONSENT_HUB_URL
1147
1300
  }) {
1148
1301
  const [mounted, setMounted] = react.useState(false);
1149
1302
  const [visible, setVisible] = react.useState(false);
@@ -1159,11 +1312,32 @@ function CookieConsentBanner({
1159
1312
  }
1160
1313
  if (!forceShow && !isGeoConsentRequired(countryCode)) {
1161
1314
  setVisible(false);
1315
+ void queryNetworkConsentHub(consentHubUrl, 1200).then((networkStatus) => {
1316
+ if (networkStatus === "accepted") {
1317
+ acceptAllCookies();
1318
+ } else if (networkStatus === "rejected") {
1319
+ rejectOptionalCookies();
1320
+ }
1321
+ });
1162
1322
  return;
1163
1323
  }
1164
- const timer = window.setTimeout(() => setVisible(true), 300);
1165
- return () => window.clearTimeout(timer);
1166
- }, [countryCode, forceShow]);
1324
+ let cancelled = false;
1325
+ void queryNetworkConsentHub(consentHubUrl, 1e3).then((networkStatus) => {
1326
+ if (cancelled) return;
1327
+ if (networkStatus === "accepted") {
1328
+ acceptAllCookies();
1329
+ setVisible(false);
1330
+ } else if (networkStatus === "rejected") {
1331
+ rejectOptionalCookies();
1332
+ setVisible(false);
1333
+ } else {
1334
+ setVisible(true);
1335
+ }
1336
+ });
1337
+ return () => {
1338
+ cancelled = true;
1339
+ };
1340
+ }, [countryCode, forceShow, consentHubUrl]);
1167
1341
  react.useEffect(() => {
1168
1342
  const onConsentChange = () => {
1169
1343
  if (hasConsented()) {
@@ -1179,12 +1353,14 @@ function CookieConsentBanner({
1179
1353
  setVisible(false);
1180
1354
  void recordConsentToCompliance(record, {
1181
1355
  endpoint: complianceEndpoint});
1356
+ setNetworkConsentHub("accepted", consentHubUrl);
1182
1357
  };
1183
1358
  const handleReject = () => {
1184
1359
  const record = rejectOptionalCookies();
1185
1360
  setVisible(false);
1186
1361
  void recordConsentToCompliance(record, {
1187
1362
  endpoint: complianceEndpoint});
1363
+ setNetworkConsentHub("rejected", consentHubUrl);
1188
1364
  };
1189
1365
  const defaultText = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1190
1366
  "We use cookies and device data to analyze performance, support local sponsors, and remember your reading preferences across our news network. View",
@@ -1769,6 +1945,7 @@ exports.COOKIE_CONSENT_KEY = COOKIE_CONSENT_KEY;
1769
1945
  exports.COOKIE_CONSENT_MAX_AGE_SECONDS = COOKIE_CONSENT_MAX_AGE_SECONDS;
1770
1946
  exports.CookieConsentBanner = CookieConsentBanner;
1771
1947
  exports.CookieSettingsView = CookieSettingsView;
1948
+ exports.DEFAULT_CONSENT_HUB_URL = DEFAULT_CONSENT_HUB_URL;
1772
1949
  exports.DEFAULT_PREFERENCES_ACCEPTED = DEFAULT_PREFERENCES_ACCEPTED;
1773
1950
  exports.DEFAULT_PREFERENCES_REJECTED = DEFAULT_PREFERENCES_REJECTED;
1774
1951
  exports.EU_EEA_UK_COUNTRIES = EU_EEA_UK_COUNTRIES;
@@ -1777,6 +1954,7 @@ exports.FEATURE_NAMES = FEATURE_NAMES;
1777
1954
  exports.JOB_EMPLOYMENT_TYPES = JOB_EMPLOYMENT_TYPES;
1778
1955
  exports.LAYOUT_COOKIE = LAYOUT_COOKIE;
1779
1956
  exports.MEET_ACTIVITIES = MEET_ACTIVITIES;
1957
+ exports.NETWORK_CONSENT_STORAGE_KEY = NETWORK_CONSENT_STORAGE_KEY;
1780
1958
  exports.NEWS_CACHE = NEWS_CACHE;
1781
1959
  exports.NewsError = NewsError;
1782
1960
  exports.SESSION_IDLE_MS = SESSION_IDLE_MS;
@@ -1852,6 +2030,7 @@ exports.publicationFromSnapshot = publicationFromSnapshot;
1852
2030
  exports.publicationJsonLd = publicationJsonLd;
1853
2031
  exports.publicationMeta = publicationMeta;
1854
2032
  exports.publicationRecord = publicationRecord;
2033
+ exports.queryNetworkConsentHub = queryNetworkConsentHub;
1855
2034
  exports.recordConsentToCompliance = recordConsentToCompliance;
1856
2035
  exports.referralCode = referralCode;
1857
2036
  exports.rejectOptionalCookies = rejectOptionalCookies;
@@ -1865,6 +2044,7 @@ exports.sectionDefinition = sectionDefinition;
1865
2044
  exports.sectionId = sectionId;
1866
2045
  exports.sectionPath = sectionPath;
1867
2046
  exports.setCookieConsent = setCookieConsent;
2047
+ exports.setNetworkConsentHub = setNetworkConsentHub;
1868
2048
  exports.setTheme = setTheme;
1869
2049
  exports.shortDeck = shortDeck;
1870
2050
  exports.shortText = shortText;
package/dist/index.d.cts CHANGED
@@ -272,6 +272,8 @@ declare const COOKIE_CONSENT_KEY = "sm_cookie_consent_v1";
272
272
  declare const COOKIE_CONSENT_BACKUP_KEY = "napsite_cookie_consent_v1";
273
273
  declare const COOKIE_CONSENT_EVENT = "scalemule-cookie-consent-change";
274
274
  declare const COOKIE_CONSENT_MAX_AGE_SECONDS: number;
275
+ declare const DEFAULT_CONSENT_HUB_URL = "https://bayareachronicle.com/consent-bridge.html";
276
+ declare const NETWORK_CONSENT_STORAGE_KEY = "sm_network_consent_status";
275
277
  declare const DEFAULT_PREFERENCES_REJECTED: CookiePreferences;
276
278
  declare const DEFAULT_PREFERENCES_ACCEPTED: CookiePreferences;
277
279
  declare const COOKIE_CATEGORIES: CookieCategoryDefinition[];
@@ -302,6 +304,15 @@ declare function checkUrlConsentBridge(): boolean;
302
304
  * so sister publications can adopt the user's choice without requiring a new banner prompt.
303
305
  */
304
306
  declare function decorateNetworkUrl(targetUrl: string): string;
307
+ /**
308
+ * Queries the central network iframe hub to retrieve the reader's cross-domain consent choice.
309
+ * If running on the hub origin directly, reads from local storage without an iframe.
310
+ */
311
+ declare function queryNetworkConsentHub(hubUrl?: string, timeoutMs?: number): Promise<"accepted" | "rejected" | null>;
312
+ /**
313
+ * Propagates a consent decision to the central network iframe hub so all sister publications adopt it.
314
+ */
315
+ declare function setNetworkConsentHub(status: "accepted" | "rejected" | null, hubUrl?: string): void;
305
316
  /**
306
317
  * Check if the user has already provided an explicit consent decision.
307
318
  */
@@ -378,4 +389,4 @@ declare function subscribeTheme(listener: () => void): () => void;
378
389
  */
379
390
  declare function themeInitScript(): string;
380
391
 
381
- export { ANALYTICS_COOKIE, ANALYTICS_VERSION, type Attribution, BROADSHEET_THEME, COOKIE_CATEGORIES, COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, type CookieCategory, type CookieCategoryDefinition, type CookieConsentRecord, type CookieDisclosure, type CookiePreferences, CouponOffer, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, NEWS_CACHE, NearbyUpdate, NewsArticle, NewsError, NewsItem, NewsPublication, PublicationInput, PublicationTheme, SESSION_IDLE_MS, THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, type ThemeMode, UTM_FIELDS, UUID, acceptAllCookies, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, checkUrlConsentBridge, clearCookieConsent, clearTheme, composeEdition, decorateNetworkUrl, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getCookieConsent, getStoredTheme, getSystemTheme, hasConsented, inventoryCacheOptions, isCategoryAllowed, isGeoConsentRequired, llmsText, matchesStoryTag, nearbyUpdates, newsArticleJsonLd, normalizedText, publicHttps, publicUrl, publicationJsonLd, publicationMeta, recordConsentToCompliance, referralCode, rejectOptionalCookies, resolveCoupon, resolveEffectiveTheme, resolveLayout, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setCookieConsent, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
392
+ export { ANALYTICS_COOKIE, ANALYTICS_VERSION, type Attribution, BROADSHEET_THEME, COOKIE_CATEGORIES, COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, type CookieCategory, type CookieCategoryDefinition, type CookieConsentRecord, type CookieDisclosure, type CookiePreferences, CouponOffer, DEFAULT_CONSENT_HUB_URL, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, NETWORK_CONSENT_STORAGE_KEY, NEWS_CACHE, NearbyUpdate, NewsArticle, NewsError, NewsItem, NewsPublication, PublicationInput, PublicationTheme, SESSION_IDLE_MS, THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, type ThemeMode, UTM_FIELDS, UUID, acceptAllCookies, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, checkUrlConsentBridge, clearCookieConsent, clearTheme, composeEdition, decorateNetworkUrl, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getCookieConsent, getStoredTheme, getSystemTheme, hasConsented, inventoryCacheOptions, isCategoryAllowed, isGeoConsentRequired, llmsText, matchesStoryTag, nearbyUpdates, newsArticleJsonLd, normalizedText, publicHttps, publicUrl, publicationJsonLd, publicationMeta, queryNetworkConsentHub, recordConsentToCompliance, referralCode, rejectOptionalCookies, resolveCoupon, resolveEffectiveTheme, resolveLayout, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setCookieConsent, setNetworkConsentHub, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
package/dist/index.d.ts CHANGED
@@ -272,6 +272,8 @@ declare const COOKIE_CONSENT_KEY = "sm_cookie_consent_v1";
272
272
  declare const COOKIE_CONSENT_BACKUP_KEY = "napsite_cookie_consent_v1";
273
273
  declare const COOKIE_CONSENT_EVENT = "scalemule-cookie-consent-change";
274
274
  declare const COOKIE_CONSENT_MAX_AGE_SECONDS: number;
275
+ declare const DEFAULT_CONSENT_HUB_URL = "https://bayareachronicle.com/consent-bridge.html";
276
+ declare const NETWORK_CONSENT_STORAGE_KEY = "sm_network_consent_status";
275
277
  declare const DEFAULT_PREFERENCES_REJECTED: CookiePreferences;
276
278
  declare const DEFAULT_PREFERENCES_ACCEPTED: CookiePreferences;
277
279
  declare const COOKIE_CATEGORIES: CookieCategoryDefinition[];
@@ -302,6 +304,15 @@ declare function checkUrlConsentBridge(): boolean;
302
304
  * so sister publications can adopt the user's choice without requiring a new banner prompt.
303
305
  */
304
306
  declare function decorateNetworkUrl(targetUrl: string): string;
307
+ /**
308
+ * Queries the central network iframe hub to retrieve the reader's cross-domain consent choice.
309
+ * If running on the hub origin directly, reads from local storage without an iframe.
310
+ */
311
+ declare function queryNetworkConsentHub(hubUrl?: string, timeoutMs?: number): Promise<"accepted" | "rejected" | null>;
312
+ /**
313
+ * Propagates a consent decision to the central network iframe hub so all sister publications adopt it.
314
+ */
315
+ declare function setNetworkConsentHub(status: "accepted" | "rejected" | null, hubUrl?: string): void;
305
316
  /**
306
317
  * Check if the user has already provided an explicit consent decision.
307
318
  */
@@ -378,4 +389,4 @@ declare function subscribeTheme(listener: () => void): () => void;
378
389
  */
379
390
  declare function themeInitScript(): string;
380
391
 
381
- export { ANALYTICS_COOKIE, ANALYTICS_VERSION, type Attribution, BROADSHEET_THEME, COOKIE_CATEGORIES, COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, type CookieCategory, type CookieCategoryDefinition, type CookieConsentRecord, type CookieDisclosure, type CookiePreferences, CouponOffer, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, NEWS_CACHE, NearbyUpdate, NewsArticle, NewsError, NewsItem, NewsPublication, PublicationInput, PublicationTheme, SESSION_IDLE_MS, THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, type ThemeMode, UTM_FIELDS, UUID, acceptAllCookies, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, checkUrlConsentBridge, clearCookieConsent, clearTheme, composeEdition, decorateNetworkUrl, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getCookieConsent, getStoredTheme, getSystemTheme, hasConsented, inventoryCacheOptions, isCategoryAllowed, isGeoConsentRequired, llmsText, matchesStoryTag, nearbyUpdates, newsArticleJsonLd, normalizedText, publicHttps, publicUrl, publicationJsonLd, publicationMeta, recordConsentToCompliance, referralCode, rejectOptionalCookies, resolveCoupon, resolveEffectiveTheme, resolveLayout, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setCookieConsent, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
392
+ export { ANALYTICS_COOKIE, ANALYTICS_VERSION, type Attribution, BROADSHEET_THEME, COOKIE_CATEGORIES, COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, type CookieCategory, type CookieCategoryDefinition, type CookieConsentRecord, type CookieDisclosure, type CookiePreferences, CouponOffer, DEFAULT_CONSENT_HUB_URL, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, NETWORK_CONSENT_STORAGE_KEY, NEWS_CACHE, NearbyUpdate, NewsArticle, NewsError, NewsItem, NewsPublication, PublicationInput, PublicationTheme, SESSION_IDLE_MS, THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, type ThemeMode, UTM_FIELDS, UUID, acceptAllCookies, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, checkUrlConsentBridge, clearCookieConsent, clearTheme, composeEdition, decorateNetworkUrl, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getCookieConsent, getStoredTheme, getSystemTheme, hasConsented, inventoryCacheOptions, isCategoryAllowed, isGeoConsentRequired, llmsText, matchesStoryTag, nearbyUpdates, newsArticleJsonLd, normalizedText, publicHttps, publicUrl, publicationJsonLd, publicationMeta, queryNetworkConsentHub, recordConsentToCompliance, referralCode, rejectOptionalCookies, resolveCoupon, resolveEffectiveTheme, resolveLayout, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setCookieConsent, setNetworkConsentHub, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
package/dist/index.js CHANGED
@@ -3,9 +3,9 @@ import { definePublication } from './chunk-C7JTEHTH.js';
3
3
  export { BROADSHEET_THEME, FEATURE_NAMES, LAYOUT_COOKIE, acceptRemoteRecord, acceptSnapshot, definePublication, featureEnabled, parseSnapshot, publicationFromSnapshot, publicationRecord, resolveLayout, snapshotFromRecord, syncPublication } from './chunk-C7JTEHTH.js';
4
4
  export { CLASSIFIED_CATEGORIES, JOB_EMPLOYMENT_TYPES, categoryLabel, classifiedPath, classifiedSearchPath, clipChars, dealDollars, dealGoPath, dealsFeedPath, employmentLabel, isClassifiedCategory, isEmploymentType, jobEmployerBody, jobOpeningBody, jobPostingBody, prepareClassified, prepareJobPost, publicJobPath, publicJobsPath } from './chunk-C7ZPLH2K.js';
5
5
  export { MEET_ACTIVITIES, activityLabel, canHostMeetup, isAdult, prepareMeetup, screenMessage } from './chunk-GB36YM56.js';
6
- export { CookieConsentBanner } from './chunk-EKQXS63J.js';
7
- export { CookieSettingsView } from './chunk-ZSA6YQBV.js';
8
- export { COOKIE_CATEGORIES, COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, acceptAllCookies, checkUrlConsentBridge, clearCookieConsent, decorateNetworkUrl, getCookieConsent, hasConsented, isCategoryAllowed, isGeoConsentRequired, recordConsentToCompliance, rejectOptionalCookies, setCookieConsent } from './chunk-CWZWU4HE.js';
6
+ export { CookieConsentBanner } from './chunk-5MHPE77S.js';
7
+ export { CookieSettingsView } from './chunk-FUUL2PSF.js';
8
+ export { COOKIE_CATEGORIES, 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, recordConsentToCompliance, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from './chunk-L5OE6DND.js';
9
9
 
10
10
  // src/preset.ts
11
11
  var walnutCreekTimes = definePublication({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalemule/news-publication",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Shared server framework for ScaleMule local news publications. Walnut Creek Times is the broadsheet default; each paper supplies its own identity and feature flags.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",