- renderJournalBody runs the UI-SPEC L7 order on the sanitized body:
h1 demotion, the CMS phrase auto-links, the outbound rules and lazy,
async images, with vue-seo-layer's autolink, applyOutbound and
imageAttrs; PostBody feeds it the page's resolve answer (autolinks,
autolink_max, outbound, url) and the seo.links.newTabHint option
- the sanitizer keeps a link rel of only nofollow, sponsored and ugc
(the Blog Editor's link form, as the Journal plugin's policy does);
target is never kept, the outbound rules add it
- editor-corpus.json copied again from sm-journal-plugin (link-rel and
image-decorative entries)
- smoke:ssr script; expectations for auto-links, both new-tab modes and
the hint switched off
- extend vue-seo-layer (link dependency during development) and drop
@nuxtjs/seo: the page head, canonical and the one JSON-LD graph come
from the CMS resolve answer; the post's own title, excerpt and image
apply only while there is no CMS answer
- remove the journal sitemap source and the copied shared purge route,
library and plugin (the SEO layer serves POST /api/__site__/cache/purge);
the deprecated POST /api/__journal__/cache/purge keeps working
- post title is h1 while the Journal API reports content_h1_to_h2 on
(or absent) and p.journal-post__title while off; journal.postTitleTag
('auto' | 'h1' | 'p') overrides it; body h1 headings are demoted to h2
while the setting is on (gateJournalHtml/sanitizeJournalHtml demoteH1)
- journal.breadcrumbs option and post-title CSS tokens
- smoke harness: count=, header=, noheader= and resolves lines; the
fixture API also answers the SEO resolve and site endpoints
BREAKING CHANGE: the layer no longer installs @nuxtjs/seo (no
nuxt-site-config, nuxt-schema-org, robots or sitemap module, no
/api/__sitemap__/journal source, no useSiteConfig()); apps take their
head, sitemaps and robots from the SEO plugin through vue-seo-layer.
- htmlGate.ts mirrors the four editor-output rules of the Go policy:
figure data-embed (^youtube$) and data-id (^[A-Za-z0-9_-]{11}$),
img alt with any text, ol start (integer)
- embeds.ts: EMBED_PROVIDERS (youtube on youtube-nocookie.com),
EMBED_PLACEHOLDER and expandEmbeds
- JournalPostBody and JournalCategoryHeader render
expandEmbeds(sanitizeJournalHtml(html)); payload transforms only sanitize
- .journal-embed styles (16 / 9 block, borderless iframe)
- tests: byte copy of the editor corpus, mirror and pipeline cases;
acme hello-acme carries a placeholder and the SSR smoke checks the iframe
- README Embeds section and decision note Policy amendment
The three-regex gate could be bypassed (an attribute without a space,
<svg/onload>, entity-encoded or tab-split javascript: URLs, MathML
xlink:href, base, meta refresh, forms) and it blanked a whole post or
category when ordinary text such as "Data: 12 maja 2024" matched.
- sanitizeJournalHtml runs sanitize-html with the Journal plugin's
bluemonday policy: UGC elements plus footer, class, schema.org
microdata, four validated inline styles, footnote roles, dir=auto,
two chat transcript data attributes; http, https, mailto and
relative URLs only
- gateJournalHtml and isSafeJournalHtml keep their signatures; html is
always the sanitized value and is never blanked
- post body, category content and both page payloads are sanitized;
the blocked notice, its style and string, and the blocked props and
content_blocked field are removed
- toPostView moves to postView.ts so list pages and cards do not load
the sanitizer
- tests cover every bypass from the review, the Data:/metadata: text
and an imported author footer; the SSR smoke expects the unsafe
sample's safe paragraphs
- journal module registers the Journal pages at journal.routes paths
- typed anonymous-GET client, html gate, SSR x-forwarded-for forwarding
- fixture API, built-server SSR smoke and git-tag install check