@scalemule/news-publication 0.0.93 → 0.0.95
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/bin/scalemule-article.mjs +13 -6
- package/dist/article-workflow-client.cjs +22 -8
- package/dist/article-workflow-client.d.cts +10 -1
- package/dist/article-workflow-client.d.ts +10 -1
- package/dist/article-workflow-client.js +18 -9
- package/dist/{chunk-SNQKSUWB.js → chunk-7SAFGLPH.js} +6 -1
- package/dist/index.cjs +6 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -26,7 +26,8 @@ Unspecified fields and media are retained. Default: save for review.
|
|
|
26
26
|
APPROVE or changes a policy. Legacy onboarding requires an explicit
|
|
27
27
|
--enable-review-policy value. Scheduled legacy articles stop before onboarding.
|
|
28
28
|
Use --expected-generation when coordinating an edit with another editor.
|
|
29
|
-
Default edit deadline: 10000 ms.
|
|
29
|
+
Default edit deadline: 10000 ms (--timeout-ms, API work). The public page check after --release
|
|
30
|
+
has its own --page-timeout-ms (default 60000). Reuse the same patch/key/checkpoint on retry.
|
|
30
31
|
RELEASE_HELD means the revision is saved and existing review gates remain.
|
|
31
32
|
|
|
32
33
|
replace-photo accepts a local file and uses normal member/API-key credentials.
|
|
@@ -58,7 +59,7 @@ that every website/CDN cache already displays the new image.
|
|
|
58
59
|
try {
|
|
59
60
|
const { values, positionals } = parseArgs({
|
|
60
61
|
allowPositionals: true, strict: true,
|
|
61
|
-
options: Object.fromEntries(['publication', 'article', 'file-id', 'expected-version', 'metadata', 'application-id', 'api-url', 'url', 'file', 'operation-key', 'state', 'timeout-ms','patch','expected-generation','enable-review-policy','manifest','submission'].map(k => [k, { type: 'string' }]).concat([['asset',{type:'string',multiple:true}],['help', { type: 'boolean' }],['release',{type:'boolean'}]])),
|
|
62
|
+
options: Object.fromEntries(['publication', 'article', 'file-id', 'expected-version', 'metadata', 'application-id', 'api-url', 'url', 'file', 'operation-key', 'state', 'timeout-ms','page-timeout-ms','patch','expected-generation','enable-review-policy','manifest','submission'].map(k => [k, { type: 'string' }]).concat([['asset',{type:'string',multiple:true}],['help', { type: 'boolean' }],['release',{type:'boolean'}]])),
|
|
62
63
|
});
|
|
63
64
|
if (values.help || !positionals.length) {
|
|
64
65
|
console.log(help);
|
|
@@ -68,6 +69,10 @@ try {
|
|
|
68
69
|
const budget = Number(values['timeout-ms'] ?? (command==='edit'?10000:30000));
|
|
69
70
|
if (!Number.isFinite(budget) || budget < 100 || budget > 120000) throw Error('--timeout-ms must be between 100 and 120000');
|
|
70
71
|
const remaining = () => { const ms = Math.floor(budget - (performance.now()-commandStarted)); if (ms < 1) throw Error('Operation deadline reached; resume the same operation'); return ms; };
|
|
72
|
+
// The public page check has its own deadline: caches and rolling pods make it slower than the API, and
|
|
73
|
+
// a slow page must never consume the API operation's budget or vice versa.
|
|
74
|
+
const pageBudget = Number(values['page-timeout-ms'] ?? 60000);
|
|
75
|
+
if (!Number.isFinite(pageBudget) || pageBudget < 1000 || pageBudget > 300000) throw Error('--page-timeout-ms must be between 1000 and 300000');
|
|
71
76
|
if (extra.length || !['submit','status','inspect', 'replace-cover', 'replace-photo','edit'].includes(command)) throw Error('Use submit, status, inspect, edit, replace-cover or replace-photo; see --help');
|
|
72
77
|
if (values.url) {
|
|
73
78
|
if (!process.env.SCALEMULE_API_KEY || !process.env.SCALEMULE_ACCESS_TOKEN || values['application-id']) throw Error('URL resolution requires normal publication member/API-key credentials');
|
|
@@ -152,15 +157,17 @@ try {
|
|
|
152
157
|
});
|
|
153
158
|
if(values.url&&values.release&&['published','already_published'].includes(result.state)){
|
|
154
159
|
let verified=false,reason;
|
|
160
|
+
const pageStarted=performance.now();
|
|
161
|
+
const pageRemaining=()=>{const ms=Math.floor(pageBudget-(performance.now()-pageStarted));if(ms<1)throw Error('Public page deadline reached; the page may still be refreshing. Resume the same operation or raise --page-timeout-ms');return ms;};
|
|
155
162
|
try{
|
|
156
|
-
const snapshot=await client.publicArticle(checkpoint.sourceIdentity.slug,AbortSignal.timeout(
|
|
163
|
+
const snapshot=await client.publicArticle(checkpoint.sourceIdentity.slug,AbortSignal.timeout(pageRemaining()));
|
|
157
164
|
const article=snapshot.article;
|
|
158
165
|
if(!article||!article.content_html||article.id!==values.article)throw Error('Published reader snapshot is missing');
|
|
159
166
|
while(!verified){
|
|
160
|
-
const response=await fetch(values.url,{redirect:'error',cache:'no-store',signal:AbortSignal.timeout(Math.min(5000,
|
|
167
|
+
const response=await fetch(values.url,{redirect:'error',cache:'no-store',signal:AbortSignal.timeout(Math.min(5000,pageRemaining()))});
|
|
161
168
|
const html=await response.text();
|
|
162
|
-
verified=response.ok&&articleEditHtmlMatches(html,{title:article.title,headline:article.headline,content_html:article.content_html,card_titles:(article.metadata?.cards??[]).map(c=>c.title),tags:checkpoint.document.tag_ids?article.tags:undefined});
|
|
163
|
-
if(!verified)await new Promise(r=>setTimeout(r,Math.min(
|
|
169
|
+
verified=response.ok&&articleEditHtmlMatches(html,{title:article.title,headline:article.headline,seo_title:'seo_title' in patch?article.seo_title:undefined,content_html:article.content_html,card_titles:(article.metadata?.cards??[]).map(c=>c.title),tags:checkpoint.document.tag_ids?article.tags:undefined});
|
|
170
|
+
if(!verified)await new Promise(r=>setTimeout(r,Math.min(1000,pageRemaining())));
|
|
164
171
|
}
|
|
165
172
|
}catch(error){reason=error.message;}
|
|
166
173
|
if(!verified){console.error(JSON.stringify({...result,state:'published_public_verification_pending',stage:'public_page',message:'The exact revision is published; rendered prose/cards/tags remain unverified. Resume the same edit.',reason}));process.exitCode=2;}
|
|
@@ -36,6 +36,11 @@ function articleEditHtmlMatches(html, expected) {
|
|
|
36
36
|
(m) => text(m[1]) === shown
|
|
37
37
|
);
|
|
38
38
|
if (!headline) return false;
|
|
39
|
+
const seo = expected.seo_title?.trim();
|
|
40
|
+
if (seo) {
|
|
41
|
+
const pageTitle = text(visible.match(/<title\b[^>]*>([\s\S]*?)<\/title>/iu)?.[1] ?? "");
|
|
42
|
+
if (pageTitle !== plain(seo) && !pageTitle.startsWith(plain(seo) + " ")) return false;
|
|
43
|
+
}
|
|
39
44
|
const paragraphs = [
|
|
40
45
|
...expected.content_html.matchAll(
|
|
41
46
|
/<(p|li|h[2-6]|blockquote)\b[^>]*>([\s\S]*?)<\/\1>/giu
|
|
@@ -55,13 +60,10 @@ function articleEditHtmlMatches(html, expected) {
|
|
|
55
60
|
}
|
|
56
61
|
}))) return false;
|
|
57
62
|
}
|
|
58
|
-
const titles = [
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
].flatMap(
|
|
63
|
-
(m) => [...m[1].matchAll(/<h2\b[^>]*>([\s\S]*?)<\/h2>/giu)].map((m2) => text(m2[1]))
|
|
64
|
-
);
|
|
63
|
+
const titles = [...visible.matchAll(/<aside\b([^>]*)>([\s\S]*?)<\/aside>/giu)].filter((m) => /\bdata-entity-card=["'][^"']+["']/iu.test(m[1]) || /class=["'][^"']*\barticle-verified-card\b/iu.test(m[1])).flatMap((m) => {
|
|
64
|
+
const first = m[2].match(/<h2\b[^>]*>([\s\S]*?)<\/h2>/iu);
|
|
65
|
+
return first ? [text(first[1])] : [];
|
|
66
|
+
});
|
|
65
67
|
return JSON.stringify(titles.sort()) === JSON.stringify(expected.card_titles.map(plain).sort());
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -354,7 +356,12 @@ function headlineProblems(fields) {
|
|
|
354
356
|
problems.push(`${name} must be a string`);
|
|
355
357
|
return;
|
|
356
358
|
}
|
|
359
|
+
if (!value.trim()) {
|
|
360
|
+
problems.push(`${name} is blank; omit it to fall back to the title`);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
357
363
|
if (headlineLength(value.trim()) > max) problems.push(`${name} exceeds ${max} characters`);
|
|
364
|
+
if (/[\p{Cc}]/u.test(value)) problems.push(`${name} contains control characters`);
|
|
358
365
|
};
|
|
359
366
|
check("headline", fields.headline, HEADLINE_MAX_CHARS);
|
|
360
367
|
check("fly_title", fields.fly_title, FLY_TITLE_MAX_CHARS);
|
|
@@ -506,6 +513,13 @@ async function runArticleEdit(t, input) {
|
|
|
506
513
|
throw error;
|
|
507
514
|
})
|
|
508
515
|
]);
|
|
516
|
+
const headlineKeys = ["headline", "fly_title", "seo_title"].filter((key) => key in input.patch);
|
|
517
|
+
if (headlineKeys.length && options.capabilities?.headline_set !== true)
|
|
518
|
+
throw new ArticleEditOperationError(
|
|
519
|
+
"CAPABILITY_UNAVAILABLE",
|
|
520
|
+
"preflight",
|
|
521
|
+
`The server must expose headline_set before editing ${headlineKeys.join(", ")}; no article was changed`
|
|
522
|
+
);
|
|
509
523
|
if (options.workflow_version !== 1 || options.capabilities?.versioned_editorial_fields !== true)
|
|
510
524
|
throw new ArticleEditOperationError(
|
|
511
525
|
"CAPABILITY_UNAVAILABLE",
|
|
@@ -668,7 +682,7 @@ async function runArticleEdit(t, input) {
|
|
|
668
682
|
409,
|
|
669
683
|
state.revisionId
|
|
670
684
|
);
|
|
671
|
-
for (const key of ["title", "subtitle", "content_markdown", "excerpt"])
|
|
685
|
+
for (const key of ["title", "headline", "fly_title", "seo_title", "subtitle", "content_markdown", "excerpt"])
|
|
672
686
|
if (state.document?.[key] !== void 0 && !equal(after[key] ?? "", state.document[key]))
|
|
673
687
|
throw new ArticleEditOperationError(
|
|
674
688
|
"VERIFICATION_CONFLICT",
|
|
@@ -3,10 +3,17 @@ import { A as ArticleFormat, b as ArticleLayout } from './article-presentation-0
|
|
|
3
3
|
/** Check rendered image tags, not a URL mentioned only in serialized page data. */
|
|
4
4
|
declare function articlePhotoHtmlMatches(html: string, lead: string | string[], social: string): boolean;
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Requires visible body and actual card asides; serialized page data is not delivery.
|
|
8
|
+
* Cards are recognised by either rendering the papers use: the package's `article-verified-card`
|
|
9
|
+
* aside, or the papers' entity cards (`<aside data-entity-card="venue|event|…">`), each titled by its h2.
|
|
10
|
+
* When the edit carried a search title, the document's `<title>` must show it (a site may append its
|
|
11
|
+
* own name after it).
|
|
12
|
+
*/
|
|
7
13
|
declare function articleEditHtmlMatches(html: string, expected: {
|
|
8
14
|
title: string;
|
|
9
15
|
headline?: string | null;
|
|
16
|
+
seo_title?: string | null;
|
|
10
17
|
content_html: string;
|
|
11
18
|
card_titles: string[];
|
|
12
19
|
tags?: {
|
|
@@ -208,6 +215,8 @@ type ArticleWorkflowOptions = {
|
|
|
208
215
|
prioritized_narration_processing?: boolean;
|
|
209
216
|
content_first_editor_document?: boolean;
|
|
210
217
|
versioned_editorial_fields?: boolean;
|
|
218
|
+
/** The server stores headline, fly_title and seo_title on the versioned document. */
|
|
219
|
+
headline_set?: boolean;
|
|
211
220
|
versioned_editorial_tags?: boolean;
|
|
212
221
|
managed_submission_version?: number | null;
|
|
213
222
|
multipart_submission?: boolean;
|
|
@@ -3,10 +3,17 @@ import { A as ArticleFormat, b as ArticleLayout } from './article-presentation-0
|
|
|
3
3
|
/** Check rendered image tags, not a URL mentioned only in serialized page data. */
|
|
4
4
|
declare function articlePhotoHtmlMatches(html: string, lead: string | string[], social: string): boolean;
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Requires visible body and actual card asides; serialized page data is not delivery.
|
|
8
|
+
* Cards are recognised by either rendering the papers use: the package's `article-verified-card`
|
|
9
|
+
* aside, or the papers' entity cards (`<aside data-entity-card="venue|event|…">`), each titled by its h2.
|
|
10
|
+
* When the edit carried a search title, the document's `<title>` must show it (a site may append its
|
|
11
|
+
* own name after it).
|
|
12
|
+
*/
|
|
7
13
|
declare function articleEditHtmlMatches(html: string, expected: {
|
|
8
14
|
title: string;
|
|
9
15
|
headline?: string | null;
|
|
16
|
+
seo_title?: string | null;
|
|
10
17
|
content_html: string;
|
|
11
18
|
card_titles: string[];
|
|
12
19
|
tags?: {
|
|
@@ -208,6 +215,8 @@ type ArticleWorkflowOptions = {
|
|
|
208
215
|
prioritized_narration_processing?: boolean;
|
|
209
216
|
content_first_editor_document?: boolean;
|
|
210
217
|
versioned_editorial_fields?: boolean;
|
|
218
|
+
/** The server stores headline, fly_title and seo_title on the versioned document. */
|
|
219
|
+
headline_set?: boolean;
|
|
211
220
|
versioned_editorial_tags?: boolean;
|
|
212
221
|
managed_submission_version?: number | null;
|
|
213
222
|
multipart_submission?: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { headlineProblems } from './chunk-
|
|
1
|
+
import { headlineProblems } from './chunk-7SAFGLPH.js';
|
|
2
2
|
|
|
3
3
|
// src/article-photo-verification.ts
|
|
4
4
|
function articlePhotoHtmlMatches(html, lead, social) {
|
|
@@ -36,6 +36,11 @@ function articleEditHtmlMatches(html, expected) {
|
|
|
36
36
|
(m) => text(m[1]) === shown
|
|
37
37
|
);
|
|
38
38
|
if (!headline) return false;
|
|
39
|
+
const seo = expected.seo_title?.trim();
|
|
40
|
+
if (seo) {
|
|
41
|
+
const pageTitle = text(visible.match(/<title\b[^>]*>([\s\S]*?)<\/title>/iu)?.[1] ?? "");
|
|
42
|
+
if (pageTitle !== plain(seo) && !pageTitle.startsWith(plain(seo) + " ")) return false;
|
|
43
|
+
}
|
|
39
44
|
const paragraphs = [
|
|
40
45
|
...expected.content_html.matchAll(
|
|
41
46
|
/<(p|li|h[2-6]|blockquote)\b[^>]*>([\s\S]*?)<\/\1>/giu
|
|
@@ -55,13 +60,10 @@ function articleEditHtmlMatches(html, expected) {
|
|
|
55
60
|
}
|
|
56
61
|
}))) return false;
|
|
57
62
|
}
|
|
58
|
-
const titles = [
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
].flatMap(
|
|
63
|
-
(m) => [...m[1].matchAll(/<h2\b[^>]*>([\s\S]*?)<\/h2>/giu)].map((m2) => text(m2[1]))
|
|
64
|
-
);
|
|
63
|
+
const titles = [...visible.matchAll(/<aside\b([^>]*)>([\s\S]*?)<\/aside>/giu)].filter((m) => /\bdata-entity-card=["'][^"']+["']/iu.test(m[1]) || /class=["'][^"']*\barticle-verified-card\b/iu.test(m[1])).flatMap((m) => {
|
|
64
|
+
const first = m[2].match(/<h2\b[^>]*>([\s\S]*?)<\/h2>/iu);
|
|
65
|
+
return first ? [text(first[1])] : [];
|
|
66
|
+
});
|
|
65
67
|
return JSON.stringify(titles.sort()) === JSON.stringify(expected.card_titles.map(plain).sort());
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -483,6 +485,13 @@ async function runArticleEdit(t, input) {
|
|
|
483
485
|
throw error;
|
|
484
486
|
})
|
|
485
487
|
]);
|
|
488
|
+
const headlineKeys = ["headline", "fly_title", "seo_title"].filter((key) => key in input.patch);
|
|
489
|
+
if (headlineKeys.length && options.capabilities?.headline_set !== true)
|
|
490
|
+
throw new ArticleEditOperationError(
|
|
491
|
+
"CAPABILITY_UNAVAILABLE",
|
|
492
|
+
"preflight",
|
|
493
|
+
`The server must expose headline_set before editing ${headlineKeys.join(", ")}; no article was changed`
|
|
494
|
+
);
|
|
486
495
|
if (options.workflow_version !== 1 || options.capabilities?.versioned_editorial_fields !== true)
|
|
487
496
|
throw new ArticleEditOperationError(
|
|
488
497
|
"CAPABILITY_UNAVAILABLE",
|
|
@@ -645,7 +654,7 @@ async function runArticleEdit(t, input) {
|
|
|
645
654
|
409,
|
|
646
655
|
state.revisionId
|
|
647
656
|
);
|
|
648
|
-
for (const key of ["title", "subtitle", "content_markdown", "excerpt"])
|
|
657
|
+
for (const key of ["title", "headline", "fly_title", "seo_title", "subtitle", "content_markdown", "excerpt"])
|
|
649
658
|
if (state.document?.[key] !== void 0 && !equal(after[key] ?? "", state.document[key]))
|
|
650
659
|
throw new ArticleEditOperationError(
|
|
651
660
|
"VERIFICATION_CONFLICT",
|
|
@@ -15,7 +15,7 @@ function headlineSet(article, selection = {}) {
|
|
|
15
15
|
const title = text(article.title) ?? "";
|
|
16
16
|
const headline = text(display?.display_title) ?? text(article.headline) ?? title;
|
|
17
17
|
return {
|
|
18
|
-
flyTitle: text(article.fly_title) ?? text(article.section),
|
|
18
|
+
flyTitle: text(display?.fly_title) ?? text(article.fly_title) ?? text(article.section),
|
|
19
19
|
headline,
|
|
20
20
|
rubric: text(display?.deck) ?? text(article.subtitle),
|
|
21
21
|
seoTitle: text(article.seo_title) ?? title,
|
|
@@ -30,7 +30,12 @@ function headlineProblems(fields) {
|
|
|
30
30
|
problems.push(`${name} must be a string`);
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
+
if (!value.trim()) {
|
|
34
|
+
problems.push(`${name} is blank; omit it to fall back to the title`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
33
37
|
if (headlineLength(value.trim()) > max) problems.push(`${name} exceeds ${max} characters`);
|
|
38
|
+
if (/[\p{Cc}]/u.test(value)) problems.push(`${name} contains control characters`);
|
|
34
39
|
};
|
|
35
40
|
check("headline", fields.headline, HEADLINE_MAX_CHARS);
|
|
36
41
|
check("fly_title", fields.fly_title, FLY_TITLE_MAX_CHARS);
|
package/dist/index.cjs
CHANGED
|
@@ -825,7 +825,7 @@ function headlineSet(article, selection = {}) {
|
|
|
825
825
|
const title = text(article.title) ?? "";
|
|
826
826
|
const headline = text(display?.display_title) ?? text(article.headline) ?? title;
|
|
827
827
|
return {
|
|
828
|
-
flyTitle: text(article.fly_title) ?? text(article.section),
|
|
828
|
+
flyTitle: text(display?.fly_title) ?? text(article.fly_title) ?? text(article.section),
|
|
829
829
|
headline,
|
|
830
830
|
rubric: text(display?.deck) ?? text(article.subtitle),
|
|
831
831
|
seoTitle: text(article.seo_title) ?? title,
|
|
@@ -840,7 +840,12 @@ function headlineProblems(fields) {
|
|
|
840
840
|
problems.push(`${name} must be a string`);
|
|
841
841
|
return;
|
|
842
842
|
}
|
|
843
|
+
if (!value.trim()) {
|
|
844
|
+
problems.push(`${name} is blank; omit it to fall back to the title`);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
843
847
|
if (headlineLength(value.trim()) > max) problems.push(`${name} exceeds ${max} characters`);
|
|
848
|
+
if (/[\p{Cc}]/u.test(value)) problems.push(`${name} contains control characters`);
|
|
844
849
|
};
|
|
845
850
|
check("headline", fields.headline, HEADLINE_MAX_CHARS);
|
|
846
851
|
check("fly_title", fields.fly_title, FLY_TITLE_MAX_CHARS);
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { CookieSettingsView } from './chunk-PBRDIXQI.js';
|
|
|
8
8
|
import { localPublications } from './chunk-NNEY6VBX.js';
|
|
9
9
|
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, EDITORIAL_PRINCIPLES, EU_EEA_UK_COUNTRIES, NETWORK_CONSENT_STORAGE_KEY, NETWORK_PARENT, acceptAllCookies, checkUrlConsentBridge, clearCookieConsent, communityPublications, consentModel, decorateNetworkUrl, effectivePreferences, findPublicationByHost, findPublicationBySlug, getCookieConsent, getNetworkPublicationUrl, getNetworkReaderHandoffUrl, hasConsented, impliedPreferences, isCategoryAllowed, isGeoConsentRequired, listedPublications, localPublications, queryNetworkConsentHub, recordConsentToCompliance, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub, topicalPublications } from './chunk-NNEY6VBX.js';
|
|
10
10
|
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';
|
|
11
|
-
export { FLY_TITLE_MAX_CHARS, HEADLINE_MAX_CHARS, HEADLINE_RECOMMENDED_CHARS, RUBRIC_MAX_CHARS, SEO_TITLE_MAX_CHARS, headlineLength, headlineProblems, headlineSet } from './chunk-
|
|
11
|
+
export { FLY_TITLE_MAX_CHARS, HEADLINE_MAX_CHARS, HEADLINE_RECOMMENDED_CHARS, RUBRIC_MAX_CHARS, SEO_TITLE_MAX_CHARS, headlineLength, headlineProblems, headlineSet } from './chunk-7SAFGLPH.js';
|
|
12
12
|
export { communityMapEmbeds } from './chunk-IMYBSG7J.js';
|
|
13
13
|
export { articleFormatLabel, articleHeroRatio, articlePresentation, formatArtworkCaption, parseDocumentBlocks, renderArticleBlocksToHtml, sanitizeInlineMarkdown } from './chunk-DN3TBZLK.js';
|
|
14
14
|
import { definePublication } from './chunk-57YVL6BD.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/news-publication",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.95",
|
|
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
|
"bin": {
|