@scalemule/news-publication 0.0.20 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +53 -0
- package/dist/index.d.cts +44 -1
- package/dist/index.d.ts +44 -1
- package/dist/index.js +53 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1836,6 +1836,57 @@ function readerSources(input) {
|
|
|
1836
1836
|
return output;
|
|
1837
1837
|
}
|
|
1838
1838
|
|
|
1839
|
+
// src/listening.ts
|
|
1840
|
+
function publicationListeningTrack(article, publicationId, publicationName, origin) {
|
|
1841
|
+
const articleUrl2 = new URL(`/news/${encodeURIComponent(article.slug)}`, origin).href;
|
|
1842
|
+
let storyId = articleUrl2;
|
|
1843
|
+
if (article.canonical_url) {
|
|
1844
|
+
try {
|
|
1845
|
+
const canonical = new URL(article.canonical_url);
|
|
1846
|
+
if (canonical.protocol === "https:" && !canonical.username && !canonical.password && /^\/news\/[^/]+\/?$/.test(canonical.pathname) && localPublications.some((item) => new URL(item.url).hostname === canonical.hostname.replace(/^www\./, ""))) {
|
|
1847
|
+
canonical.search = "";
|
|
1848
|
+
canonical.hash = "";
|
|
1849
|
+
canonical.hostname = canonical.hostname.replace(/^www\./, "");
|
|
1850
|
+
canonical.pathname = canonical.pathname.replace(/\/$/, "");
|
|
1851
|
+
storyId = canonical.href;
|
|
1852
|
+
}
|
|
1853
|
+
} catch {
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
const revision = article.editorial?.modified_at;
|
|
1857
|
+
return {
|
|
1858
|
+
id: article.id,
|
|
1859
|
+
publicationId,
|
|
1860
|
+
publicationName,
|
|
1861
|
+
title: article.title,
|
|
1862
|
+
articleUrl: articleUrl2,
|
|
1863
|
+
storyId,
|
|
1864
|
+
...revision && Number.isFinite(Date.parse(revision)) ? { revision } : {},
|
|
1865
|
+
...article.audio?.duration_ms && article.audio.duration_ms > 0 ? { durationSeconds: article.audio.duration_ms / 1e3 } : {},
|
|
1866
|
+
...article.section ? { section: article.section } : {},
|
|
1867
|
+
...article.published_at ? { publishedAt: article.published_at } : {}
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
async function publicationListeningCandidates(items, read, publicationId, publicationName, origin) {
|
|
1871
|
+
const output = [];
|
|
1872
|
+
const recent = items.filter((item) => !item.editorial?.duplicate_url).slice(0, 30);
|
|
1873
|
+
let failures = 0;
|
|
1874
|
+
for (let i = 0; i < recent.length; i += 4) {
|
|
1875
|
+
const batch = await Promise.allSettled(recent.slice(i, i + 4).map((item) => read(item.slug)));
|
|
1876
|
+
for (const result of batch) {
|
|
1877
|
+
if (result.status === "rejected") {
|
|
1878
|
+
failures++;
|
|
1879
|
+
continue;
|
|
1880
|
+
}
|
|
1881
|
+
const article = result.value;
|
|
1882
|
+
if (!article.editorial?.duplicate_url && article.audio?.url && article.audio.duration_ms && article.audio.duration_ms > 0)
|
|
1883
|
+
output.push(publicationListeningTrack(article, publicationId, publicationName, origin));
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
if (!output.length && failures) throw new Error("Audio inventory could not be loaded");
|
|
1887
|
+
return output.sort((a, b) => (b.publishedAt ?? "").localeCompare(a.publishedAt ?? ""));
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1839
1890
|
Object.defineProperty(exports, "COOKIE_CONSENT_BACKUP_KEY", {
|
|
1840
1891
|
enumerable: true,
|
|
1841
1892
|
get: function () { return compliance.COOKIE_CONSENT_BACKUP_KEY; }
|
|
@@ -2007,6 +2058,8 @@ exports.publicJobsPath = publicJobsPath;
|
|
|
2007
2058
|
exports.publicUrl = publicUrl;
|
|
2008
2059
|
exports.publicationFromSnapshot = publicationFromSnapshot;
|
|
2009
2060
|
exports.publicationJsonLd = publicationJsonLd;
|
|
2061
|
+
exports.publicationListeningCandidates = publicationListeningCandidates;
|
|
2062
|
+
exports.publicationListeningTrack = publicationListeningTrack;
|
|
2010
2063
|
exports.publicationMeta = publicationMeta;
|
|
2011
2064
|
exports.publicationRecord = publicationRecord;
|
|
2012
2065
|
exports.readerSources = readerSources;
|
package/dist/index.d.cts
CHANGED
|
@@ -311,4 +311,47 @@ declare function readerSources(input: unknown): {
|
|
|
311
311
|
publisher?: string;
|
|
312
312
|
}[];
|
|
313
313
|
|
|
314
|
-
|
|
314
|
+
interface ListeningArticle {
|
|
315
|
+
id: string;
|
|
316
|
+
slug: string;
|
|
317
|
+
title: string;
|
|
318
|
+
canonical_url?: string | null;
|
|
319
|
+
section?: string | null;
|
|
320
|
+
published_at?: string;
|
|
321
|
+
editorial?: {
|
|
322
|
+
duplicate_url?: string;
|
|
323
|
+
modified_at?: string;
|
|
324
|
+
} | null;
|
|
325
|
+
audio?: {
|
|
326
|
+
url?: string | null;
|
|
327
|
+
duration_ms?: number | null;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/** Public metadata only. Never cache signed recording URLs in reader history. */
|
|
331
|
+
declare function publicationListeningTrack(article: ListeningArticle, publicationId: string, publicationName: string, origin: string): {
|
|
332
|
+
publishedAt?: string | undefined;
|
|
333
|
+
section?: string | undefined;
|
|
334
|
+
durationSeconds?: number | undefined;
|
|
335
|
+
revision?: string | undefined;
|
|
336
|
+
id: string;
|
|
337
|
+
publicationId: string;
|
|
338
|
+
publicationName: string;
|
|
339
|
+
title: string;
|
|
340
|
+
articleUrl: string;
|
|
341
|
+
storyId: string;
|
|
342
|
+
};
|
|
343
|
+
/** Bounded public read fan-out, initiated only when a reader requests a catch-up queue. */
|
|
344
|
+
declare function publicationListeningCandidates<T extends ListeningArticle>(items: T[], read: (slug: string) => Promise<ListeningArticle>, publicationId: string, publicationName: string, origin: string): Promise<{
|
|
345
|
+
publishedAt?: string | undefined;
|
|
346
|
+
section?: string | undefined;
|
|
347
|
+
durationSeconds?: number | undefined;
|
|
348
|
+
revision?: string | undefined;
|
|
349
|
+
id: string;
|
|
350
|
+
publicationId: string;
|
|
351
|
+
publicationName: string;
|
|
352
|
+
title: string;
|
|
353
|
+
articleUrl: string;
|
|
354
|
+
storyId: string;
|
|
355
|
+
}[]>;
|
|
356
|
+
|
|
357
|
+
export { ANALYTICS_COOKIE, ANALYTICS_VERSION, ArticleProvenance, type Attribution, BROADSHEET_THEME, COOKIE_CATEGORIES, CouponOffer, EDITORIAL_SECTION_ORDER, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, type ListeningArticle, 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, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, clearTheme, composeEdition, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getStoredTheme, getSystemTheme, inventoryCacheOptions, llmsText, matchesStoryTag, nearbyUpdates, newsArticleJsonLd, normalizedText, orderedSections, publicHttps, publicUrl, publicationJsonLd, publicationListeningCandidates, publicationListeningTrack, publicationMeta, readerSources, recordConsentToCompliance, referralCode, resolveCoupon, resolveEffectiveTheme, resolveLayout, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
|
package/dist/index.d.ts
CHANGED
|
@@ -311,4 +311,47 @@ declare function readerSources(input: unknown): {
|
|
|
311
311
|
publisher?: string;
|
|
312
312
|
}[];
|
|
313
313
|
|
|
314
|
-
|
|
314
|
+
interface ListeningArticle {
|
|
315
|
+
id: string;
|
|
316
|
+
slug: string;
|
|
317
|
+
title: string;
|
|
318
|
+
canonical_url?: string | null;
|
|
319
|
+
section?: string | null;
|
|
320
|
+
published_at?: string;
|
|
321
|
+
editorial?: {
|
|
322
|
+
duplicate_url?: string;
|
|
323
|
+
modified_at?: string;
|
|
324
|
+
} | null;
|
|
325
|
+
audio?: {
|
|
326
|
+
url?: string | null;
|
|
327
|
+
duration_ms?: number | null;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/** Public metadata only. Never cache signed recording URLs in reader history. */
|
|
331
|
+
declare function publicationListeningTrack(article: ListeningArticle, publicationId: string, publicationName: string, origin: string): {
|
|
332
|
+
publishedAt?: string | undefined;
|
|
333
|
+
section?: string | undefined;
|
|
334
|
+
durationSeconds?: number | undefined;
|
|
335
|
+
revision?: string | undefined;
|
|
336
|
+
id: string;
|
|
337
|
+
publicationId: string;
|
|
338
|
+
publicationName: string;
|
|
339
|
+
title: string;
|
|
340
|
+
articleUrl: string;
|
|
341
|
+
storyId: string;
|
|
342
|
+
};
|
|
343
|
+
/** Bounded public read fan-out, initiated only when a reader requests a catch-up queue. */
|
|
344
|
+
declare function publicationListeningCandidates<T extends ListeningArticle>(items: T[], read: (slug: string) => Promise<ListeningArticle>, publicationId: string, publicationName: string, origin: string): Promise<{
|
|
345
|
+
publishedAt?: string | undefined;
|
|
346
|
+
section?: string | undefined;
|
|
347
|
+
durationSeconds?: number | undefined;
|
|
348
|
+
revision?: string | undefined;
|
|
349
|
+
id: string;
|
|
350
|
+
publicationId: string;
|
|
351
|
+
publicationName: string;
|
|
352
|
+
title: string;
|
|
353
|
+
articleUrl: string;
|
|
354
|
+
storyId: string;
|
|
355
|
+
}[]>;
|
|
356
|
+
|
|
357
|
+
export { ANALYTICS_COOKIE, ANALYTICS_VERSION, ArticleProvenance, type Attribution, BROADSHEET_THEME, COOKIE_CATEGORIES, CouponOffer, EDITORIAL_SECTION_ORDER, EVENTS, EditorialSection, type EffectiveTheme, FeatureName, HomepageSelection, LAYOUT_COOKIE, type ListeningArticle, 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, activeNearby, applyTheme, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, clearTheme, composeEdition, defaultRevalidateTargets, definePublication, displayHeadline, edgeCacheControl, editorialSections, featureEnabled, feedCacheKey, feedCacheOptions, filterNews, getStoredTheme, getSystemTheme, inventoryCacheOptions, llmsText, matchesStoryTag, nearbyUpdates, newsArticleJsonLd, normalizedText, orderedSections, publicHttps, publicUrl, publicationJsonLd, publicationListeningCandidates, publicationListeningTrack, publicationMeta, readerSources, recordConsentToCompliance, referralCode, resolveCoupon, resolveEffectiveTheme, resolveLayout, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { CLASSIFIED_CATEGORIES, JOB_EMPLOYMENT_TYPES, categoryLabel, classifiedP
|
|
|
6
6
|
export { MEET_ACTIVITIES, activityLabel, canHostMeetup, isAdult, prepareMeetup, screenMessage } from './chunk-GB36YM56.js';
|
|
7
7
|
export { CookieConsentBanner } from './chunk-HTMIFWNA.js';
|
|
8
8
|
export { CookieSettingsView } from './chunk-3MFKPHO3.js';
|
|
9
|
+
import { localPublications } from './chunk-2IYYEFLD.js';
|
|
9
10
|
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, communityPublications, decorateNetworkUrl, findPublicationByHost, findPublicationBySlug, getCookieConsent, getNetworkPublicationUrl, hasConsented, isCategoryAllowed, isGeoConsentRequired, listedPublications, localPublications, queryNetworkConsentHub, recordConsentToCompliance, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from './chunk-2IYYEFLD.js';
|
|
10
11
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
11
12
|
|
|
@@ -517,4 +518,55 @@ function readerSources(input) {
|
|
|
517
518
|
return output;
|
|
518
519
|
}
|
|
519
520
|
|
|
520
|
-
|
|
521
|
+
// src/listening.ts
|
|
522
|
+
function publicationListeningTrack(article, publicationId, publicationName, origin) {
|
|
523
|
+
const articleUrl2 = new URL(`/news/${encodeURIComponent(article.slug)}`, origin).href;
|
|
524
|
+
let storyId = articleUrl2;
|
|
525
|
+
if (article.canonical_url) {
|
|
526
|
+
try {
|
|
527
|
+
const canonical = new URL(article.canonical_url);
|
|
528
|
+
if (canonical.protocol === "https:" && !canonical.username && !canonical.password && /^\/news\/[^/]+\/?$/.test(canonical.pathname) && localPublications.some((item) => new URL(item.url).hostname === canonical.hostname.replace(/^www\./, ""))) {
|
|
529
|
+
canonical.search = "";
|
|
530
|
+
canonical.hash = "";
|
|
531
|
+
canonical.hostname = canonical.hostname.replace(/^www\./, "");
|
|
532
|
+
canonical.pathname = canonical.pathname.replace(/\/$/, "");
|
|
533
|
+
storyId = canonical.href;
|
|
534
|
+
}
|
|
535
|
+
} catch {
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
const revision = article.editorial?.modified_at;
|
|
539
|
+
return {
|
|
540
|
+
id: article.id,
|
|
541
|
+
publicationId,
|
|
542
|
+
publicationName,
|
|
543
|
+
title: article.title,
|
|
544
|
+
articleUrl: articleUrl2,
|
|
545
|
+
storyId,
|
|
546
|
+
...revision && Number.isFinite(Date.parse(revision)) ? { revision } : {},
|
|
547
|
+
...article.audio?.duration_ms && article.audio.duration_ms > 0 ? { durationSeconds: article.audio.duration_ms / 1e3 } : {},
|
|
548
|
+
...article.section ? { section: article.section } : {},
|
|
549
|
+
...article.published_at ? { publishedAt: article.published_at } : {}
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
async function publicationListeningCandidates(items, read, publicationId, publicationName, origin) {
|
|
553
|
+
const output = [];
|
|
554
|
+
const recent = items.filter((item) => !item.editorial?.duplicate_url).slice(0, 30);
|
|
555
|
+
let failures = 0;
|
|
556
|
+
for (let i = 0; i < recent.length; i += 4) {
|
|
557
|
+
const batch = await Promise.allSettled(recent.slice(i, i + 4).map((item) => read(item.slug)));
|
|
558
|
+
for (const result of batch) {
|
|
559
|
+
if (result.status === "rejected") {
|
|
560
|
+
failures++;
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
const article = result.value;
|
|
564
|
+
if (!article.editorial?.duplicate_url && article.audio?.url && article.audio.duration_ms && article.audio.duration_ms > 0)
|
|
565
|
+
output.push(publicationListeningTrack(article, publicationId, publicationName, origin));
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (!output.length && failures) throw new Error("Audio inventory could not be loaded");
|
|
569
|
+
return output.sort((a, b) => (b.publishedAt ?? "").localeCompare(a.publishedAt ?? ""));
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export { ANALYTICS_COOKIE, ANALYTICS_VERSION, ArticleProvenance, EDITORIAL_SECTION_ORDER, EVENTS, NEWS_CACHE, NewsError, SESSION_IDLE_MS, UTM_FIELDS, UUID, activeNearby, articleCacheKey, articleCacheOptions, articleMeta, articleUrl, attribution, briefSummary, composeEdition, defaultRevalidateTargets, displayHeadline, edgeCacheControl, editorialSections, feedCacheKey, feedCacheOptions, filterNews, inventoryCacheOptions, llmsText, matchesStoryTag, nearbyUpdates, newsArticleJsonLd, normalizedText, orderedSections, publicHttps, publicUrl, publicationJsonLd, publicationListeningCandidates, publicationListeningTrack, publicationMeta, readerSources, referralCode, resolveCoupon, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/news-publication",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
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",
|