@scalemule/news-publication 0.0.66 → 0.0.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.cjs +50 -20
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +50 -20
- package/dist/{snapshot-qj4BeNzB.d.cts → snapshot-BBTow5Bn.d.cts} +1 -1
- package/dist/{snapshot-CjP7bSXJ.d.ts → snapshot-CHdsfUnU.d.ts} +1 -1
- package/dist/snapshot-file.d.cts +2 -2
- package/dist/snapshot-file.d.ts +2 -2
- package/dist/{types-DBi49N8m.d.cts → types-22lEf_UU.d.cts} +5 -0
- package/dist/{types-DBi49N8m.d.ts → types-22lEf_UU.d.ts} +5 -0
- package/dist/verified-card.d.cts +1 -1
- package/dist/verified-card.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -301,3 +301,7 @@ users by email or forward one application’s reader token/API key to another.
|
|
|
301
301
|
Provision and verify each RP before enabling sign-in or contribution flags.
|
|
302
302
|
|
|
303
303
|
The publisher-supplied `PawMark` preserves the approved SVG paths. Hosts may set `--paw-logo-ink` and `--paw-logo-heart` on their `.paw` scope; the defaults follow the accessible page foreground and coral accent.
|
|
304
|
+
|
|
305
|
+
### Homepage image identity
|
|
306
|
+
|
|
307
|
+
`NewsItem.visual_identity` is a versioned public identity from the Blog feed. `composeEdition` allocates covers across the entire bounded inventory, gives the selected lead priority, and holds repeated covers as `null` without dropping stories or mutating inputs. Never re-add duplicate images as fallback. Legacy Photo rendition URLs are normalized by tenant/asset ID; server-side Photo identity detects copies under different IDs and ordinary resize/re-encoding/crop variants. Do not fetch or decode images in page components. Preserve existing caption/credit policy. See platform `docs/HOMEPAGE-PHOTO-IDENTITY.md` for storage, rights, concurrency and rollout tests.
|
package/dist/index.cjs
CHANGED
|
@@ -158,42 +158,72 @@ function editorialSections(items) {
|
|
|
158
158
|
}
|
|
159
159
|
return Array.from(groups, ([name, articles]) => ({ ...sectionDefinition(name), items: articles }));
|
|
160
160
|
}
|
|
161
|
+
function coverIdentity(item) {
|
|
162
|
+
if (!item.cover_image_url?.trim()) return null;
|
|
163
|
+
const identity = item.visual_identity;
|
|
164
|
+
if (identity?.version === 1 && /^[a-f0-9]{64}$/u.test(identity.key)) return `pixels:${identity.key}`;
|
|
165
|
+
try {
|
|
166
|
+
const url = new URL(item.cover_image_url.trim());
|
|
167
|
+
if (url.protocol !== "https:" || url.username || url.password) return null;
|
|
168
|
+
if (url.hostname === "cdn-public.scalemule.com") {
|
|
169
|
+
const match = url.pathname.match(/^\/([a-f0-9-]{36})\/anonymous\/photos\/([a-f0-9-]{36})\//iu);
|
|
170
|
+
if (match) return `photo:${match[1].toLowerCase()}:${match[2].toLowerCase()}`;
|
|
171
|
+
}
|
|
172
|
+
if (["api.scalemule.com", "gw.scalemule.com"].includes(url.hostname)) {
|
|
173
|
+
const match = url.pathname.match(/^\/v1\/photos\/public\/([a-f0-9-]{36})(?:\/|$)/iu);
|
|
174
|
+
if (match) return `photo-public:${match[1].toLowerCase()}`;
|
|
175
|
+
}
|
|
176
|
+
url.hash = "";
|
|
177
|
+
url.searchParams.sort();
|
|
178
|
+
return `url:${url.toString()}`;
|
|
179
|
+
} catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
161
183
|
function composeEdition(items, selection = {}, now = Date.now()) {
|
|
162
184
|
const seen = /* @__PURE__ */ new Set();
|
|
163
|
-
|
|
185
|
+
let inventory = items.slice(0, 200).filter((item) => {
|
|
164
186
|
if (!item.id || !item.slug || seen.has(item.id)) return false;
|
|
165
187
|
seen.add(item.id);
|
|
166
188
|
return true;
|
|
167
189
|
});
|
|
168
190
|
const pins = !selection.pinned_until || Date.parse(selection.pinned_until) > now ? selection : {};
|
|
169
|
-
const
|
|
170
|
-
const
|
|
191
|
+
const selectedLead = inventory.find((item) => item.slug === pins.lead_slug) ?? inventory[0];
|
|
192
|
+
const rest = inventory.filter((item) => item !== selectedLead);
|
|
171
193
|
const requested = new Set(pins.secondary_slugs ?? []);
|
|
172
194
|
const ordered = [
|
|
173
|
-
...(pins.secondary_slugs ?? []).flatMap((slug) =>
|
|
174
|
-
...
|
|
195
|
+
...(pins.secondary_slugs ?? []).flatMap((slug) => rest.find((item) => item.slug === slug) ?? []),
|
|
196
|
+
...rest.filter((item) => !requested.has(item.slug))
|
|
175
197
|
];
|
|
176
|
-
const
|
|
198
|
+
const originalOrder = Array.from(new Map(ordered.map((item) => [item.id, item])).values());
|
|
177
199
|
const seenImages = /* @__PURE__ */ new Set();
|
|
178
|
-
|
|
179
|
-
|
|
200
|
+
const duplicateImages = /* @__PURE__ */ new Set();
|
|
201
|
+
const display = /* @__PURE__ */ new Map();
|
|
202
|
+
for (const item of [selectedLead, ...originalOrder]) {
|
|
203
|
+
if (!item) continue;
|
|
204
|
+
const key = coverIdentity(item);
|
|
205
|
+
if (key && seenImages.has(key)) {
|
|
206
|
+
duplicateImages.add(item.id);
|
|
207
|
+
display.set(item.id, { ...item, cover_image_url: null });
|
|
208
|
+
} else {
|
|
209
|
+
display.set(item.id, item);
|
|
210
|
+
if (key) seenImages.add(key);
|
|
211
|
+
}
|
|
180
212
|
}
|
|
213
|
+
inventory = inventory.map((item) => display.get(item.id));
|
|
214
|
+
const lead = selectedLead ? display.get(selectedLead.id) : void 0;
|
|
215
|
+
let remaining = rest.map((item) => display.get(item.id));
|
|
216
|
+
const uniqueOrdered = originalOrder.map((item) => display.get(item.id));
|
|
181
217
|
const secondary = [];
|
|
182
|
-
const
|
|
218
|
+
const deferred = [];
|
|
183
219
|
for (const item of uniqueOrdered) {
|
|
184
220
|
if (secondary.length >= 3) break;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
deferredWithDuplicateImage.push(item);
|
|
188
|
-
} else {
|
|
189
|
-
secondary.push(item);
|
|
190
|
-
if (img) seenImages.add(img);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
while (secondary.length < 3 && deferredWithDuplicateImage.length > 0) {
|
|
194
|
-
secondary.push(deferredWithDuplicateImage.shift());
|
|
221
|
+
if (duplicateImages.has(item.id)) deferred.push(item);
|
|
222
|
+
else secondary.push(item);
|
|
195
223
|
}
|
|
196
|
-
|
|
224
|
+
while (secondary.length < 3 && deferred.length > 0) secondary.push(deferred.shift());
|
|
225
|
+
const secondaryIds = new Set(secondary.map((item) => item.id));
|
|
226
|
+
remaining = remaining.filter((item) => !secondaryIds.has(item.id));
|
|
197
227
|
const eligible2 = remaining.filter((item) => {
|
|
198
228
|
const age = now - Date.parse(item.published_at);
|
|
199
229
|
return item.excerpt?.trim() && age >= 0 && age <= 7 * 864e5;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as PublicationTheme, P as PublicationInput, N as NewsPublication, F as FeatureName, b as NewsItem, H as HomepageSelection, c as NearbyUpdate, E as EditorialSection, d as NewsArticle, C as CouponOffer } from './types-
|
|
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-
|
|
1
|
+
import { a as PublicationTheme, P as PublicationInput, N as NewsPublication, F as FeatureName, b as NewsItem, H as HomepageSelection, c as NearbyUpdate, E as EditorialSection, d as NewsArticle, C as CouponOffer } from './types-22lEf_UU.cjs';
|
|
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-22lEf_UU.cjs';
|
|
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-CO9Unz5M.cjs';
|
|
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.cjs';
|
|
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-
|
|
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-BBTow5Bn.cjs';
|
|
6
6
|
import { CookieCategoryDefinition, CookieConsentRecord } from '@scalemule/compliance';
|
|
7
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, consentModel, decorateNetworkUrl, effectivePreferences, getCookieConsent, hasConsented, impliedPreferences, isCategoryAllowed, isGeoConsentRequired, queryNetworkConsentHub, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from '@scalemule/compliance';
|
|
8
8
|
export { CookieConsentBanner, CookieConsentBannerProps } from './cookie-consent-banner.cjs';
|
|
@@ -237,9 +237,9 @@ declare function sectionId(name: string): string;
|
|
|
237
237
|
declare function sectionPath(name: string): string;
|
|
238
238
|
declare function sectionDefinition(name: string): EditorialSection;
|
|
239
239
|
declare function editorialSections(items: NewsItem[]): EditorialSection[];
|
|
240
|
-
/** Published inventory only.
|
|
240
|
+
/** Published inventory only. All image-bearing slots share one allocation. */
|
|
241
241
|
declare function composeEdition(items: NewsItem[], selection?: HomepageSelection, now?: number): {
|
|
242
|
-
lead: NewsItem;
|
|
242
|
+
lead: NewsItem | undefined;
|
|
243
243
|
secondary: NewsItem[];
|
|
244
244
|
briefs: NewsItem[];
|
|
245
245
|
compact: NewsItem[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as PublicationTheme, P as PublicationInput, N as NewsPublication, F as FeatureName, b as NewsItem, H as HomepageSelection, c as NearbyUpdate, E as EditorialSection, d as NewsArticle, C as CouponOffer } from './types-
|
|
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-
|
|
1
|
+
import { a as PublicationTheme, P as PublicationInput, N as NewsPublication, F as FeatureName, b as NewsItem, H as HomepageSelection, c as NearbyUpdate, E as EditorialSection, d as NewsArticle, C as CouponOffer } from './types-22lEf_UU.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-22lEf_UU.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-BWpxY20X.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-
|
|
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-CHdsfUnU.js';
|
|
6
6
|
import { CookieCategoryDefinition, CookieConsentRecord } from '@scalemule/compliance';
|
|
7
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, consentModel, decorateNetworkUrl, effectivePreferences, getCookieConsent, hasConsented, impliedPreferences, isCategoryAllowed, isGeoConsentRequired, queryNetworkConsentHub, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from '@scalemule/compliance';
|
|
8
8
|
export { CookieConsentBanner, CookieConsentBannerProps } from './cookie-consent-banner.js';
|
|
@@ -237,9 +237,9 @@ declare function sectionId(name: string): string;
|
|
|
237
237
|
declare function sectionPath(name: string): string;
|
|
238
238
|
declare function sectionDefinition(name: string): EditorialSection;
|
|
239
239
|
declare function editorialSections(items: NewsItem[]): EditorialSection[];
|
|
240
|
-
/** Published inventory only.
|
|
240
|
+
/** Published inventory only. All image-bearing slots share one allocation. */
|
|
241
241
|
declare function composeEdition(items: NewsItem[], selection?: HomepageSelection, now?: number): {
|
|
242
|
-
lead: NewsItem;
|
|
242
|
+
lead: NewsItem | undefined;
|
|
243
243
|
secondary: NewsItem[];
|
|
244
244
|
briefs: NewsItem[];
|
|
245
245
|
compact: NewsItem[];
|
package/dist/index.js
CHANGED
|
@@ -101,42 +101,72 @@ function editorialSections(items) {
|
|
|
101
101
|
}
|
|
102
102
|
return Array.from(groups, ([name, articles]) => ({ ...sectionDefinition(name), items: articles }));
|
|
103
103
|
}
|
|
104
|
+
function coverIdentity(item) {
|
|
105
|
+
if (!item.cover_image_url?.trim()) return null;
|
|
106
|
+
const identity = item.visual_identity;
|
|
107
|
+
if (identity?.version === 1 && /^[a-f0-9]{64}$/u.test(identity.key)) return `pixels:${identity.key}`;
|
|
108
|
+
try {
|
|
109
|
+
const url = new URL(item.cover_image_url.trim());
|
|
110
|
+
if (url.protocol !== "https:" || url.username || url.password) return null;
|
|
111
|
+
if (url.hostname === "cdn-public.scalemule.com") {
|
|
112
|
+
const match = url.pathname.match(/^\/([a-f0-9-]{36})\/anonymous\/photos\/([a-f0-9-]{36})\//iu);
|
|
113
|
+
if (match) return `photo:${match[1].toLowerCase()}:${match[2].toLowerCase()}`;
|
|
114
|
+
}
|
|
115
|
+
if (["api.scalemule.com", "gw.scalemule.com"].includes(url.hostname)) {
|
|
116
|
+
const match = url.pathname.match(/^\/v1\/photos\/public\/([a-f0-9-]{36})(?:\/|$)/iu);
|
|
117
|
+
if (match) return `photo-public:${match[1].toLowerCase()}`;
|
|
118
|
+
}
|
|
119
|
+
url.hash = "";
|
|
120
|
+
url.searchParams.sort();
|
|
121
|
+
return `url:${url.toString()}`;
|
|
122
|
+
} catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
104
126
|
function composeEdition(items, selection = {}, now = Date.now()) {
|
|
105
127
|
const seen = /* @__PURE__ */ new Set();
|
|
106
|
-
|
|
128
|
+
let inventory = items.slice(0, 200).filter((item) => {
|
|
107
129
|
if (!item.id || !item.slug || seen.has(item.id)) return false;
|
|
108
130
|
seen.add(item.id);
|
|
109
131
|
return true;
|
|
110
132
|
});
|
|
111
133
|
const pins = !selection.pinned_until || Date.parse(selection.pinned_until) > now ? selection : {};
|
|
112
|
-
const
|
|
113
|
-
const
|
|
134
|
+
const selectedLead = inventory.find((item) => item.slug === pins.lead_slug) ?? inventory[0];
|
|
135
|
+
const rest = inventory.filter((item) => item !== selectedLead);
|
|
114
136
|
const requested = new Set(pins.secondary_slugs ?? []);
|
|
115
137
|
const ordered = [
|
|
116
|
-
...(pins.secondary_slugs ?? []).flatMap((slug) =>
|
|
117
|
-
...
|
|
138
|
+
...(pins.secondary_slugs ?? []).flatMap((slug) => rest.find((item) => item.slug === slug) ?? []),
|
|
139
|
+
...rest.filter((item) => !requested.has(item.slug))
|
|
118
140
|
];
|
|
119
|
-
const
|
|
141
|
+
const originalOrder = Array.from(new Map(ordered.map((item) => [item.id, item])).values());
|
|
120
142
|
const seenImages = /* @__PURE__ */ new Set();
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
const duplicateImages = /* @__PURE__ */ new Set();
|
|
144
|
+
const display = /* @__PURE__ */ new Map();
|
|
145
|
+
for (const item of [selectedLead, ...originalOrder]) {
|
|
146
|
+
if (!item) continue;
|
|
147
|
+
const key = coverIdentity(item);
|
|
148
|
+
if (key && seenImages.has(key)) {
|
|
149
|
+
duplicateImages.add(item.id);
|
|
150
|
+
display.set(item.id, { ...item, cover_image_url: null });
|
|
151
|
+
} else {
|
|
152
|
+
display.set(item.id, item);
|
|
153
|
+
if (key) seenImages.add(key);
|
|
154
|
+
}
|
|
123
155
|
}
|
|
156
|
+
inventory = inventory.map((item) => display.get(item.id));
|
|
157
|
+
const lead = selectedLead ? display.get(selectedLead.id) : void 0;
|
|
158
|
+
let remaining = rest.map((item) => display.get(item.id));
|
|
159
|
+
const uniqueOrdered = originalOrder.map((item) => display.get(item.id));
|
|
124
160
|
const secondary = [];
|
|
125
|
-
const
|
|
161
|
+
const deferred = [];
|
|
126
162
|
for (const item of uniqueOrdered) {
|
|
127
163
|
if (secondary.length >= 3) break;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
deferredWithDuplicateImage.push(item);
|
|
131
|
-
} else {
|
|
132
|
-
secondary.push(item);
|
|
133
|
-
if (img) seenImages.add(img);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
while (secondary.length < 3 && deferredWithDuplicateImage.length > 0) {
|
|
137
|
-
secondary.push(deferredWithDuplicateImage.shift());
|
|
164
|
+
if (duplicateImages.has(item.id)) deferred.push(item);
|
|
165
|
+
else secondary.push(item);
|
|
138
166
|
}
|
|
139
|
-
|
|
167
|
+
while (secondary.length < 3 && deferred.length > 0) secondary.push(deferred.shift());
|
|
168
|
+
const secondaryIds = new Set(secondary.map((item) => item.id));
|
|
169
|
+
remaining = remaining.filter((item) => !secondaryIds.has(item.id));
|
|
140
170
|
const eligible2 = remaining.filter((item) => {
|
|
141
171
|
const age = now - Date.parse(item.published_at);
|
|
142
172
|
return item.excerpt?.trim() && age >= 0 && age <= 7 * 864e5;
|
package/dist/snapshot-file.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-
|
|
2
|
-
import './types-
|
|
1
|
+
import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-BBTow5Bn.cjs';
|
|
2
|
+
import './types-22lEf_UU.cjs';
|
|
3
3
|
|
|
4
4
|
declare function readSnapshotFile(file: string): Promise<PublicationSnapshot | null>;
|
|
5
5
|
/**
|
package/dist/snapshot-file.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-
|
|
2
|
-
import './types-
|
|
1
|
+
import { P as PublicationSnapshot, S as SnapshotHooks, a as SyncedPublication } from './snapshot-CHdsfUnU.js';
|
|
2
|
+
import './types-22lEf_UU.js';
|
|
3
3
|
|
|
4
4
|
declare function readSnapshotFile(file: string): Promise<PublicationSnapshot | null>;
|
|
5
5
|
/**
|
|
@@ -100,6 +100,11 @@ type NewsItem = {
|
|
|
100
100
|
title: string;
|
|
101
101
|
excerpt: string | null;
|
|
102
102
|
cover_image_url: string | null;
|
|
103
|
+
/** Versioned canonical pixel identity supplied by the publication owner. */
|
|
104
|
+
visual_identity?: {
|
|
105
|
+
version: number;
|
|
106
|
+
key: string;
|
|
107
|
+
} | null;
|
|
103
108
|
published_at: string;
|
|
104
109
|
updated_at: string;
|
|
105
110
|
reading_time_minutes: number;
|
|
@@ -100,6 +100,11 @@ type NewsItem = {
|
|
|
100
100
|
title: string;
|
|
101
101
|
excerpt: string | null;
|
|
102
102
|
cover_image_url: string | null;
|
|
103
|
+
/** Versioned canonical pixel identity supplied by the publication owner. */
|
|
104
|
+
visual_identity?: {
|
|
105
|
+
version: number;
|
|
106
|
+
key: string;
|
|
107
|
+
} | null;
|
|
103
108
|
published_at: string;
|
|
104
109
|
updated_at: string;
|
|
105
110
|
reading_time_minutes: number;
|
package/dist/verified-card.d.cts
CHANGED
package/dist/verified-card.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/news-publication",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.67",
|
|
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",
|