payload-live-preview 2.0.2 → 2.0.3

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.
Files changed (57) hide show
  1. package/README.md +11 -8
  2. package/dist/adapters/astro/index.js +1 -1
  3. package/dist/adapters/astro/index.js.map +1 -1
  4. package/dist/adapters/astro/middleware-entry.js +1 -1
  5. package/dist/adapters/astro/middleware-entry.js.map +1 -1
  6. package/dist/adapters/nextjs/index.js +1 -1
  7. package/dist/adapters/nextjs/index.js.map +1 -1
  8. package/dist/adapters/nuxt/index.js +1 -1
  9. package/dist/adapters/nuxt/index.js.map +1 -1
  10. package/dist/adapters/sveltekit/index.js +1 -1
  11. package/dist/adapters/sveltekit/index.js.map +1 -1
  12. package/dist/client.cjs +1 -1
  13. package/dist/client.cjs.map +1 -1
  14. package/dist/client.js +1 -1
  15. package/dist/client.js.map +1 -1
  16. package/dist/core.cjs +1 -1
  17. package/dist/core.cjs.map +1 -1
  18. package/dist/core.d.cts +3 -2
  19. package/dist/core.d.ts +3 -2
  20. package/dist/core.js +1 -1
  21. package/dist/core.js.map +1 -1
  22. package/dist/doctor-cli.d.ts +1 -1
  23. package/dist/doctor-cli.js +1 -1
  24. package/dist/doctor-cli.js.map +1 -1
  25. package/dist/doctor.d.ts +2 -2
  26. package/dist/doctor.js +1 -1
  27. package/dist/doctor.js.map +1 -1
  28. package/dist/fragment.cjs.map +1 -1
  29. package/dist/fragment.js.map +1 -1
  30. package/dist/index.cjs +1 -1
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +3 -2
  33. package/dist/index.d.ts +3 -2
  34. package/dist/index.js +1 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/lean.cjs +1 -1
  37. package/dist/lean.cjs.map +1 -1
  38. package/dist/lean.js +1 -1
  39. package/dist/lean.js.map +1 -1
  40. package/dist/lexical.cjs +1 -1
  41. package/dist/lexical.cjs.map +1 -1
  42. package/dist/lexical.js +1 -1
  43. package/dist/lexical.js.map +1 -1
  44. package/dist/plugins.cjs +1 -1
  45. package/dist/plugins.cjs.map +1 -1
  46. package/dist/plugins.js +1 -1
  47. package/dist/plugins.js.map +1 -1
  48. package/dist/{probe-DqaItcwX.d.ts → probe-DX_4wsBu.d.ts} +6 -0
  49. package/dist/server.cjs +1 -1
  50. package/dist/server.cjs.map +1 -1
  51. package/dist/server.js +1 -1
  52. package/dist/server.js.map +1 -1
  53. package/dist/structural.cjs +2 -2
  54. package/dist/structural.cjs.map +1 -1
  55. package/dist/structural.js +2 -2
  56. package/dist/structural.js.map +1 -1
  57. package/package.json +1 -1
package/dist/lexical.js CHANGED
@@ -1,2 +1,2 @@
1
- var e;var t=/* @__PURE__ */new Set(["http:","https:","mailto:","tel:"]),r=/^\s*(?:javascript|data|vbscript|file|blob|about)\s*:/i,n=/^(?:\.{1,2}\/|[a-zA-Z0-9_-]+\/?)/,o=/^[\\/]{2}/,i=/[\t\n\r]/g;function isSafeUrl(e){if("string"!=typeof e)return!1;const a=e.trim().replace(i,"");if(0===a.length)return!1;if(r.test(a))return!1;if(a.startsWith("#")||a.startsWith("?"))return!0;if(o.test(a))return!0;if(a.startsWith("/"))return!0;try{const e=new URL(a);return t.has(e.protocol)}catch{return n.test(a)}}function isExternalHttpUrl(e){const t=e.trim().replace(i,"");return/^https?:\/\//i.test(t)||o.test(t)}var a=/* @__PURE__ */new Set;function l(e){a.has(e)||(a.add(e),function(e){try{console.warn(e)}catch{}}(`[live-preview] LP0409: the strict sanitizer removed \`${e}\` from written markup; the 1.x default (\`sanitizerPolicy: 'compat'\`) kept it. ${function(e){return e.startsWith("data-payload-")?"A binding inside CMS content is refused by design — an editor could otherwise aim a write at any element on the page (docs/security.md)":"id"===e||"name"===e?"CMS content that can name an element can shadow a global of that name — DOM clobbering, refused by design (docs/security.md)":"List it in `allowedDataAttributes` if the page needs it, or set `sanitizerPolicy: 'compat'` to keep every `data-*` as 1.x did"}(e)}.`))}var s=/* @__PURE__ */new Set(["p","br","strong","b","em","i","u","s","strike","mark","small","h1","h2","h3","h4","h5","h6","ul","ol","li","dl","dt","dd","blockquote","code","pre","kbd","samp","var","a","span","div","section","article","aside","header","footer","nav","figure","figcaption","img","picture","source","audio","video","sub","sup","hr","time","abbr","cite","q","table","thead","tbody","tfoot","tr","th","td","caption","colgroup","col"]),c=/* @__PURE__ */new Set(["input","button","textarea","select","option","label"]),u=/* @__PURE__ */new Set(["script","style","iframe","object","embed","link","meta","base","form","input","button","select","textarea","svg","math","template","frame","frameset","noframes","noscript"]),d=/* @__PURE__ */new Set(["id","class","lang","dir","title","role","tabindex"]),p="aria-",f="data-",h={a:/* @__PURE__ */new Set(["href","target","rel","download","hreflang","type"]),img:/* @__PURE__ */new Set(["src","srcset","sizes","alt","width","height","loading","decoding"]),picture:/* @__PURE__ */new Set([]),source:/* @__PURE__ */new Set(["src","srcset","sizes","type","media"]),audio:/* @__PURE__ */new Set(["src","controls","autoplay","loop","muted","preload"]),video:/* @__PURE__ */new Set(["src","poster","controls","autoplay","loop","muted","preload","width","height","playsinline"]),time:/* @__PURE__ */new Set(["datetime"]),abbr:/* @__PURE__ */new Set(["title"]),q:/* @__PURE__ */new Set(["cite"]),blockquote:/* @__PURE__ */new Set(["cite"]),table:/* @__PURE__ */new Set(["summary"]),th:/* @__PURE__ */new Set(["colspan","rowspan","scope","headers","abbr"]),td:/* @__PURE__ */new Set(["colspan","rowspan","headers"]),col:/* @__PURE__ */new Set(["span"]),colgroup:/* @__PURE__ */new Set(["span"]),ol:/* @__PURE__ */new Set(["start","reversed","type"]),li:/* @__PURE__ */new Set(["value"]),code:/* @__PURE__ */new Set(["class"]),pre:/* @__PURE__ */new Set(["class"])},m=/* @__PURE__ */new Set(["href","src","cite","poster"]),g=class extends Error{name="SanitizerEnvironmentError"},b=/* @__PURE__ */new Set(["id","name","data-payload-key","data-payload-nested-key","data-payload-nested-template"]),y=/* @__PURE__ */Symbol.for("payload-live-preview.sanitizer-document");function setSanitizerDocument(e){globalThis[y]=e??void 0}function sanitizeHtml(t,r){return function(t){const r=$();if(!r)throw"undefined"!=typeof __INLINE_BUILD__&&__INLINE_BUILD__?new Error("sanitizeHtml needs a DOM"):new g("sanitizeHtml needs a DOM; provide one with setSanitizerDocument() during SSR.");if(""===t)return"";const n=function(){{const e=/* @__PURE__ */new Map;for(const[t,r]of Object.entries(h))e.set(t,r);return{allowedTags:s,attrByTag:e,allowFormControls:!1,templateMode:!1,mode:"strict",allowedData:/* @__PURE__ */new Set}}}(),o=r.createElement("template");return o.innerHTML=function(t){const r=function(){if(void 0!==e)return e;const t=function(){const e=globalThis.trustedTypes;if("object"==typeof e&&null!==e)return"function"==typeof e.createPolicy?e:void 0}();try{e=void 0===t?null:t.createPolicy("payload-live-preview",{createHTML:e=>e})}catch{e=null}return e}();return null===r?t:r.createHTML(t)}(t),v(o.content,n),o.innerHTML}(t)}function $(){if("undefined"==typeof __INLINE_BUILD__||!__INLINE_BUILD__){const e=globalThis[y];if(e)return e}if("undefined"!=typeof document)return document}function v(e,t){for(const r of Array.from(e.childNodes))1===r.nodeType?w(r,t):8===r.nodeType&&r.remove()}function w(e,t){const r=e.tagName.toLowerCase();if(!u.has(r)||t.allowFormControls&&c.has(r)){if(!t.allowedTags.has(r))return v(e,t),void e.replaceWith(...e.childNodes);!function(e,t,r){const n=r.attrByTag.get(t);for(const t of Array.from(e.attributes)){const o=t.name.toLowerCase();if(o.startsWith("on")||"style"===o)e.removeAttribute(t.name);else{if("strict"===r.mode){if(r.templateMode&&b.has(o))continue;if("id"===o||"name"===o||o.startsWith("data-payload-")){e.removeAttribute(t.name),"name"===o&&!0!==n?.has(o)||l(o);continue}if(o.startsWith(f)){r.allowedData.has(o)||(e.removeAttribute(t.name),l(o));continue}if(d.has(o)||o.startsWith(p))continue}else if(d.has(o)||o.startsWith(p)||o.startsWith(f))continue;n?.has(o)?m.has(o)&&!isSafeUrl(t.value)?e.removeAttribute(t.name):"srcset"!==o||S(t.value)||e.removeAttribute(t.name):e.removeAttribute(t.name)}}}(e,r,t),"a"===r&&function(e){const t=e.getAttribute("href");null!==t&&isExternalHttpUrl(t)&&(e.setAttribute("rel","noopener noreferrer"),e.hasAttribute("target")||e.setAttribute("target","_blank"))}(e),v(e,t)}else e.remove()}function S(e){for(const t of e.split(",")){const e=t.trim();if(0===e.length)continue;const[r=e]=e.split(/\s/,1);if(!isSafeUrl(r))return!1}return!0}var k=Object.freeze({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"}),H=/[&<>"'/`=]/g;function escapeHtml(e){return e.replace(H,e=>k[e])}var T=Object.freeze({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"}),A=/[&<>"']/g;function escapeHtmlAttribute(e){return e.replace(A,e=>T[e])}var _={BOLD:1,ITALIC:2,STRIKETHROUGH:4,UNDERLINE:8,CODE:16,SUBSCRIPT:32,SUPERSCRIPT:64,HIGHLIGHT:128},L={1:"left",2:"center",3:"right",4:"justify"},x=/* @__PURE__ */new Set(["left","center","right","justify","start","end"]);function C(e){const t=e.format;return"string"==typeof t&&x.has(t)?t:"number"==typeof t?L[t]:void 0}function U(e){const t=e.indent;return"number"==typeof t&&t>0?t:0}function I(e){return"rtl"===e.direction?' dir="rtl"':"ltr"===e.direction?' dir="ltr"':""}function z(e){const t=C(e),r=U(e),n=[];return void 0!==t&&n.push(`lp-align-${t}`),r>0&&n.push(`lp-indent-${String(r)}`),0===n.length?"":` class="${n.join(" ")}"`}var E=/* @__PURE__ */new Set(["h1","h2","h3","h4","h5","h6"]);function D(e){return"object"==typeof e&&null!==e?e:void 0}function B(e){return D(e)}function N(e){return e.replace(/[^a-zA-Z0-9_-]/g,"-").toLowerCase()}function j(e){return"string"==typeof e&&e.length>0?e:void 0}var M=' target="_blank" rel="noopener noreferrer"',R=(e,t)=>{const r=t.renderChildren(e.children??[]),n=D(e.fields),o=function(e,t){if("internal"===t?.linkType)return function(e){const t=D(D(e)?.value),r=t?.url;if("string"==typeof r&&r.length>0)return r;const n=t?.slug;return"string"==typeof n&&n.length>0?`/${n}`:void 0}(t.doc);const r=t?.url??e.url;return"string"==typeof r&&r.length>0?r:void 0}(e,n);if(void 0===o||!isSafeUrl(o))return r;const i="string"==typeof e.title?` title="${escapeHtml(e.title)}"`:"";return`<a href="${escapeHtmlAttribute(o)}"${function(e,t,r){if(!0===t?.newTab||isExternalHttpUrl(r))return M;const n="string"==typeof e.target?e.target:"";return""===n?"":"_blank"===n?M:` target="${escapeHtml(n)}"`}(e,n,o)}${i}>${r}</a>`};function W(e){if("string"==typeof e.text)return e.text;if(!e.children)return"";let t="";for(const r of e.children)t+=W(r);return t}function O(e){return`${"number"==typeof e.width?` width="${String(e.width)}"`:""}${"number"==typeof e.height?` height="${String(e.height)}"`:""}`}function P(e){return"string"==typeof e.mimeType?` type="${escapeHtmlAttribute(e.mimeType)}"`:""}var q=/* @__PURE__ */new Map;function G(e,t){q.set(e,t)}function F(e){return q.get(e)}function K(){return[...q.keys()]}function Z(e,t,r,n){const o=D(e.fields)??{},i="string"==typeof o.blockType?o.blockType:"",a=N(i),l=""===a?n:`${n} ${n}--${a}`;if(""!==i){const e=F(i)??F(a);if(e)return e(o,{renderChildren:t.renderChildren});t.onUnrenderedBlock?.(i,l)}return`<${r} class="${l}"></${r}>`}function J(e,t){return"number"==typeof t&&t>1?` ${e}="${String(t)}"`:""}var Q={text:e=>{let t=escapeHtml("string"==typeof e.text?e.text:"");const r="number"==typeof e.format?e.format:0;return 0!==(r&_.CODE)&&(t=`<code>${t}</code>`),0!==(r&_.BOLD)&&(t=`<strong>${t}</strong>`),0!==(r&_.ITALIC)&&(t=`<em>${t}</em>`),0!==(r&_.UNDERLINE)&&(t=`<u>${t}</u>`),0!==(r&_.STRIKETHROUGH)&&(t=`<s>${t}</s>`),0!==(r&_.SUBSCRIPT)&&(t=`<sub>${t}</sub>`),0!==(r&_.SUPERSCRIPT)&&(t=`<sup>${t}</sup>`),0!==(r&_.HIGHLIGHT)&&(t=`<mark>${t}</mark>`),t},paragraph:(e,t)=>{const r=t.renderChildren(e.children??[]);return`<p${I(e)}${z(e)}>${r}</p>`},heading:(e,t)=>{const r="string"==typeof e.tag?e.tag.toLowerCase():"h2",n=E.has(r)?r:"h2",o=t.renderChildren(e.children??[]);return`<${n}${I(e)}${z(e)}>${o}</${n}>`},list:(e,t)=>{const r="string"==typeof e.listType?e.listType:"bullet",n="number"===r?"ol":"ul",o="number"===r&&"number"==typeof e.start&&e.start>1?` start="${String(e.start)}"`:"",i="check"===r?' role="list"':"",a=t.renderChildren(e.children??[]);return`<${n}${I(e)}${z(e)}${o}${i}>${a}</${n}>`},listitem:(e,t)=>{const r=t.renderChildren(e.children??[]);if("boolean"==typeof e.checked)return`<li role="checkbox" aria-checked="${e.checked?"true":"false"}"${z(e)}>${r}</li>`;const n="number"==typeof e.value?` value="${escapeHtml(String(e.value))}"`:"";return`<li${I(e)}${z(e)}${n}>${r}</li>`},link:R,autolink:R,quote:(e,t)=>{const r=t.renderChildren(e.children??[]);return`<blockquote${I(e)}${z(e)}>${r}</blockquote>`},code:e=>{const t=N("string"==typeof e.language?e.language:"");return`<pre><code${""===t?"":` class="language-${t}"`}>${escapeHtml(W(e))}</code></pre>`},"code-highlight":e=>{const t="string"==typeof e.text?e.text:"";return`<span${"string"==typeof e.highlightType?` class="token-${N(e.highlightType)}"`:""}>${escapeHtml(t)}</span>`},linebreak:()=>"<br>",horizontalrule:()=>"<hr>",tab:()=>"\t",upload:e=>{const t=B(e.value);if(void 0===t)return"";const r=t.url;if("string"!=typeof r||!isSafeUrl(r))return"";const n="string"==typeof t.mimeType?t.mimeType:"";return n.startsWith("video/")?function(e,t){return`<video controls${O(e)}><source src="${escapeHtmlAttribute(t)}"${P(e)}></video>`}(t,r):n.startsWith("audio/")?function(e,t){return`<audio controls><source src="${escapeHtmlAttribute(t)}"${P(e)}></audio>`}(t,r):""===n||n.startsWith("image/")?function(e,t){const r="string"==typeof e.alt?escapeHtml(e.alt):"";return`<img src="${escapeHtmlAttribute(t)}" alt="${r}"${O(e)} loading="lazy" decoding="async">`}(t,r):function(e,t){const r="string"==typeof e.filename?escapeHtml(e.filename):escapeHtml(t);return`<a href="${escapeHtmlAttribute(t)}" target="_blank" rel="noopener noreferrer">${r}</a>`}(t,r)},relationship:e=>{const t="string"==typeof e.relationTo?e.relationTo:"",r=D(e.value),n=escapeHtml((r&&function(e){const t=j(e.title)??j(e.name)??j(e.slug);return void 0!==t?t:void 0===e.id?void 0:String(e.id)}(r))??`#${t}`),o=N(t),i=""===o?' class="lp-relation"':` class="lp-relation lp-relation--${o}"`,a=r?.url;return"string"==typeof a&&isSafeUrl(a)?`<a href="${escapeHtmlAttribute(a)}"${i}>${n}</a>`:`<span${i}>${n}</span>`},block:(e,t)=>Z(e,t,"div","lp-block"),inlineBlock:(e,t)=>Z(e,t,"span","lp-inline-block"),table:(e,t)=>`<table${I(e)}><tbody>${t.renderChildren(e.children??[])}</tbody></table>`,tablerow:(e,t)=>`<tr>${t.renderChildren(e.children??[])}</tr>`,tablecell:(e,t)=>{const r="number"==typeof e.headerState?e.headerState:0,n=3&r?"th":"td";return`<${n}${1===r?' scope="col"':2===r?' scope="row"':""}${J("colspan",e.colSpan)}${J("rowspan",e.rowSpan)}>${t.renderChildren(e.children??[])}</${n}>`}},V=/* @__PURE__ */new Map;function X(e,t){V.set(e,t)}function Y(e){return V.get(e)??Q[e]}var ee=!1;function te(e){if("object"!=typeof e||null===e)return!1;if(!("root"in e))return!1;const t=e.root;return"object"==typeof t&&null!==t&&"children"in t&&Array.isArray(t.children)}function re(e,t={}){if(!te(e))return"";const r=function(e){const t={renderChildren:e=>{let r="";for(const n of e)r+=oe(n,t);return r},resolveAlignment:C,resolveIndent:U,onUnrenderedBlock:e};return t}(t.onUnrenderedBlock).renderChildren(e.root.children);return!1===t.sanitize?r:void 0!==$()?sanitizeHtml(r):(function(){if(!ee){ee=!0;try{console.warn('[live-preview] lexicalToHtml() has no sanitizer document and returned unsanitised HTML; call setSanitizerDocument() (linkedom/jsdom) for server rendering, see "HTML sanitization" in docs/security.md.')}catch{}}}(),r)}function ne(e){return te(e)?e.root.children.map(ie).join("\n").trim():""}function oe(e,t){const r=Y(e.type);return r?r(e,t):void 0!==e.children?t.renderChildren(e.children):""}function ie(e){if("string"==typeof e.text)return e.text;if("linebreak"===e.type)return"\n";if(void 0===e.children)return"";let t="";for(const r of e.children)t+=ie(r);return t}function ae(e,t){const r=e[t];return"string"==typeof r&&r.length>0?r:void 0}function le(e,t){const r=ae(e,t);return void 0!==r&&isSafeUrl(r)?r:void 0}function se(e){const t=ae(e,"caption");return void 0!==t?`<figcaption>${escapeHtml(t)}</figcaption>`:""}var ce=(e,t)=>{const r=N(ae(e,"importance")??"info"),n=ae(e,"title"),o=ae(e,"text"),i=function(e){const t=e.body??e.content;if("object"!=typeof t||null===t)return;const r=t.root;return r&&Array.isArray(r.children)?r.children:void 0}(e);return`<aside class="lp-block-callout lp-block-callout--${r}">${void 0!==n?`<strong>${escapeHtml(n)}</strong>`:""}${void 0!==i?t.renderChildren(i):void 0!==o?`<p>${escapeHtml(o)}</p>`:""}</aside>`},ue=e=>{const t=B(e.image),r=t?.url??le(e,"imageUrl");if(void 0===r||!isSafeUrl(r))return"";const n=t?.alt??ae(e,"alt")??"";return`<figure class="lp-block-image"><img src="${escapeHtmlAttribute(r)}" alt="${escapeHtmlAttribute(n)}"${function(e){return`${"number"==typeof e?.width?` width="${String(e.width)}"`:""}${"number"==typeof e?.height?` height="${String(e.height)}"`:""}`}(t)} loading="lazy" decoding="async">${se(e)}</figure>`},de=e=>{const t=B(e.video),r=t?.url??le(e,"videoUrl");if(void 0===r||!isSafeUrl(r))return"";const n=t?.mimeType??ae(e,"mimeType"),o=void 0!==n?` type="${escapeHtmlAttribute(n)}"`:"",i=le(e,"poster");return`<figure class="lp-block-video"><video controls${void 0!==i?` poster="${escapeHtmlAttribute(i)}"`:""}><source src="${escapeHtmlAttribute(r)}"${o}></video>${se(e)}</figure>`},pe=e=>{const t=ae(e,"code")??ae(e,"content");if(void 0===t)return"";const r=N(ae(e,"language")??""),n=""===r?"":` class="language-${r}"`;return`<figure class="lp-block-code">${se(e)}<pre><code${n}>${escapeHtml(t)}</code></pre></figure>`},fe=e=>{const t=ae(e,"label")??ae(e,"text"),r=le(e,"href")??le(e,"url");if(void 0===t||void 0===r)return"";const n=ae(e,"lead"),o=void 0!==n?`<p class="lp-block-cta__lead">${escapeHtml(n)}</p>`:"",i=[he(t,r,!0)],a=ae(e,"secondaryLabel"),l=le(e,"secondaryHref");return void 0!==a&&void 0!==l&&i.push(he(a,l,!1)),`<div class="lp-block-cta">${o}<div class="lp-block-cta__actions">${i.join("")}</div></div>`};function he(e,t,r){const n=isExternalHttpUrl(t)?' target="_blank" rel="noopener noreferrer"':"";return`<a class="lp-block-cta__button lp-block-cta__button--${r?"primary":"secondary"}" href="${escapeHtmlAttribute(t)}"${n}>${escapeHtml(e)}</a>`}function me(){G("callout",ce),G("image-block",ue),G("imageBlock",ue),G("image",ue),G("video-block",de),G("videoBlock",de),G("video",de),G("code-block",pe),G("codeBlock",pe),G("code",pe),G("cta-block",fe),G("ctaBlock",fe),G("cta",fe)}export{_ as TextFormat,te as isLexicalContent,re as lexicalToHtml,ne as lexicalToPlainText,F as lookupBlockRenderer,Y as lookupLexicalNode,G as registerBlockRenderer,me as registerDefaultBlocks,X as registerLexicalNode,K as registeredBlockTypes,setSanitizerDocument};
1
+ var e=/* @__PURE__ */Symbol.for("payload-live-preview.trusted-types");var t=/* @__PURE__ */new Set(["http:","https:","mailto:","tel:"]),r=/^\s*(?:javascript|data|vbscript|file|blob|about)\s*:/i,n=/^(?:\.{1,2}\/|[a-zA-Z0-9_-]+\/?)/,o=/^[\\/]{2}/,i=/[\t\n\r]/g;function isSafeUrl(e){if("string"!=typeof e)return!1;const a=e.trim().replace(i,"");if(0===a.length)return!1;if(r.test(a))return!1;if(a.startsWith("#")||a.startsWith("?"))return!0;if(o.test(a))return!0;if(a.startsWith("/"))return!0;try{const e=new URL(a);return t.has(e.protocol)}catch{return n.test(a)}}function isExternalHttpUrl(e){const t=e.trim().replace(i,"");return/^https?:\/\//i.test(t)||o.test(t)}var a=/* @__PURE__ */new Set;function l(e){a.has(e)||(a.add(e),function(e){try{console.warn(e)}catch{}}(`[live-preview] LP0409: the strict sanitizer removed \`${e}\` from written markup; the 1.x default (\`sanitizerPolicy: 'compat'\`) kept it. ${function(e){return e.startsWith("data-payload-")?"A binding inside CMS content is refused by design — an editor could otherwise aim a write at any element on the page (docs/security.md)":"id"===e||"name"===e?"CMS content that can name an element can shadow a global of that name — DOM clobbering, refused by design (docs/security.md)":"List it in `allowedDataAttributes` if the page needs it, or set `sanitizerPolicy: 'compat'` to keep every `data-*` as 1.x did"}(e)}.`))}var s=/* @__PURE__ */new Set(["p","br","strong","b","em","i","u","s","strike","mark","small","h1","h2","h3","h4","h5","h6","ul","ol","li","dl","dt","dd","blockquote","code","pre","kbd","samp","var","a","span","div","section","article","aside","header","footer","nav","figure","figcaption","img","picture","source","audio","video","sub","sup","hr","time","abbr","cite","q","table","thead","tbody","tfoot","tr","th","td","caption","colgroup","col"]),c=/* @__PURE__ */new Set(["input","button","textarea","select","option","label"]),u=/* @__PURE__ */new Set(["script","style","iframe","object","embed","link","meta","base","form","input","button","select","textarea","svg","math","template","frame","frameset","noframes","noscript"]),d=/* @__PURE__ */new Set(["id","class","lang","dir","title","role","tabindex"]),p="aria-",f="data-",h={a:/* @__PURE__ */new Set(["href","target","rel","download","hreflang","type"]),img:/* @__PURE__ */new Set(["src","srcset","sizes","alt","width","height","loading","decoding"]),picture:/* @__PURE__ */new Set([]),source:/* @__PURE__ */new Set(["src","srcset","sizes","type","media"]),audio:/* @__PURE__ */new Set(["src","controls","autoplay","loop","muted","preload"]),video:/* @__PURE__ */new Set(["src","poster","controls","autoplay","loop","muted","preload","width","height","playsinline"]),time:/* @__PURE__ */new Set(["datetime"]),abbr:/* @__PURE__ */new Set(["title"]),q:/* @__PURE__ */new Set(["cite"]),blockquote:/* @__PURE__ */new Set(["cite"]),table:/* @__PURE__ */new Set(["summary"]),th:/* @__PURE__ */new Set(["colspan","rowspan","scope","headers","abbr"]),td:/* @__PURE__ */new Set(["colspan","rowspan","headers"]),col:/* @__PURE__ */new Set(["span"]),colgroup:/* @__PURE__ */new Set(["span"]),ol:/* @__PURE__ */new Set(["start","reversed","type"]),li:/* @__PURE__ */new Set(["value"]),code:/* @__PURE__ */new Set(["class"]),pre:/* @__PURE__ */new Set(["class"])},m=/* @__PURE__ */new Set(["href","src","cite","poster"]),g=class extends Error{name="SanitizerEnvironmentError"},b=/* @__PURE__ */new Set(["id","name","data-payload-key","data-payload-nested-key","data-payload-nested-template"]),y=/* @__PURE__ */Symbol.for("payload-live-preview.sanitizer-document");function setSanitizerDocument(e){globalThis[y]=e??void 0}function sanitizeHtml(t,r){return function(t){const r=$();if(!r)throw"undefined"!=typeof __INLINE_BUILD__&&__INLINE_BUILD__?new Error("sanitizeHtml needs a DOM"):new g("sanitizeHtml needs a DOM; provide one with setSanitizerDocument() during SSR.");if(""===t)return"";const n=function(){{const e=/* @__PURE__ */new Map;for(const[t,r]of Object.entries(h))e.set(t,r);return{allowedTags:s,attrByTag:e,allowFormControls:!1,templateMode:!1,mode:"strict",allowedData:/* @__PURE__ */new Set}}}(),o=r.createElement("template");return o.innerHTML=function(t){const r=function(){const t=function(){const t=globalThis,r=t[e];if(void 0!==r)return r;const n={};return t[e]=n,n}();if(void 0!==t.override)return t.override;if(void 0!==t.auto)return t.auto;const r=function(){const e=globalThis.trustedTypes;if("object"==typeof e&&null!==e)return"function"==typeof e.createPolicy?e:void 0}();try{t.auto=void 0===r?null:r.createPolicy("payload-live-preview",{createHTML:e=>e})}catch{t.auto=null}return t.auto}();return null===r?t:r.createHTML(t)}(t),v(o.content,n),o.innerHTML}(t)}function $(){if("undefined"==typeof __INLINE_BUILD__||!__INLINE_BUILD__){const e=globalThis[y];if(e)return e}if("undefined"!=typeof document)return document}function v(e,t){for(const r of Array.from(e.childNodes))1===r.nodeType?w(r,t):8===r.nodeType&&r.remove()}function w(e,t){const r=e.tagName.toLowerCase();if(!u.has(r)||t.allowFormControls&&c.has(r)){if(!t.allowedTags.has(r))return v(e,t),void e.replaceWith(...e.childNodes);!function(e,t,r){const n=r.attrByTag.get(t);for(const t of Array.from(e.attributes)){const o=t.name.toLowerCase();if(o.startsWith("on")||"style"===o)e.removeAttribute(t.name);else{if("strict"===r.mode){if(r.templateMode&&b.has(o))continue;if("id"===o||"name"===o||o.startsWith("data-payload-")){e.removeAttribute(t.name),"name"===o&&!0!==n?.has(o)||l(o);continue}if(o.startsWith(f)){r.allowedData.has(o)||(e.removeAttribute(t.name),l(o));continue}if(d.has(o)||o.startsWith(p))continue}else if(d.has(o)||o.startsWith(p)||o.startsWith(f))continue;n?.has(o)?m.has(o)&&!isSafeUrl(t.value)?e.removeAttribute(t.name):"srcset"!==o||S(t.value)||e.removeAttribute(t.name):e.removeAttribute(t.name)}}}(e,r,t),"a"===r&&function(e){const t=e.getAttribute("href");null!==t&&isExternalHttpUrl(t)&&(e.setAttribute("rel","noopener noreferrer"),e.hasAttribute("target")||e.setAttribute("target","_blank"))}(e),v(e,t)}else e.remove()}function S(e){for(const t of e.split(",")){const e=t.trim();if(0===e.length)continue;const[r=e]=e.split(/\s/,1);if(!isSafeUrl(r))return!1}return!0}var k=Object.freeze({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"}),H=/[&<>"'/`=]/g;function escapeHtml(e){return e.replace(H,e=>k[e])}var T=Object.freeze({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"}),A=/[&<>"']/g;function escapeHtmlAttribute(e){return e.replace(A,e=>T[e])}var _={BOLD:1,ITALIC:2,STRIKETHROUGH:4,UNDERLINE:8,CODE:16,SUBSCRIPT:32,SUPERSCRIPT:64,HIGHLIGHT:128},L={1:"left",2:"center",3:"right",4:"justify"},x=/* @__PURE__ */new Set(["left","center","right","justify","start","end"]);function C(e){const t=e.format;return"string"==typeof t&&x.has(t)?t:"number"==typeof t?L[t]:void 0}function U(e){const t=e.indent;return"number"==typeof t&&t>0?t:0}function I(e){return"rtl"===e.direction?' dir="rtl"':"ltr"===e.direction?' dir="ltr"':""}function z(e){const t=C(e),r=U(e),n=[];return void 0!==t&&n.push(`lp-align-${t}`),r>0&&n.push(`lp-indent-${String(r)}`),0===n.length?"":` class="${n.join(" ")}"`}var E=/* @__PURE__ */new Set(["h1","h2","h3","h4","h5","h6"]);function D(e){return"object"==typeof e&&null!==e?e:void 0}function B(e){return D(e)}function N(e){return e.replace(/[^a-zA-Z0-9_-]/g,"-").toLowerCase()}function j(e){return"string"==typeof e&&e.length>0?e:void 0}var M=' target="_blank" rel="noopener noreferrer"',R=(e,t)=>{const r=t.renderChildren(e.children??[]),n=D(e.fields),o=function(e,t){if("internal"===t?.linkType)return function(e){const t=D(D(e)?.value),r=t?.url;if("string"==typeof r&&r.length>0)return r;const n=t?.slug;return"string"==typeof n&&n.length>0?`/${n}`:void 0}(t.doc);const r=t?.url??e.url;return"string"==typeof r&&r.length>0?r:void 0}(e,n);if(void 0===o||!isSafeUrl(o))return r;const i="string"==typeof e.title?` title="${escapeHtml(e.title)}"`:"";return`<a href="${escapeHtmlAttribute(o)}"${function(e,t,r){if(!0===t?.newTab||isExternalHttpUrl(r))return M;const n="string"==typeof e.target?e.target:"";return""===n?"":"_blank"===n?M:` target="${escapeHtml(n)}"`}(e,n,o)}${i}>${r}</a>`};function W(e){if("string"==typeof e.text)return e.text;if(!e.children)return"";let t="";for(const r of e.children)t+=W(r);return t}function O(e){return`${"number"==typeof e.width?` width="${String(e.width)}"`:""}${"number"==typeof e.height?` height="${String(e.height)}"`:""}`}function P(e){return"string"==typeof e.mimeType?` type="${escapeHtmlAttribute(e.mimeType)}"`:""}var q=/* @__PURE__ */new Map;function G(e,t){q.set(e,t)}function F(e){return q.get(e)}function K(){return[...q.keys()]}function Z(e,t,r,n){const o=D(e.fields)??{},i="string"==typeof o.blockType?o.blockType:"",a=N(i),l=""===a?n:`${n} ${n}--${a}`;if(""!==i){const e=F(i)??F(a);if(e)return e(o,{renderChildren:t.renderChildren});t.onUnrenderedBlock?.(i,l)}return`<${r} class="${l}"></${r}>`}function J(e,t){return"number"==typeof t&&t>1?` ${e}="${String(t)}"`:""}var Q={text:e=>{let t=escapeHtml("string"==typeof e.text?e.text:"");const r="number"==typeof e.format?e.format:0;return 0!==(r&_.CODE)&&(t=`<code>${t}</code>`),0!==(r&_.BOLD)&&(t=`<strong>${t}</strong>`),0!==(r&_.ITALIC)&&(t=`<em>${t}</em>`),0!==(r&_.UNDERLINE)&&(t=`<u>${t}</u>`),0!==(r&_.STRIKETHROUGH)&&(t=`<s>${t}</s>`),0!==(r&_.SUBSCRIPT)&&(t=`<sub>${t}</sub>`),0!==(r&_.SUPERSCRIPT)&&(t=`<sup>${t}</sup>`),0!==(r&_.HIGHLIGHT)&&(t=`<mark>${t}</mark>`),t},paragraph:(e,t)=>{const r=t.renderChildren(e.children??[]);return`<p${I(e)}${z(e)}>${r}</p>`},heading:(e,t)=>{const r="string"==typeof e.tag?e.tag.toLowerCase():"h2",n=E.has(r)?r:"h2",o=t.renderChildren(e.children??[]);return`<${n}${I(e)}${z(e)}>${o}</${n}>`},list:(e,t)=>{const r="string"==typeof e.listType?e.listType:"bullet",n="number"===r?"ol":"ul",o="number"===r&&"number"==typeof e.start&&e.start>1?` start="${String(e.start)}"`:"",i="check"===r?' role="list"':"",a=t.renderChildren(e.children??[]);return`<${n}${I(e)}${z(e)}${o}${i}>${a}</${n}>`},listitem:(e,t)=>{const r=t.renderChildren(e.children??[]);if("boolean"==typeof e.checked)return`<li role="checkbox" aria-checked="${e.checked?"true":"false"}"${z(e)}>${r}</li>`;const n="number"==typeof e.value?` value="${escapeHtml(String(e.value))}"`:"";return`<li${I(e)}${z(e)}${n}>${r}</li>`},link:R,autolink:R,quote:(e,t)=>{const r=t.renderChildren(e.children??[]);return`<blockquote${I(e)}${z(e)}>${r}</blockquote>`},code:e=>{const t=N("string"==typeof e.language?e.language:"");return`<pre><code${""===t?"":` class="language-${t}"`}>${escapeHtml(W(e))}</code></pre>`},"code-highlight":e=>{const t="string"==typeof e.text?e.text:"";return`<span${"string"==typeof e.highlightType?` class="token-${N(e.highlightType)}"`:""}>${escapeHtml(t)}</span>`},linebreak:()=>"<br>",horizontalrule:()=>"<hr>",tab:()=>"\t",upload:e=>{const t=B(e.value);if(void 0===t)return"";const r=t.url;if("string"!=typeof r||!isSafeUrl(r))return"";const n="string"==typeof t.mimeType?t.mimeType:"";return n.startsWith("video/")?function(e,t){return`<video controls${O(e)}><source src="${escapeHtmlAttribute(t)}"${P(e)}></video>`}(t,r):n.startsWith("audio/")?function(e,t){return`<audio controls><source src="${escapeHtmlAttribute(t)}"${P(e)}></audio>`}(t,r):""===n||n.startsWith("image/")?function(e,t){const r="string"==typeof e.alt?escapeHtml(e.alt):"";return`<img src="${escapeHtmlAttribute(t)}" alt="${r}"${O(e)} loading="lazy" decoding="async">`}(t,r):function(e,t){const r="string"==typeof e.filename?escapeHtml(e.filename):escapeHtml(t);return`<a href="${escapeHtmlAttribute(t)}" target="_blank" rel="noopener noreferrer">${r}</a>`}(t,r)},relationship:e=>{const t="string"==typeof e.relationTo?e.relationTo:"",r=D(e.value),n=escapeHtml((r&&function(e){const t=j(e.title)??j(e.name)??j(e.slug);return void 0!==t?t:void 0===e.id?void 0:String(e.id)}(r))??`#${t}`),o=N(t),i=""===o?' class="lp-relation"':` class="lp-relation lp-relation--${o}"`,a=r?.url;return"string"==typeof a&&isSafeUrl(a)?`<a href="${escapeHtmlAttribute(a)}"${i}>${n}</a>`:`<span${i}>${n}</span>`},block:(e,t)=>Z(e,t,"div","lp-block"),inlineBlock:(e,t)=>Z(e,t,"span","lp-inline-block"),table:(e,t)=>`<table${I(e)}><tbody>${t.renderChildren(e.children??[])}</tbody></table>`,tablerow:(e,t)=>`<tr>${t.renderChildren(e.children??[])}</tr>`,tablecell:(e,t)=>{const r="number"==typeof e.headerState?e.headerState:0,n=3&r?"th":"td";return`<${n}${1===r?' scope="col"':2===r?' scope="row"':""}${J("colspan",e.colSpan)}${J("rowspan",e.rowSpan)}>${t.renderChildren(e.children??[])}</${n}>`}},V=/* @__PURE__ */new Map;function X(e,t){V.set(e,t)}function Y(e){return V.get(e)??Q[e]}var ee=!1;function te(e){if("object"!=typeof e||null===e)return!1;if(!("root"in e))return!1;const t=e.root;return"object"==typeof t&&null!==t&&"children"in t&&Array.isArray(t.children)}function re(e,t={}){if(!te(e))return"";const r=function(e){const t={renderChildren:e=>{let r="";for(const n of e)r+=oe(n,t);return r},resolveAlignment:C,resolveIndent:U,onUnrenderedBlock:e};return t}(t.onUnrenderedBlock).renderChildren(e.root.children);return!1===t.sanitize?r:void 0!==$()?sanitizeHtml(r):(function(){if(!ee){ee=!0;try{console.warn('[live-preview] lexicalToHtml() has no sanitizer document and returned unsanitised HTML; call setSanitizerDocument() (linkedom/jsdom) for server rendering, see "HTML sanitization" in docs/security.md.')}catch{}}}(),r)}function ne(e){return te(e)?e.root.children.map(ie).join("\n").trim():""}function oe(e,t){const r=Y(e.type);return r?r(e,t):void 0!==e.children?t.renderChildren(e.children):""}function ie(e){if("string"==typeof e.text)return e.text;if("linebreak"===e.type)return"\n";if(void 0===e.children)return"";let t="";for(const r of e.children)t+=ie(r);return t}function ae(e,t){const r=e[t];return"string"==typeof r&&r.length>0?r:void 0}function le(e,t){const r=ae(e,t);return void 0!==r&&isSafeUrl(r)?r:void 0}function se(e){const t=ae(e,"caption");return void 0!==t?`<figcaption>${escapeHtml(t)}</figcaption>`:""}var ce=(e,t)=>{const r=N(ae(e,"importance")??"info"),n=ae(e,"title"),o=ae(e,"text"),i=function(e){const t=e.body??e.content;if("object"!=typeof t||null===t)return;const r=t.root;return r&&Array.isArray(r.children)?r.children:void 0}(e);return`<aside class="lp-block-callout lp-block-callout--${r}">${void 0!==n?`<strong>${escapeHtml(n)}</strong>`:""}${void 0!==i?t.renderChildren(i):void 0!==o?`<p>${escapeHtml(o)}</p>`:""}</aside>`},ue=e=>{const t=B(e.image),r=t?.url??le(e,"imageUrl");if(void 0===r||!isSafeUrl(r))return"";const n=t?.alt??ae(e,"alt")??"";return`<figure class="lp-block-image"><img src="${escapeHtmlAttribute(r)}" alt="${escapeHtmlAttribute(n)}"${function(e){return`${"number"==typeof e?.width?` width="${String(e.width)}"`:""}${"number"==typeof e?.height?` height="${String(e.height)}"`:""}`}(t)} loading="lazy" decoding="async">${se(e)}</figure>`},de=e=>{const t=B(e.video),r=t?.url??le(e,"videoUrl");if(void 0===r||!isSafeUrl(r))return"";const n=t?.mimeType??ae(e,"mimeType"),o=void 0!==n?` type="${escapeHtmlAttribute(n)}"`:"",i=le(e,"poster");return`<figure class="lp-block-video"><video controls${void 0!==i?` poster="${escapeHtmlAttribute(i)}"`:""}><source src="${escapeHtmlAttribute(r)}"${o}></video>${se(e)}</figure>`},pe=e=>{const t=ae(e,"code")??ae(e,"content");if(void 0===t)return"";const r=N(ae(e,"language")??""),n=""===r?"":` class="language-${r}"`;return`<figure class="lp-block-code">${se(e)}<pre><code${n}>${escapeHtml(t)}</code></pre></figure>`},fe=e=>{const t=ae(e,"label")??ae(e,"text"),r=le(e,"href")??le(e,"url");if(void 0===t||void 0===r)return"";const n=ae(e,"lead"),o=void 0!==n?`<p class="lp-block-cta__lead">${escapeHtml(n)}</p>`:"",i=[he(t,r,!0)],a=ae(e,"secondaryLabel"),l=le(e,"secondaryHref");return void 0!==a&&void 0!==l&&i.push(he(a,l,!1)),`<div class="lp-block-cta">${o}<div class="lp-block-cta__actions">${i.join("")}</div></div>`};function he(e,t,r){const n=isExternalHttpUrl(t)?' target="_blank" rel="noopener noreferrer"':"";return`<a class="lp-block-cta__button lp-block-cta__button--${r?"primary":"secondary"}" href="${escapeHtmlAttribute(t)}"${n}>${escapeHtml(e)}</a>`}function me(){G("callout",ce),G("image-block",ue),G("imageBlock",ue),G("image",ue),G("video-block",de),G("videoBlock",de),G("video",de),G("code-block",pe),G("codeBlock",pe),G("code",pe),G("cta-block",fe),G("ctaBlock",fe),G("cta",fe)}export{_ as TextFormat,te as isLexicalContent,re as lexicalToHtml,ne as lexicalToPlainText,F as lookupBlockRenderer,Y as lookupLexicalNode,G as registerBlockRenderer,me as registerDefaultBlocks,X as registerLexicalNode,K as registeredBlockTypes,setSanitizerDocument};
2
2
  //# sourceMappingURL=lexical.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lexical.js","names":["autoPolicy","SAFE_PROTOCOLS","Set","DANGEROUS_PROTOCOL_PATTERN","RELATIVE_PATH","PROTOCOL_RELATIVE","PARSER_IGNORED","isSafeUrl","url","trimmed","trim","replace","length","test","startsWith","parsed","URL","has","protocol","isExternalHttpUrl","reported","reportDroppedAttribute","name","add","message","console","warn","reason","ALLOWED_TAGS","FORM_CONTROLS","REMOVE_COMPLETELY","ATTR_GLOBAL","ATTR_ARIA_PREFIX","ATTR_DATA_PREFIX","ATTR_BY_TAG","a","img","picture","source","audio","video","time","abbr","q","blockquote","table","th","td","col","colgroup","ol","li","code","pre","URL_ATTRIBUTES","SanitizerEnvironmentError","Error","TEMPLATE_ATTRIBUTES","DOCUMENT_SLOT","Symbol","for","setSanitizerDocument","doc","globalThis","sanitizeHtml","html","options","resolveDocument","__INLINE_BUILD__","resolved","attrMap","Map","tag","attrs","Object","entries","set","allowedTags","attrByTag","allowFormControls","templateMode","mode","allowedData","resolvePolicy","template","createElement","innerHTML","policy","api","candidate","trustedTypes","createPolicy","factory","createHTML","input","trustedHtml","sanitizeFragment","content","sanitizeHtmlWithPolicy","override","document","node","child","Array","from","childNodes","nodeType","sanitizeElement","remove","element","tagName","toLowerCase","replaceWith","tagAttrs","get","attr","attributes","removeAttribute","value","isSafeSrcset","sanitizeAttributes","anchor","href","getAttribute","setAttribute","hasAttribute","hardenAnchor","split","HTML_ESCAPES","freeze","HTML_ESCAPE_PATTERN","escapeHtml","text","char","ATTR_ESCAPES","ATTR_ESCAPE_PATTERN","escapeHtmlAttribute","TextFormat","BOLD","ITALIC","STRIKETHROUGH","UNDERLINE","CODE","SUBSCRIPT","SUPERSCRIPT","HIGHLIGHT","ALIGNMENT_NUMERIC","ALIGNMENT_STRING","resolveAlignment","fmt","format","resolveIndent","indent","dirAttribute","direction","layoutClassAttribute","align","classes","push","String","join","VALID_TAGS","asRecord","readMedia","sanitizeIdent","nonEmpty","BLANK_TARGET","linkRenderer","ctx","children","renderChildren","fields","slug","internalUrl","resolveUrl","titleAttr","target","targetAttribute","extractText","out","dimensionAttributes","width","height","typeAttribute","mimeType","registry","registerBlockRenderer","blockType","renderer","lookupBlockRenderer","registeredBlockTypes","keys","renderBlockNode","baseClass","custom","onUnrenderedBlock","spanAttribute","BUILTIN_NODE_RENDERERS","paragraph","heading","tagRaw","list","listType","startAttr","checkAttr","listitem","valueAttr","link","autolink","quote","language","linebreak","horizontalrule","tab","upload","mime","renderVideo","renderAudio","alt","renderImage","label","filename","renderFallbackLink","relationship","relationTo","title","id","pickRelationLabel","classAttr","block","inlineBlock","tablerow","tablecell","header","register","type","lookup","warnedNoSanitizer","isLexicalContent","root","isArray","lexicalToHtml","context","renderNode","createContext","sanitize","warnNoSanitizerOnce","lexicalToPlainText","map","extractPlainText","str","key","safeUrlOrUndefined","raw","captionHtml","caption","calloutRenderer","importance","richText","body","readLexicalChildren","imageBlockRenderer","media","videoBlockRenderer","typeAttr","poster","codeBlockRenderer","langClass","ctaBlockRenderer","lead","leadHtml","buttons","renderCtaAnchor","secondaryLabel","secondaryHref","primary","targetAttr","registerDefaultBlocks"],"sources":["../src/security/trusted-types.ts","../src/security/url-validator.ts","../src/security/sanitizer-report.ts","../src/security/sanitizer.ts","../src/security/escape.ts","../src/lexical/types.ts","../src/lexical/utils.ts","../src/lexical/nodes/paragraph.ts","../src/lexical/nodes/heading.ts","../src/lexical/value-shapes.ts","../src/lexical/nodes/link.ts","../src/lexical/nodes/code.ts","../src/lexical/nodes/upload.ts","../src/lexical/nodes/relationship.ts","../src/lexical/blocks/registry.ts","../src/lexical/nodes/block.ts","../src/lexical/nodes/table.ts","../src/lexical/nodes/builtin.ts","../src/lexical/nodes/text.ts","../src/lexical/nodes/list.ts","../src/lexical/nodes/quote.ts","../src/lexical/nodes/linebreak.ts","../src/lexical/registry.ts","../src/lexical/render.ts","../src/lexical/blocks/defaults.ts"],"sourcesContent":["/**\n * Trusted Types: every HTML sink routes through one policy, `payload-live-preview`,\n * whose `createHTML` is the identity — what reaches a sink is already sanitized\n * or escaped. Without the API, strings pass through untouched.\n */\n\n/** The subset of the Trusted Types API this module needs. */\nexport interface TrustedHtmlPolicyLike {\n createHTML(input: string): unknown;\n}\n\ninterface TrustedTypesFactoryLike {\n createPolicy(\n name: string,\n rules: { createHTML: (input: string) => string },\n ): TrustedHtmlPolicyLike;\n}\n\n/** @internal */\nexport const TRUSTED_TYPES_POLICY_NAME = 'payload-live-preview';\n\nlet policyOverride: TrustedHtmlPolicyLike | null | undefined;\nlet autoPolicy: TrustedHtmlPolicyLike | null | undefined;\n\n/**\n * Use `policy` for every sink, `null` to assign plain strings, `undefined` to\n * return to the auto-created package policy.\n */\nexport function setTrustedTypesPolicy(policy: TrustedHtmlPolicyLike | null | undefined): void {\n policyOverride = policy;\n}\n\nfunction factory(): TrustedTypesFactoryLike | undefined {\n const candidate = (globalThis as { trustedTypes?: unknown }).trustedTypes;\n if (typeof candidate !== 'object' || candidate === null) return undefined;\n const create = (candidate as { createPolicy?: unknown }).createPolicy;\n return typeof create === 'function' ? (candidate as TrustedTypesFactoryLike) : undefined;\n}\n\nfunction resolvePolicy(): TrustedHtmlPolicyLike | null {\n if (policyOverride !== undefined) return policyOverride;\n if (autoPolicy !== undefined) return autoPolicy;\n const api = factory();\n try {\n autoPolicy =\n api === undefined\n ? null\n : api.createPolicy(TRUSTED_TYPES_POLICY_NAME, { createHTML: (input) => input });\n } catch {\n // The site's `trusted-types` directive does not list this name; the\n // sink assignment will surface the enforcement error.\n autoPolicy = null;\n }\n return autoPolicy;\n}\n\n/** `html` as a `TrustedHTML` when a policy exists, else the string. Typed `string` for `innerHTML`. @internal */\nexport function trustedHtml(html: string): string {\n const policy = resolvePolicy();\n if (policy === null) return html;\n return policy.createHTML(html) as string;\n}\n\n/** Test hook: forget the auto-created policy. */\nexport function __resetTrustedTypesForTests(): void {\n policyOverride = undefined;\n autoPolicy = undefined;\n}\n","/**\n * URL safety: the one scheme allow-list the runtime, the client and the\n * sanitizer share. Empty strings are not safe (`<a href=\"\">` is never emitted).\n */\n\nconst SAFE_PROTOCOLS: ReadonlySet<string> = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n// Browsers strip leading whitespace before scheme detection.\nconst DANGEROUS_PROTOCOL_PATTERN = /^\\s*(?:javascript|data|vbscript|file|blob|about)\\s*:/i;\n\nconst RELATIVE_PATH = /^(?:\\.{1,2}\\/|[a-zA-Z0-9_-]+\\/?)/;\n\n// The URL parser treats `\\` as `/` for special schemes, so `/\\evil.com`\n// resolves to another origin rather than to a same-origin path.\nconst PROTOCOL_RELATIVE = /^[\\\\/]{2}/;\n\n/** The URL parser drops these anywhere in the input before it looks at anything. */\nconst PARSER_IGNORED = /[\\t\\n\\r]/g;\n\n/** `true` only for absolute `http`/`https`/`mailto`/`tel` URLs, protocol-relative URLs, paths, `#`/`?` fragments and relative paths. */\nexport function isSafeUrl(url: unknown): boolean {\n if (typeof url !== 'string') return false;\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n if (trimmed.length === 0) return false;\n if (DANGEROUS_PROTOCOL_PATTERN.test(trimmed)) return false;\n if (trimmed.startsWith('#') || trimmed.startsWith('?')) return true;\n if (PROTOCOL_RELATIVE.test(trimmed)) return true;\n if (trimmed.startsWith('/')) return true;\n try {\n const parsed = new URL(trimmed);\n return SAFE_PROTOCOLS.has(parsed.protocol);\n } catch {\n return RELATIVE_PATH.test(trimmed);\n }\n}\n\n/** Whether a URL points at another HTTP(S) origin, protocol-relative forms included, and so needs `noopener` hardening; every URL these two patterns match is one `isSafeUrl` admits. */\nexport function isExternalHttpUrl(url: string): boolean {\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n return /^https?:\\/\\//i.test(trimmed) || PROTOCOL_RELATIVE.test(trimmed);\n}\n\n/** The safe scheme set, for tests and introspection. */\nexport const SAFE_URL_PROTOCOLS: ReadonlySet<string> = SAFE_PROTOCOLS;\n","/**\n * LP0409 — what the strict sanitizer removed that the 1.x default kept.\n *\n * `sanitizerPolicy` defaults to `'strict'` since 2.0; before that it was\n * `'compat'`, which let `id` and every `data-*` through, and `name` only where\n * a per-tag list allowed it. The difference\n * only shows when a binding *writes* markup, so a project that upgrades and\n * whose rich text carries its own hooks loses them at the moment an editor\n * types — silently, and in the preview only. Measured on a real consumer: a\n * `data-partner-scroll` attribute driving a CSS selector disappeared on the\n * first write, with nothing said anywhere.\n *\n * So it is said here: once per attribute name per page, with the reason that\n * applies to that name rather than one sentence covering three different\n * decisions. This is a report, never a behaviour — the attribute stays removed.\n */\n\n/**\n * `console.warn` behind a try/catch rather than `@core/diagnostics`: `security`\n * is a leaf layer and may not import `core` (scripts/architecture-rules.ts), and\n * the shared helper's extra work — tolerating a logger that returns a thenable —\n * is for consumer-supplied loggers. This sink is fixed.\n */\nfunction warn(message: string): void {\n try {\n console.warn(message);\n } catch {\n // A diagnostic must never become a second failure.\n }\n}\n\nconst reported = new Set<string>();\n\n/** The binding prefix, restated rather than imported: this module must not pull the applier in. */\nconst BINDING_PREFIX = 'data-payload-';\n\nfunction reason(name: string): string {\n if (name.startsWith(BINDING_PREFIX)) {\n return (\n 'A binding inside CMS content is refused by design — an editor could otherwise ' +\n 'aim a write at any element on the page (docs/security.md)'\n );\n }\n if (name === 'id' || name === 'name') {\n return (\n 'CMS content that can name an element can shadow a global of that name — ' +\n 'DOM clobbering, refused by design (docs/security.md)'\n );\n }\n return (\n 'List it in `allowedDataAttributes` if the page needs it, or set ' +\n \"`sanitizerPolicy: 'compat'` to keep every `data-*` as 1.x did\"\n );\n}\n\n/**\n * Report one removal. Only for attributes `'compat'` would have kept: everything\n * else the sanitizer drops was refused in 1.x too and is not news to anyone.\n */\nexport function reportDroppedAttribute(name: string): void {\n if (reported.has(name)) return;\n reported.add(name);\n warn(\n `[live-preview] LP0409: the strict sanitizer removed \\`${name}\\` from written markup; ` +\n `the 1.x default (\\`sanitizerPolicy: 'compat'\\`) kept it. ${reason(name)}.`,\n );\n}\n\n/** Test seam: the report is once per page, and a test is not a page. */\nexport function resetDroppedAttributeReports(): void {\n reported.clear();\n}\n","/**\n * HTML sanitizer built on the host parser (`<template>`): allow-listed tags\n * and attributes, validated URLs, hardened external links, no `style`.\n * Needs a DOM; string-only sanitizers are historically brittle.\n */\n\nimport { trustedHtml } from './trusted-types';\nimport { isSafeUrl, isExternalHttpUrl } from './url-validator';\nimport { reportDroppedAttribute } from './sanitizer-report';\n\ndeclare const __INLINE_BUILD__: boolean | undefined;\n\n/** Tags kept with their content. Others are unwrapped unless in `REMOVE_COMPLETELY`. */\nconst ALLOWED_TAGS: ReadonlySet<string> = new Set([\n 'p',\n 'br',\n 'strong',\n 'b',\n 'em',\n 'i',\n 'u',\n 's',\n 'strike',\n 'mark',\n 'small',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'ul',\n 'ol',\n 'li',\n 'dl',\n 'dt',\n 'dd',\n 'blockquote',\n 'code',\n 'pre',\n 'kbd',\n 'samp',\n 'var',\n 'a',\n 'span',\n 'div',\n 'section',\n 'article',\n 'aside',\n 'header',\n 'footer',\n 'nav',\n 'figure',\n 'figcaption',\n 'img',\n 'picture',\n 'source',\n 'audio',\n 'video',\n 'sub',\n 'sup',\n 'hr',\n 'time',\n 'abbr',\n 'cite',\n 'q',\n 'table',\n 'thead',\n 'tbody',\n 'tfoot',\n 'tr',\n 'th',\n 'td',\n 'caption',\n 'colgroup',\n 'col',\n]);\n\n/** Tags `allowFormControls` re-admits for author templates; `form` is deliberately not one. */\nconst FORM_CONTROLS: ReadonlySet<string> = new Set([\n 'input',\n 'button',\n 'textarea',\n 'select',\n 'option',\n 'label',\n]);\n\n/** Removed with their children: the content itself is the hazard. */\nconst REMOVE_COMPLETELY: ReadonlySet<string> = new Set([\n 'script',\n 'style',\n 'iframe',\n 'object',\n 'embed',\n 'link',\n 'meta',\n 'base',\n 'form',\n 'input',\n 'button',\n 'select',\n 'textarea',\n 'svg',\n 'math',\n 'template',\n 'frame',\n 'frameset',\n 'noframes',\n 'noscript',\n]);\n\nconst ATTR_GLOBAL: ReadonlySet<string> = new Set([\n 'id',\n 'class',\n 'lang',\n 'dir',\n 'title',\n 'role',\n 'tabindex',\n]);\n\nconst ATTR_ARIA_PREFIX = 'aria-';\nconst ATTR_DATA_PREFIX = 'data-';\nconst BINDING_DATA_PREFIX = 'data-payload-';\n\nconst ATTR_BY_TAG: Readonly<Record<string, ReadonlySet<string>>> = {\n a: new Set(['href', 'target', 'rel', 'download', 'hreflang', 'type']),\n img: new Set(['src', 'srcset', 'sizes', 'alt', 'width', 'height', 'loading', 'decoding']),\n picture: new Set([]),\n source: new Set(['src', 'srcset', 'sizes', 'type', 'media']),\n audio: new Set(['src', 'controls', 'autoplay', 'loop', 'muted', 'preload']),\n video: new Set([\n 'src',\n 'poster',\n 'controls',\n 'autoplay',\n 'loop',\n 'muted',\n 'preload',\n 'width',\n 'height',\n 'playsinline',\n ]),\n time: new Set(['datetime']),\n abbr: new Set(['title']),\n q: new Set(['cite']),\n blockquote: new Set(['cite']),\n table: new Set(['summary']),\n th: new Set(['colspan', 'rowspan', 'scope', 'headers', 'abbr']),\n td: new Set(['colspan', 'rowspan', 'headers']),\n col: new Set(['span']),\n colgroup: new Set(['span']),\n ol: new Set(['start', 'reversed', 'type']),\n li: new Set(['value']),\n code: new Set(['class']),\n pre: new Set(['class']),\n};\n\nconst URL_ATTRIBUTES: ReadonlySet<string> = new Set(['href', 'src', 'cite', 'poster']);\n\n// Numeric nodeType constants keep an injected SSR document independent of a\n// browser-global `Node` constructor.\nconst ELEMENT_NODE = 1;\nconst COMMENT_NODE = 8;\n\n/** Thrown by `sanitizeHtml()` when no `document` is available (SSR without `setSanitizerDocument()`). */\nexport class SanitizerEnvironmentError extends Error {\n override readonly name = 'SanitizerEnvironmentError';\n}\n\n/**\n * `'strict'` (default) strips `id`, `name` and `data-payload-*` and passes\n * other `data-*` only via `allowedDataAttributes`; `'compat'` keeps them.\n */\nexport type SanitizerPolicyMode = 'compat' | 'strict';\n\nexport interface SanitizeOptions {\n /** Overrides the module default set by `setSanitizerPolicy()`. */\n readonly policy?: SanitizerPolicyMode;\n /** `data-*` attributes (full names) that pass under `'strict'`; `data-payload-*` never does. */\n readonly allowedDataAttributes?: readonly string[];\n /**\n * Keep `input`, `button`, `textarea`, `select`, `option` and `label` — only\n * for markup the page author wrote, never for CMS content. `form`,\n * handlers, `style` and unsafe URLs stay dropped.\n */\n readonly allowFormControls?: boolean;\n /** Extra tags to allow. Lower-case, untrimmed. */\n readonly additionalAllowedTags?: readonly string[];\n /**\n * Extra per-tag attributes, lower-case. Cannot re-admit handlers, `style`,\n * or — under `'strict'` — `id`, `name` and `data-payload-*`.\n */\n readonly additionalAllowedAttributes?: Readonly<Record<string, readonly string[]>>;\n /**\n * The input is a page-author item template, so `'strict'` keeps the\n * applier's reconciliation attributes (`TEMPLATE_ATTRIBUTES`) and nothing\n * else — every other `data-payload-*` is still stripped, so a template can\n * never add a binding.\n */\n readonly templateMode?: boolean;\n}\n\n/** What `templateMode` keeps under `'strict'`. */\nconst TEMPLATE_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'id',\n 'name',\n 'data-payload-key',\n 'data-payload-nested-key',\n 'data-payload-nested-template',\n]);\n\ninterface ResolvedPolicy {\n readonly allowedTags: ReadonlySet<string>;\n readonly allowFormControls: boolean;\n readonly templateMode: boolean;\n readonly mode: SanitizerPolicyMode;\n readonly allowedData: ReadonlySet<string>;\n readonly attrByTag: ReadonlyMap<string, ReadonlySet<string>>;\n}\n\nlet defaultMode: SanitizerPolicyMode = 'strict';\n\n/**\n * The default for calls without an explicit `policy`, per package entry. A\n * runtime carries its own `sanitizerPolicy` and never writes here (ADR 0002).\n */\nexport function setSanitizerPolicy(mode: SanitizerPolicyMode): void {\n defaultMode = mode;\n}\n\n/** `instancePolicy` sits between a per-call `options.policy` and the process default. */\nfunction resolvePolicy(\n options: SanitizeOptions | undefined,\n instancePolicy: SanitizerPolicyMode | undefined,\n): ResolvedPolicy {\n const mode = options?.policy ?? instancePolicy ?? defaultMode;\n if (!options) {\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n return {\n allowedTags: ALLOWED_TAGS,\n attrByTag: attrMap,\n allowFormControls: false,\n templateMode: false,\n mode,\n allowedData: new Set(),\n };\n }\n const allowed = new Set(ALLOWED_TAGS);\n options.additionalAllowedTags?.forEach((tag) => allowed.add(tag));\n if (options.allowFormControls === true) for (const tag of FORM_CONTROLS) allowed.add(tag);\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n for (const [tag, attrs] of Object.entries(options.additionalAllowedAttributes ?? {})) {\n const merged = new Set(attrMap.get(tag));\n for (const attr of attrs) merged.add(attr);\n attrMap.set(tag, merged);\n }\n return {\n allowedTags: allowed,\n attrByTag: attrMap,\n allowFormControls: options.allowFormControls === true,\n templateMode: options.templateMode === true,\n mode,\n allowedData: new Set(options.allowedDataAttributes?.map((name) => name.toLowerCase())),\n };\n}\n\n/** The `Document` surface the sanitizer needs; jsdom, linkedom and happy-dom all provide it. */\nexport interface SanitizerDocument {\n createElement: (tagName: string) => {\n innerHTML: string;\n readonly content: ParentNode;\n };\n}\n\n// Held on the realm, not in this module: every package entry is its own bundle\n// with its own copy of this file, and a document supplied through the root has\n// to reach the rich text `payload-live-preview/lexical` renders.\nconst DOCUMENT_SLOT: unique symbol = Symbol.for('payload-live-preview.sanitizer-document');\n\ninterface DocumentSlot {\n [DOCUMENT_SLOT]?: SanitizerDocument | undefined;\n}\n\n/** Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`; `null` clears it, for every entry. */\nexport function setSanitizerDocument(doc: SanitizerDocument | null): void {\n (globalThis as DocumentSlot)[DOCUMENT_SLOT] = doc ?? undefined;\n}\n\n/**\n * Sanitize `html`; malformed input is recovered by the parser first.\n *\n * @throws {SanitizerEnvironmentError} when no DOM is available.\n */\nexport function sanitizeHtml(html: string, options?: SanitizeOptions): string {\n return sanitizeHtmlWithPolicy(html, undefined, options);\n}\n\n/**\n * The runtime's entry: `policy` is one instance's, applied unless `options`\n * carry their own, so two clients on a page never share a policy through\n * this module. Not public — a direct caller has `options.policy`.\n */\nexport function sanitizeHtmlWithPolicy(\n html: string,\n policy: SanitizerPolicyMode | undefined,\n options?: SanitizeOptions,\n): string {\n const doc = resolveDocument();\n if (!doc) throw environmentError();\n if (html === '') return '';\n\n const resolved = resolvePolicy(options, policy);\n const template = doc.createElement('template');\n // The sanitizer's own parse is a sink too: under Trusted Types it needs the policy.\n template.innerHTML = trustedHtml(html);\n sanitizeFragment(template.content, resolved);\n return template.innerHTML;\n}\n\n// Read the define at each branch rather than through a helper: a bundler\n// folds the substituted literal in place, but will not inline a call, and the\n// SSR-only class and override must not reach the browser runtime.\nfunction environmentError(): Error {\n if (typeof __INLINE_BUILD__ !== 'undefined' && __INLINE_BUILD__) {\n return new Error('sanitizeHtml needs a DOM');\n }\n return new SanitizerEnvironmentError(\n 'sanitizeHtml needs a DOM; provide one with setSanitizerDocument() during SSR.',\n );\n}\n\nfunction resolveDocument(): SanitizerDocument | undefined {\n if (typeof __INLINE_BUILD__ === 'undefined' || !__INLINE_BUILD__) {\n const override = (globalThis as DocumentSlot)[DOCUMENT_SLOT];\n if (override) return override;\n }\n if (typeof document === 'undefined') return undefined;\n return document;\n}\n\n/** Whether a DOM is available — the global or an injected one — for callers that treat sanitizing as optional. */\nexport function hasSanitizerDocument(): boolean {\n return resolveDocument() !== undefined;\n}\n\nfunction sanitizeFragment(node: ParentNode, policy: ResolvedPolicy): void {\n // Snapshot: children are mutated during the walk.\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === ELEMENT_NODE) {\n sanitizeElement(child as Element, policy);\n } else if (child.nodeType === COMMENT_NODE) {\n child.remove();\n }\n }\n}\n\nfunction sanitizeElement(element: Element, policy: ResolvedPolicy): void {\n const tag = element.tagName.toLowerCase();\n\n if (REMOVE_COMPLETELY.has(tag) && !(policy.allowFormControls && FORM_CONTROLS.has(tag))) {\n element.remove();\n return;\n }\n\n if (!policy.allowedTags.has(tag)) {\n sanitizeFragment(element, policy);\n element.replaceWith(...element.childNodes);\n return;\n }\n\n sanitizeAttributes(element, tag, policy);\n if (tag === 'a') hardenAnchor(element);\n sanitizeFragment(element, policy);\n}\n\nfunction sanitizeAttributes(element: Element, tag: string, policy: ResolvedPolicy): void {\n const tagAttrs = policy.attrByTag.get(tag);\n\n for (const attr of Array.from(element.attributes)) {\n const name = attr.name.toLowerCase();\n if (name.startsWith('on') || name === 'style') {\n element.removeAttribute(attr.name);\n continue;\n }\n if (policy.mode === 'strict') {\n if (policy.templateMode && TEMPLATE_ATTRIBUTES.has(name)) continue;\n // DOM clobbering and binding injection (docs/security.md §5c). Checked\n // before the allow-list so an extension cannot re-admit them.\n if (name === 'id' || name === 'name' || name.startsWith(BINDING_DATA_PREFIX)) {\n element.removeAttribute(attr.name);\n // `compat` kept `name` only where a per-tag list allowed it, so only\n // there did the upgrade change anything to report.\n if (name !== 'name' || tagAttrs?.has(name) === true) reportDroppedAttribute(name);\n continue;\n }\n if (name.startsWith(ATTR_DATA_PREFIX)) {\n if (!policy.allowedData.has(name)) {\n element.removeAttribute(attr.name);\n reportDroppedAttribute(name);\n }\n continue;\n }\n if (ATTR_GLOBAL.has(name) || name.startsWith(ATTR_ARIA_PREFIX)) continue;\n } else if (\n ATTR_GLOBAL.has(name) ||\n name.startsWith(ATTR_ARIA_PREFIX) ||\n name.startsWith(ATTR_DATA_PREFIX)\n ) {\n continue;\n }\n if (tagAttrs?.has(name)) {\n if (URL_ATTRIBUTES.has(name) && !isSafeUrl(attr.value)) {\n element.removeAttribute(attr.name);\n } else if (name === 'srcset' && !isSafeSrcset(attr.value)) {\n element.removeAttribute(attr.name);\n }\n continue;\n }\n element.removeAttribute(attr.name);\n }\n}\n\n/** Every `srcset` candidate must pass; partial rewriting would silently change what renders. */\nfunction isSafeSrcset(value: string): boolean {\n for (const candidate of value.split(',')) {\n const trimmed = candidate.trim();\n if (trimmed.length === 0) continue;\n // The URL ends at the first whitespace; what follows is the descriptor.\n const [url = trimmed] = trimmed.split(/\\s/, 1);\n if (!isSafeUrl(url)) return false;\n }\n return true;\n}\n\nfunction hardenAnchor(anchor: Element): void {\n const href = anchor.getAttribute('href');\n if (href === null || !isExternalHttpUrl(href)) return;\n anchor.setAttribute('rel', 'noopener noreferrer');\n if (!anchor.hasAttribute('target')) anchor.setAttribute('target', '_blank');\n}\n\n/** The built-in allow-lists, for documentation and tests. */\nexport const SANITIZER_POLICY = Object.freeze({\n allowedTags: ALLOWED_TAGS,\n removeCompletely: REMOVE_COMPLETELY,\n globalAttributes: ATTR_GLOBAL,\n attributesByTag: ATTR_BY_TAG,\n urlAttributes: URL_ATTRIBUTES,\n});\n","/** HTML and CSS escaping primitives (OWASP XSS Prevention Cheat Sheet). DOM-free. */\n\nconst HTML_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;',\n});\n\nconst HTML_ESCAPE_PATTERN = /[&<>\"'/`=]/g;\n\n/** Escape `text` for an element body or a *quoted* attribute value; strings only, and unquoted attributes are not covered. */\nexport function escapeHtml(text: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return text.replace(HTML_ESCAPE_PATTERN, (char) => HTML_ESCAPES[char] as string);\n}\n\n/** Escape a value for a CSS `url(...)` literal; this stops the break-out, not the scheme, so pair it with `isSafeUrl()`. */\nexport function escapeCssUrl(value: string): string {\n return value.replace(/['\"()\\\\]/g, '\\\\$&');\n}\n\nconst ATTR_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n});\n\nconst ATTR_ESCAPE_PATTERN = /[&<>\"']/g;\n\n/** Escape a value for a *quoted* HTML attribute, leaving URL characters intact; it validates no scheme, so run `isSafeUrl()` on `href`/`src` first. @internal */\nexport function escapeHtmlAttribute(value: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return value.replace(ATTR_ESCAPE_PATTERN, (char) => ATTR_ESCAPES[char] as string);\n}\n\n/** `escapeHtml()` then newlines to `<br>`; the order is what makes it safe. */\nexport function escapeAndLinebreak(text: string): string {\n return escapeHtml(text).replace(/\\r\\n|\\r|\\n/g, '<br>');\n}\n","/**\n * Lexical document types. Only `type` and `children` are required; every\n * other property is forwarded opaquely to the renderer for that node type.\n */\n\n/** Lexical text-format bitmask; flags combine (`BOLD | ITALIC === 3`). @internal */\nexport const TextFormat = {\n BOLD: 1,\n ITALIC: 2,\n STRIKETHROUGH: 4,\n UNDERLINE: 8,\n CODE: 16,\n SUBSCRIPT: 32,\n SUPERSCRIPT: 64,\n HIGHLIGHT: 128,\n} as const;\n\nexport interface LexicalNode {\n readonly type: string;\n readonly version?: number;\n readonly format?: number | string;\n readonly indent?: number;\n readonly direction?: 'ltr' | 'rtl' | null;\n readonly children?: readonly LexicalNode[];\n readonly text?: string;\n readonly [extra: string]: unknown;\n}\n\nexport interface LexicalRoot {\n readonly root: {\n readonly type?: string;\n readonly children: readonly LexicalNode[];\n readonly direction?: 'ltr' | 'rtl' | null;\n readonly format?: number | string;\n readonly indent?: number;\n readonly [extra: string]: unknown;\n };\n}\n","/** Attribute helpers shared by the block-level node renderers. */\n\nimport type { LexicalNode } from './types';\n\nconst ALIGNMENT_NUMERIC: Readonly<Record<number, string>> = {\n 1: 'left',\n 2: 'center',\n 3: 'right',\n 4: 'justify',\n};\n\nconst ALIGNMENT_STRING = new Set(['left', 'center', 'right', 'justify', 'start', 'end']);\n\n/** Alignment of a block node; Payload emits it as a string or as Lexical's numeric format. */\nexport function resolveAlignment(node: LexicalNode): string | undefined {\n const fmt = node.format;\n if (typeof fmt === 'string' && ALIGNMENT_STRING.has(fmt)) return fmt;\n if (typeof fmt === 'number') return ALIGNMENT_NUMERIC[fmt];\n return undefined;\n}\n\nexport function resolveIndent(node: LexicalNode): number {\n const indent = node.indent;\n return typeof indent === 'number' && indent > 0 ? indent : 0;\n}\n\nexport function dirAttribute(node: LexicalNode): string {\n if (node.direction === 'rtl') return ' dir=\"rtl\"';\n if (node.direction === 'ltr') return ' dir=\"ltr\"';\n return '';\n}\n\n/**\n * Alignment and indent as `lp-align-*` / `lp-indent-N` classes. The sanitizer\n * strips `style` under every policy, so inline CSS would never reach the page.\n */\nexport function layoutClassAttribute(node: LexicalNode): string {\n const align = resolveAlignment(node);\n const indent = resolveIndent(node);\n const classes: string[] = [];\n if (align !== undefined) classes.push(`lp-align-${align}`);\n if (indent > 0) classes.push(`lp-indent-${String(indent)}`);\n return classes.length === 0 ? '' : ` class=\"${classes.join(' ')}\"`;\n}\n","import type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst paragraphRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n return `<p${dirAttribute(node)}${layoutClassAttribute(node)}>${children}</p>`;\n};\n\nexport { paragraphRenderer };\n","/** `heading` renderer; an unknown `tag` (transient editor states emit them) falls back to `h2`. */\n\nimport type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst VALID_TAGS = new Set(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']);\n\nconst headingRenderer: NodeRenderer = (node, ctx): string => {\n const tagRaw = typeof node['tag'] === 'string' ? node['tag'].toLowerCase() : 'h2';\n const tag = VALID_TAGS.has(tagRaw) ? tagRaw : 'h2';\n const children = ctx.renderChildren(node.children ?? []);\n return `<${tag}${dirAttribute(node)}${layoutClassAttribute(node)}>${children}</${tag}>`;\n};\n\nexport { headingRenderer };\n","/**\n * Value-shape helpers shared by the Lexical node renderers and the field\n * renderers. They live here because `field-types` may import `lexical`, never\n * the reverse (scripts/architecture-policy.ts).\n */\n\nexport interface MediaShape {\n readonly id?: string | number;\n readonly url?: string;\n readonly alt?: string;\n readonly filename?: string;\n readonly mimeType?: string;\n readonly width?: number;\n readonly height?: number;\n readonly sizes?: Readonly<\n Record<string, { readonly url?: string; readonly width?: number; readonly height?: number }>\n >;\n}\n\nexport interface RelationShape {\n readonly id?: string | number;\n readonly title?: string;\n readonly name?: string;\n readonly slug?: string;\n readonly url?: string;\n}\n\nexport function asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nexport function readMedia(value: unknown): MediaShape | undefined {\n return asRecord(value);\n}\n\n/** Reduce `value` to `[a-z0-9_-]` so it can be a class-name fragment without escaping. */\nexport function sanitizeIdent(value: string): string {\n return value.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();\n}\n\nfunction nonEmpty(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/** Label precedence for a populated relation: `title`, `name`, `slug`, then `id`. */\nexport function pickRelationLabel(value: RelationShape): string | undefined {\n const label = nonEmpty(value.title) ?? nonEmpty(value.name) ?? nonEmpty(value.slug);\n if (label !== undefined) return label;\n return value.id === undefined ? undefined : String(value.id);\n}\n","/**\n * `link` / `autolink` renderer. Payload 3.x serialises links as\n * `{ fields: { linkType, url, newTab, doc } }`; vanilla Lexical puts `url`\n * and `target` on the node itself. Both shapes are read, Payload's first.\n */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isExternalHttpUrl, isSafeUrl } from '@security/url-validator';\nimport type { NodeRenderer } from '../registry';\nimport type { LexicalNode } from '../types';\nimport { asRecord } from '../value-shapes';\n\nconst BLANK_TARGET = ' target=\"_blank\" rel=\"noopener noreferrer\"';\n\nconst linkRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n const fields = asRecord(node['fields']);\n const url = resolveUrl(node, fields);\n if (url === undefined || !isSafeUrl(url)) return children;\n const titleAttr =\n typeof node['title'] === 'string' ? ` title=\"${escapeHtml(node['title'])}\"` : '';\n return `<a href=\"${escapeHtmlAttribute(url)}\"${targetAttribute(node, fields, url)}${titleAttr}>${children}</a>`;\n};\n\nfunction resolveUrl(\n node: LexicalNode,\n fields: Record<string, unknown> | undefined,\n): string | undefined {\n if (fields?.['linkType'] === 'internal') return internalUrl(fields['doc']);\n const url = fields?.['url'] ?? node['url'];\n return typeof url === 'string' && url.length > 0 ? url : undefined;\n}\n\n/** An internal link needs the populated document; a bare id has no route to offer. */\nfunction internalUrl(doc: unknown): string | undefined {\n const value = asRecord(asRecord(doc)?.['value']);\n const url = value?.['url'];\n if (typeof url === 'string' && url.length > 0) return url;\n const slug = value?.['slug'];\n return typeof slug === 'string' && slug.length > 0 ? `/${slug}` : undefined;\n}\n\n/** `_blank` always carries `noopener noreferrer`, whichever side asked for it. */\nfunction targetAttribute(\n node: LexicalNode,\n fields: Record<string, unknown> | undefined,\n url: string,\n): string {\n if (fields?.['newTab'] === true || isExternalHttpUrl(url)) return BLANK_TARGET;\n const target = typeof node['target'] === 'string' ? node['target'] : '';\n if (target === '') return '';\n if (target === '_blank') return BLANK_TARGET;\n return ` target=\"${escapeHtml(target)}\"`;\n}\n\nexport { linkRenderer };\n","/** `code` (fenced block) and `code-highlight` (token span) renderers. */\n\nimport { escapeHtml } from '@security/escape';\nimport type { NodeRenderer } from '../registry';\nimport type { LexicalNode } from '../types';\nimport { sanitizeIdent } from '../value-shapes';\n\nconst codeRenderer: NodeRenderer = (node): string => {\n const language = sanitizeIdent(typeof node['language'] === 'string' ? node['language'] : '');\n const langClass = language === '' ? '' : ` class=\"language-${language}\"`;\n return `<pre><code${langClass}>${escapeHtml(extractText(node))}</code></pre>`;\n};\n\nconst codeHighlightRenderer: NodeRenderer = (node): string => {\n const text = typeof node.text === 'string' ? node.text : '';\n const highlight =\n typeof node['highlightType'] === 'string'\n ? ` class=\"token-${sanitizeIdent(node['highlightType'])}\"`\n : '';\n return `<span${highlight}>${escapeHtml(text)}</span>`;\n};\n\nexport { codeRenderer, codeHighlightRenderer };\n\nfunction extractText(node: LexicalNode): string {\n if (typeof node.text === 'string') return node.text;\n if (!node.children) return '';\n let out = '';\n for (const child of node.children) out += extractText(child);\n return out;\n}\n","/**\n * `upload` renderer: `<img>` for image (or unknown) MIME types, `<video>` /\n * `<audio>` for media, a download link otherwise. An unsafe URL renders nothing.\n */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isSafeUrl } from '@security/url-validator';\nimport type { NodeRenderer } from '../registry';\nimport { readMedia, type MediaShape } from '../value-shapes';\n\nconst uploadRenderer: NodeRenderer = (node): string => {\n const value = readMedia(node['value']);\n if (value === undefined) return '';\n const url = value.url;\n if (typeof url !== 'string' || !isSafeUrl(url)) return '';\n\n const mime = typeof value.mimeType === 'string' ? value.mimeType : '';\n if (mime.startsWith('video/')) return renderVideo(value, url);\n if (mime.startsWith('audio/')) return renderAudio(value, url);\n if (mime === '' || mime.startsWith('image/')) return renderImage(value, url);\n return renderFallbackLink(value, url);\n};\n\nexport { uploadRenderer };\n\nfunction dimensionAttributes(value: MediaShape): string {\n const width = typeof value.width === 'number' ? ` width=\"${String(value.width)}\"` : '';\n const height = typeof value.height === 'number' ? ` height=\"${String(value.height)}\"` : '';\n return `${width}${height}`;\n}\n\nfunction typeAttribute(value: MediaShape): string {\n return typeof value.mimeType === 'string' ? ` type=\"${escapeHtmlAttribute(value.mimeType)}\"` : '';\n}\n\nfunction renderImage(value: MediaShape, url: string): string {\n const alt = typeof value.alt === 'string' ? escapeHtml(value.alt) : '';\n return `<img src=\"${escapeHtmlAttribute(url)}\" alt=\"${alt}\"${dimensionAttributes(value)} loading=\"lazy\" decoding=\"async\">`;\n}\n\nfunction renderVideo(value: MediaShape, url: string): string {\n return `<video controls${dimensionAttributes(value)}><source src=\"${escapeHtmlAttribute(url)}\"${typeAttribute(value)}></video>`;\n}\n\nfunction renderAudio(value: MediaShape, url: string): string {\n return `<audio controls><source src=\"${escapeHtmlAttribute(url)}\"${typeAttribute(value)}></audio>`;\n}\n\nfunction renderFallbackLink(value: MediaShape, url: string): string {\n const label = typeof value.filename === 'string' ? escapeHtml(value.filename) : escapeHtml(url);\n return `<a href=\"${escapeHtmlAttribute(url)}\" target=\"_blank\" rel=\"noopener noreferrer\">${label}</a>`;\n}\n","/** `relationship` renderer: a link when the populated document carries a URL, a span otherwise. */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isSafeUrl } from '@security/url-validator';\nimport type { NodeRenderer } from '../registry';\nimport { asRecord, pickRelationLabel, sanitizeIdent, type RelationShape } from '../value-shapes';\n\nconst relationshipRenderer: NodeRenderer = (node): string => {\n const relationTo = typeof node['relationTo'] === 'string' ? node['relationTo'] : '';\n const value = asRecord(node['value']) as RelationShape | undefined;\n const label = escapeHtml((value && pickRelationLabel(value)) ?? `#${relationTo}`);\n const slug = sanitizeIdent(relationTo);\n const classAttr =\n slug === '' ? ' class=\"lp-relation\"' : ` class=\"lp-relation lp-relation--${slug}\"`;\n const url = value?.url;\n if (typeof url === 'string' && isSafeUrl(url)) {\n return `<a href=\"${escapeHtmlAttribute(url)}\"${classAttr}>${label}</a>`;\n }\n return `<span${classAttr}>${label}</span>`;\n};\n\nexport { relationshipRenderer };\n","/** Block-renderer registry keyed by Payload block slug; consulted by the `block` and `inlineBlock` nodes. */\n\nimport type { LexicalNode } from '../types';\n\nexport interface BlockRenderContext {\n /** Render nested Lexical content through the node registry. */\n readonly renderChildren: (children: readonly LexicalNode[]) => string;\n}\n\n/** Receives the block's `fields` (with `blockType`) and returns HTML. */\nexport type BlockRenderer = (\n fields: Record<string, unknown>,\n context: BlockRenderContext,\n) => string;\n\nconst registry = new Map<string, BlockRenderer>();\n\n/** Register or replace the renderer for `blockType`. */\nexport function registerBlockRenderer(blockType: string, renderer: BlockRenderer): void {\n registry.set(blockType, renderer);\n}\n\n/** @internal */\nexport function lookupBlockRenderer(blockType: string): BlockRenderer | undefined {\n return registry.get(blockType);\n}\n\n/** @internal */\nexport function registeredBlockTypes(): readonly string[] {\n return [...registry.keys()];\n}\n\n/** Test-only: clear the registry. */\nexport function __resetBlockRegistryForTests(): void {\n registry.clear();\n}\n","/**\n * `block` and `inlineBlock` renderers for Payload's BlocksFeature. The block\n * registry is consulted first; without a renderer for the slug the node becomes\n * an empty, class-tagged element a consumer can style or replace.\n *\n * That element is a placeholder, not a rendering. `UNRENDERED_BLOCK_SELECTOR`\n * names it so the write path can keep the markup the server already rendered\n * for the block in its place, instead of replacing a figure and its image with\n * an empty div (LP0410). Whether that succeeds is decided there, not here: this\n * renderer only tells the context which slug it had no renderer for, and the\n * write says what became of it (LP0410 kept, LP0413 lost).\n */\n\nimport { lookupBlockRenderer } from '../blocks/registry';\nimport type { NodeRenderer, RenderNodeContext } from '../registry';\nimport type { LexicalNode } from '../types';\nimport { asRecord, sanitizeIdent } from '../value-shapes';\n\n/**\n * The placeholders above, in the rendered tree. Both are empty by construction,\n * and a registered renderer's output is not: it carries the block's content and\n * its own class (`lp-block-callout`, …).\n */\nexport const UNRENDERED_BLOCK_SELECTOR = '.lp-block:empty,.lp-inline-block:empty';\n\nfunction renderBlockNode(\n node: LexicalNode,\n ctx: RenderNodeContext,\n tag: 'div' | 'span',\n baseClass: string,\n): string {\n const fields = asRecord(node['fields']) ?? {};\n const blockType = typeof fields['blockType'] === 'string' ? fields['blockType'] : '';\n const slug = sanitizeIdent(blockType);\n const classes = slug === '' ? baseClass : `${baseClass} ${baseClass}--${slug}`;\n if (blockType !== '') {\n const custom = lookupBlockRenderer(blockType) ?? lookupBlockRenderer(slug);\n if (custom) return custom(fields, { renderChildren: ctx.renderChildren });\n // The real slug is known only here — the class carries `sanitizeIdent(slug)`,\n // and a hint that names the wrong one to register is no hint.\n ctx.onUnrenderedBlock?.(blockType, classes);\n }\n return `<${tag} class=\"${classes}\"></${tag}>`;\n}\n\nconst blockRenderer: NodeRenderer = (node, ctx) => renderBlockNode(node, ctx, 'div', 'lp-block');\n\nconst inlineBlockRenderer: NodeRenderer = (node, ctx) =>\n renderBlockNode(node, ctx, 'span', 'lp-inline-block');\n\nexport { blockRenderer, inlineBlockRenderer };\n","/** `table` / `tablerow` / `tablecell` renderers for the `@lexical/table` shapes Payload's table feature emits. */\n\nimport type { NodeRenderer } from '../registry';\nimport { dirAttribute } from '../utils';\n\n// `@lexical/table` TableCellHeaderStates: ROW marks a cell in a header row, COLUMN one in a header column.\nconst HEADER_ROW = 1;\nconst HEADER_COLUMN = 2;\n\nconst tableRenderer: NodeRenderer = (node, ctx) =>\n `<table${dirAttribute(node)}><tbody>${ctx.renderChildren(node.children ?? [])}</tbody></table>`;\n\nconst tableRowRenderer: NodeRenderer = (node, ctx) =>\n `<tr>${ctx.renderChildren(node.children ?? [])}</tr>`;\n\nconst tableCellRenderer: NodeRenderer = (node, ctx): string => {\n const header = typeof node['headerState'] === 'number' ? node['headerState'] : 0;\n const tag = (header & (HEADER_ROW | HEADER_COLUMN)) === 0 ? 'td' : 'th';\n const scope =\n header === HEADER_ROW ? ' scope=\"col\"' : header === HEADER_COLUMN ? ' scope=\"row\"' : '';\n return `<${tag}${scope}${spanAttribute('colspan', node['colSpan'])}${spanAttribute('rowspan', node['rowSpan'])}>${ctx.renderChildren(node.children ?? [])}</${tag}>`;\n};\n\nfunction spanAttribute(name: string, value: unknown): string {\n return typeof value === 'number' && value > 1 ? ` ${name}=\"${String(value)}\"` : '';\n}\n\nexport { tableRenderer, tableRowRenderer, tableCellRenderer };\n","import type { NodeRenderer } from '../registry';\nimport { textRenderer } from './text';\nimport { paragraphRenderer } from './paragraph';\nimport { headingRenderer } from './heading';\nimport { listRenderer, listItemRenderer } from './list';\nimport { linkRenderer } from './link';\nimport { quoteRenderer } from './quote';\nimport { codeRenderer, codeHighlightRenderer } from './code';\nimport { linebreakRenderer, horizontalRuleRenderer, tabRenderer } from './linebreak';\nimport { uploadRenderer } from './upload';\nimport { relationshipRenderer } from './relationship';\nimport { blockRenderer, inlineBlockRenderer } from './block';\nimport { tableCellRenderer, tableRenderer, tableRowRenderer } from './table';\n\n// A value table instead of `register()` calls at import time: a consumer that\n// never renders Lexical content must not carry these under `sideEffects: false`.\nexport const BUILTIN_NODE_RENDERERS: Readonly<Record<string, NodeRenderer>> = {\n text: textRenderer,\n paragraph: paragraphRenderer,\n heading: headingRenderer,\n list: listRenderer,\n listitem: listItemRenderer,\n link: linkRenderer,\n autolink: linkRenderer,\n quote: quoteRenderer,\n code: codeRenderer,\n 'code-highlight': codeHighlightRenderer,\n linebreak: linebreakRenderer,\n horizontalrule: horizontalRuleRenderer,\n tab: tabRenderer,\n upload: uploadRenderer,\n relationship: relationshipRenderer,\n block: blockRenderer,\n inlineBlock: inlineBlockRenderer,\n table: tableRenderer,\n tablerow: tableRowRenderer,\n tablecell: tableCellRenderer,\n};\n","/** `text` renderer. Format flags wrap in a fixed order so equal input gives byte-equal output. */\n\nimport { escapeHtml } from '@security/escape';\nimport type { LexicalNode } from '../types';\nimport { TextFormat } from '../types';\nimport type { NodeRenderer } from '../registry';\n\nconst textRenderer: NodeRenderer = (node: LexicalNode): string => {\n const raw = typeof node.text === 'string' ? node.text : '';\n let out = escapeHtml(raw);\n const format = typeof node.format === 'number' ? node.format : 0;\n if ((format & TextFormat.CODE) !== 0) out = `<code>${out}</code>`;\n if ((format & TextFormat.BOLD) !== 0) out = `<strong>${out}</strong>`;\n if ((format & TextFormat.ITALIC) !== 0) out = `<em>${out}</em>`;\n if ((format & TextFormat.UNDERLINE) !== 0) out = `<u>${out}</u>`;\n if ((format & TextFormat.STRIKETHROUGH) !== 0) out = `<s>${out}</s>`;\n if ((format & TextFormat.SUBSCRIPT) !== 0) out = `<sub>${out}</sub>`;\n if ((format & TextFormat.SUPERSCRIPT) !== 0) out = `<sup>${out}</sup>`;\n if ((format & TextFormat.HIGHLIGHT) !== 0) out = `<mark>${out}</mark>`;\n return out;\n};\n\nexport { textRenderer };\n","/** `list` / `listitem` renderers: `bullet` → `<ul>`, `number` → `<ol>`, `check` → `<ul role=\"list\">` with `aria-checked` items. */\n\nimport { escapeHtml } from '@security/escape';\nimport type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst listRenderer: NodeRenderer = (node, ctx): string => {\n const listType = typeof node['listType'] === 'string' ? node['listType'] : 'bullet';\n const tag = listType === 'number' ? 'ol' : 'ul';\n const startAttr =\n listType === 'number' && typeof node['start'] === 'number' && node['start'] > 1\n ? ` start=\"${String(node['start'])}\"`\n : '';\n const checkAttr = listType === 'check' ? ' role=\"list\"' : '';\n const children = ctx.renderChildren(node.children ?? []);\n return `<${tag}${dirAttribute(node)}${layoutClassAttribute(node)}${startAttr}${checkAttr}>${children}</${tag}>`;\n};\n\nconst listItemRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n if (typeof node['checked'] === 'boolean') {\n const state = node['checked'] ? 'true' : 'false';\n return `<li role=\"checkbox\" aria-checked=\"${state}\"${layoutClassAttribute(node)}>${children}</li>`;\n }\n const valueAttr =\n typeof node['value'] === 'number' ? ` value=\"${escapeHtml(String(node['value']))}\"` : '';\n return `<li${dirAttribute(node)}${layoutClassAttribute(node)}${valueAttr}>${children}</li>`;\n};\n\nexport { listRenderer, listItemRenderer };\n","import type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst quoteRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n return `<blockquote${dirAttribute(node)}${layoutClassAttribute(node)}>${children}</blockquote>`;\n};\n\nexport { quoteRenderer };\n","import type { NodeRenderer } from '../registry';\n\nconst linebreakRenderer: NodeRenderer = () => '<br>';\nconst horizontalRuleRenderer: NodeRenderer = () => '<hr>';\nconst tabRenderer: NodeRenderer = () => '\\t';\n\nexport { linebreakRenderer, horizontalRuleRenderer, tabRenderer };\n","/** Node-renderer registry: consumer registrations layered over the built-in table. */\n\nimport type { LexicalNode } from './types';\nimport { BUILTIN_NODE_RENDERERS } from './nodes/builtin';\n\nexport interface RenderNodeContext {\n /** Render child nodes through the registry. */\n readonly renderChildren: (children: readonly LexicalNode[]) => string;\n /** Text alignment of a block node, or `undefined`. */\n readonly resolveAlignment: (node: LexicalNode) => string | undefined;\n /** Indent level of a node, `0` when none. */\n readonly resolveIndent: (node: LexicalNode) => number;\n /**\n * Where a `block` or `inlineBlock` without a renderer is reported, with the\n * slug Payload sent and the class of the placeholder written in its place.\n * `undefined` on a plain `lexicalToHtml()` call; the `richText` write sets it.\n */\n readonly onUnrenderedBlock?: ((blockType: string, placeholderClass: string) => void) | undefined;\n}\n\nexport type NodeRenderer = (node: LexicalNode, context: RenderNodeContext) => string;\n\nconst registry = new Map<string, NodeRenderer>();\n\n/** Register or replace the renderer for `type`. */\nexport function register(type: string, renderer: NodeRenderer): void {\n registry.set(type, renderer);\n}\n\n/** @internal */\nexport function lookup(type: string): NodeRenderer | undefined {\n return registry.get(type) ?? BUILTIN_NODE_RENDERERS[type];\n}\n\nexport function registeredTypes(): readonly string[] {\n return [...new Set([...Object.keys(BUILTIN_NODE_RENDERERS), ...registry.keys()])];\n}\n\n/** Test-only: drop consumer registrations. */\nexport function __resetForTests(): void {\n registry.clear();\n}\n","/**\n * Lexical → HTML. Each node dispatches to the renderer registered for its\n * `type`; an unknown node renders its children so content is never lost.\n */\n\nimport { sanitizeHtml, hasSanitizerDocument } from '@security/sanitizer';\nimport { lookup, type RenderNodeContext } from './registry';\nimport type { LexicalNode, LexicalRoot } from './types';\nimport { resolveAlignment, resolveIndent } from './utils';\n\nexport interface LexicalRenderOptions {\n /** Pass the result through `sanitizeHtml()` (default `true`). */\n readonly sanitize?: boolean;\n /**\n * Called for every `block` or `inlineBlock` the registry has no renderer\n * for, with the block's slug as Payload sent it and the class its empty\n * placeholder carries. The `richText` write listens: it is the one caller\n * that later knows whether the server's markup for the block survived, so\n * the diagnostic is spoken there (LP0410, LP0413), not here.\n */\n readonly onUnrenderedBlock?: (blockType: string, placeholderClass: string) => void;\n}\n\nlet warnedNoSanitizer = false;\n\n/** @internal */\nexport function isLexicalContent(value: unknown): value is LexicalRoot {\n if (typeof value !== 'object' || value === null) return false;\n if (!('root' in value)) return false;\n const root = value.root;\n if (typeof root !== 'object' || root === null) return false;\n if (!('children' in root)) return false;\n return Array.isArray(root.children);\n}\n\n/** Render a Lexical document to HTML; without `setSanitizerDocument()` the result is unsanitised and warns once. */\nexport function lexicalToHtml(content: LexicalRoot, options: LexicalRenderOptions = {}): string {\n if (!isLexicalContent(content)) return '';\n const html = createContext(options.onUnrenderedBlock).renderChildren(content.root.children);\n if (options.sanitize === false) return html;\n if (hasSanitizerDocument()) return sanitizeHtml(html);\n warnNoSanitizerOnce();\n return html;\n}\n\n/** Plain text of a document, paragraphs separated by `\\n`. */\nexport function lexicalToPlainText(content: LexicalRoot): string {\n if (!isLexicalContent(content)) return '';\n return content.root.children.map(extractPlainText).join('\\n').trim();\n}\n\n/** Test-only: allow the SSR warning to fire again. */\nexport function __resetSanitizerWarningForTests(): void {\n warnedNoSanitizer = false;\n}\n\n/**\n * One context per document: `renderChildren` closes over it so a nested\n * block — a `block` inside a list item, an `inlineBlock` inside a paragraph —\n * reports to the same listener as a top-level one.\n */\nfunction createContext(\n onUnrenderedBlock: RenderNodeContext['onUnrenderedBlock'],\n): RenderNodeContext {\n const context: RenderNodeContext = {\n renderChildren: (children) => {\n let out = '';\n for (const child of children) out += renderNode(child, context);\n return out;\n },\n resolveAlignment,\n resolveIndent,\n onUnrenderedBlock,\n };\n return context;\n}\n\nfunction renderNode(node: LexicalNode, context: RenderNodeContext): string {\n const renderer = lookup(node.type);\n if (renderer) return renderer(node, context);\n return node.children !== undefined ? context.renderChildren(node.children) : '';\n}\n\nfunction extractPlainText(node: LexicalNode): string {\n if (typeof node.text === 'string') return node.text;\n if (node.type === 'linebreak') return '\\n';\n if (node.children === undefined) return '';\n let out = '';\n for (const child of node.children) out += extractPlainText(child);\n return out;\n}\n\n// This layer may not import `@core/diagnostics` (architecture policy), so the\n// warn-once lives here; a hostile or absent console must not break rendering.\nfunction warnNoSanitizerOnce(): void {\n if (warnedNoSanitizer) return;\n warnedNoSanitizer = true;\n try {\n console.warn(\n '[live-preview] lexicalToHtml() has no sanitizer document and returned unsanitised HTML; ' +\n 'call setSanitizerDocument() (linkedom/jsdom) for server rendering, see \"HTML sanitization\" in docs/security.md.',\n );\n } catch {\n // Diagnostics never become a second failure.\n }\n}\n","/**\n * Opt-in renderers for the block patterns most Payload sites ship (callout,\n * image, video, code, cta). Each reads well-known field names only, escapes\n * every value, validates URLs and renders nothing when a required field is\n * missing. Register with `registerDefaultBlocks()`.\n */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isExternalHttpUrl, isSafeUrl } from '@security/url-validator';\nimport type { LexicalNode } from '../types';\nimport { readMedia, sanitizeIdent, type MediaShape } from '../value-shapes';\nimport { registerBlockRenderer, type BlockRenderer } from './registry';\n\nfunction str(fields: Record<string, unknown>, key: string): string | undefined {\n const value = fields[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction safeUrlOrUndefined(fields: Record<string, unknown>, key: string): string | undefined {\n const raw = str(fields, key);\n return raw !== undefined && isSafeUrl(raw) ? raw : undefined;\n}\n\nfunction captionHtml(fields: Record<string, unknown>): string {\n const caption = str(fields, 'caption');\n return caption !== undefined ? `<figcaption>${escapeHtml(caption)}</figcaption>` : '';\n}\n\nfunction dimensionAttributes(media: MediaShape | undefined): string {\n const width = typeof media?.width === 'number' ? ` width=\"${String(media.width)}\"` : '';\n const height = typeof media?.height === 'number' ? ` height=\"${String(media.height)}\"` : '';\n return `${width}${height}`;\n}\n\n/** Fields: `text` or a Lexical `body`/`content`, optional `title`, `importance` (default `info`). */\nconst calloutRenderer: BlockRenderer = (fields, ctx) => {\n const importance = sanitizeIdent(str(fields, 'importance') ?? 'info');\n const title = str(fields, 'title');\n const text = str(fields, 'text');\n const richText = readLexicalChildren(fields);\n\n const titleHtml = title !== undefined ? `<strong>${escapeHtml(title)}</strong>` : '';\n const bodyHtml =\n richText !== undefined\n ? ctx.renderChildren(richText)\n : text !== undefined\n ? `<p>${escapeHtml(text)}</p>`\n : '';\n return `<aside class=\"lp-block-callout lp-block-callout--${importance}\">${titleHtml}${bodyHtml}</aside>`;\n};\n\n/** Fields: `image` (media) or `imageUrl`, `alt`, optional `caption`. */\nconst imageBlockRenderer: BlockRenderer = (fields) => {\n const media = readMedia(fields['image']);\n const url = media?.url ?? safeUrlOrUndefined(fields, 'imageUrl');\n if (url === undefined || !isSafeUrl(url)) return '';\n const alt = media?.alt ?? str(fields, 'alt') ?? '';\n return `<figure class=\"lp-block-image\"><img src=\"${escapeHtmlAttribute(url)}\" alt=\"${escapeHtmlAttribute(alt)}\"${dimensionAttributes(media)} loading=\"lazy\" decoding=\"async\">${captionHtml(fields)}</figure>`;\n};\n\n/** Fields: `video` (media) or `videoUrl`, `mimeType`, optional `poster` and `caption`. */\nconst videoBlockRenderer: BlockRenderer = (fields) => {\n const media = readMedia(fields['video']);\n const url = media?.url ?? safeUrlOrUndefined(fields, 'videoUrl');\n if (url === undefined || !isSafeUrl(url)) return '';\n const mime = media?.mimeType ?? str(fields, 'mimeType');\n const typeAttr = mime !== undefined ? ` type=\"${escapeHtmlAttribute(mime)}\"` : '';\n const poster = safeUrlOrUndefined(fields, 'poster');\n const posterAttr = poster !== undefined ? ` poster=\"${escapeHtmlAttribute(poster)}\"` : '';\n return `<figure class=\"lp-block-video\"><video controls${posterAttr}><source src=\"${escapeHtmlAttribute(url)}\"${typeAttr}></video>${captionHtml(fields)}</figure>`;\n};\n\n/** Fields: `code` or `content`, optional `language` and `caption`. */\nconst codeBlockRenderer: BlockRenderer = (fields) => {\n const code = str(fields, 'code') ?? str(fields, 'content');\n if (code === undefined) return '';\n const language = sanitizeIdent(str(fields, 'language') ?? '');\n const langClass = language === '' ? '' : ` class=\"language-${language}\"`;\n return `<figure class=\"lp-block-code\">${captionHtml(fields)}<pre><code${langClass}>${escapeHtml(code)}</code></pre></figure>`;\n};\n\n/** Fields: `label`/`text` and `href`/`url`; optional `lead`, `secondaryLabel`, `secondaryHref`. */\nconst ctaBlockRenderer: BlockRenderer = (fields) => {\n const label = str(fields, 'label') ?? str(fields, 'text');\n const href = safeUrlOrUndefined(fields, 'href') ?? safeUrlOrUndefined(fields, 'url');\n if (label === undefined || href === undefined) return '';\n const lead = str(fields, 'lead');\n const leadHtml =\n lead !== undefined ? `<p class=\"lp-block-cta__lead\">${escapeHtml(lead)}</p>` : '';\n\n const buttons = [renderCtaAnchor(label, href, true)];\n const secondaryLabel = str(fields, 'secondaryLabel');\n const secondaryHref = safeUrlOrUndefined(fields, 'secondaryHref');\n if (secondaryLabel !== undefined && secondaryHref !== undefined) {\n buttons.push(renderCtaAnchor(secondaryLabel, secondaryHref, false));\n }\n return `<div class=\"lp-block-cta\">${leadHtml}<div class=\"lp-block-cta__actions\">${buttons.join('')}</div></div>`;\n};\n\nfunction renderCtaAnchor(label: string, href: string, primary: boolean): string {\n const targetAttr = isExternalHttpUrl(href) ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : '';\n const variant = primary ? 'primary' : 'secondary';\n return `<a class=\"lp-block-cta__button lp-block-cta__button--${variant}\" href=\"${escapeHtmlAttribute(href)}\"${targetAttr}>${escapeHtml(label)}</a>`;\n}\n\nfunction readLexicalChildren(fields: Record<string, unknown>): readonly LexicalNode[] | undefined {\n const body = fields['body'] ?? fields['content'];\n if (typeof body !== 'object' || body === null) return undefined;\n const root = (body as { root?: { children?: unknown } }).root;\n if (!root || !Array.isArray(root.children)) return undefined;\n return root.children as readonly LexicalNode[];\n}\n\n/** Register every default block renderer under its kebab-, camel- and short slug. Idempotent. */\nexport function registerDefaultBlocks(): void {\n registerBlockRenderer('callout', calloutRenderer);\n registerBlockRenderer('image-block', imageBlockRenderer);\n registerBlockRenderer('imageBlock', imageBlockRenderer);\n registerBlockRenderer('image', imageBlockRenderer);\n registerBlockRenderer('video-block', videoBlockRenderer);\n registerBlockRenderer('videoBlock', videoBlockRenderer);\n registerBlockRenderer('video', videoBlockRenderer);\n registerBlockRenderer('code-block', codeBlockRenderer);\n registerBlockRenderer('codeBlock', codeBlockRenderer);\n registerBlockRenderer('code', codeBlockRenderer);\n registerBlockRenderer('cta-block', ctaBlockRenderer);\n registerBlockRenderer('ctaBlock', ctaBlockRenderer);\n registerBlockRenderer('cta', ctaBlockRenderer);\n}\n\nexport {\n calloutRenderer,\n imageBlockRenderer,\n videoBlockRenderer,\n codeBlockRenderer,\n ctaBlockRenderer,\n};\n"],"mappings":"AAmBO,IAGHA,ECjBJ,IAAMC,iBAAA,IAA0CC,IAAI,CAAC,QAAS,SAAU,UAAW,SAG7EC,EAA6B,wDAE7BC,EAAgB,mCAIhBC,EAAoB,YAGpBC,EAAiB,YAGhB,SAASC,UAAUC,GACxB,GAAmB,iBAARA,EAAkB,OAAO,EACpC,MAAMC,EAAUD,EAAIE,OAAOC,QAAQL,EAAgB,IACnD,GAAuB,IAAnBG,EAAQG,OAAc,OAAO,EACjC,GAAIT,EAA2BU,KAAKJ,GAAU,OAAO,EACrD,GAAIA,EAAQK,WAAW,MAAQL,EAAQK,WAAW,KAAM,OAAO,EAC/D,GAAIT,EAAkBQ,KAAKJ,GAAU,OAAO,EAC5C,GAAIA,EAAQK,WAAW,KAAM,OAAO,EACpC,IACE,MAAMC,EAAS,IAAIC,IAAIP,GACvB,OAAOR,EAAegB,IAAIF,EAAOG,SACnC,OACE,OAAOd,EAAcS,KAAKJ,EAC5B,CACF,CAGO,SAASU,kBAAkBX,GAChC,MAAMC,EAAUD,EAAIE,OAAOC,QAAQL,EAAgB,IACnD,MAAO,gBAAgBO,KAAKJ,IAAYJ,EAAkBQ,KAAKJ,EACjE,CCTA,IAAMW,iBAAA,IAAelB,IA4Bd,SAASmB,EAAuBC,GACjCF,EAASH,IAAIK,KACjBF,EAASG,IAAID,GAtCf,SAAcE,GACZ,IACEC,QAAQC,KAAKF,EACf,OAEA,CACF,CAiCEE,CACE,yDAAyDJ,qFA3B7D,SAAgBA,GACd,OAAIA,EAAKR,WAHY,iBAKjB,0IAIS,OAATQ,GAA0B,SAATA,EAEjB,+HAKF,+HAGJ,CAWkEK,CAAOL,OAEzE,CCrDA,IAAMM,iBAAA,IAAwC1B,IAAI,CAChD,IACA,KACA,SACA,IACA,KACA,IACA,IACA,IACA,SACA,OACA,QACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,aACA,OACA,MACA,MACA,OACA,MACA,IACA,OACA,MACA,UACA,UACA,QACA,SACA,SACA,MACA,SACA,aACA,MACA,UACA,SACA,QACA,QACA,MACA,MACA,KACA,OACA,OACA,OACA,IACA,QACA,QACA,QACA,QACA,KACA,KACA,KACA,UACA,WACA,QAII2B,iBAAA,IAAyC3B,IAAI,CACjD,QACA,SACA,WACA,SACA,SACA,UAII4B,iBAAA,IAA6C5B,IAAI,CACrD,SACA,QACA,SACA,SACA,QACA,OACA,OACA,OACA,OACA,QACA,SACA,SACA,WACA,MACA,OACA,WACA,QACA,WACA,WACA,aAGI6B,iBAAA,IAAuC7B,IAAI,CAC/C,KACA,QACA,OACA,MACA,QACA,OACA,aAGI8B,EAAmB,QACnBC,EAAmB,QAGnBC,EAA6D,CACjEC,iBAAG,IAAIjC,IAAI,CAAC,OAAQ,SAAU,MAAO,WAAY,WAAY,SAC7DkC,mBAAK,IAAIlC,IAAI,CAAC,MAAO,SAAU,QAAS,MAAO,QAAS,SAAU,UAAW,aAC7EmC,uBAAS,IAAInC,IAAI,IACjBoC,sBAAA,IAAYpC,IAAI,CAAC,MAAO,SAAU,QAAS,OAAQ,UACnDqC,qBAAO,IAAIrC,IAAI,CAAC,MAAO,WAAY,WAAY,OAAQ,QAAS,YAChEsC,qBAAA,IAAWtC,IAAI,CACb,MACA,SACA,WACA,WACA,OACA,QACA,UACA,QACA,SACA,gBAEFuC,oBAAM,IAAIvC,IAAI,CAAC,aACfwC,oBAAM,IAAIxC,IAAI,CAAC,UACfyC,iBAAG,IAAIzC,IAAI,CAAC,SACZ0C,0BAAY,IAAI1C,IAAI,CAAC,SACrB2C,qBAAO,IAAI3C,IAAI,CAAC,YAChB4C,kBAAA,IAAQ5C,IAAI,CAAC,UAAW,UAAW,QAAS,UAAW,SACvD6C,kBAAI,IAAI7C,IAAI,CAAC,UAAW,UAAW,YACnC8C,mBAAK,IAAI9C,IAAI,CAAC,SACd+C,wBAAU,IAAI/C,IAAI,CAAC,SACnBgD,kBAAI,IAAIhD,IAAI,CAAC,QAAS,WAAY,SAClCiD,kBAAI,IAAIjD,IAAI,CAAC,UACbkD,oBAAM,IAAIlD,IAAI,CAAC,UACfmD,mBAAK,IAAInD,IAAI,CAAC,WAGVoD,iBAAA,IAA0CpD,IAAI,CAAC,OAAQ,MAAO,OAAQ,WAQ/DqD,EAAN,cAAwCC,MAC3BlC,KAAO,6BAqCrBmC,iBAAA,IAA+CvD,IAAI,CACvD,KACA,OACA,mBACA,0BACA,iCAuEIwD,iBAA+BC,OAAOC,IAAI,2CAOzC,SAASC,qBAAqBC,GAClCC,WAA4BL,GAAiBI,QAAO,CACvD,CAOO,SAASE,aAAaC,EAAcC,GACzC,OAQK,SACLD,GAIA,MAAMH,EAAMK,IACZ,IAAKL,EAAK,KAesB,oBAArBM,kBAAoCA,iBACtC,IAAIZ,MAAM,4BAEZ,IAAID,EACT,iFAlBF,GAAa,KAATU,EAAa,MAAO,GAExB,MAAMI,EAlFR,WAKgB,CACZ,MAAMC,qBAAcC,IACpB,UAAYC,EAAKC,KAAUC,OAAOC,QAAQzC,GAAcoC,EAAQM,IAAIJ,EAAKC,GACzE,MAAO,CACLI,YAAajD,EACbkD,UAAWR,EACXS,mBAAmB,EACnBC,cAAc,EACdC,KAxBiC,SAyBjCC,2BAAA,IAAiBhF,IAErB,CAmBF,CA+CmBiF,GACXC,EAAWtB,EAAIuB,cAAc,YAInC,OAFAD,EAASE,UHrQJ,SAAqBrB,GAC1B,MAAMsB,EAnBR,WAEE,QAAmB,IAAfvF,EAA0B,OAAOA,EACrC,MAAMwF,EAVR,WACE,MAAMC,EAAa1B,WAA0C2B,aAC7D,GAAyB,iBAAdD,GAAwC,OAAdA,EAErC,MAAyB,mBADTA,EAAyCE,aAClBF,OAAwC,CACjF,CAKcG,GACZ,IACE5F,OACU,IAARwF,EACI,KACAA,EAAIG,aA5B2B,uBA4Ba,CAAEE,WAAaC,GAAUA,GAC7E,OAGE9F,EAAa,IACf,CACA,OAAOA,CACT,CAIiBmF,GACf,OAAe,OAAXI,EAAwBtB,EACrBsB,EAAOM,WAAW5B,EAC3B,CGiQuB8B,CAAY9B,GACjC+B,EAAiBZ,EAASa,QAAS5B,GAC5Be,EAASE,SAClB,CAvBSY,CAAuBjC,EAChC,CAoCA,SAASE,IACP,GAAgC,oBAArBC,mBAAqCA,iBAAkB,CAChE,MAAM+B,EAAYpC,WAA4BL,GAC9C,GAAIyC,EAAU,OAAOA,CACvB,CACA,GAAwB,oBAAbC,SACX,OAAOA,QACT,CAOA,SAASJ,EAAiBK,EAAkBd,GAE1C,UAAWe,KAASC,MAAMC,KAAKH,EAAKI,YA5LjB,IA6LbH,EAAMI,SACRC,EAAgBL,EAAkBf,GA7LnB,IA8LNe,EAAMI,UACfJ,EAAMM,QAGZ,CAEA,SAASD,EAAgBE,EAAkBtB,GACzC,MAAMf,EAAMqC,EAAQC,QAAQC,cAE5B,IAAIjF,EAAkBb,IAAIuD,IAAUe,EAAOR,mBAAqBlD,EAAcZ,IAAIuD,GAAlF,CAKA,IAAKe,EAAOV,YAAY5D,IAAIuD,GAG1B,OAFAwB,EAAiBa,EAAStB,QAC1BsB,EAAQG,eAAeH,EAAQJ,aASnC,SAA4BI,EAAkBrC,EAAae,GACzD,MAAM0B,EAAW1B,EAAOT,UAAUoC,IAAI1C,GAEtC,UAAW2C,KAAQZ,MAAMC,KAAKK,EAAQO,YAAa,CACjD,MAAM9F,EAAO6F,EAAK7F,KAAKyF,cACvB,GAAIzF,EAAKR,WAAW,OAAkB,UAATQ,EAC3BuF,EAAQQ,gBAAgBF,EAAK7F,UAD/B,CAIA,GAAoB,WAAhBiE,EAAON,KAAmB,CAC5B,GAAIM,EAAOP,cAAgBvB,EAAoBxC,IAAIK,GAAO,SAG1D,GAAa,OAATA,GAA0B,SAATA,GAAmBA,EAAKR,WA5QvB,iBA4QwD,CAC5E+F,EAAQQ,gBAAgBF,EAAK7F,MAGhB,SAATA,IAA2C,IAAxB2F,GAAUhG,IAAIK,IAAUD,EAA6BC,GAC5E,QACF,CACA,GAAIA,EAAKR,WAAWmB,GAAmB,CAChCsD,EAAOL,YAAYjE,IAAIK,KAC1BuF,EAAQQ,gBAAgBF,EAAK7F,MAC7BD,EAAuBC,IAEzB,QACF,CACA,GAAIS,EAAYd,IAAIK,IAASA,EAAKR,WAAWkB,GAAmB,QAClE,SACED,EAAYd,IAAIK,IAChBA,EAAKR,WAAWkB,IAChBV,EAAKR,WAAWmB,GAEhB,SAEEgF,GAAUhG,IAAIK,GACZgC,EAAerC,IAAIK,KAAUf,UAAU4G,EAAKG,OAC9CT,EAAQQ,gBAAgBF,EAAK7F,MACX,WAATA,GAAsBiG,EAAaJ,EAAKG,QACjDT,EAAQQ,gBAAgBF,EAAK7F,MAIjCuF,EAAQQ,gBAAgBF,EAAK7F,KAnC7B,CAoCF,CACF,CAlDEkG,CAAmBX,EAASrC,EAAKe,GACrB,MAARf,GA+DN,SAAsBiD,GACpB,MAAMC,EAAOD,EAAOE,aAAa,QACpB,OAATD,GAAkBvG,kBAAkBuG,KACxCD,EAAOG,aAAa,MAAO,uBACtBH,EAAOI,aAAa,WAAWJ,EAAOG,aAAa,SAAU,UACpE,CApEmBE,CAAajB,GAC9Bb,EAAiBa,EAAStB,EAV1B,MAFEsB,EAAQD,QAaZ,CAkDA,SAASW,EAAaD,GACpB,UAAW7B,KAAa6B,EAAMS,MAAM,KAAM,CACxC,MAAMtH,EAAUgF,EAAU/E,OAC1B,GAAuB,IAAnBD,EAAQG,OAAc,SAE1B,MAAOJ,EAAMC,GAAWA,EAAQsH,MAAM,KAAM,GAC5C,IAAKxH,UAAUC,GAAM,OAAO,CAC9B,CACA,OAAO,CACT,CClbA,IAAMwH,EAAiDtD,OAAOuD,OAAO,CACnE,IAAK,QACL,IAAK,OACL,IAAK,OACL,IAAK,SACL,IAAK,SACL,IAAK,SACL,IAAK,SACL,IAAK,WAGDC,EAAsB,cAGrB,SAASC,WAAWC,GAGzB,OAAOA,EAAKzH,QAAQuH,EAAsBG,GAASL,EAAaK,GAClE,CAOA,IAAMC,EAAiD5D,OAAOuD,OAAO,CACnE,IAAK,QACL,IAAK,OACL,IAAK,OACL,IAAK,SACL,IAAK,WAGDM,EAAsB,WAGrB,SAASC,oBAAoBlB,GAGlC,OAAOA,EAAM3G,QAAQ4H,EAAsBF,GAASC,EAAaD,GACnE,CCpCO,IAAMI,EAAa,CACxBC,KAAM,EACNC,OAAQ,EACRC,cAAe,EACfC,UAAW,EACXC,KAAM,GACNC,UAAW,GACXC,YAAa,GACbC,UAAW,KCVPC,EAAsD,CAC1D,EAAG,OACH,EAAG,SACH,EAAG,QACH,EAAG,WAGCC,iBAAmB,IAAIjJ,IAAI,CAAC,OAAQ,SAAU,QAAS,UAAW,QAAS,QAG1E,SAASkJ,EAAiB/C,GAC/B,MAAMgD,EAAMhD,EAAKiD,OACjB,MAAmB,iBAARD,GAAoBF,EAAiBlI,IAAIoI,GAAaA,EAC9C,iBAARA,EAAyBH,EAAkBG,QAAtD,CAEF,CAEO,SAASE,EAAclD,GAC5B,MAAMmD,EAASnD,EAAKmD,OACpB,MAAyB,iBAAXA,GAAuBA,EAAS,EAAIA,EAAS,CAC7D,CAEO,SAASC,EAAapD,GAC3B,MAAuB,QAAnBA,EAAKqD,UAA4B,aACd,QAAnBrD,EAAKqD,UAA4B,aAC9B,EACT,CAMO,SAASC,EAAqBtD,GACnC,MAAMuD,EAAQR,EAAiB/C,GACzBmD,EAASD,EAAclD,GACvBwD,EAAoB,GAG1B,YAFc,IAAVD,GAAqBC,EAAQC,KAAK,YAAYF,KAC9CJ,EAAS,GAAGK,EAAQC,KAAK,aAAaC,OAAOP,MACvB,IAAnBK,EAAQjJ,OAAe,GAAK,WAAWiJ,EAAQG,KAAK,OAC7D,CCxCA,ICEMC,iBAAa,IAAI/J,IAAI,CAAC,KAAM,KAAM,KAAM,KAAM,KAAM,OCsBnD,SAASgK,EAAS5C,GACvB,MAAwB,iBAAVA,GAAgC,OAAVA,EAC/BA,OACD,CACN,CAEO,SAAS6C,EAAU7C,GACxB,OAAO4C,EAAS5C,EAClB,CAGO,SAAS8C,EAAc9C,GAC5B,OAAOA,EAAM3G,QAAQ,kBAAmB,KAAKoG,aAC/C,CAEA,SAASsD,EAAS/C,GAChB,MAAwB,iBAAVA,GAAsBA,EAAM1G,OAAS,EAAI0G,OAAQ,CACjE,CChCA,IAAMgD,EAAe,6CAEfC,EAA6B,CAAClE,EAAMmE,KACxC,MAAMC,EAAWD,EAAIE,eAAerE,EAAKoE,UAAY,IAC/CE,EAAST,EAAS7D,EAAa,QAC/B7F,EAOR,SACE6F,EACAsE,GAEA,GAA6B,aAAzBA,GAAmB,SAAM,OAM/B,SAAqB7G,GACnB,MAAMwD,EAAQ4C,EAASA,EAASpG,IAAc,OACxCtD,EAAM8G,GAAa,IACzB,GAAmB,iBAAR9G,GAAoBA,EAAII,OAAS,EAAG,OAAOJ,EACtD,MAAMoK,EAAOtD,GAAc,KAC3B,MAAuB,iBAATsD,GAAqBA,EAAKhK,OAAS,EAAI,IAAIgK,SAAS,CACpE,CAZkDC,CAAYF,EAAY,KACxE,MAAMnK,EAAMmK,GAAc,KAAKtE,EAAU,IACzC,MAAsB,iBAAR7F,GAAoBA,EAAII,OAAS,EAAIJ,OAAM,CAC3D,CAdcsK,CAAWzE,EAAMsE,GAC7B,QAAY,IAARnK,IAAsBD,UAAUC,GAAM,OAAOiK,EACjD,MAAMM,EACqB,iBAAlB1E,EAAY,MAAiB,WAAW8B,WAAW9B,EAAY,UAAQ,GAChF,MAAO,YAAYmC,oBAAoBhI,MAsBzC,SACE6F,EACAsE,EACAnK,GAEA,IAA2B,IAAvBmK,GAAiB,QAAcxJ,kBAAkBX,GAAM,OAAO8J,EAClE,MAAMU,EAAmC,iBAAnB3E,EAAa,OAAiBA,EAAa,OAAI,GACrE,MAAe,KAAX2E,EAAsB,GACX,WAAXA,EAA4BV,EACzB,YAAYnC,WAAW6C,KAChC,CAhCiDC,CAAgB5E,EAAMsE,EAAQnK,KAAOuK,KAAaN,SCGnG,SAASS,EAAY7E,GACnB,GAAyB,iBAAdA,EAAK+B,KAAS,OAAiB/B,EAAK+B,KAC/C,IAAK/B,EAAKoE,SAAU,MAAO,GAC3B,IAAIU,EAAM,GACV,UAAW7E,KAASD,EAAKoE,SAAUU,GAAOD,EAAY5E,GACtD,OAAO6E,CACT,CCLA,SAASC,EAAoB9D,GAG3B,MAAO,GAF8B,iBAAhBA,EAAM+D,MAAqB,WAAWtB,OAAOzC,EAAM+D,UAAY,KAC7C,iBAAjB/D,EAAMgE,OAAsB,YAAYvB,OAAOzC,EAAMgE,WAAa,IAE1F,CAEA,SAASC,EAAcjE,GACrB,MAAiC,iBAAnBA,EAAMkE,SAAwB,UAAUhD,oBAAoBlB,EAAMkE,aAAe,EACjG,CC1BA,ICQMC,iBAAA,IAAelH,IAGd,SAASmH,EAAsBC,EAAmBC,GACvDH,EAAS7G,IAAI+G,EAAWC,EAC1B,CAGO,SAASC,EAAoBF,GAClC,OAAOF,EAASvE,IAAIyE,EACtB,CAGO,SAASG,IACd,MAAO,IAAIL,EAASM,OACtB,CCLA,SAASC,EACP3F,EACAmE,EACAhG,EACAyH,GAEA,MAAMtB,EAAST,EAAS7D,EAAa,SAAM,GACrCsF,EAA2C,iBAAxBhB,EAAkB,UAAiBA,EAAkB,UAAI,GAC5EC,EAAOR,EAAcuB,GACrB9B,EAAmB,KAATe,EAAcqB,EAAY,GAAGA,KAAaA,MAAcrB,IACxE,GAAkB,KAAde,EAAkB,CACpB,MAAMO,EAASL,EAAoBF,IAAcE,EAAoBjB,GACrE,GAAIsB,EAAA,OAAeA,EAAOvB,EAAQ,CAAED,eAAgBF,EAAIE,iBAGxDF,EAAI2B,oBAAoBR,EAAW9B,EACrC,CACA,MAAO,IAAIrF,YAAcqF,QAAcrF,IACzC,CCpBA,SAAS4H,EAAc9K,EAAcgG,GACnC,MAAwB,iBAAVA,GAAsBA,EAAQ,EAAI,IAAIhG,MAASyI,OAAOzC,MAAY,EAClF,CCTO,IAAM+E,EAAiE,CAC5EjE,KCVkC/B,IAElC,IAAI8E,EAAMhD,WADuB,iBAAd9B,EAAK+B,KAAoB/B,EAAK+B,KAAO,IAExD,MAAMkB,EAAgC,iBAAhBjD,EAAKiD,OAAsBjD,EAAKiD,OAAS,EAS/D,OARmC,KAA9BA,EAASb,EAAWK,QAAaqC,EAAM,SAASA,YAClB,KAA9B7B,EAASb,EAAWC,QAAayC,EAAM,WAAWA,cAClB,KAAhC7B,EAASb,EAAWE,UAAewC,EAAM,OAAOA,UACb,KAAnC7B,EAASb,EAAWI,aAAkBsC,EAAM,MAAMA,SACX,KAAvC7B,EAASb,EAAWG,iBAAsBuC,EAAM,MAAMA,SACnB,KAAnC7B,EAASb,EAAWM,aAAkBoC,EAAM,QAAQA,WACf,KAArC7B,EAASb,EAAWO,eAAoBmC,EAAM,QAAQA,WACnB,KAAnC7B,EAASb,EAAWQ,aAAkBkC,EAAM,SAASA,YACnDA,GDDPmB,UVfsC,CAACjG,EAAMmE,KAC7C,MAAMC,EAAWD,EAAIE,eAAerE,EAAKoE,UAAY,IACrD,MAAO,KAAKhB,EAAapD,KAAQsD,EAAqBtD,MAASoE,SUc/D8B,QTZoC,CAAClG,EAAMmE,KAC3C,MAAMgC,EAAgC,iBAAhBnG,EAAU,IAAiBA,EAAU,IAAEU,cAAgB,KACvEvC,EAAMyF,EAAWhJ,IAAIuL,GAAUA,EAAS,KACxC/B,EAAWD,EAAIE,eAAerE,EAAKoE,UAAY,IACrD,MAAO,IAAIjG,IAAMiF,EAAapD,KAAQsD,EAAqBtD,MAASoE,MAAajG,MSSjFiI,KEdiC,CAACpG,EAAMmE,KACxC,MAAMkC,EAAuC,iBAArBrG,EAAe,SAAiBA,EAAe,SAAI,SACrE7B,EAAmB,WAAbkI,EAAwB,KAAO,KACrCC,EACS,WAAbD,GAAkD,iBAAlBrG,EAAY,OAAkBA,EAAY,MAAI,EAC1E,WAAW0D,OAAO1D,EAAY,UAC9B,GACAuG,EAAyB,UAAbF,EAAuB,eAAiB,GACpDjC,EAAWD,EAAIE,eAAerE,EAAKoE,UAAY,IACrD,MAAO,IAAIjG,IAAMiF,EAAapD,KAAQsD,EAAqBtD,KAAQsG,IAAYC,KAAanC,MAAajG,MFMzGqI,SEHqC,CAACxG,EAAMmE,KAC5C,MAAMC,EAAWD,EAAIE,eAAerE,EAAKoE,UAAY,IACrD,GAA+B,kBAApBpE,EAAc,QAEvB,MAAO,qCADOA,EAAc,QAAI,OAAS,WACYsD,EAAqBtD,MAASoE,SAErF,MAAMqC,EACqB,iBAAlBzG,EAAY,MAAiB,WAAW8B,WAAW4B,OAAO1D,EAAY,WAAS,GACxF,MAAO,MAAMoD,EAAapD,KAAQsD,EAAqBtD,KAAQyG,KAAarC,UFJ5EsC,KAAMxC,EACNyC,SAAUzC,EACV0C,MGrBkC,CAAC5G,EAAMmE,KACzC,MAAMC,EAAWD,EAAIE,eAAerE,EAAKoE,UAAY,IACrD,MAAO,cAAchB,EAAapD,KAAQsD,EAAqBtD,MAASoE,kBHoBxErH,KNlBkCiD,IAClC,MAAM6G,EAAW9C,EAA0C,iBAArB/D,EAAe,SAAiBA,EAAe,SAAI,IAEzF,MAAO,aADwB,KAAb6G,EAAkB,GAAK,oBAAoBA,QAC5B/E,WAAW+C,EAAY7E,oBMgBxD,iBNb2CA,IAC3C,MAAM+B,EAA4B,iBAAd/B,EAAK+B,KAAoB/B,EAAK+B,KAAO,GAKzD,MAAO,QAH4B,iBAA1B/B,EAAoB,cACvB,iBAAiB+D,EAAc/D,EAAoB,kBACnD,MACsB8B,WAAWC,aMQvC+E,UIzBsC,IAAM,OJ0B5CC,eIzB2C,IAAM,OJ0BjDC,IIzBgC,IAAM,KJ0BtCC,OLpBoCjH,IACpC,MAAMiB,EAAQ6C,EAAU9D,EAAY,OACpC,QAAc,IAAViB,EAAqB,MAAO,GAChC,MAAM9G,EAAM8G,EAAM9G,IAClB,GAAmB,iBAARA,IAAqBD,UAAUC,GAAM,MAAO,GAEvD,MAAM+M,EAAiC,iBAAnBjG,EAAMkE,SAAwBlE,EAAMkE,SAAW,GACnE,OAAI+B,EAAKzM,WAAW,UAuBtB,SAAqBwG,EAAmB9G,GACtC,MAAO,kBAAkB4K,EAAoB9D,mBAAuBkB,oBAAoBhI,MAAQ+K,EAAcjE,aAChH,CAzBwCkG,CAAYlG,EAAO9G,GACrD+M,EAAKzM,WAAW,UA0BtB,SAAqBwG,EAAmB9G,GACtC,MAAO,gCAAgCgI,oBAAoBhI,MAAQ+K,EAAcjE,aACnF,CA5BwCmG,CAAYnG,EAAO9G,GAC5C,KAAT+M,GAAeA,EAAKzM,WAAW,UAgBrC,SAAqBwG,EAAmB9G,GACtC,MAAMkN,EAA2B,iBAAdpG,EAAMoG,IAAmBvF,WAAWb,EAAMoG,KAAO,GACpE,MAAO,aAAalF,oBAAoBhI,YAAckN,KAAOtC,EAAoB9D,qCACnF,CAnBuDqG,CAAYrG,EAAO9G,GA6B1E,SAA4B8G,EAAmB9G,GAC7C,MAAMoN,EAAkC,iBAAnBtG,EAAMuG,SAAwB1F,WAAWb,EAAMuG,UAAY1F,WAAW3H,GAC3F,MAAO,YAAYgI,oBAAoBhI,iDAAmDoN,OAC5F,CA/BSE,CAAmBxG,EAAO9G,IKWjCuN,aJxB0C1H,IAC1C,MAAM2H,EAA2C,iBAAvB3H,EAAiB,WAAiBA,EAAiB,WAAI,GAC3EiB,EAAQ4C,EAAS7D,EAAY,OAC7BuH,EAAQzF,YAAYb,GJqCrB,SAA2BA,GAChC,MAAMsG,EAAQvD,EAAS/C,EAAM2G,QAAU5D,EAAS/C,EAAMhG,OAAS+I,EAAS/C,EAAMsD,MAC9E,YAAc,IAAVgD,EAA4BA,OACZ,IAAbtG,EAAM4G,QAAmB,EAAYnE,OAAOzC,EAAM4G,GAC3D,CIzCqCC,CAAkB7G,KAAW,IAAI0G,KAC9DpD,EAAOR,EAAc4D,GACrBI,EACK,KAATxD,EAAc,uBAAyB,oCAAoCA,KACvEpK,EAAM8G,GAAO9G,IACnB,MAAmB,iBAARA,GAAoBD,UAAUC,GAChC,YAAYgI,oBAAoBhI,MAAQ4N,KAAaR,QAEvD,QAAQQ,KAAaR,YIc5BS,MFakC,CAAChI,EAAMmE,IAAQwB,EAAgB3F,EAAMmE,EAAK,MAAO,YEZnF8D,YFcwC,CAACjI,EAAMmE,IAC/CwB,EAAgB3F,EAAMmE,EAAK,OAAQ,mBEdnC3H,MDzBkC,CAACwD,EAAMmE,IACzC,SAASf,EAAapD,aAAgBmE,EAAIE,eAAerE,EAAKoE,UAAY,sBCyB1E8D,SDvBqC,CAAClI,EAAMmE,IAC5C,OAAOA,EAAIE,eAAerE,EAAKoE,UAAY,WCuB3C+D,UDrBsC,CAACnI,EAAMmE,KAC7C,MAAMiE,EAAwC,iBAAxBpI,EAAkB,YAAiBA,EAAkB,YAAI,EACzE7B,EAAO,EAAAiK,EAAsD,KAAP,KAG5D,MAAO,IAAIjK,IAdM,IAafiK,EAAwB,eAZN,IAYuBA,EAA2B,eAAiB,KAC9DrC,EAAc,UAAW/F,EAAc,WAAK+F,EAAc,UAAW/F,EAAc,YAAMmE,EAAIE,eAAerE,EAAKoE,UAAY,QAAQjG,OME1JiH,qBAAelH,IAGd,SAASmK,EAASC,EAAc/C,GACrCH,EAAS7G,IAAI+J,EAAM/C,EACrB,CAGO,SAASgD,EAAOD,GACrB,OAAOlD,EAASvE,IAAIyH,IAAStC,EAAuBsC,EACtD,CCTA,IAAIE,IAAoB,EAGjB,SAASC,GAAiBxH,GAC/B,GAAqB,iBAAVA,GAAgC,OAAVA,EAAgB,OAAO,EACxD,KAAM,SAAUA,GAAQ,OAAO,EAC/B,MAAMyH,EAAOzH,EAAMyH,KACnB,MAAoB,iBAATA,GAA8B,OAATA,GAC1B,aAAcA,GACbxI,MAAMyI,QAAQD,EAAKtE,SAC5B,CAGO,SAASwE,GAAchJ,EAAsB/B,EAAgC,IAClF,IAAK4K,GAAiB7I,GAAU,MAAO,GACvC,MAAMhC,EAuBR,SACEkI,GAEA,MAAM+C,EAA6B,CACjCxE,eAAiBD,IACf,IAAIU,EAAM,GACV,UAAW7E,KAASmE,EAAUU,GAAOgE,GAAW7I,EAAO4I,GACvD,OAAO/D,GAET/B,mBACAG,gBACA4C,qBAEF,OAAO+C,CACT,CArCeE,CAAclL,EAAQiI,mBAAmBzB,eAAezE,EAAQ8I,KAAKtE,UAClF,OAAyB,IAArBvG,EAAQmL,SAA2BpL,OpBmTV,IAAtBE,IoBlT4BH,aAAaC,IAsDlD,WACE,IAAI4K,GAAJ,CACAA,IAAoB,EACpB,IACEpN,QAAQC,KACN,0MAGJ,OAEA,CATuB,CAUzB,CAhEE4N,GACOrL,EACT,CAGO,SAASsL,GAAmBtJ,GACjC,OAAK6I,GAAiB7I,GACfA,EAAQ8I,KAAKtE,SAAS+E,IAAIC,IAAkBzF,KAAK,MAAMtJ,OADvB,EAEzC,CA4BA,SAASyO,GAAW9I,EAAmB6I,GACrC,MAAMtD,EAAWgD,EAAOvI,EAAKsI,MAC7B,OAAI/C,EAAiBA,EAASvF,EAAM6I,QACX,IAAlB7I,EAAKoE,SAAyByE,EAAQxE,eAAerE,EAAKoE,UAAY,EAC/E,CAEA,SAASgF,GAAiBpJ,GACxB,GAAyB,iBAAdA,EAAK+B,KAAS,OAAiB/B,EAAK+B,KAC/C,GAAkB,cAAd/B,EAAKsI,KAAsB,MAAO,KACtC,QAAsB,IAAlBtI,EAAKoE,SAAwB,MAAO,GACxC,IAAIU,EAAM,GACV,UAAW7E,KAASD,EAAKoE,SAAUU,GAAOsE,GAAiBnJ,GAC3D,OAAO6E,CACT,CC7EA,SAASuE,GAAI/E,EAAiCgF,GAC5C,MAAMrI,EAAQqD,EAAOgF,GACrB,MAAwB,iBAAVrI,GAAsBA,EAAM1G,OAAS,EAAI0G,OAAQ,CACjE,CAEA,SAASsI,GAAmBjF,EAAiCgF,GAC3D,MAAME,EAAMH,GAAI/E,EAAQgF,GACxB,YAAe,IAARE,GAAqBtP,UAAUsP,GAAOA,OAAM,CACrD,CAEA,SAASC,GAAYnF,GACnB,MAAMoF,EAAUL,GAAI/E,EAAQ,WAC5B,YAAmB,IAAZoF,EAAwB,eAAe5H,WAAW4H,kBAA0B,EACrF,CASA,IAAMC,GAAiC,CAACrF,EAAQH,KAC9C,MAAMyF,EAAa7F,EAAcsF,GAAI/E,EAAQ,eAAiB,QACxDsD,EAAQyB,GAAI/E,EAAQ,SACpBvC,EAAOsH,GAAI/E,EAAQ,QACnBuF,EAkER,SAA6BvF,GAC3B,MAAMwF,EAAOxF,EAAa,MAAKA,EAAgB,QAC/C,GAAoB,iBAATwF,GAA8B,OAATA,EAAe,OAC/C,MAAMpB,EAAQoB,EAA2CpB,KACzD,OAAKA,GAASxI,MAAMyI,QAAQD,EAAKtE,UAC1BsE,EAAKtE,cADgC,CAE9C,CAxEmB2F,CAAoBzF,GASrC,MAAO,oDAAoDsF,WAP/B,IAAVhC,EAAsB,WAAW9F,WAAW8F,cAAoB,UAEnE,IAAbiC,EACI1F,EAAIE,eAAewF,QACV,IAAT9H,EACE,MAAMD,WAAWC,SACjB,cAKJiI,GAAqC1F,IACzC,MAAM2F,EAAQnG,EAAUQ,EAAc,OAChCnK,EAAM8P,GAAO9P,KAAOoP,GAAmBjF,EAAQ,YACrD,QAAY,IAARnK,IAAsBD,UAAUC,GAAM,MAAO,GACjD,MAAMkN,EAAM4C,GAAO5C,KAAOgC,GAAI/E,EAAQ,QAAU,GAChD,MAAO,4CAA4CnC,oBAAoBhI,YAAcgI,oBAAoBkF,MA7B3G,SAA6B4C,GAG3B,MAAO,GAF+B,iBAAjBA,GAAOjF,MAAqB,WAAWtB,OAAOuG,EAAMjF,UAAY,KAC7C,iBAAlBiF,GAAOhF,OAAsB,YAAYvB,OAAOuG,EAAMhF,WAAa,IAE3F,CAyBmHF,CAAoBkF,sCAA0CR,GAAYnF,eAIvL4F,GAAqC5F,IACzC,MAAM2F,EAAQnG,EAAUQ,EAAc,OAChCnK,EAAM8P,GAAO9P,KAAOoP,GAAmBjF,EAAQ,YACrD,QAAY,IAARnK,IAAsBD,UAAUC,GAAM,MAAO,GACjD,MAAM+M,EAAO+C,GAAO9E,UAAYkE,GAAI/E,EAAQ,YACtC6F,OAAoB,IAATjD,EAAqB,UAAU/E,oBAAoB+E,MAAW,GACzEkD,EAASb,GAAmBjF,EAAQ,UAE1C,MAAO,sDADuB,IAAX8F,EAAuB,YAAYjI,oBAAoBiI,MAAa,mBACJjI,oBAAoBhI,MAAQgQ,aAAoBV,GAAYnF,eAI3I+F,GAAoC/F,IACxC,MAAMvH,EAAOsM,GAAI/E,EAAQ,SAAW+E,GAAI/E,EAAQ,WAChD,QAAa,IAATvH,EAAoB,MAAO,GAC/B,MAAM8J,EAAW9C,EAAcsF,GAAI/E,EAAQ,aAAe,IACpDgG,EAAyB,KAAbzD,EAAkB,GAAK,oBAAoBA,KAC7D,MAAO,iCAAiC4C,GAAYnF,eAAoBgG,KAAaxI,WAAW/E,4BAI5FwN,GAAmCjG,IACvC,MAAMiD,EAAQ8B,GAAI/E,EAAQ,UAAY+E,GAAI/E,EAAQ,QAC5CjD,EAAOkI,GAAmBjF,EAAQ,SAAWiF,GAAmBjF,EAAQ,OAC9E,QAAc,IAAViD,QAAgC,IAATlG,EAAoB,MAAO,GACtD,MAAMmJ,EAAOnB,GAAI/E,EAAQ,QACnBmG,OACK,IAATD,EAAqB,iCAAiC1I,WAAW0I,SAAc,GAE3EE,EAAU,CAACC,GAAgBpD,EAAOlG,GAAM,IACxCuJ,EAAiBvB,GAAI/E,EAAQ,kBAC7BuG,EAAgBtB,GAAmBjF,EAAQ,iBAIjD,YAHuB,IAAnBsG,QAAkD,IAAlBC,GAClCH,EAAQjH,KAAKkH,GAAgBC,EAAgBC,GAAe,IAEvD,6BAA6BJ,uCAA8CC,EAAQ/G,KAAK,mBAGjG,SAASgH,GAAgBpD,EAAelG,EAAcyJ,GACpD,MAAMC,EAAajQ,kBAAkBuG,GAAQ,6CAA+C,GAE5F,MAAO,wDADSyJ,EAAU,UAAY,sBAC2C3I,oBAAoBd,MAAS0J,KAAcjJ,WAAWyF,QACzI,CAWO,SAASyD,KACd3F,EAAsB,UAAWsE,IACjCtE,EAAsB,cAAe2E,IACrC3E,EAAsB,aAAc2E,IACpC3E,EAAsB,QAAS2E,IAC/B3E,EAAsB,cAAe6E,IACrC7E,EAAsB,aAAc6E,IACpC7E,EAAsB,QAAS6E,IAC/B7E,EAAsB,aAAcgF,IACpChF,EAAsB,YAAagF,IACnChF,EAAsB,OAAQgF,IAC9BhF,EAAsB,YAAakF,IACnClF,EAAsB,WAAYkF,IAClClF,EAAsB,MAAOkF,GAC/B,Q","ignoreList":[]}
1
+ {"version":3,"file":"lexical.js","names":["SLOT","Symbol","for","SAFE_PROTOCOLS","Set","DANGEROUS_PROTOCOL_PATTERN","RELATIVE_PATH","PROTOCOL_RELATIVE","PARSER_IGNORED","isSafeUrl","url","trimmed","trim","replace","length","test","startsWith","parsed","URL","has","protocol","isExternalHttpUrl","reported","reportDroppedAttribute","name","add","message","console","warn","reason","ALLOWED_TAGS","FORM_CONTROLS","REMOVE_COMPLETELY","ATTR_GLOBAL","ATTR_ARIA_PREFIX","ATTR_DATA_PREFIX","ATTR_BY_TAG","a","img","picture","source","audio","video","time","abbr","q","blockquote","table","th","td","col","colgroup","ol","li","code","pre","URL_ATTRIBUTES","SanitizerEnvironmentError","Error","TEMPLATE_ATTRIBUTES","DOCUMENT_SLOT","setSanitizerDocument","doc","globalThis","sanitizeHtml","html","options","resolveDocument","__INLINE_BUILD__","resolved","attrMap","Map","tag","attrs","Object","entries","set","allowedTags","attrByTag","allowFormControls","templateMode","mode","allowedData","resolvePolicy","template","createElement","innerHTML","policy","policies","realm","existing","created","shared","override","auto","api","candidate","trustedTypes","createPolicy","factory","createHTML","input","trustedHtml","sanitizeFragment","content","sanitizeHtmlWithPolicy","document","node","child","Array","from","childNodes","nodeType","sanitizeElement","remove","element","tagName","toLowerCase","replaceWith","tagAttrs","get","attr","attributes","removeAttribute","value","isSafeSrcset","sanitizeAttributes","anchor","href","getAttribute","setAttribute","hasAttribute","hardenAnchor","split","HTML_ESCAPES","freeze","HTML_ESCAPE_PATTERN","escapeHtml","text","char","ATTR_ESCAPES","ATTR_ESCAPE_PATTERN","escapeHtmlAttribute","TextFormat","BOLD","ITALIC","STRIKETHROUGH","UNDERLINE","CODE","SUBSCRIPT","SUPERSCRIPT","HIGHLIGHT","ALIGNMENT_NUMERIC","ALIGNMENT_STRING","resolveAlignment","fmt","format","resolveIndent","indent","dirAttribute","direction","layoutClassAttribute","align","classes","push","String","join","VALID_TAGS","asRecord","readMedia","sanitizeIdent","nonEmpty","BLANK_TARGET","linkRenderer","ctx","children","renderChildren","fields","slug","internalUrl","resolveUrl","titleAttr","target","targetAttribute","extractText","out","dimensionAttributes","width","height","typeAttribute","mimeType","registry","registerBlockRenderer","blockType","renderer","lookupBlockRenderer","registeredBlockTypes","keys","renderBlockNode","baseClass","custom","onUnrenderedBlock","spanAttribute","BUILTIN_NODE_RENDERERS","paragraph","heading","tagRaw","list","listType","startAttr","checkAttr","listitem","valueAttr","link","autolink","quote","language","linebreak","horizontalrule","tab","upload","mime","renderVideo","renderAudio","alt","renderImage","label","filename","renderFallbackLink","relationship","relationTo","title","id","pickRelationLabel","classAttr","block","inlineBlock","tablerow","tablecell","header","register","type","lookup","warnedNoSanitizer","isLexicalContent","root","isArray","lexicalToHtml","context","renderNode","createContext","sanitize","warnNoSanitizerOnce","lexicalToPlainText","map","extractPlainText","str","key","safeUrlOrUndefined","raw","captionHtml","caption","calloutRenderer","importance","richText","body","readLexicalChildren","imageBlockRenderer","media","videoBlockRenderer","typeAttr","poster","codeBlockRenderer","langClass","ctaBlockRenderer","lead","leadHtml","buttons","renderCtaAnchor","secondaryLabel","secondaryHref","primary","targetAttr","registerDefaultBlocks"],"sources":["../src/security/trusted-types.ts","../src/security/url-validator.ts","../src/security/sanitizer-report.ts","../src/security/sanitizer.ts","../src/security/escape.ts","../src/lexical/types.ts","../src/lexical/utils.ts","../src/lexical/nodes/paragraph.ts","../src/lexical/nodes/heading.ts","../src/lexical/value-shapes.ts","../src/lexical/nodes/link.ts","../src/lexical/nodes/code.ts","../src/lexical/nodes/upload.ts","../src/lexical/nodes/relationship.ts","../src/lexical/blocks/registry.ts","../src/lexical/nodes/block.ts","../src/lexical/nodes/table.ts","../src/lexical/nodes/builtin.ts","../src/lexical/nodes/text.ts","../src/lexical/nodes/list.ts","../src/lexical/nodes/quote.ts","../src/lexical/nodes/linebreak.ts","../src/lexical/registry.ts","../src/lexical/render.ts","../src/lexical/blocks/defaults.ts"],"sourcesContent":["/**\n * Trusted Types: every HTML sink routes through one policy, `payload-live-preview`,\n * whose `createHTML` is the identity — what reaches a sink is already sanitized\n * or escaped. Without the API, strings pass through untouched.\n */\n\n/** The subset of the Trusted Types API this module needs. */\nexport interface TrustedHtmlPolicyLike {\n createHTML(input: string): unknown;\n}\n\ninterface TrustedTypesFactoryLike {\n createPolicy(\n name: string,\n rules: { createHTML: (input: string) => string },\n ): TrustedHtmlPolicyLike;\n}\n\n/** @internal */\nexport const TRUSTED_TYPES_POLICY_NAME = 'payload-live-preview';\n\n// Held on the realm, not in this module: every package entry is its own bundle\n// with its own copy of this file, and a page's `trusted-types` directive allows\n// the name once. A second copy that asked for it again would be refused and fall\n// back to strings; instead every copy shares the one policy, and a policy set\n// through one entry reaches the others.\nconst SLOT: unique symbol = Symbol.for('payload-live-preview.trusted-types');\ninterface SharedPolicies {\n override?: TrustedHtmlPolicyLike | null | undefined;\n auto?: TrustedHtmlPolicyLike | null | undefined;\n}\ninterface Realm {\n [SLOT]?: SharedPolicies | undefined;\n}\nfunction shared(): SharedPolicies {\n const realm = globalThis as Realm;\n const existing = realm[SLOT];\n if (existing !== undefined) return existing;\n const created: SharedPolicies = {};\n realm[SLOT] = created;\n return created;\n}\n\n/**\n * Use `policy` for every sink, `null` to assign plain strings, `undefined` to\n * return to the auto-created package policy.\n */\nexport function setTrustedTypesPolicy(policy: TrustedHtmlPolicyLike | null | undefined): void {\n shared().override = policy;\n}\n\nfunction factory(): TrustedTypesFactoryLike | undefined {\n const candidate = (globalThis as { trustedTypes?: unknown }).trustedTypes;\n if (typeof candidate !== 'object' || candidate === null) return undefined;\n const create = (candidate as { createPolicy?: unknown }).createPolicy;\n return typeof create === 'function' ? (candidate as TrustedTypesFactoryLike) : undefined;\n}\n\nfunction resolvePolicy(): TrustedHtmlPolicyLike | null {\n const policies = shared();\n if (policies.override !== undefined) return policies.override;\n if (policies.auto !== undefined) return policies.auto;\n const api = factory();\n try {\n policies.auto =\n api === undefined\n ? null\n : api.createPolicy(TRUSTED_TYPES_POLICY_NAME, { createHTML: (input) => input });\n } catch {\n // The site's `trusted-types` directive does not list this name; the\n // sink assignment will surface the enforcement error.\n policies.auto = null;\n }\n return policies.auto;\n}\n\n/** `html` as a `TrustedHTML` when a policy exists, else the string. Typed `string` for `innerHTML`. @internal */\nexport function trustedHtml(html: string): string {\n const policy = resolvePolicy();\n if (policy === null) return html;\n return policy.createHTML(html) as string;\n}\n\n/** Test hook: forget the auto-created policy. */\nexport function __resetTrustedTypesForTests(): void {\n (globalThis as Realm)[SLOT] = undefined;\n}\n","/**\n * URL safety: the one scheme allow-list the runtime, the client and the\n * sanitizer share. Empty strings are not safe (`<a href=\"\">` is never emitted).\n */\n\nconst SAFE_PROTOCOLS: ReadonlySet<string> = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n// Browsers strip leading whitespace before scheme detection.\nconst DANGEROUS_PROTOCOL_PATTERN = /^\\s*(?:javascript|data|vbscript|file|blob|about)\\s*:/i;\n\nconst RELATIVE_PATH = /^(?:\\.{1,2}\\/|[a-zA-Z0-9_-]+\\/?)/;\n\n// The URL parser treats `\\` as `/` for special schemes, so `/\\evil.com`\n// resolves to another origin rather than to a same-origin path.\nconst PROTOCOL_RELATIVE = /^[\\\\/]{2}/;\n\n/** The URL parser drops these anywhere in the input before it looks at anything. */\nconst PARSER_IGNORED = /[\\t\\n\\r]/g;\n\n/** `true` only for absolute `http`/`https`/`mailto`/`tel` URLs, protocol-relative URLs, paths, `#`/`?` fragments and relative paths. */\nexport function isSafeUrl(url: unknown): boolean {\n if (typeof url !== 'string') return false;\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n if (trimmed.length === 0) return false;\n if (DANGEROUS_PROTOCOL_PATTERN.test(trimmed)) return false;\n if (trimmed.startsWith('#') || trimmed.startsWith('?')) return true;\n if (PROTOCOL_RELATIVE.test(trimmed)) return true;\n if (trimmed.startsWith('/')) return true;\n try {\n const parsed = new URL(trimmed);\n return SAFE_PROTOCOLS.has(parsed.protocol);\n } catch {\n return RELATIVE_PATH.test(trimmed);\n }\n}\n\n/** Whether a URL points at another HTTP(S) origin, protocol-relative forms included, and so needs `noopener` hardening; every URL these two patterns match is one `isSafeUrl` admits. */\nexport function isExternalHttpUrl(url: string): boolean {\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n return /^https?:\\/\\//i.test(trimmed) || PROTOCOL_RELATIVE.test(trimmed);\n}\n\n/** The safe scheme set, for tests and introspection. */\nexport const SAFE_URL_PROTOCOLS: ReadonlySet<string> = SAFE_PROTOCOLS;\n","/**\n * LP0409 — what the strict sanitizer removed that the 1.x default kept.\n *\n * `sanitizerPolicy` defaults to `'strict'` since 2.0; before that it was\n * `'compat'`, which let `id` and every `data-*` through, and `name` only where\n * a per-tag list allowed it. The difference\n * only shows when a binding *writes* markup, so a project that upgrades and\n * whose rich text carries its own hooks loses them at the moment an editor\n * types — silently, and in the preview only. Measured on a real consumer: a\n * `data-partner-scroll` attribute driving a CSS selector disappeared on the\n * first write, with nothing said anywhere.\n *\n * So it is said here: once per attribute name per page, with the reason that\n * applies to that name rather than one sentence covering three different\n * decisions. This is a report, never a behaviour — the attribute stays removed.\n */\n\n/**\n * `console.warn` behind a try/catch rather than `@core/diagnostics`: `security`\n * is a leaf layer and may not import `core` (scripts/architecture-rules.ts), and\n * the shared helper's extra work — tolerating a logger that returns a thenable —\n * is for consumer-supplied loggers. This sink is fixed.\n */\nfunction warn(message: string): void {\n try {\n console.warn(message);\n } catch {\n // A diagnostic must never become a second failure.\n }\n}\n\nconst reported = new Set<string>();\n\n/** The binding prefix, restated rather than imported: this module must not pull the applier in. */\nconst BINDING_PREFIX = 'data-payload-';\n\nfunction reason(name: string): string {\n if (name.startsWith(BINDING_PREFIX)) {\n return (\n 'A binding inside CMS content is refused by design — an editor could otherwise ' +\n 'aim a write at any element on the page (docs/security.md)'\n );\n }\n if (name === 'id' || name === 'name') {\n return (\n 'CMS content that can name an element can shadow a global of that name — ' +\n 'DOM clobbering, refused by design (docs/security.md)'\n );\n }\n return (\n 'List it in `allowedDataAttributes` if the page needs it, or set ' +\n \"`sanitizerPolicy: 'compat'` to keep every `data-*` as 1.x did\"\n );\n}\n\n/**\n * Report one removal. Only for attributes `'compat'` would have kept: everything\n * else the sanitizer drops was refused in 1.x too and is not news to anyone.\n */\nexport function reportDroppedAttribute(name: string): void {\n if (reported.has(name)) return;\n reported.add(name);\n warn(\n `[live-preview] LP0409: the strict sanitizer removed \\`${name}\\` from written markup; ` +\n `the 1.x default (\\`sanitizerPolicy: 'compat'\\`) kept it. ${reason(name)}.`,\n );\n}\n\n/** Test seam: the report is once per page, and a test is not a page. */\nexport function resetDroppedAttributeReports(): void {\n reported.clear();\n}\n","/**\n * HTML sanitizer built on the host parser (`<template>`): allow-listed tags\n * and attributes, validated URLs, hardened external links, no `style`.\n * Needs a DOM; string-only sanitizers are historically brittle.\n */\n\nimport { trustedHtml } from './trusted-types';\nimport { isSafeUrl, isExternalHttpUrl } from './url-validator';\nimport { reportDroppedAttribute } from './sanitizer-report';\n\ndeclare const __INLINE_BUILD__: boolean | undefined;\n\n/** Tags kept with their content. Others are unwrapped unless in `REMOVE_COMPLETELY`. */\nconst ALLOWED_TAGS: ReadonlySet<string> = new Set([\n 'p',\n 'br',\n 'strong',\n 'b',\n 'em',\n 'i',\n 'u',\n 's',\n 'strike',\n 'mark',\n 'small',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'ul',\n 'ol',\n 'li',\n 'dl',\n 'dt',\n 'dd',\n 'blockquote',\n 'code',\n 'pre',\n 'kbd',\n 'samp',\n 'var',\n 'a',\n 'span',\n 'div',\n 'section',\n 'article',\n 'aside',\n 'header',\n 'footer',\n 'nav',\n 'figure',\n 'figcaption',\n 'img',\n 'picture',\n 'source',\n 'audio',\n 'video',\n 'sub',\n 'sup',\n 'hr',\n 'time',\n 'abbr',\n 'cite',\n 'q',\n 'table',\n 'thead',\n 'tbody',\n 'tfoot',\n 'tr',\n 'th',\n 'td',\n 'caption',\n 'colgroup',\n 'col',\n]);\n\n/** Tags `allowFormControls` re-admits for author templates; `form` is deliberately not one. */\nconst FORM_CONTROLS: ReadonlySet<string> = new Set([\n 'input',\n 'button',\n 'textarea',\n 'select',\n 'option',\n 'label',\n]);\n\n/** Removed with their children: the content itself is the hazard. */\nconst REMOVE_COMPLETELY: ReadonlySet<string> = new Set([\n 'script',\n 'style',\n 'iframe',\n 'object',\n 'embed',\n 'link',\n 'meta',\n 'base',\n 'form',\n 'input',\n 'button',\n 'select',\n 'textarea',\n 'svg',\n 'math',\n 'template',\n 'frame',\n 'frameset',\n 'noframes',\n 'noscript',\n]);\n\nconst ATTR_GLOBAL: ReadonlySet<string> = new Set([\n 'id',\n 'class',\n 'lang',\n 'dir',\n 'title',\n 'role',\n 'tabindex',\n]);\n\nconst ATTR_ARIA_PREFIX = 'aria-';\nconst ATTR_DATA_PREFIX = 'data-';\nconst BINDING_DATA_PREFIX = 'data-payload-';\n\nconst ATTR_BY_TAG: Readonly<Record<string, ReadonlySet<string>>> = {\n a: new Set(['href', 'target', 'rel', 'download', 'hreflang', 'type']),\n img: new Set(['src', 'srcset', 'sizes', 'alt', 'width', 'height', 'loading', 'decoding']),\n picture: new Set([]),\n source: new Set(['src', 'srcset', 'sizes', 'type', 'media']),\n audio: new Set(['src', 'controls', 'autoplay', 'loop', 'muted', 'preload']),\n video: new Set([\n 'src',\n 'poster',\n 'controls',\n 'autoplay',\n 'loop',\n 'muted',\n 'preload',\n 'width',\n 'height',\n 'playsinline',\n ]),\n time: new Set(['datetime']),\n abbr: new Set(['title']),\n q: new Set(['cite']),\n blockquote: new Set(['cite']),\n table: new Set(['summary']),\n th: new Set(['colspan', 'rowspan', 'scope', 'headers', 'abbr']),\n td: new Set(['colspan', 'rowspan', 'headers']),\n col: new Set(['span']),\n colgroup: new Set(['span']),\n ol: new Set(['start', 'reversed', 'type']),\n li: new Set(['value']),\n code: new Set(['class']),\n pre: new Set(['class']),\n};\n\nconst URL_ATTRIBUTES: ReadonlySet<string> = new Set(['href', 'src', 'cite', 'poster']);\n\n// Numeric nodeType constants keep an injected SSR document independent of a\n// browser-global `Node` constructor.\nconst ELEMENT_NODE = 1;\nconst COMMENT_NODE = 8;\n\n/** Thrown by `sanitizeHtml()` when no `document` is available (SSR without `setSanitizerDocument()`). */\nexport class SanitizerEnvironmentError extends Error {\n override readonly name = 'SanitizerEnvironmentError';\n}\n\n/**\n * `'strict'` (default) strips `id`, `name` and `data-payload-*` and passes\n * other `data-*` only via `allowedDataAttributes`; `'compat'` keeps them.\n */\nexport type SanitizerPolicyMode = 'compat' | 'strict';\n\nexport interface SanitizeOptions {\n /** Overrides the module default set by `setSanitizerPolicy()`. */\n readonly policy?: SanitizerPolicyMode;\n /** `data-*` attributes (full names) that pass under `'strict'`; `data-payload-*` never does. */\n readonly allowedDataAttributes?: readonly string[];\n /**\n * Keep `input`, `button`, `textarea`, `select`, `option` and `label` — only\n * for markup the page author wrote, never for CMS content. `form`,\n * handlers, `style` and unsafe URLs stay dropped.\n */\n readonly allowFormControls?: boolean;\n /** Extra tags to allow. Lower-case, untrimmed. */\n readonly additionalAllowedTags?: readonly string[];\n /**\n * Extra per-tag attributes, lower-case. Cannot re-admit handlers, `style`,\n * or — under `'strict'` — `id`, `name` and `data-payload-*`.\n */\n readonly additionalAllowedAttributes?: Readonly<Record<string, readonly string[]>>;\n /**\n * The input is a page-author item template, so `'strict'` keeps the\n * applier's reconciliation attributes (`TEMPLATE_ATTRIBUTES`) and nothing\n * else — every other `data-payload-*` is still stripped, so a template can\n * never add a binding.\n */\n readonly templateMode?: boolean;\n}\n\n/** What `templateMode` keeps under `'strict'`. */\nconst TEMPLATE_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'id',\n 'name',\n 'data-payload-key',\n 'data-payload-nested-key',\n 'data-payload-nested-template',\n]);\n\ninterface ResolvedPolicy {\n readonly allowedTags: ReadonlySet<string>;\n readonly allowFormControls: boolean;\n readonly templateMode: boolean;\n readonly mode: SanitizerPolicyMode;\n readonly allowedData: ReadonlySet<string>;\n readonly attrByTag: ReadonlyMap<string, ReadonlySet<string>>;\n}\n\nlet defaultMode: SanitizerPolicyMode = 'strict';\n\n/**\n * The default for calls without an explicit `policy`, per package entry. A\n * runtime carries its own `sanitizerPolicy` and never writes here (ADR 0002).\n */\nexport function setSanitizerPolicy(mode: SanitizerPolicyMode): void {\n defaultMode = mode;\n}\n\n/** `instancePolicy` sits between a per-call `options.policy` and the process default. */\nfunction resolvePolicy(\n options: SanitizeOptions | undefined,\n instancePolicy: SanitizerPolicyMode | undefined,\n): ResolvedPolicy {\n const mode = options?.policy ?? instancePolicy ?? defaultMode;\n if (!options) {\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n return {\n allowedTags: ALLOWED_TAGS,\n attrByTag: attrMap,\n allowFormControls: false,\n templateMode: false,\n mode,\n allowedData: new Set(),\n };\n }\n const allowed = new Set(ALLOWED_TAGS);\n options.additionalAllowedTags?.forEach((tag) => allowed.add(tag));\n if (options.allowFormControls === true) for (const tag of FORM_CONTROLS) allowed.add(tag);\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n for (const [tag, attrs] of Object.entries(options.additionalAllowedAttributes ?? {})) {\n const merged = new Set(attrMap.get(tag));\n for (const attr of attrs) merged.add(attr);\n attrMap.set(tag, merged);\n }\n return {\n allowedTags: allowed,\n attrByTag: attrMap,\n allowFormControls: options.allowFormControls === true,\n templateMode: options.templateMode === true,\n mode,\n allowedData: new Set(options.allowedDataAttributes?.map((name) => name.toLowerCase())),\n };\n}\n\n/** The `Document` surface the sanitizer needs; jsdom, linkedom and happy-dom all provide it. */\nexport interface SanitizerDocument {\n createElement: (tagName: string) => {\n innerHTML: string;\n readonly content: ParentNode;\n };\n}\n\n// Held on the realm, not in this module: every package entry is its own bundle\n// with its own copy of this file, and a document supplied through the root has\n// to reach the rich text `payload-live-preview/lexical` renders.\nconst DOCUMENT_SLOT: unique symbol = Symbol.for('payload-live-preview.sanitizer-document');\n\ninterface DocumentSlot {\n [DOCUMENT_SLOT]?: SanitizerDocument | undefined;\n}\n\n/** Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`; `null` clears it, for every entry. */\nexport function setSanitizerDocument(doc: SanitizerDocument | null): void {\n (globalThis as DocumentSlot)[DOCUMENT_SLOT] = doc ?? undefined;\n}\n\n/**\n * Sanitize `html`; malformed input is recovered by the parser first.\n *\n * @throws {SanitizerEnvironmentError} when no DOM is available.\n */\nexport function sanitizeHtml(html: string, options?: SanitizeOptions): string {\n return sanitizeHtmlWithPolicy(html, undefined, options);\n}\n\n/**\n * The runtime's entry: `policy` is one instance's, applied unless `options`\n * carry their own, so two clients on a page never share a policy through\n * this module. Not public — a direct caller has `options.policy`.\n */\nexport function sanitizeHtmlWithPolicy(\n html: string,\n policy: SanitizerPolicyMode | undefined,\n options?: SanitizeOptions,\n): string {\n const doc = resolveDocument();\n if (!doc) throw environmentError();\n if (html === '') return '';\n\n const resolved = resolvePolicy(options, policy);\n const template = doc.createElement('template');\n // The sanitizer's own parse is a sink too: under Trusted Types it needs the policy.\n template.innerHTML = trustedHtml(html);\n sanitizeFragment(template.content, resolved);\n return template.innerHTML;\n}\n\n// Read the define at each branch rather than through a helper: a bundler\n// folds the substituted literal in place, but will not inline a call, and the\n// SSR-only class and override must not reach the browser runtime.\nfunction environmentError(): Error {\n if (typeof __INLINE_BUILD__ !== 'undefined' && __INLINE_BUILD__) {\n return new Error('sanitizeHtml needs a DOM');\n }\n return new SanitizerEnvironmentError(\n 'sanitizeHtml needs a DOM; provide one with setSanitizerDocument() during SSR.',\n );\n}\n\nfunction resolveDocument(): SanitizerDocument | undefined {\n if (typeof __INLINE_BUILD__ === 'undefined' || !__INLINE_BUILD__) {\n const override = (globalThis as DocumentSlot)[DOCUMENT_SLOT];\n if (override) return override;\n }\n if (typeof document === 'undefined') return undefined;\n return document;\n}\n\n/** Whether a DOM is available — the global or an injected one — for callers that treat sanitizing as optional. */\nexport function hasSanitizerDocument(): boolean {\n return resolveDocument() !== undefined;\n}\n\nfunction sanitizeFragment(node: ParentNode, policy: ResolvedPolicy): void {\n // Snapshot: children are mutated during the walk.\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === ELEMENT_NODE) {\n sanitizeElement(child as Element, policy);\n } else if (child.nodeType === COMMENT_NODE) {\n child.remove();\n }\n }\n}\n\nfunction sanitizeElement(element: Element, policy: ResolvedPolicy): void {\n const tag = element.tagName.toLowerCase();\n\n if (REMOVE_COMPLETELY.has(tag) && !(policy.allowFormControls && FORM_CONTROLS.has(tag))) {\n element.remove();\n return;\n }\n\n if (!policy.allowedTags.has(tag)) {\n sanitizeFragment(element, policy);\n element.replaceWith(...element.childNodes);\n return;\n }\n\n sanitizeAttributes(element, tag, policy);\n if (tag === 'a') hardenAnchor(element);\n sanitizeFragment(element, policy);\n}\n\nfunction sanitizeAttributes(element: Element, tag: string, policy: ResolvedPolicy): void {\n const tagAttrs = policy.attrByTag.get(tag);\n\n for (const attr of Array.from(element.attributes)) {\n const name = attr.name.toLowerCase();\n if (name.startsWith('on') || name === 'style') {\n element.removeAttribute(attr.name);\n continue;\n }\n if (policy.mode === 'strict') {\n if (policy.templateMode && TEMPLATE_ATTRIBUTES.has(name)) continue;\n // DOM clobbering and binding injection (docs/security.md §5c). Checked\n // before the allow-list so an extension cannot re-admit them.\n if (name === 'id' || name === 'name' || name.startsWith(BINDING_DATA_PREFIX)) {\n element.removeAttribute(attr.name);\n // `compat` kept `name` only where a per-tag list allowed it, so only\n // there did the upgrade change anything to report.\n if (name !== 'name' || tagAttrs?.has(name) === true) reportDroppedAttribute(name);\n continue;\n }\n if (name.startsWith(ATTR_DATA_PREFIX)) {\n if (!policy.allowedData.has(name)) {\n element.removeAttribute(attr.name);\n reportDroppedAttribute(name);\n }\n continue;\n }\n if (ATTR_GLOBAL.has(name) || name.startsWith(ATTR_ARIA_PREFIX)) continue;\n } else if (\n ATTR_GLOBAL.has(name) ||\n name.startsWith(ATTR_ARIA_PREFIX) ||\n name.startsWith(ATTR_DATA_PREFIX)\n ) {\n continue;\n }\n if (tagAttrs?.has(name)) {\n if (URL_ATTRIBUTES.has(name) && !isSafeUrl(attr.value)) {\n element.removeAttribute(attr.name);\n } else if (name === 'srcset' && !isSafeSrcset(attr.value)) {\n element.removeAttribute(attr.name);\n }\n continue;\n }\n element.removeAttribute(attr.name);\n }\n}\n\n/** Every `srcset` candidate must pass; partial rewriting would silently change what renders. */\nfunction isSafeSrcset(value: string): boolean {\n for (const candidate of value.split(',')) {\n const trimmed = candidate.trim();\n if (trimmed.length === 0) continue;\n // The URL ends at the first whitespace; what follows is the descriptor.\n const [url = trimmed] = trimmed.split(/\\s/, 1);\n if (!isSafeUrl(url)) return false;\n }\n return true;\n}\n\nfunction hardenAnchor(anchor: Element): void {\n const href = anchor.getAttribute('href');\n if (href === null || !isExternalHttpUrl(href)) return;\n anchor.setAttribute('rel', 'noopener noreferrer');\n if (!anchor.hasAttribute('target')) anchor.setAttribute('target', '_blank');\n}\n\n/** The built-in allow-lists, for documentation and tests. */\nexport const SANITIZER_POLICY = Object.freeze({\n allowedTags: ALLOWED_TAGS,\n removeCompletely: REMOVE_COMPLETELY,\n globalAttributes: ATTR_GLOBAL,\n attributesByTag: ATTR_BY_TAG,\n urlAttributes: URL_ATTRIBUTES,\n});\n","/** HTML and CSS escaping primitives (OWASP XSS Prevention Cheat Sheet). DOM-free. */\n\nconst HTML_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;',\n});\n\nconst HTML_ESCAPE_PATTERN = /[&<>\"'/`=]/g;\n\n/** Escape `text` for an element body or a *quoted* attribute value; strings only, and unquoted attributes are not covered. */\nexport function escapeHtml(text: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return text.replace(HTML_ESCAPE_PATTERN, (char) => HTML_ESCAPES[char] as string);\n}\n\n/** Escape a value for a CSS `url(...)` literal; this stops the break-out, not the scheme, so pair it with `isSafeUrl()`. */\nexport function escapeCssUrl(value: string): string {\n return value.replace(/['\"()\\\\]/g, '\\\\$&');\n}\n\nconst ATTR_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n});\n\nconst ATTR_ESCAPE_PATTERN = /[&<>\"']/g;\n\n/** Escape a value for a *quoted* HTML attribute, leaving URL characters intact; it validates no scheme, so run `isSafeUrl()` on `href`/`src` first. @internal */\nexport function escapeHtmlAttribute(value: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return value.replace(ATTR_ESCAPE_PATTERN, (char) => ATTR_ESCAPES[char] as string);\n}\n\n/** `escapeHtml()` then newlines to `<br>`; the order is what makes it safe. */\nexport function escapeAndLinebreak(text: string): string {\n return escapeHtml(text).replace(/\\r\\n|\\r|\\n/g, '<br>');\n}\n","/**\n * Lexical document types. Only `type` and `children` are required; every\n * other property is forwarded opaquely to the renderer for that node type.\n */\n\n/** Lexical text-format bitmask; flags combine (`BOLD | ITALIC === 3`). @internal */\nexport const TextFormat = {\n BOLD: 1,\n ITALIC: 2,\n STRIKETHROUGH: 4,\n UNDERLINE: 8,\n CODE: 16,\n SUBSCRIPT: 32,\n SUPERSCRIPT: 64,\n HIGHLIGHT: 128,\n} as const;\n\nexport interface LexicalNode {\n readonly type: string;\n readonly version?: number;\n readonly format?: number | string;\n readonly indent?: number;\n readonly direction?: 'ltr' | 'rtl' | null;\n readonly children?: readonly LexicalNode[];\n readonly text?: string;\n readonly [extra: string]: unknown;\n}\n\nexport interface LexicalRoot {\n readonly root: {\n readonly type?: string;\n readonly children: readonly LexicalNode[];\n readonly direction?: 'ltr' | 'rtl' | null;\n readonly format?: number | string;\n readonly indent?: number;\n readonly [extra: string]: unknown;\n };\n}\n","/** Attribute helpers shared by the block-level node renderers. */\n\nimport type { LexicalNode } from './types';\n\nconst ALIGNMENT_NUMERIC: Readonly<Record<number, string>> = {\n 1: 'left',\n 2: 'center',\n 3: 'right',\n 4: 'justify',\n};\n\nconst ALIGNMENT_STRING = new Set(['left', 'center', 'right', 'justify', 'start', 'end']);\n\n/** Alignment of a block node; Payload emits it as a string or as Lexical's numeric format. */\nexport function resolveAlignment(node: LexicalNode): string | undefined {\n const fmt = node.format;\n if (typeof fmt === 'string' && ALIGNMENT_STRING.has(fmt)) return fmt;\n if (typeof fmt === 'number') return ALIGNMENT_NUMERIC[fmt];\n return undefined;\n}\n\nexport function resolveIndent(node: LexicalNode): number {\n const indent = node.indent;\n return typeof indent === 'number' && indent > 0 ? indent : 0;\n}\n\nexport function dirAttribute(node: LexicalNode): string {\n if (node.direction === 'rtl') return ' dir=\"rtl\"';\n if (node.direction === 'ltr') return ' dir=\"ltr\"';\n return '';\n}\n\n/**\n * Alignment and indent as `lp-align-*` / `lp-indent-N` classes. The sanitizer\n * strips `style` under every policy, so inline CSS would never reach the page.\n */\nexport function layoutClassAttribute(node: LexicalNode): string {\n const align = resolveAlignment(node);\n const indent = resolveIndent(node);\n const classes: string[] = [];\n if (align !== undefined) classes.push(`lp-align-${align}`);\n if (indent > 0) classes.push(`lp-indent-${String(indent)}`);\n return classes.length === 0 ? '' : ` class=\"${classes.join(' ')}\"`;\n}\n","import type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst paragraphRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n return `<p${dirAttribute(node)}${layoutClassAttribute(node)}>${children}</p>`;\n};\n\nexport { paragraphRenderer };\n","/** `heading` renderer; an unknown `tag` (transient editor states emit them) falls back to `h2`. */\n\nimport type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst VALID_TAGS = new Set(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']);\n\nconst headingRenderer: NodeRenderer = (node, ctx): string => {\n const tagRaw = typeof node['tag'] === 'string' ? node['tag'].toLowerCase() : 'h2';\n const tag = VALID_TAGS.has(tagRaw) ? tagRaw : 'h2';\n const children = ctx.renderChildren(node.children ?? []);\n return `<${tag}${dirAttribute(node)}${layoutClassAttribute(node)}>${children}</${tag}>`;\n};\n\nexport { headingRenderer };\n","/**\n * Value-shape helpers shared by the Lexical node renderers and the field\n * renderers. They live here because `field-types` may import `lexical`, never\n * the reverse (scripts/architecture-policy.ts).\n */\n\nexport interface MediaShape {\n readonly id?: string | number;\n readonly url?: string;\n readonly alt?: string;\n readonly filename?: string;\n readonly mimeType?: string;\n readonly width?: number;\n readonly height?: number;\n readonly sizes?: Readonly<\n Record<string, { readonly url?: string; readonly width?: number; readonly height?: number }>\n >;\n}\n\nexport interface RelationShape {\n readonly id?: string | number;\n readonly title?: string;\n readonly name?: string;\n readonly slug?: string;\n readonly url?: string;\n}\n\nexport function asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nexport function readMedia(value: unknown): MediaShape | undefined {\n return asRecord(value);\n}\n\n/** Reduce `value` to `[a-z0-9_-]` so it can be a class-name fragment without escaping. */\nexport function sanitizeIdent(value: string): string {\n return value.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();\n}\n\nfunction nonEmpty(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/** Label precedence for a populated relation: `title`, `name`, `slug`, then `id`. */\nexport function pickRelationLabel(value: RelationShape): string | undefined {\n const label = nonEmpty(value.title) ?? nonEmpty(value.name) ?? nonEmpty(value.slug);\n if (label !== undefined) return label;\n return value.id === undefined ? undefined : String(value.id);\n}\n","/**\n * `link` / `autolink` renderer. Payload 3.x serialises links as\n * `{ fields: { linkType, url, newTab, doc } }`; vanilla Lexical puts `url`\n * and `target` on the node itself. Both shapes are read, Payload's first.\n */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isExternalHttpUrl, isSafeUrl } from '@security/url-validator';\nimport type { NodeRenderer } from '../registry';\nimport type { LexicalNode } from '../types';\nimport { asRecord } from '../value-shapes';\n\nconst BLANK_TARGET = ' target=\"_blank\" rel=\"noopener noreferrer\"';\n\nconst linkRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n const fields = asRecord(node['fields']);\n const url = resolveUrl(node, fields);\n if (url === undefined || !isSafeUrl(url)) return children;\n const titleAttr =\n typeof node['title'] === 'string' ? ` title=\"${escapeHtml(node['title'])}\"` : '';\n return `<a href=\"${escapeHtmlAttribute(url)}\"${targetAttribute(node, fields, url)}${titleAttr}>${children}</a>`;\n};\n\nfunction resolveUrl(\n node: LexicalNode,\n fields: Record<string, unknown> | undefined,\n): string | undefined {\n if (fields?.['linkType'] === 'internal') return internalUrl(fields['doc']);\n const url = fields?.['url'] ?? node['url'];\n return typeof url === 'string' && url.length > 0 ? url : undefined;\n}\n\n/** An internal link needs the populated document; a bare id has no route to offer. */\nfunction internalUrl(doc: unknown): string | undefined {\n const value = asRecord(asRecord(doc)?.['value']);\n const url = value?.['url'];\n if (typeof url === 'string' && url.length > 0) return url;\n const slug = value?.['slug'];\n return typeof slug === 'string' && slug.length > 0 ? `/${slug}` : undefined;\n}\n\n/** `_blank` always carries `noopener noreferrer`, whichever side asked for it. */\nfunction targetAttribute(\n node: LexicalNode,\n fields: Record<string, unknown> | undefined,\n url: string,\n): string {\n if (fields?.['newTab'] === true || isExternalHttpUrl(url)) return BLANK_TARGET;\n const target = typeof node['target'] === 'string' ? node['target'] : '';\n if (target === '') return '';\n if (target === '_blank') return BLANK_TARGET;\n return ` target=\"${escapeHtml(target)}\"`;\n}\n\nexport { linkRenderer };\n","/** `code` (fenced block) and `code-highlight` (token span) renderers. */\n\nimport { escapeHtml } from '@security/escape';\nimport type { NodeRenderer } from '../registry';\nimport type { LexicalNode } from '../types';\nimport { sanitizeIdent } from '../value-shapes';\n\nconst codeRenderer: NodeRenderer = (node): string => {\n const language = sanitizeIdent(typeof node['language'] === 'string' ? node['language'] : '');\n const langClass = language === '' ? '' : ` class=\"language-${language}\"`;\n return `<pre><code${langClass}>${escapeHtml(extractText(node))}</code></pre>`;\n};\n\nconst codeHighlightRenderer: NodeRenderer = (node): string => {\n const text = typeof node.text === 'string' ? node.text : '';\n const highlight =\n typeof node['highlightType'] === 'string'\n ? ` class=\"token-${sanitizeIdent(node['highlightType'])}\"`\n : '';\n return `<span${highlight}>${escapeHtml(text)}</span>`;\n};\n\nexport { codeRenderer, codeHighlightRenderer };\n\nfunction extractText(node: LexicalNode): string {\n if (typeof node.text === 'string') return node.text;\n if (!node.children) return '';\n let out = '';\n for (const child of node.children) out += extractText(child);\n return out;\n}\n","/**\n * `upload` renderer: `<img>` for image (or unknown) MIME types, `<video>` /\n * `<audio>` for media, a download link otherwise. An unsafe URL renders nothing.\n */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isSafeUrl } from '@security/url-validator';\nimport type { NodeRenderer } from '../registry';\nimport { readMedia, type MediaShape } from '../value-shapes';\n\nconst uploadRenderer: NodeRenderer = (node): string => {\n const value = readMedia(node['value']);\n if (value === undefined) return '';\n const url = value.url;\n if (typeof url !== 'string' || !isSafeUrl(url)) return '';\n\n const mime = typeof value.mimeType === 'string' ? value.mimeType : '';\n if (mime.startsWith('video/')) return renderVideo(value, url);\n if (mime.startsWith('audio/')) return renderAudio(value, url);\n if (mime === '' || mime.startsWith('image/')) return renderImage(value, url);\n return renderFallbackLink(value, url);\n};\n\nexport { uploadRenderer };\n\nfunction dimensionAttributes(value: MediaShape): string {\n const width = typeof value.width === 'number' ? ` width=\"${String(value.width)}\"` : '';\n const height = typeof value.height === 'number' ? ` height=\"${String(value.height)}\"` : '';\n return `${width}${height}`;\n}\n\nfunction typeAttribute(value: MediaShape): string {\n return typeof value.mimeType === 'string' ? ` type=\"${escapeHtmlAttribute(value.mimeType)}\"` : '';\n}\n\nfunction renderImage(value: MediaShape, url: string): string {\n const alt = typeof value.alt === 'string' ? escapeHtml(value.alt) : '';\n return `<img src=\"${escapeHtmlAttribute(url)}\" alt=\"${alt}\"${dimensionAttributes(value)} loading=\"lazy\" decoding=\"async\">`;\n}\n\nfunction renderVideo(value: MediaShape, url: string): string {\n return `<video controls${dimensionAttributes(value)}><source src=\"${escapeHtmlAttribute(url)}\"${typeAttribute(value)}></video>`;\n}\n\nfunction renderAudio(value: MediaShape, url: string): string {\n return `<audio controls><source src=\"${escapeHtmlAttribute(url)}\"${typeAttribute(value)}></audio>`;\n}\n\nfunction renderFallbackLink(value: MediaShape, url: string): string {\n const label = typeof value.filename === 'string' ? escapeHtml(value.filename) : escapeHtml(url);\n return `<a href=\"${escapeHtmlAttribute(url)}\" target=\"_blank\" rel=\"noopener noreferrer\">${label}</a>`;\n}\n","/** `relationship` renderer: a link when the populated document carries a URL, a span otherwise. */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isSafeUrl } from '@security/url-validator';\nimport type { NodeRenderer } from '../registry';\nimport { asRecord, pickRelationLabel, sanitizeIdent, type RelationShape } from '../value-shapes';\n\nconst relationshipRenderer: NodeRenderer = (node): string => {\n const relationTo = typeof node['relationTo'] === 'string' ? node['relationTo'] : '';\n const value = asRecord(node['value']) as RelationShape | undefined;\n const label = escapeHtml((value && pickRelationLabel(value)) ?? `#${relationTo}`);\n const slug = sanitizeIdent(relationTo);\n const classAttr =\n slug === '' ? ' class=\"lp-relation\"' : ` class=\"lp-relation lp-relation--${slug}\"`;\n const url = value?.url;\n if (typeof url === 'string' && isSafeUrl(url)) {\n return `<a href=\"${escapeHtmlAttribute(url)}\"${classAttr}>${label}</a>`;\n }\n return `<span${classAttr}>${label}</span>`;\n};\n\nexport { relationshipRenderer };\n","/** Block-renderer registry keyed by Payload block slug; consulted by the `block` and `inlineBlock` nodes. */\n\nimport type { LexicalNode } from '../types';\n\nexport interface BlockRenderContext {\n /** Render nested Lexical content through the node registry. */\n readonly renderChildren: (children: readonly LexicalNode[]) => string;\n}\n\n/** Receives the block's `fields` (with `blockType`) and returns HTML. */\nexport type BlockRenderer = (\n fields: Record<string, unknown>,\n context: BlockRenderContext,\n) => string;\n\nconst registry = new Map<string, BlockRenderer>();\n\n/** Register or replace the renderer for `blockType`. */\nexport function registerBlockRenderer(blockType: string, renderer: BlockRenderer): void {\n registry.set(blockType, renderer);\n}\n\n/** @internal */\nexport function lookupBlockRenderer(blockType: string): BlockRenderer | undefined {\n return registry.get(blockType);\n}\n\n/** @internal */\nexport function registeredBlockTypes(): readonly string[] {\n return [...registry.keys()];\n}\n\n/** Test-only: clear the registry. */\nexport function __resetBlockRegistryForTests(): void {\n registry.clear();\n}\n","/**\n * `block` and `inlineBlock` renderers for Payload's BlocksFeature. The block\n * registry is consulted first; without a renderer for the slug the node becomes\n * an empty, class-tagged element a consumer can style or replace.\n *\n * That element is a placeholder, not a rendering. `UNRENDERED_BLOCK_SELECTOR`\n * names it so the write path can keep the markup the server already rendered\n * for the block in its place, instead of replacing a figure and its image with\n * an empty div (LP0410). Whether that succeeds is decided there, not here: this\n * renderer only tells the context which slug it had no renderer for, and the\n * write says what became of it (LP0410 kept, LP0413 lost).\n */\n\nimport { lookupBlockRenderer } from '../blocks/registry';\nimport type { NodeRenderer, RenderNodeContext } from '../registry';\nimport type { LexicalNode } from '../types';\nimport { asRecord, sanitizeIdent } from '../value-shapes';\n\n/**\n * The placeholders above, in the rendered tree. Both are empty by construction,\n * and a registered renderer's output is not: it carries the block's content and\n * its own class (`lp-block-callout`, …).\n */\nexport const UNRENDERED_BLOCK_SELECTOR = '.lp-block:empty,.lp-inline-block:empty';\n\nfunction renderBlockNode(\n node: LexicalNode,\n ctx: RenderNodeContext,\n tag: 'div' | 'span',\n baseClass: string,\n): string {\n const fields = asRecord(node['fields']) ?? {};\n const blockType = typeof fields['blockType'] === 'string' ? fields['blockType'] : '';\n const slug = sanitizeIdent(blockType);\n const classes = slug === '' ? baseClass : `${baseClass} ${baseClass}--${slug}`;\n if (blockType !== '') {\n const custom = lookupBlockRenderer(blockType) ?? lookupBlockRenderer(slug);\n if (custom) return custom(fields, { renderChildren: ctx.renderChildren });\n // The real slug is known only here — the class carries `sanitizeIdent(slug)`,\n // and a hint that names the wrong one to register is no hint.\n ctx.onUnrenderedBlock?.(blockType, classes);\n }\n return `<${tag} class=\"${classes}\"></${tag}>`;\n}\n\nconst blockRenderer: NodeRenderer = (node, ctx) => renderBlockNode(node, ctx, 'div', 'lp-block');\n\nconst inlineBlockRenderer: NodeRenderer = (node, ctx) =>\n renderBlockNode(node, ctx, 'span', 'lp-inline-block');\n\nexport { blockRenderer, inlineBlockRenderer };\n","/** `table` / `tablerow` / `tablecell` renderers for the `@lexical/table` shapes Payload's table feature emits. */\n\nimport type { NodeRenderer } from '../registry';\nimport { dirAttribute } from '../utils';\n\n// `@lexical/table` TableCellHeaderStates: ROW marks a cell in a header row, COLUMN one in a header column.\nconst HEADER_ROW = 1;\nconst HEADER_COLUMN = 2;\n\nconst tableRenderer: NodeRenderer = (node, ctx) =>\n `<table${dirAttribute(node)}><tbody>${ctx.renderChildren(node.children ?? [])}</tbody></table>`;\n\nconst tableRowRenderer: NodeRenderer = (node, ctx) =>\n `<tr>${ctx.renderChildren(node.children ?? [])}</tr>`;\n\nconst tableCellRenderer: NodeRenderer = (node, ctx): string => {\n const header = typeof node['headerState'] === 'number' ? node['headerState'] : 0;\n const tag = (header & (HEADER_ROW | HEADER_COLUMN)) === 0 ? 'td' : 'th';\n const scope =\n header === HEADER_ROW ? ' scope=\"col\"' : header === HEADER_COLUMN ? ' scope=\"row\"' : '';\n return `<${tag}${scope}${spanAttribute('colspan', node['colSpan'])}${spanAttribute('rowspan', node['rowSpan'])}>${ctx.renderChildren(node.children ?? [])}</${tag}>`;\n};\n\nfunction spanAttribute(name: string, value: unknown): string {\n return typeof value === 'number' && value > 1 ? ` ${name}=\"${String(value)}\"` : '';\n}\n\nexport { tableRenderer, tableRowRenderer, tableCellRenderer };\n","import type { NodeRenderer } from '../registry';\nimport { textRenderer } from './text';\nimport { paragraphRenderer } from './paragraph';\nimport { headingRenderer } from './heading';\nimport { listRenderer, listItemRenderer } from './list';\nimport { linkRenderer } from './link';\nimport { quoteRenderer } from './quote';\nimport { codeRenderer, codeHighlightRenderer } from './code';\nimport { linebreakRenderer, horizontalRuleRenderer, tabRenderer } from './linebreak';\nimport { uploadRenderer } from './upload';\nimport { relationshipRenderer } from './relationship';\nimport { blockRenderer, inlineBlockRenderer } from './block';\nimport { tableCellRenderer, tableRenderer, tableRowRenderer } from './table';\n\n// A value table instead of `register()` calls at import time: a consumer that\n// never renders Lexical content must not carry these under `sideEffects: false`.\nexport const BUILTIN_NODE_RENDERERS: Readonly<Record<string, NodeRenderer>> = {\n text: textRenderer,\n paragraph: paragraphRenderer,\n heading: headingRenderer,\n list: listRenderer,\n listitem: listItemRenderer,\n link: linkRenderer,\n autolink: linkRenderer,\n quote: quoteRenderer,\n code: codeRenderer,\n 'code-highlight': codeHighlightRenderer,\n linebreak: linebreakRenderer,\n horizontalrule: horizontalRuleRenderer,\n tab: tabRenderer,\n upload: uploadRenderer,\n relationship: relationshipRenderer,\n block: blockRenderer,\n inlineBlock: inlineBlockRenderer,\n table: tableRenderer,\n tablerow: tableRowRenderer,\n tablecell: tableCellRenderer,\n};\n","/** `text` renderer. Format flags wrap in a fixed order so equal input gives byte-equal output. */\n\nimport { escapeHtml } from '@security/escape';\nimport type { LexicalNode } from '../types';\nimport { TextFormat } from '../types';\nimport type { NodeRenderer } from '../registry';\n\nconst textRenderer: NodeRenderer = (node: LexicalNode): string => {\n const raw = typeof node.text === 'string' ? node.text : '';\n let out = escapeHtml(raw);\n const format = typeof node.format === 'number' ? node.format : 0;\n if ((format & TextFormat.CODE) !== 0) out = `<code>${out}</code>`;\n if ((format & TextFormat.BOLD) !== 0) out = `<strong>${out}</strong>`;\n if ((format & TextFormat.ITALIC) !== 0) out = `<em>${out}</em>`;\n if ((format & TextFormat.UNDERLINE) !== 0) out = `<u>${out}</u>`;\n if ((format & TextFormat.STRIKETHROUGH) !== 0) out = `<s>${out}</s>`;\n if ((format & TextFormat.SUBSCRIPT) !== 0) out = `<sub>${out}</sub>`;\n if ((format & TextFormat.SUPERSCRIPT) !== 0) out = `<sup>${out}</sup>`;\n if ((format & TextFormat.HIGHLIGHT) !== 0) out = `<mark>${out}</mark>`;\n return out;\n};\n\nexport { textRenderer };\n","/** `list` / `listitem` renderers: `bullet` → `<ul>`, `number` → `<ol>`, `check` → `<ul role=\"list\">` with `aria-checked` items. */\n\nimport { escapeHtml } from '@security/escape';\nimport type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst listRenderer: NodeRenderer = (node, ctx): string => {\n const listType = typeof node['listType'] === 'string' ? node['listType'] : 'bullet';\n const tag = listType === 'number' ? 'ol' : 'ul';\n const startAttr =\n listType === 'number' && typeof node['start'] === 'number' && node['start'] > 1\n ? ` start=\"${String(node['start'])}\"`\n : '';\n const checkAttr = listType === 'check' ? ' role=\"list\"' : '';\n const children = ctx.renderChildren(node.children ?? []);\n return `<${tag}${dirAttribute(node)}${layoutClassAttribute(node)}${startAttr}${checkAttr}>${children}</${tag}>`;\n};\n\nconst listItemRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n if (typeof node['checked'] === 'boolean') {\n const state = node['checked'] ? 'true' : 'false';\n return `<li role=\"checkbox\" aria-checked=\"${state}\"${layoutClassAttribute(node)}>${children}</li>`;\n }\n const valueAttr =\n typeof node['value'] === 'number' ? ` value=\"${escapeHtml(String(node['value']))}\"` : '';\n return `<li${dirAttribute(node)}${layoutClassAttribute(node)}${valueAttr}>${children}</li>`;\n};\n\nexport { listRenderer, listItemRenderer };\n","import type { NodeRenderer } from '../registry';\nimport { dirAttribute, layoutClassAttribute } from '../utils';\n\nconst quoteRenderer: NodeRenderer = (node, ctx): string => {\n const children = ctx.renderChildren(node.children ?? []);\n return `<blockquote${dirAttribute(node)}${layoutClassAttribute(node)}>${children}</blockquote>`;\n};\n\nexport { quoteRenderer };\n","import type { NodeRenderer } from '../registry';\n\nconst linebreakRenderer: NodeRenderer = () => '<br>';\nconst horizontalRuleRenderer: NodeRenderer = () => '<hr>';\nconst tabRenderer: NodeRenderer = () => '\\t';\n\nexport { linebreakRenderer, horizontalRuleRenderer, tabRenderer };\n","/** Node-renderer registry: consumer registrations layered over the built-in table. */\n\nimport type { LexicalNode } from './types';\nimport { BUILTIN_NODE_RENDERERS } from './nodes/builtin';\n\nexport interface RenderNodeContext {\n /** Render child nodes through the registry. */\n readonly renderChildren: (children: readonly LexicalNode[]) => string;\n /** Text alignment of a block node, or `undefined`. */\n readonly resolveAlignment: (node: LexicalNode) => string | undefined;\n /** Indent level of a node, `0` when none. */\n readonly resolveIndent: (node: LexicalNode) => number;\n /**\n * Where a `block` or `inlineBlock` without a renderer is reported, with the\n * slug Payload sent and the class of the placeholder written in its place.\n * `undefined` on a plain `lexicalToHtml()` call; the `richText` write sets it.\n */\n readonly onUnrenderedBlock?: ((blockType: string, placeholderClass: string) => void) | undefined;\n}\n\nexport type NodeRenderer = (node: LexicalNode, context: RenderNodeContext) => string;\n\nconst registry = new Map<string, NodeRenderer>();\n\n/** Register or replace the renderer for `type`. */\nexport function register(type: string, renderer: NodeRenderer): void {\n registry.set(type, renderer);\n}\n\n/** @internal */\nexport function lookup(type: string): NodeRenderer | undefined {\n return registry.get(type) ?? BUILTIN_NODE_RENDERERS[type];\n}\n\nexport function registeredTypes(): readonly string[] {\n return [...new Set([...Object.keys(BUILTIN_NODE_RENDERERS), ...registry.keys()])];\n}\n\n/** Test-only: drop consumer registrations. */\nexport function __resetForTests(): void {\n registry.clear();\n}\n","/**\n * Lexical → HTML. Each node dispatches to the renderer registered for its\n * `type`; an unknown node renders its children so content is never lost.\n */\n\nimport { sanitizeHtml, hasSanitizerDocument } from '@security/sanitizer';\nimport { lookup, type RenderNodeContext } from './registry';\nimport type { LexicalNode, LexicalRoot } from './types';\nimport { resolveAlignment, resolveIndent } from './utils';\n\nexport interface LexicalRenderOptions {\n /** Pass the result through `sanitizeHtml()` (default `true`). */\n readonly sanitize?: boolean;\n /**\n * Called for every `block` or `inlineBlock` the registry has no renderer\n * for, with the block's slug as Payload sent it and the class its empty\n * placeholder carries. The `richText` write listens: it is the one caller\n * that later knows whether the server's markup for the block survived, so\n * the diagnostic is spoken there (LP0410, LP0413), not here.\n */\n readonly onUnrenderedBlock?: (blockType: string, placeholderClass: string) => void;\n}\n\nlet warnedNoSanitizer = false;\n\n/** @internal */\nexport function isLexicalContent(value: unknown): value is LexicalRoot {\n if (typeof value !== 'object' || value === null) return false;\n if (!('root' in value)) return false;\n const root = value.root;\n if (typeof root !== 'object' || root === null) return false;\n if (!('children' in root)) return false;\n return Array.isArray(root.children);\n}\n\n/** Render a Lexical document to HTML; without `setSanitizerDocument()` the result is unsanitised and warns once. */\nexport function lexicalToHtml(content: LexicalRoot, options: LexicalRenderOptions = {}): string {\n if (!isLexicalContent(content)) return '';\n const html = createContext(options.onUnrenderedBlock).renderChildren(content.root.children);\n if (options.sanitize === false) return html;\n if (hasSanitizerDocument()) return sanitizeHtml(html);\n warnNoSanitizerOnce();\n return html;\n}\n\n/** Plain text of a document, paragraphs separated by `\\n`. */\nexport function lexicalToPlainText(content: LexicalRoot): string {\n if (!isLexicalContent(content)) return '';\n return content.root.children.map(extractPlainText).join('\\n').trim();\n}\n\n/** Test-only: allow the SSR warning to fire again. */\nexport function __resetSanitizerWarningForTests(): void {\n warnedNoSanitizer = false;\n}\n\n/**\n * One context per document: `renderChildren` closes over it so a nested\n * block — a `block` inside a list item, an `inlineBlock` inside a paragraph —\n * reports to the same listener as a top-level one.\n */\nfunction createContext(\n onUnrenderedBlock: RenderNodeContext['onUnrenderedBlock'],\n): RenderNodeContext {\n const context: RenderNodeContext = {\n renderChildren: (children) => {\n let out = '';\n for (const child of children) out += renderNode(child, context);\n return out;\n },\n resolveAlignment,\n resolveIndent,\n onUnrenderedBlock,\n };\n return context;\n}\n\nfunction renderNode(node: LexicalNode, context: RenderNodeContext): string {\n const renderer = lookup(node.type);\n if (renderer) return renderer(node, context);\n return node.children !== undefined ? context.renderChildren(node.children) : '';\n}\n\nfunction extractPlainText(node: LexicalNode): string {\n if (typeof node.text === 'string') return node.text;\n if (node.type === 'linebreak') return '\\n';\n if (node.children === undefined) return '';\n let out = '';\n for (const child of node.children) out += extractPlainText(child);\n return out;\n}\n\n// This layer may not import `@core/diagnostics` (architecture policy), so the\n// warn-once lives here; a hostile or absent console must not break rendering.\nfunction warnNoSanitizerOnce(): void {\n if (warnedNoSanitizer) return;\n warnedNoSanitizer = true;\n try {\n console.warn(\n '[live-preview] lexicalToHtml() has no sanitizer document and returned unsanitised HTML; ' +\n 'call setSanitizerDocument() (linkedom/jsdom) for server rendering, see \"HTML sanitization\" in docs/security.md.',\n );\n } catch {\n // Diagnostics never become a second failure.\n }\n}\n","/**\n * Opt-in renderers for the block patterns most Payload sites ship (callout,\n * image, video, code, cta). Each reads well-known field names only, escapes\n * every value, validates URLs and renders nothing when a required field is\n * missing. Register with `registerDefaultBlocks()`.\n */\n\nimport { escapeHtml, escapeHtmlAttribute } from '@security/escape';\nimport { isExternalHttpUrl, isSafeUrl } from '@security/url-validator';\nimport type { LexicalNode } from '../types';\nimport { readMedia, sanitizeIdent, type MediaShape } from '../value-shapes';\nimport { registerBlockRenderer, type BlockRenderer } from './registry';\n\nfunction str(fields: Record<string, unknown>, key: string): string | undefined {\n const value = fields[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction safeUrlOrUndefined(fields: Record<string, unknown>, key: string): string | undefined {\n const raw = str(fields, key);\n return raw !== undefined && isSafeUrl(raw) ? raw : undefined;\n}\n\nfunction captionHtml(fields: Record<string, unknown>): string {\n const caption = str(fields, 'caption');\n return caption !== undefined ? `<figcaption>${escapeHtml(caption)}</figcaption>` : '';\n}\n\nfunction dimensionAttributes(media: MediaShape | undefined): string {\n const width = typeof media?.width === 'number' ? ` width=\"${String(media.width)}\"` : '';\n const height = typeof media?.height === 'number' ? ` height=\"${String(media.height)}\"` : '';\n return `${width}${height}`;\n}\n\n/** Fields: `text` or a Lexical `body`/`content`, optional `title`, `importance` (default `info`). */\nconst calloutRenderer: BlockRenderer = (fields, ctx) => {\n const importance = sanitizeIdent(str(fields, 'importance') ?? 'info');\n const title = str(fields, 'title');\n const text = str(fields, 'text');\n const richText = readLexicalChildren(fields);\n\n const titleHtml = title !== undefined ? `<strong>${escapeHtml(title)}</strong>` : '';\n const bodyHtml =\n richText !== undefined\n ? ctx.renderChildren(richText)\n : text !== undefined\n ? `<p>${escapeHtml(text)}</p>`\n : '';\n return `<aside class=\"lp-block-callout lp-block-callout--${importance}\">${titleHtml}${bodyHtml}</aside>`;\n};\n\n/** Fields: `image` (media) or `imageUrl`, `alt`, optional `caption`. */\nconst imageBlockRenderer: BlockRenderer = (fields) => {\n const media = readMedia(fields['image']);\n const url = media?.url ?? safeUrlOrUndefined(fields, 'imageUrl');\n if (url === undefined || !isSafeUrl(url)) return '';\n const alt = media?.alt ?? str(fields, 'alt') ?? '';\n return `<figure class=\"lp-block-image\"><img src=\"${escapeHtmlAttribute(url)}\" alt=\"${escapeHtmlAttribute(alt)}\"${dimensionAttributes(media)} loading=\"lazy\" decoding=\"async\">${captionHtml(fields)}</figure>`;\n};\n\n/** Fields: `video` (media) or `videoUrl`, `mimeType`, optional `poster` and `caption`. */\nconst videoBlockRenderer: BlockRenderer = (fields) => {\n const media = readMedia(fields['video']);\n const url = media?.url ?? safeUrlOrUndefined(fields, 'videoUrl');\n if (url === undefined || !isSafeUrl(url)) return '';\n const mime = media?.mimeType ?? str(fields, 'mimeType');\n const typeAttr = mime !== undefined ? ` type=\"${escapeHtmlAttribute(mime)}\"` : '';\n const poster = safeUrlOrUndefined(fields, 'poster');\n const posterAttr = poster !== undefined ? ` poster=\"${escapeHtmlAttribute(poster)}\"` : '';\n return `<figure class=\"lp-block-video\"><video controls${posterAttr}><source src=\"${escapeHtmlAttribute(url)}\"${typeAttr}></video>${captionHtml(fields)}</figure>`;\n};\n\n/** Fields: `code` or `content`, optional `language` and `caption`. */\nconst codeBlockRenderer: BlockRenderer = (fields) => {\n const code = str(fields, 'code') ?? str(fields, 'content');\n if (code === undefined) return '';\n const language = sanitizeIdent(str(fields, 'language') ?? '');\n const langClass = language === '' ? '' : ` class=\"language-${language}\"`;\n return `<figure class=\"lp-block-code\">${captionHtml(fields)}<pre><code${langClass}>${escapeHtml(code)}</code></pre></figure>`;\n};\n\n/** Fields: `label`/`text` and `href`/`url`; optional `lead`, `secondaryLabel`, `secondaryHref`. */\nconst ctaBlockRenderer: BlockRenderer = (fields) => {\n const label = str(fields, 'label') ?? str(fields, 'text');\n const href = safeUrlOrUndefined(fields, 'href') ?? safeUrlOrUndefined(fields, 'url');\n if (label === undefined || href === undefined) return '';\n const lead = str(fields, 'lead');\n const leadHtml =\n lead !== undefined ? `<p class=\"lp-block-cta__lead\">${escapeHtml(lead)}</p>` : '';\n\n const buttons = [renderCtaAnchor(label, href, true)];\n const secondaryLabel = str(fields, 'secondaryLabel');\n const secondaryHref = safeUrlOrUndefined(fields, 'secondaryHref');\n if (secondaryLabel !== undefined && secondaryHref !== undefined) {\n buttons.push(renderCtaAnchor(secondaryLabel, secondaryHref, false));\n }\n return `<div class=\"lp-block-cta\">${leadHtml}<div class=\"lp-block-cta__actions\">${buttons.join('')}</div></div>`;\n};\n\nfunction renderCtaAnchor(label: string, href: string, primary: boolean): string {\n const targetAttr = isExternalHttpUrl(href) ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : '';\n const variant = primary ? 'primary' : 'secondary';\n return `<a class=\"lp-block-cta__button lp-block-cta__button--${variant}\" href=\"${escapeHtmlAttribute(href)}\"${targetAttr}>${escapeHtml(label)}</a>`;\n}\n\nfunction readLexicalChildren(fields: Record<string, unknown>): readonly LexicalNode[] | undefined {\n const body = fields['body'] ?? fields['content'];\n if (typeof body !== 'object' || body === null) return undefined;\n const root = (body as { root?: { children?: unknown } }).root;\n if (!root || !Array.isArray(root.children)) return undefined;\n return root.children as readonly LexicalNode[];\n}\n\n/** Register every default block renderer under its kebab-, camel- and short slug. Idempotent. */\nexport function registerDefaultBlocks(): void {\n registerBlockRenderer('callout', calloutRenderer);\n registerBlockRenderer('image-block', imageBlockRenderer);\n registerBlockRenderer('imageBlock', imageBlockRenderer);\n registerBlockRenderer('image', imageBlockRenderer);\n registerBlockRenderer('video-block', videoBlockRenderer);\n registerBlockRenderer('videoBlock', videoBlockRenderer);\n registerBlockRenderer('video', videoBlockRenderer);\n registerBlockRenderer('code-block', codeBlockRenderer);\n registerBlockRenderer('codeBlock', codeBlockRenderer);\n registerBlockRenderer('code', codeBlockRenderer);\n registerBlockRenderer('cta-block', ctaBlockRenderer);\n registerBlockRenderer('ctaBlock', ctaBlockRenderer);\n registerBlockRenderer('cta', ctaBlockRenderer);\n}\n\nexport {\n calloutRenderer,\n imageBlockRenderer,\n videoBlockRenderer,\n codeBlockRenderer,\n ctaBlockRenderer,\n};\n"],"mappings":"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","ignoreList":[]}