@scalemule/news-publication 0.0.20 → 0.0.22

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.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { b as PublicationTheme, c as PublicationInput, N as NewsPublication, F as FeatureName, H as HomepageSelection, d as NearbyUpdate, e as NewsItem, E as EditorialSection, f as NewsArticle, C as CouponOffer } from './snapshot-OZFP3-Up.js';
2
- export { A as ArticleCitation, g as CategoryRef, h as CouponSettings, i as CoverImageMetadata, j as FEATURE_NAMES, k as FeatureFlags, l as NewsFeed, m as NewsLayoutId, n as PublicationModules, o as PublicationRecord, P as PublicationSnapshot, R as ReferralSettings, S as SnapshotHooks, p as StoryDisplay, q as SyncSource, a as SyncedPublication, T as TagRef, r as acceptRemoteRecord, s as acceptSnapshot, t as parseSnapshot, u as publicationFromSnapshot, v as publicationRecord, w as snapshotFromRecord, x as syncPublication } from './snapshot-OZFP3-Up.js';
1
+ import { a as PublicationTheme, P as PublicationInput, N as NewsPublication, F as FeatureName, H as HomepageSelection, b as NearbyUpdate, c as NewsItem, E as EditorialSection, d as NewsArticle, C as CouponOffer } from './types-DFDCZHbS.js';
2
+ export { A as ArticleCitation, e as CardType, f as CategoryRef, g as CouponSettings, h as CoverImageMetadata, i as FEATURE_NAMES, j as FeatureFlags, k as NewsFeed, l as NewsLayoutId, m as PublicationModules, R as ReferralSettings, S as StoryDisplay, T as TagRef, V as VerifiedCard, n as VerifiedCardAction, o as VerifiedCardFact, p as VerifiedCardImage } from './types-DFDCZHbS.js';
3
3
  export { M as MEET_ACTIVITIES, b as MeetActivity, c as MeetupInput, a as PreparedMeetup, P as PublicPlace, d as activityLabel, e as canHostMeetup, i as isAdult, p as prepareMeetup, s as screenMessage } from './meet-RWmfj3I3.js';
4
4
  export { b as CLASSIFIED_CATEGORIES, c as ClassifiedCategory, C as ClassifiedListing, E as EmploymentType, J as JOB_EMPLOYMENT_TYPES, d as PreparedClassified, e as PreparedJob, P as PublicDeal, f as PublicDealOffer, a as PublicJob, g as categoryLabel, h as classifiedPath, i as classifiedSearchPath, j as clipChars, k as dealDollars, l as dealGoPath, m as dealsFeedPath, n as employmentLabel, o as isClassifiedCategory, p as isEmploymentType, q as jobEmployerBody, r as jobOpeningBody, s as jobPostingBody, t as prepareClassified, u as prepareJobPost, v as publicJobPath, w as publicJobsPath } from './marketplace-29i5w4LS.js';
5
+ export { b as PublicationRecord, P as PublicationSnapshot, S as SnapshotHooks, c as SyncSource, a as SyncedPublication, d as acceptRemoteRecord, e as acceptSnapshot, p as parseSnapshot, f as publicationFromSnapshot, g as publicationRecord, s as snapshotFromRecord, h as syncPublication } from './snapshot-CxuyMF39.js';
5
6
  import { CookieCategoryDefinition, CookieConsentRecord } from '@scalemule/compliance';
6
7
  export { COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, CookieCategory, CookieCategoryDefinition, CookieConsentRecord, CookieDisclosure, CookiePreferences, DEFAULT_CONSENT_HUB_URL, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EU_EEA_UK_COUNTRIES, NETWORK_CONSENT_STORAGE_KEY, acceptAllCookies, checkUrlConsentBridge, clearCookieConsent, decorateNetworkUrl, getCookieConsent, hasConsented, isCategoryAllowed, isGeoConsentRequired, queryNetworkConsentHub, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from '@scalemule/compliance';
7
8
  export { CookieConsentBanner, CookieConsentBannerProps } from './cookie-consent-banner.js';
@@ -10,6 +11,7 @@ export { ThemeToggle, ThemeToggleProps } from './theme-toggle.js';
10
11
  export { PublicationNetworkItem, communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications } from './network.js';
11
12
  export { LocalNetworkBar, LocalNetworkBarProps } from './network-bar.js';
12
13
  import * as react from 'react';
14
+ export { VerifiedCardComponent, VerifiedCardSection, getArticleCards, isSafeActionUrl } from './verified-card.js';
13
15
 
14
16
  /** Walnut Creek Times broadsheet colors. A paper overrides only what it changes. */
15
17
  declare const BROADSHEET_THEME: PublicationTheme;
@@ -311,4 +313,47 @@ declare function readerSources(input: unknown): {
311
313
  publisher?: string;
312
314
  }[];
313
315
 
314
- export { ANALYTICS_COOKIE, ANALYTICS_VERSION, ArticleProvenance, type Attribution, BROADSHEET_THEME, COOKIE_CATEGORIES, CouponOffer, EDITORIAL_SECTION_ORDER, 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, 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, publicationMeta, readerSources, recordConsentToCompliance, referralCode, resolveCoupon, resolveEffectiveTheme, resolveLayout, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, setTheme, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, subscribeTheme, themeInitScript, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
316
+ interface ListeningArticle {
317
+ id: string;
318
+ slug: string;
319
+ title: string;
320
+ canonical_url?: string | null;
321
+ section?: string | null;
322
+ published_at?: string;
323
+ editorial?: {
324
+ duplicate_url?: string;
325
+ modified_at?: string;
326
+ } | null;
327
+ audio?: {
328
+ url?: string | null;
329
+ duration_ms?: number | null;
330
+ };
331
+ }
332
+ /** Public metadata only. Never cache signed recording URLs in reader history. */
333
+ declare function publicationListeningTrack(article: ListeningArticle, publicationId: string, publicationName: string, origin: string): {
334
+ publishedAt?: string | undefined;
335
+ section?: string | undefined;
336
+ durationSeconds?: number | undefined;
337
+ revision?: string | undefined;
338
+ id: string;
339
+ publicationId: string;
340
+ publicationName: string;
341
+ title: string;
342
+ articleUrl: string;
343
+ storyId: string;
344
+ };
345
+ /** Bounded public read fan-out, initiated only when a reader requests a catch-up queue. */
346
+ declare function publicationListeningCandidates<T extends ListeningArticle>(items: T[], read: (slug: string) => Promise<ListeningArticle>, publicationId: string, publicationName: string, origin: string): Promise<{
347
+ publishedAt?: string | undefined;
348
+ section?: string | undefined;
349
+ durationSeconds?: number | undefined;
350
+ revision?: string | undefined;
351
+ id: string;
352
+ publicationId: string;
353
+ publicationName: string;
354
+ title: string;
355
+ articleUrl: string;
356
+ storyId: string;
357
+ }[]>;
358
+
359
+ 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
@@ -1,11 +1,13 @@
1
1
  export { THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, ThemeToggle, applyTheme, clearTheme, getStoredTheme, getSystemTheme, resolveEffectiveTheme, setTheme, subscribeTheme, themeInitScript } from './chunk-NQD3M7ZY.js';
2
2
  export { LocalNetworkBar } from './chunk-QBT66OVE.js';
3
+ export { VerifiedCardComponent, VerifiedCardSection, getArticleCards, isSafeActionUrl } from './chunk-I3ZTQCV3.js';
3
4
  import { definePublication } from './chunk-C7JTEHTH.js';
4
5
  export { BROADSHEET_THEME, FEATURE_NAMES, LAYOUT_COOKIE, acceptRemoteRecord, acceptSnapshot, definePublication, featureEnabled, parseSnapshot, publicationFromSnapshot, publicationRecord, resolveLayout, snapshotFromRecord, syncPublication } from './chunk-C7JTEHTH.js';
5
6
  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';
6
7
  export { MEET_ACTIVITIES, activityLabel, canHostMeetup, isAdult, prepareMeetup, screenMessage } from './chunk-GB36YM56.js';
7
8
  export { CookieConsentBanner } from './chunk-HTMIFWNA.js';
8
9
  export { CookieSettingsView } from './chunk-3MFKPHO3.js';
10
+ import { localPublications } from './chunk-2IYYEFLD.js';
9
11
  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
12
  import { jsxs, jsx } from 'react/jsx-runtime';
11
13
 
@@ -517,4 +519,55 @@ function readerSources(input) {
517
519
  return output;
518
520
  }
519
521
 
520
- 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, publicationMeta, readerSources, referralCode, resolveCoupon, revalidateDecision, secretsMatch, sectionDefinition, sectionId, sectionPath, shortDeck, shortText, shouldServeLastKnown, storyDate, storyTowns, townSlug, validCalendarDate, walnutCreekTimes, withLastKnown };
522
+ // src/listening.ts
523
+ function publicationListeningTrack(article, publicationId, publicationName, origin) {
524
+ const articleUrl2 = new URL(`/news/${encodeURIComponent(article.slug)}`, origin).href;
525
+ let storyId = articleUrl2;
526
+ if (article.canonical_url) {
527
+ try {
528
+ const canonical = new URL(article.canonical_url);
529
+ if (canonical.protocol === "https:" && !canonical.username && !canonical.password && /^\/news\/[^/]+\/?$/.test(canonical.pathname) && localPublications.some((item) => new URL(item.url).hostname === canonical.hostname.replace(/^www\./, ""))) {
530
+ canonical.search = "";
531
+ canonical.hash = "";
532
+ canonical.hostname = canonical.hostname.replace(/^www\./, "");
533
+ canonical.pathname = canonical.pathname.replace(/\/$/, "");
534
+ storyId = canonical.href;
535
+ }
536
+ } catch {
537
+ }
538
+ }
539
+ const revision = article.editorial?.modified_at;
540
+ return {
541
+ id: article.id,
542
+ publicationId,
543
+ publicationName,
544
+ title: article.title,
545
+ articleUrl: articleUrl2,
546
+ storyId,
547
+ ...revision && Number.isFinite(Date.parse(revision)) ? { revision } : {},
548
+ ...article.audio?.duration_ms && article.audio.duration_ms > 0 ? { durationSeconds: article.audio.duration_ms / 1e3 } : {},
549
+ ...article.section ? { section: article.section } : {},
550
+ ...article.published_at ? { publishedAt: article.published_at } : {}
551
+ };
552
+ }
553
+ async function publicationListeningCandidates(items, read, publicationId, publicationName, origin) {
554
+ const output = [];
555
+ const recent = items.filter((item) => !item.editorial?.duplicate_url).slice(0, 30);
556
+ let failures = 0;
557
+ for (let i = 0; i < recent.length; i += 4) {
558
+ const batch = await Promise.allSettled(recent.slice(i, i + 4).map((item) => read(item.slug)));
559
+ for (const result of batch) {
560
+ if (result.status === "rejected") {
561
+ failures++;
562
+ continue;
563
+ }
564
+ const article = result.value;
565
+ if (!article.editorial?.duplicate_url && article.audio?.url && article.audio.duration_ms && article.audio.duration_ms > 0)
566
+ output.push(publicationListeningTrack(article, publicationId, publicationName, origin));
567
+ }
568
+ }
569
+ if (!output.length && failures) throw new Error("Audio inventory could not be loaded");
570
+ return output.sort((a, b) => (b.publishedAt ?? "").localeCompare(a.publishedAt ?? ""));
571
+ }
572
+
573
+ 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 };
@@ -0,0 +1,48 @@
1
+ import { P as PublicationInput, N as NewsPublication } from './types-DFDCZHbS.cjs';
2
+
3
+ /**
4
+ * Serializable application config. Code hooks (`matchTag`, `coupons.resolve`)
5
+ * stay in the site and are attached after the snapshot loads.
6
+ */
7
+ type PublicationRecord = Omit<PublicationInput, "matchTag" | "coupons"> & {
8
+ coupons?: Omit<NonNullable<PublicationInput["coupons"]>, "resolve">;
9
+ };
10
+ /** Last config the application accepted. Age never invalidates it. */
11
+ type PublicationSnapshot = {
12
+ version: 1;
13
+ syncedAt: string;
14
+ record: PublicationRecord;
15
+ };
16
+ type SnapshotHooks = {
17
+ matchTag?: PublicationInput["matchTag"];
18
+ resolveCoupon?: NonNullable<PublicationInput["coupons"]>["resolve"];
19
+ };
20
+ type SyncSource = "fresh" | "retained";
21
+ type SyncedPublication = {
22
+ publication: NewsPublication;
23
+ snapshot: PublicationSnapshot;
24
+ source: SyncSource;
25
+ /** How long this snapshot has been the one on disk. Zero for a fresh sync. */
26
+ ageMs: number;
27
+ };
28
+ declare function publicationRecord(publication: NewsPublication): PublicationRecord;
29
+ declare function snapshotFromRecord(record: PublicationRecord, syncedAt?: string): PublicationSnapshot;
30
+ declare function parseSnapshot(raw: string): PublicationSnapshot | null;
31
+ declare function acceptSnapshot(value: unknown): PublicationSnapshot | null;
32
+ /** A remote payload replaces the snapshot only when it is a complete record for this paper. */
33
+ declare function acceptRemoteRecord(value: unknown, expectedSlug?: string): PublicationRecord | null;
34
+ declare function publicationFromSnapshot(snapshot: PublicationSnapshot, hooks?: SnapshotHooks): NewsPublication;
35
+ /**
36
+ * Fetch the application config. Any failure, timeout, or malformed body keeps
37
+ * the previous snapshot. Nothing here expires a snapshot because the API was
38
+ * unreachable for hours or days.
39
+ */
40
+ declare function syncPublication(input: {
41
+ previous: PublicationSnapshot | null;
42
+ fetchRecord: () => Promise<unknown>;
43
+ expectedSlug?: string;
44
+ now?: number;
45
+ hooks?: SnapshotHooks;
46
+ }): Promise<SyncedPublication>;
47
+
48
+ export { type PublicationSnapshot as P, type SnapshotHooks as S, type SyncedPublication as a, type PublicationRecord as b, type SyncSource as c, acceptRemoteRecord as d, acceptSnapshot as e, publicationFromSnapshot as f, publicationRecord as g, syncPublication as h, parseSnapshot as p, snapshotFromRecord as s };
@@ -0,0 +1,48 @@
1
+ import { P as PublicationInput, N as NewsPublication } from './types-DFDCZHbS.js';
2
+
3
+ /**
4
+ * Serializable application config. Code hooks (`matchTag`, `coupons.resolve`)
5
+ * stay in the site and are attached after the snapshot loads.
6
+ */
7
+ type PublicationRecord = Omit<PublicationInput, "matchTag" | "coupons"> & {
8
+ coupons?: Omit<NonNullable<PublicationInput["coupons"]>, "resolve">;
9
+ };
10
+ /** Last config the application accepted. Age never invalidates it. */
11
+ type PublicationSnapshot = {
12
+ version: 1;
13
+ syncedAt: string;
14
+ record: PublicationRecord;
15
+ };
16
+ type SnapshotHooks = {
17
+ matchTag?: PublicationInput["matchTag"];
18
+ resolveCoupon?: NonNullable<PublicationInput["coupons"]>["resolve"];
19
+ };
20
+ type SyncSource = "fresh" | "retained";
21
+ type SyncedPublication = {
22
+ publication: NewsPublication;
23
+ snapshot: PublicationSnapshot;
24
+ source: SyncSource;
25
+ /** How long this snapshot has been the one on disk. Zero for a fresh sync. */
26
+ ageMs: number;
27
+ };
28
+ declare function publicationRecord(publication: NewsPublication): PublicationRecord;
29
+ declare function snapshotFromRecord(record: PublicationRecord, syncedAt?: string): PublicationSnapshot;
30
+ declare function parseSnapshot(raw: string): PublicationSnapshot | null;
31
+ declare function acceptSnapshot(value: unknown): PublicationSnapshot | null;
32
+ /** A remote payload replaces the snapshot only when it is a complete record for this paper. */
33
+ declare function acceptRemoteRecord(value: unknown, expectedSlug?: string): PublicationRecord | null;
34
+ declare function publicationFromSnapshot(snapshot: PublicationSnapshot, hooks?: SnapshotHooks): NewsPublication;
35
+ /**
36
+ * Fetch the application config. Any failure, timeout, or malformed body keeps
37
+ * the previous snapshot. Nothing here expires a snapshot because the API was
38
+ * unreachable for hours or days.
39
+ */
40
+ declare function syncPublication(input: {
41
+ previous: PublicationSnapshot | null;
42
+ fetchRecord: () => Promise<unknown>;
43
+ expectedSlug?: string;
44
+ now?: number;
45
+ hooks?: SnapshotHooks;
46
+ }): Promise<SyncedPublication>;
47
+
48
+ export { type PublicationSnapshot as P, type SnapshotHooks as S, type SyncedPublication as a, type PublicationRecord as b, type SyncSource as c, acceptRemoteRecord as d, acceptSnapshot as e, publicationFromSnapshot as f, publicationRecord as g, syncPublication as h, parseSnapshot as p, snapshotFromRecord as s };
@@ -1,4 +1,5 @@
1
- import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-OZFP3-Up.cjs';
1
+ import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-C0IGpt-B.cjs';
2
+ import './types-DFDCZHbS.cjs';
2
3
 
3
4
  declare function readSnapshotFile(file: string): Promise<PublicationSnapshot | null>;
4
5
  /**
@@ -1,4 +1,5 @@
1
- import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-OZFP3-Up.js';
1
+ import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-CxuyMF39.js';
2
+ import './types-DFDCZHbS.js';
2
3
 
3
4
  declare function readSnapshotFile(file: string): Promise<PublicationSnapshot | null>;
4
5
  /**
@@ -134,6 +134,44 @@ type ArticleCitation = {
134
134
  title?: string;
135
135
  publisher?: string;
136
136
  };
137
+ type CardType = "PLACE" | "ACTIVITY" | "EVENT" | "ORGANIZATION" | "PRODUCT";
138
+ type VerifiedCardAction = {
139
+ label: string;
140
+ url: string;
141
+ primary?: boolean;
142
+ };
143
+ type VerifiedCardFact = {
144
+ label: string;
145
+ value: string;
146
+ href?: string;
147
+ };
148
+ type VerifiedCardImage = {
149
+ file_id?: string;
150
+ master_url?: string;
151
+ url?: string;
152
+ width?: number;
153
+ height?: number;
154
+ alt?: string;
155
+ caption?: string;
156
+ attribution?: string;
157
+ label?: string;
158
+ ai_generated?: boolean;
159
+ };
160
+ type VerifiedCard = {
161
+ id: string;
162
+ cardType: CardType;
163
+ kicker: string;
164
+ title: string;
165
+ subtitle?: string;
166
+ summary?: string;
167
+ badge?: string;
168
+ facts: VerifiedCardFact[];
169
+ actions: VerifiedCardAction[];
170
+ verificationNote: string;
171
+ verifiedAt: string;
172
+ image?: VerifiedCardImage;
173
+ rating?: number | string;
174
+ };
137
175
  type NewsArticle = NewsItem & {
138
176
  content_html: string;
139
177
  subtitle?: string;
@@ -167,6 +205,7 @@ type NewsArticle = NewsItem & {
167
205
  attribution: string;
168
206
  ai_generated: boolean;
169
207
  }[];
208
+ cards?: VerifiedCard[] | unknown[];
170
209
  };
171
210
  };
172
211
  type StoryDisplay = {
@@ -199,49 +238,4 @@ type EditorialSection = {
199
238
  items: NewsItem[];
200
239
  };
201
240
 
202
- /**
203
- * Serializable application config. Code hooks (`matchTag`, `coupons.resolve`)
204
- * stay in the site and are attached after the snapshot loads.
205
- */
206
- type PublicationRecord = Omit<PublicationInput, "matchTag" | "coupons"> & {
207
- coupons?: Omit<NonNullable<PublicationInput["coupons"]>, "resolve">;
208
- };
209
- /** Last config the application accepted. Age never invalidates it. */
210
- type PublicationSnapshot = {
211
- version: 1;
212
- syncedAt: string;
213
- record: PublicationRecord;
214
- };
215
- type SnapshotHooks = {
216
- matchTag?: PublicationInput["matchTag"];
217
- resolveCoupon?: NonNullable<PublicationInput["coupons"]>["resolve"];
218
- };
219
- type SyncSource = "fresh" | "retained";
220
- type SyncedPublication = {
221
- publication: NewsPublication;
222
- snapshot: PublicationSnapshot;
223
- source: SyncSource;
224
- /** How long this snapshot has been the one on disk. Zero for a fresh sync. */
225
- ageMs: number;
226
- };
227
- declare function publicationRecord(publication: NewsPublication): PublicationRecord;
228
- declare function snapshotFromRecord(record: PublicationRecord, syncedAt?: string): PublicationSnapshot;
229
- declare function parseSnapshot(raw: string): PublicationSnapshot | null;
230
- declare function acceptSnapshot(value: unknown): PublicationSnapshot | null;
231
- /** A remote payload replaces the snapshot only when it is a complete record for this paper. */
232
- declare function acceptRemoteRecord(value: unknown, expectedSlug?: string): PublicationRecord | null;
233
- declare function publicationFromSnapshot(snapshot: PublicationSnapshot, hooks?: SnapshotHooks): NewsPublication;
234
- /**
235
- * Fetch the application config. Any failure, timeout, or malformed body keeps
236
- * the previous snapshot. Nothing here expires a snapshot because the API was
237
- * unreachable for hours or days.
238
- */
239
- declare function syncPublication(input: {
240
- previous: PublicationSnapshot | null;
241
- fetchRecord: () => Promise<unknown>;
242
- expectedSlug?: string;
243
- now?: number;
244
- hooks?: SnapshotHooks;
245
- }): Promise<SyncedPublication>;
246
-
247
- export { type ArticleCitation as A, type CouponOffer as C, type EditorialSection as E, type FeatureName as F, type HomepageSelection as H, type NewsPublication as N, type PublicationSnapshot as P, type ReferralSettings as R, type SnapshotHooks as S, type TagRef as T, type SyncedPublication as a, type PublicationTheme as b, type PublicationInput as c, type NearbyUpdate as d, type NewsItem as e, type NewsArticle as f, type CategoryRef as g, type CouponSettings as h, type CoverImageMetadata as i, FEATURE_NAMES as j, type FeatureFlags as k, type NewsFeed as l, type NewsLayoutId as m, type PublicationModules as n, type PublicationRecord as o, type StoryDisplay as p, type SyncSource as q, acceptRemoteRecord as r, acceptSnapshot as s, parseSnapshot as t, publicationFromSnapshot as u, publicationRecord as v, snapshotFromRecord as w, syncPublication as x };
241
+ export { type ArticleCitation as A, type CouponOffer as C, type EditorialSection as E, type FeatureName as F, type HomepageSelection as H, type NewsPublication as N, type PublicationInput as P, type ReferralSettings as R, type StoryDisplay as S, type TagRef as T, type VerifiedCard as V, type PublicationTheme as a, type NearbyUpdate as b, type NewsItem as c, type NewsArticle as d, type CardType as e, type CategoryRef as f, type CouponSettings as g, type CoverImageMetadata as h, FEATURE_NAMES as i, type FeatureFlags as j, type NewsFeed as k, type NewsLayoutId as l, type PublicationModules as m, type VerifiedCardAction as n, type VerifiedCardFact as o, type VerifiedCardImage as p };
@@ -134,6 +134,44 @@ type ArticleCitation = {
134
134
  title?: string;
135
135
  publisher?: string;
136
136
  };
137
+ type CardType = "PLACE" | "ACTIVITY" | "EVENT" | "ORGANIZATION" | "PRODUCT";
138
+ type VerifiedCardAction = {
139
+ label: string;
140
+ url: string;
141
+ primary?: boolean;
142
+ };
143
+ type VerifiedCardFact = {
144
+ label: string;
145
+ value: string;
146
+ href?: string;
147
+ };
148
+ type VerifiedCardImage = {
149
+ file_id?: string;
150
+ master_url?: string;
151
+ url?: string;
152
+ width?: number;
153
+ height?: number;
154
+ alt?: string;
155
+ caption?: string;
156
+ attribution?: string;
157
+ label?: string;
158
+ ai_generated?: boolean;
159
+ };
160
+ type VerifiedCard = {
161
+ id: string;
162
+ cardType: CardType;
163
+ kicker: string;
164
+ title: string;
165
+ subtitle?: string;
166
+ summary?: string;
167
+ badge?: string;
168
+ facts: VerifiedCardFact[];
169
+ actions: VerifiedCardAction[];
170
+ verificationNote: string;
171
+ verifiedAt: string;
172
+ image?: VerifiedCardImage;
173
+ rating?: number | string;
174
+ };
137
175
  type NewsArticle = NewsItem & {
138
176
  content_html: string;
139
177
  subtitle?: string;
@@ -167,6 +205,7 @@ type NewsArticle = NewsItem & {
167
205
  attribution: string;
168
206
  ai_generated: boolean;
169
207
  }[];
208
+ cards?: VerifiedCard[] | unknown[];
170
209
  };
171
210
  };
172
211
  type StoryDisplay = {
@@ -199,49 +238,4 @@ type EditorialSection = {
199
238
  items: NewsItem[];
200
239
  };
201
240
 
202
- /**
203
- * Serializable application config. Code hooks (`matchTag`, `coupons.resolve`)
204
- * stay in the site and are attached after the snapshot loads.
205
- */
206
- type PublicationRecord = Omit<PublicationInput, "matchTag" | "coupons"> & {
207
- coupons?: Omit<NonNullable<PublicationInput["coupons"]>, "resolve">;
208
- };
209
- /** Last config the application accepted. Age never invalidates it. */
210
- type PublicationSnapshot = {
211
- version: 1;
212
- syncedAt: string;
213
- record: PublicationRecord;
214
- };
215
- type SnapshotHooks = {
216
- matchTag?: PublicationInput["matchTag"];
217
- resolveCoupon?: NonNullable<PublicationInput["coupons"]>["resolve"];
218
- };
219
- type SyncSource = "fresh" | "retained";
220
- type SyncedPublication = {
221
- publication: NewsPublication;
222
- snapshot: PublicationSnapshot;
223
- source: SyncSource;
224
- /** How long this snapshot has been the one on disk. Zero for a fresh sync. */
225
- ageMs: number;
226
- };
227
- declare function publicationRecord(publication: NewsPublication): PublicationRecord;
228
- declare function snapshotFromRecord(record: PublicationRecord, syncedAt?: string): PublicationSnapshot;
229
- declare function parseSnapshot(raw: string): PublicationSnapshot | null;
230
- declare function acceptSnapshot(value: unknown): PublicationSnapshot | null;
231
- /** A remote payload replaces the snapshot only when it is a complete record for this paper. */
232
- declare function acceptRemoteRecord(value: unknown, expectedSlug?: string): PublicationRecord | null;
233
- declare function publicationFromSnapshot(snapshot: PublicationSnapshot, hooks?: SnapshotHooks): NewsPublication;
234
- /**
235
- * Fetch the application config. Any failure, timeout, or malformed body keeps
236
- * the previous snapshot. Nothing here expires a snapshot because the API was
237
- * unreachable for hours or days.
238
- */
239
- declare function syncPublication(input: {
240
- previous: PublicationSnapshot | null;
241
- fetchRecord: () => Promise<unknown>;
242
- expectedSlug?: string;
243
- now?: number;
244
- hooks?: SnapshotHooks;
245
- }): Promise<SyncedPublication>;
246
-
247
- export { type ArticleCitation as A, type CouponOffer as C, type EditorialSection as E, type FeatureName as F, type HomepageSelection as H, type NewsPublication as N, type PublicationSnapshot as P, type ReferralSettings as R, type SnapshotHooks as S, type TagRef as T, type SyncedPublication as a, type PublicationTheme as b, type PublicationInput as c, type NearbyUpdate as d, type NewsItem as e, type NewsArticle as f, type CategoryRef as g, type CouponSettings as h, type CoverImageMetadata as i, FEATURE_NAMES as j, type FeatureFlags as k, type NewsFeed as l, type NewsLayoutId as m, type PublicationModules as n, type PublicationRecord as o, type StoryDisplay as p, type SyncSource as q, acceptRemoteRecord as r, acceptSnapshot as s, parseSnapshot as t, publicationFromSnapshot as u, publicationRecord as v, snapshotFromRecord as w, syncPublication as x };
241
+ export { type ArticleCitation as A, type CouponOffer as C, type EditorialSection as E, type FeatureName as F, type HomepageSelection as H, type NewsPublication as N, type PublicationInput as P, type ReferralSettings as R, type StoryDisplay as S, type TagRef as T, type VerifiedCard as V, type PublicationTheme as a, type NearbyUpdate as b, type NewsItem as c, type NewsArticle as d, type CardType as e, type CategoryRef as f, type CouponSettings as g, type CoverImageMetadata as h, FEATURE_NAMES as i, type FeatureFlags as j, type NewsFeed as k, type NewsLayoutId as l, type PublicationModules as m, type VerifiedCardAction as n, type VerifiedCardFact as o, type VerifiedCardImage as p };