polotno-node 2.13.0 → 2.14.0

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.
@@ -0,0 +1,2 @@
1
+ const{entries:_t,setPrototypeOf:ct,isFrozen:Yt,getPrototypeOf:Xt,getOwnPropertyDescriptor:jt}=Object;let{freeze:S,seal:L,create:ve}=Object,{apply:ke,construct:Ue}=typeof Reflect<"u"&&Reflect;S||(S=function(o){return o});L||(L=function(o){return o});ke||(ke=function(o,l){for(var a=arguments.length,c=new Array(a>2?a-2:0),O=2;O<a;O++)c[O-2]=arguments[O];return o.apply(l,c)});Ue||(Ue=function(o){for(var l=arguments.length,a=new Array(l>1?l-1:0),c=1;c<l;c++)a[c-1]=arguments[c];return new o(...a)});const ce=R(Array.prototype.forEach),Vt=R(Array.prototype.lastIndexOf),ft=R(Array.prototype.pop),q=R(Array.prototype.push),$t=R(Array.prototype.splice),ue=R(String.prototype.toLowerCase),Ie=R(String.prototype.toString),Ce=R(String.prototype.match),K=R(String.prototype.replace),qt=R(String.prototype.indexOf),Kt=R(String.prototype.trim),y=R(Object.prototype.hasOwnProperty),h=R(RegExp.prototype.test),Z=Zt(TypeError);function R(s){return function(o){o instanceof RegExp&&(o.lastIndex=0);for(var l=arguments.length,a=new Array(l>1?l-1:0),c=1;c<l;c++)a[c-1]=arguments[c];return ke(s,o,a)}}function Zt(s){return function(){for(var o=arguments.length,l=new Array(o),a=0;a<o;a++)l[a]=arguments[a];return Ue(s,l)}}function r(s,o){let l=arguments.length>2&&arguments[2]!==void 0?arguments[2]:ue;ct&&ct(s,null);let a=o.length;for(;a--;){let c=o[a];if(typeof c=="string"){const O=l(c);O!==c&&(Yt(o)||(o[a]=O),c=O)}s[c]=!0}return s}function Jt(s){for(let o=0;o<s.length;o++)y(s,o)||(s[o]=null);return s}function I(s){const o=ve(null);for(const[l,a]of _t(s))y(s,l)&&(Array.isArray(a)?o[l]=Jt(a):a&&typeof a=="object"&&a.constructor===Object?o[l]=I(a):o[l]=a);return o}function J(s,o){for(;s!==null;){const a=jt(s,o);if(a){if(a.get)return R(a.get);if(typeof a.value=="function")return R(a.value)}s=Xt(s)}function l(){return null}return l}const ut=S(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","search","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),Me=S(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","enterkeyhint","exportparts","filter","font","g","glyph","glyphref","hkern","image","inputmode","line","lineargradient","marker","mask","metadata","mpath","part","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),we=S(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),Qt=S(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),xe=S(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),en=S(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),mt=S(["#text"]),pt=S(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","exportparts","face","for","headers","height","hidden","high","href","hreflang","id","inert","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","part","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","slot","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns","slot"]),Pe=S(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","mask-type","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),Tt=S(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),fe=S(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),tn=L(/\{\{[\w\W]*|[\w\W]*\}\}/gm),nn=L(/<%[\w\W]*|[\w\W]*%>/gm),on=L(/\$\{[\w\W]*/gm),an=L(/^data-[\-\w.\u00B7-\uFFFF]+$/),rn=L(/^aria-[\-\w]+$/),gt=L(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),sn=L(/^(?:\w+script|data):/i),ln=L(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),At=L(/^html$/i),cn=L(/^[a-z][.\w]*(-[.\w]+)+$/i);var dt=Object.freeze({__proto__:null,ARIA_ATTR:rn,ATTR_WHITESPACE:ln,CUSTOM_ELEMENT:cn,DATA_ATTR:an,DOCTYPE_NAME:At,ERB_EXPR:nn,IS_ALLOWED_URI:gt,IS_SCRIPT_OR_DATA:sn,MUSTACHE_EXPR:tn,TMPLIT_EXPR:on});const Q={element:1,text:3,progressingInstruction:7,comment:8,document:9},fn=function(){return typeof window>"u"?null:window},un=function(o,l){if(typeof o!="object"||typeof o.createPolicy!="function")return null;let a=null;const c="data-tt-policy-suffix";l&&l.hasAttribute(c)&&(a=l.getAttribute(c));const O="dompurify"+(a?"#"+a:"");try{return o.createPolicy(O,{createHTML(v){return v},createScriptURL(v){return v}})}catch{return console.warn("TrustedTypes policy "+O+" could not be created."),null}},Et=function(){return{afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}};function ht(){let s=arguments.length>0&&arguments[0]!==void 0?arguments[0]:fn();const o=i=>ht(i);if(o.version="3.3.1",o.removed=[],!s||!s.document||s.document.nodeType!==Q.document||!s.Element)return o.isSupported=!1,o;let{document:l}=s;const a=l,c=a.currentScript,{DocumentFragment:O,HTMLTemplateElement:v,Node:me,Element:Fe,NodeFilter:B,NamedNodeMap:St=s.NamedNodeMap||s.MozNamedAttrMap,HTMLFormElement:Rt,DOMParser:Ot,trustedTypes:ee}=s,Y=Fe.prototype,Dt=J(Y,"cloneNode"),Lt=J(Y,"remove"),yt=J(Y,"nextSibling"),bt=J(Y,"childNodes"),te=J(Y,"parentNode");if(typeof v=="function"){const i=l.createElement("template");i.content&&i.content.ownerDocument&&(l=i.content.ownerDocument)}let g,X="";const{implementation:pe,createNodeIterator:Nt,createDocumentFragment:It,getElementsByTagName:Ct}=l,{importNode:Mt}=a;let A=Et();o.isSupported=typeof _t=="function"&&typeof te=="function"&&pe&&pe.createHTMLDocument!==void 0;const{MUSTACHE_EXPR:Te,ERB_EXPR:de,TMPLIT_EXPR:Ee,DATA_ATTR:wt,ARIA_ATTR:xt,IS_SCRIPT_OR_DATA:Pt,ATTR_WHITESPACE:He,CUSTOM_ELEMENT:vt}=dt;let{IS_ALLOWED_URI:ze}=dt,T=null;const Ge=r({},[...ut,...Me,...we,...xe,...mt]);let d=null;const We=r({},[...pt,...Pe,...Tt,...fe]);let u=Object.seal(ve(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),j=null,_e=null;const k=Object.seal(ve(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}}));let Be=!0,ge=!0,Ye=!1,Xe=!0,U=!1,ne=!0,x=!1,Ae=!1,he=!1,F=!1,oe=!1,ie=!1,je=!0,Ve=!1;const kt="user-content-";let Se=!0,V=!1,H={},b=null;const Re=r({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let $e=null;const qe=r({},["audio","video","img","source","image","track"]);let Oe=null;const Ke=r({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ae="http://www.w3.org/1998/Math/MathML",re="http://www.w3.org/2000/svg",C="http://www.w3.org/1999/xhtml";let z=C,De=!1,Le=null;const Ut=r({},[ae,re,C],Ie);let se=r({},["mi","mo","mn","ms","mtext"]),le=r({},["annotation-xml"]);const Ft=r({},["title","style","font","a","script"]);let $=null;const Ht=["application/xhtml+xml","text/html"],zt="text/html";let p=null,G=null;const Gt=l.createElement("form"),Ze=function(e){return e instanceof RegExp||e instanceof Function},ye=function(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(!(G&&G===e)){if((!e||typeof e!="object")&&(e={}),e=I(e),$=Ht.indexOf(e.PARSER_MEDIA_TYPE)===-1?zt:e.PARSER_MEDIA_TYPE,p=$==="application/xhtml+xml"?Ie:ue,T=y(e,"ALLOWED_TAGS")?r({},e.ALLOWED_TAGS,p):Ge,d=y(e,"ALLOWED_ATTR")?r({},e.ALLOWED_ATTR,p):We,Le=y(e,"ALLOWED_NAMESPACES")?r({},e.ALLOWED_NAMESPACES,Ie):Ut,Oe=y(e,"ADD_URI_SAFE_ATTR")?r(I(Ke),e.ADD_URI_SAFE_ATTR,p):Ke,$e=y(e,"ADD_DATA_URI_TAGS")?r(I(qe),e.ADD_DATA_URI_TAGS,p):qe,b=y(e,"FORBID_CONTENTS")?r({},e.FORBID_CONTENTS,p):Re,j=y(e,"FORBID_TAGS")?r({},e.FORBID_TAGS,p):I({}),_e=y(e,"FORBID_ATTR")?r({},e.FORBID_ATTR,p):I({}),H=y(e,"USE_PROFILES")?e.USE_PROFILES:!1,Be=e.ALLOW_ARIA_ATTR!==!1,ge=e.ALLOW_DATA_ATTR!==!1,Ye=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Xe=e.ALLOW_SELF_CLOSE_IN_ATTR!==!1,U=e.SAFE_FOR_TEMPLATES||!1,ne=e.SAFE_FOR_XML!==!1,x=e.WHOLE_DOCUMENT||!1,F=e.RETURN_DOM||!1,oe=e.RETURN_DOM_FRAGMENT||!1,ie=e.RETURN_TRUSTED_TYPE||!1,he=e.FORCE_BODY||!1,je=e.SANITIZE_DOM!==!1,Ve=e.SANITIZE_NAMED_PROPS||!1,Se=e.KEEP_CONTENT!==!1,V=e.IN_PLACE||!1,ze=e.ALLOWED_URI_REGEXP||gt,z=e.NAMESPACE||C,se=e.MATHML_TEXT_INTEGRATION_POINTS||se,le=e.HTML_INTEGRATION_POINTS||le,u=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&Ze(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(u.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&Ze(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(u.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(u.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),U&&(ge=!1),oe&&(F=!0),H&&(T=r({},mt),d=[],H.html===!0&&(r(T,ut),r(d,pt)),H.svg===!0&&(r(T,Me),r(d,Pe),r(d,fe)),H.svgFilters===!0&&(r(T,we),r(d,Pe),r(d,fe)),H.mathMl===!0&&(r(T,xe),r(d,Tt),r(d,fe))),e.ADD_TAGS&&(typeof e.ADD_TAGS=="function"?k.tagCheck=e.ADD_TAGS:(T===Ge&&(T=I(T)),r(T,e.ADD_TAGS,p))),e.ADD_ATTR&&(typeof e.ADD_ATTR=="function"?k.attributeCheck=e.ADD_ATTR:(d===We&&(d=I(d)),r(d,e.ADD_ATTR,p))),e.ADD_URI_SAFE_ATTR&&r(Oe,e.ADD_URI_SAFE_ATTR,p),e.FORBID_CONTENTS&&(b===Re&&(b=I(b)),r(b,e.FORBID_CONTENTS,p)),e.ADD_FORBID_CONTENTS&&(b===Re&&(b=I(b)),r(b,e.ADD_FORBID_CONTENTS,p)),Se&&(T["#text"]=!0),x&&r(T,["html","head","body"]),T.table&&(r(T,["tbody"]),delete j.tbody),e.TRUSTED_TYPES_POLICY){if(typeof e.TRUSTED_TYPES_POLICY.createHTML!="function")throw Z('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if(typeof e.TRUSTED_TYPES_POLICY.createScriptURL!="function")throw Z('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');g=e.TRUSTED_TYPES_POLICY,X=g.createHTML("")}else g===void 0&&(g=un(ee,c)),g!==null&&typeof X=="string"&&(X=g.createHTML(""));S&&S(e),G=e}},Je=r({},[...Me,...we,...Qt]),Qe=r({},[...xe,...en]),Wt=function(e){let t=te(e);(!t||!t.tagName)&&(t={namespaceURI:z,tagName:"template"});const n=ue(e.tagName),f=ue(t.tagName);return Le[e.namespaceURI]?e.namespaceURI===re?t.namespaceURI===C?n==="svg":t.namespaceURI===ae?n==="svg"&&(f==="annotation-xml"||se[f]):!!Je[n]:e.namespaceURI===ae?t.namespaceURI===C?n==="math":t.namespaceURI===re?n==="math"&&le[f]:!!Qe[n]:e.namespaceURI===C?t.namespaceURI===re&&!le[f]||t.namespaceURI===ae&&!se[f]?!1:!Qe[n]&&(Ft[n]||!Je[n]):!!($==="application/xhtml+xml"&&Le[e.namespaceURI]):!1},N=function(e){q(o.removed,{element:e});try{te(e).removeChild(e)}catch{Lt(e)}},P=function(e,t){try{q(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch{q(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),e==="is")if(F||oe)try{N(t)}catch{}else try{t.setAttribute(e,"")}catch{}},et=function(e){let t=null,n=null;if(he)e="<remove></remove>"+e;else{const m=Ce(e,/^[\r\n\t ]+/);n=m&&m[0]}$==="application/xhtml+xml"&&z===C&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const f=g?g.createHTML(e):e;if(z===C)try{t=new Ot().parseFromString(f,$)}catch{}if(!t||!t.documentElement){t=pe.createDocument(z,"template",null);try{t.documentElement.innerHTML=De?X:f}catch{}}const _=t.body||t.documentElement;return e&&n&&_.insertBefore(l.createTextNode(n),_.childNodes[0]||null),z===C?Ct.call(t,x?"html":"body")[0]:x?t.documentElement:_},tt=function(e){return Nt.call(e.ownerDocument||e,e,B.SHOW_ELEMENT|B.SHOW_COMMENT|B.SHOW_TEXT|B.SHOW_PROCESSING_INSTRUCTION|B.SHOW_CDATA_SECTION,null)},be=function(e){return e instanceof Rt&&(typeof e.nodeName!="string"||typeof e.textContent!="string"||typeof e.removeChild!="function"||!(e.attributes instanceof St)||typeof e.removeAttribute!="function"||typeof e.setAttribute!="function"||typeof e.namespaceURI!="string"||typeof e.insertBefore!="function"||typeof e.hasChildNodes!="function")},nt=function(e){return typeof me=="function"&&e instanceof me};function M(i,e,t){ce(i,n=>{n.call(o,e,t,G)})}const ot=function(e){let t=null;if(M(A.beforeSanitizeElements,e,null),be(e))return N(e),!0;const n=p(e.nodeName);if(M(A.uponSanitizeElement,e,{tagName:n,allowedTags:T}),ne&&e.hasChildNodes()&&!nt(e.firstElementChild)&&h(/<[/\w!]/g,e.innerHTML)&&h(/<[/\w!]/g,e.textContent)||e.nodeType===Q.progressingInstruction||ne&&e.nodeType===Q.comment&&h(/<[/\w]/g,e.data))return N(e),!0;if(!(k.tagCheck instanceof Function&&k.tagCheck(n))&&(!T[n]||j[n])){if(!j[n]&&at(n)&&(u.tagNameCheck instanceof RegExp&&h(u.tagNameCheck,n)||u.tagNameCheck instanceof Function&&u.tagNameCheck(n)))return!1;if(Se&&!b[n]){const f=te(e)||e.parentNode,_=bt(e)||e.childNodes;if(_&&f){const m=_.length;for(let D=m-1;D>=0;--D){const w=Dt(_[D],!0);w.__removalCount=(e.__removalCount||0)+1,f.insertBefore(w,yt(e))}}}return N(e),!0}return e instanceof Fe&&!Wt(e)||(n==="noscript"||n==="noembed"||n==="noframes")&&h(/<\/no(script|embed|frames)/i,e.innerHTML)?(N(e),!0):(U&&e.nodeType===Q.text&&(t=e.textContent,ce([Te,de,Ee],f=>{t=K(t,f," ")}),e.textContent!==t&&(q(o.removed,{element:e.cloneNode()}),e.textContent=t)),M(A.afterSanitizeElements,e,null),!1)},it=function(e,t,n){if(je&&(t==="id"||t==="name")&&(n in l||n in Gt))return!1;if(!(ge&&!_e[t]&&h(wt,t))){if(!(Be&&h(xt,t))){if(!(k.attributeCheck instanceof Function&&k.attributeCheck(t,e))){if(!d[t]||_e[t]){if(!(at(e)&&(u.tagNameCheck instanceof RegExp&&h(u.tagNameCheck,e)||u.tagNameCheck instanceof Function&&u.tagNameCheck(e))&&(u.attributeNameCheck instanceof RegExp&&h(u.attributeNameCheck,t)||u.attributeNameCheck instanceof Function&&u.attributeNameCheck(t,e))||t==="is"&&u.allowCustomizedBuiltInElements&&(u.tagNameCheck instanceof RegExp&&h(u.tagNameCheck,n)||u.tagNameCheck instanceof Function&&u.tagNameCheck(n))))return!1}else if(!Oe[t]){if(!h(ze,K(n,He,""))){if(!((t==="src"||t==="xlink:href"||t==="href")&&e!=="script"&&qt(n,"data:")===0&&$e[e])){if(!(Ye&&!h(Pt,K(n,He,"")))){if(n)return!1}}}}}}}return!0},at=function(e){return e!=="annotation-xml"&&Ce(e,vt)},rt=function(e){M(A.beforeSanitizeAttributes,e,null);const{attributes:t}=e;if(!t||be(e))return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:d,forceKeepAttr:void 0};let f=t.length;for(;f--;){const _=t[f],{name:m,namespaceURI:D,value:w}=_,W=p(m),Ne=w;let E=m==="value"?Ne:Kt(Ne);if(n.attrName=W,n.attrValue=E,n.keepAttr=!0,n.forceKeepAttr=void 0,M(A.uponSanitizeAttribute,e,n),E=n.attrValue,Ve&&(W==="id"||W==="name")&&(P(m,e),E=kt+E),ne&&h(/((--!?|])>)|<\/(style|title|textarea)/i,E)){P(m,e);continue}if(W==="attributename"&&Ce(E,"href")){P(m,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){P(m,e);continue}if(!Xe&&h(/\/>/i,E)){P(m,e);continue}U&&ce([Te,de,Ee],lt=>{E=K(E,lt," ")});const st=p(e.nodeName);if(!it(st,W,E)){P(m,e);continue}if(g&&typeof ee=="object"&&typeof ee.getAttributeType=="function"&&!D)switch(ee.getAttributeType(st,W)){case"TrustedHTML":{E=g.createHTML(E);break}case"TrustedScriptURL":{E=g.createScriptURL(E);break}}if(E!==Ne)try{D?e.setAttributeNS(D,m,E):e.setAttribute(m,E),be(e)?N(e):ft(o.removed)}catch{P(m,e)}}M(A.afterSanitizeAttributes,e,null)},Bt=function i(e){let t=null;const n=tt(e);for(M(A.beforeSanitizeShadowDOM,e,null);t=n.nextNode();)M(A.uponSanitizeShadowNode,t,null),ot(t),rt(t),t.content instanceof O&&i(t.content);M(A.afterSanitizeShadowDOM,e,null)};return o.sanitize=function(i){let e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},t=null,n=null,f=null,_=null;if(De=!i,De&&(i="<!-->"),typeof i!="string"&&!nt(i))if(typeof i.toString=="function"){if(i=i.toString(),typeof i!="string")throw Z("dirty is not a string, aborting")}else throw Z("toString is not a function");if(!o.isSupported)return i;if(Ae||ye(e),o.removed=[],typeof i=="string"&&(V=!1),V){if(i.nodeName){const w=p(i.nodeName);if(!T[w]||j[w])throw Z("root node is forbidden and cannot be sanitized in-place")}}else if(i instanceof me)t=et("<!---->"),n=t.ownerDocument.importNode(i,!0),n.nodeType===Q.element&&n.nodeName==="BODY"||n.nodeName==="HTML"?t=n:t.appendChild(n);else{if(!F&&!U&&!x&&i.indexOf("<")===-1)return g&&ie?g.createHTML(i):i;if(t=et(i),!t)return F?null:ie?X:""}t&&he&&N(t.firstChild);const m=tt(V?i:t);for(;f=m.nextNode();)ot(f),rt(f),f.content instanceof O&&Bt(f.content);if(V)return i;if(F){if(oe)for(_=It.call(t.ownerDocument);t.firstChild;)_.appendChild(t.firstChild);else _=t;return(d.shadowroot||d.shadowrootmode)&&(_=Mt.call(a,_,!0)),_}let D=x?t.outerHTML:t.innerHTML;return x&&T["!doctype"]&&t.ownerDocument&&t.ownerDocument.doctype&&t.ownerDocument.doctype.name&&h(At,t.ownerDocument.doctype.name)&&(D="<!DOCTYPE "+t.ownerDocument.doctype.name+`>
2
+ `+D),U&&ce([Te,de,Ee],w=>{D=K(D,w," ")}),g&&ie?g.createHTML(D):D},o.setConfig=function(){let i=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};ye(i),Ae=!0},o.clearConfig=function(){G=null,Ae=!1},o.isValidAttribute=function(i,e,t){G||ye({});const n=p(i),f=p(e);return it(n,f,t)},o.addHook=function(i,e){typeof e=="function"&&q(A[i],e)},o.removeHook=function(i,e){if(e!==void 0){const t=Vt(A[i],e);return t===-1?void 0:$t(A[i],t,1)[0]}return ft(A[i])},o.removeHooks=function(i){A[i]=[]},o.removeAllHooks=function(){A=Et()},o}var mn=ht();export{mn as default};
package/dist/index.html CHANGED
@@ -8,7 +8,7 @@
8
8
  }
9
9
  </style>
10
10
  <meta name="viewport" content="width=device-width, initial-scale=1" />
11
- <script type="module" crossorigin src="./assets/index-vFr48NCL.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-CeWB3Frt.js"></script>
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
package/index.d.ts CHANGED
@@ -18,6 +18,8 @@ declare module 'polotno-node' {
18
18
  mimeType?: string;
19
19
  pageId?: string;
20
20
  onProgress?: (progress: number) => void;
21
+ /** Path to save CPU profile (.cpuprofile) - loadable in Chrome DevTools */
22
+ profilePath?: string;
21
23
  }
22
24
 
23
25
  export interface PDFRenderOptions extends RenderOptions {
@@ -28,6 +30,12 @@ declare module 'polotno-node' {
28
30
  cropMarkSize?: number;
29
31
  }
30
32
 
33
+ export interface VideoRenderOptions extends RenderOptions {
34
+ fps?: number;
35
+ pixelRatio?: number;
36
+ onProgress?: (progress: number, frameTime?: number) => void;
37
+ }
38
+
31
39
  // JSON Structure for Rendering
32
40
  export interface RenderJSON {
33
41
  [key: string]: any;
@@ -85,6 +93,14 @@ declare module 'polotno-node' {
85
93
  json: RenderJSON,
86
94
  options?: RenderOptions
87
95
  ) => Promise<string>;
96
+ jsonToVideoDataURL: (
97
+ json: RenderJSON,
98
+ options?: VideoRenderOptions
99
+ ) => Promise<string>;
100
+ jsonToVideoBase64: (
101
+ json: RenderJSON,
102
+ options?: VideoRenderOptions
103
+ ) => Promise<string>;
88
104
  createPage: () => Promise<Page>;
89
105
  }
90
106
 
package/instance.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const path = require('path');
2
+ const fs = require('fs');
2
3
  const DEFAULT_CLIENT = `file:${path.join(__dirname, 'dist', 'index.html')}`;
3
4
 
4
5
  module.exports.createPage = async (browser, url, requestInterceptor) => {
@@ -105,6 +106,57 @@ module.exports.createInstance = async ({
105
106
  ? null
106
107
  : await module.exports.createPage(browser, visitPage, requestInterceptor);
107
108
 
109
+ async function ensureAssetErrorHelpers(page) {
110
+ await page.evaluate(() => {
111
+ // Define helpers once per page. They unify asset-loading error handling
112
+ // across all exports (dataURL/image/pdf/video).
113
+ if (!window.__polotnoConsumeAssetError) {
114
+ window.__polotnoConsumeAssetError = (attrs) => {
115
+ const error = window._polotnoError;
116
+ if (!error) return null;
117
+
118
+ // Clear immediately to avoid double-reporting.
119
+ window._polotnoError = null;
120
+
121
+ const message = String(error);
122
+ const isFontError = message.indexOf('Timeout for loading font') >= 0;
123
+ const skipFontError = isFontError && attrs && attrs.skipFontError;
124
+
125
+ const isImageError = message.indexOf('image ') >= 0;
126
+ const skipImageError = isImageError && attrs && attrs.skipImageError;
127
+
128
+ if (skipFontError || skipImageError) {
129
+ return null;
130
+ }
131
+ return message;
132
+ };
133
+ }
134
+
135
+ if (!window.__polotnoThrowAssetErrorIfAny) {
136
+ window.__polotnoThrowAssetErrorIfAny = (attrs) => {
137
+ const message = window.__polotnoConsumeAssetError(attrs);
138
+ if (message) {
139
+ throw new Error('Asset loading error: ' + message);
140
+ }
141
+ };
142
+ }
143
+ });
144
+ }
145
+
146
+ async function consumeAssetLoadingErrorMessage(page, attrs) {
147
+ try {
148
+ return await page.evaluate((attrs) => {
149
+ if (window.__polotnoConsumeAssetError) {
150
+ return window.__polotnoConsumeAssetError(attrs);
151
+ }
152
+ return null;
153
+ }, attrs);
154
+ } catch (e) {
155
+ // If the page is already crashed/unavailable, we can't inspect the error.
156
+ return null;
157
+ }
158
+ }
159
+
108
160
  const run = async (func, ...args) => {
109
161
  const page = useParallelPages
110
162
  ? await module.exports.createPage(browser, visitPage, requestInterceptor)
@@ -118,6 +170,16 @@ module.exports.createInstance = async ({
118
170
 
119
171
  busyPages.push(page);
120
172
 
173
+ // Setup profiling if profilePath is provided
174
+ let cdpSession = null;
175
+ const profilePath = args[1]?.profilePath;
176
+ console.log('profilePath', profilePath);
177
+ if (profilePath) {
178
+ cdpSession = await page.target().createCDPSession();
179
+ await cdpSession.send('Profiler.enable');
180
+ await cdpSession.send('Profiler.start');
181
+ }
182
+
121
183
  try {
122
184
  if (args[1]?.assetLoadTimeout) {
123
185
  await page.evaluate((timeout) => {
@@ -176,8 +238,8 @@ module.exports.createInstance = async ({
176
238
  }
177
239
  if (args[1]?.onProgress) {
178
240
  const originalProgress = args[1].onProgress;
179
- await page.exposeFunction('onProgress', async (progress) => {
180
- originalProgress(progress);
241
+ await page.exposeFunction('onProgress', async (progress, frameTime) => {
242
+ originalProgress(progress, frameTime);
181
243
  });
182
244
  }
183
245
  if (args[1]?.textOverflow) {
@@ -202,23 +264,22 @@ module.exports.createInstance = async ({
202
264
  );
203
265
  }
204
266
  });
267
+ await ensureAssetErrorHelpers(page);
205
268
  const result = await page.evaluate(func, ...args);
206
- const error = await page.evaluate(() => window._polotnoError);
207
- if (error) {
208
- // clear error
209
- await page.evaluate(() => {
210
- window._polotnoError = null;
211
- });
212
- const message = error.toString();
213
- const isFontError = message.indexOf('Timeout for loading font') >= 0;
214
- const skipError = isFontError && args[1]?.skipFontError;
215
269
 
216
- const isImageError = message.indexOf('image ') >= 0;
217
- const skipImageError = isImageError && args[1]?.skipImageError;
270
+ // Stop profiler and save profile if enabled
271
+ if (cdpSession && profilePath) {
272
+ const { profile } = await cdpSession.send('Profiler.stop');
273
+ fs.writeFileSync(profilePath, JSON.stringify(profile));
274
+ console.log(`CPU profile saved to: ${profilePath}`);
275
+ }
218
276
 
219
- if (!skipError && !skipImageError) {
220
- throw new Error('Asset loading error: ' + error);
221
- }
277
+ const assetErrorMessage = await consumeAssetLoadingErrorMessage(
278
+ page,
279
+ args[1]
280
+ );
281
+ if (assetErrorMessage) {
282
+ throw new Error('Asset loading error: ' + assetErrorMessage);
222
283
  }
223
284
  // remove busy page
224
285
  busyPages.splice(busyPages.indexOf(page), 1);
@@ -227,11 +288,32 @@ module.exports.createInstance = async ({
227
288
  }
228
289
  return result;
229
290
  } catch (e) {
291
+ // Stop profiler and save profile even on error
292
+ if (cdpSession && profilePath) {
293
+ console.log('saving profile');
294
+ try {
295
+ const { profile } = await cdpSession.send('Profiler.stop');
296
+ fs.writeFileSync(profilePath, JSON.stringify(profile));
297
+ console.log(`CPU profile saved to: ${profilePath}`);
298
+ } catch (profileError) {
299
+ console.error('Failed to save profile:', profileError.message);
300
+ }
301
+ }
302
+
303
+ // If `page.evaluate()` failed (e.g. thrown during onProgress), still prefer
304
+ // a captured Polotno asset-loading error when available.
305
+ const assetErrorMessage = await consumeAssetLoadingErrorMessage(
306
+ page,
307
+ args[1]
308
+ );
230
309
  // remove busy page
231
310
  busyPages.splice(busyPages.indexOf(page), 1);
232
311
  if (useParallelPages) {
233
312
  await page.close();
234
313
  }
314
+ if (assetErrorMessage) {
315
+ throw new Error('Asset loading error: ' + assetErrorMessage);
316
+ }
235
317
  throw e;
236
318
  }
237
319
  };
@@ -299,6 +381,77 @@ module.exports.createInstance = async ({
299
381
  return blob;
300
382
  };
301
383
 
384
+ const jsonToVideoDataURL = async (json, attrs) => {
385
+ return await run(
386
+ async (json, attrs) => {
387
+ const pixelRatio = attrs.pixelRatio || 1;
388
+ store.loadJSON(json);
389
+ await store.waitLoading();
390
+ window.__polotnoThrowAssetErrorIfAny(attrs);
391
+
392
+ // keep store internals consistent with image/pdf exports
393
+ store.setElementsPixelRatio(pixelRatio);
394
+
395
+ // loop through all pages and wait for loading for all layout calculations
396
+ // (this helps stabilize text/layout across multi-page designs)
397
+ for (const page of store.pages) {
398
+ store.selectPage(page.id);
399
+ await store.waitLoading();
400
+ window.__polotnoThrowAssetErrorIfAny(attrs);
401
+ }
402
+ if (store.pages.length > 0) {
403
+ store.selectPage(store.pages[0].id);
404
+ await store.waitLoading();
405
+ window.__polotnoThrowAssetErrorIfAny(attrs);
406
+ }
407
+
408
+ // For video export, we always use 'resize' text overflow mode
409
+ // to ensure text fits properly in animations. User preferences are ignored for now.
410
+ window.config.setTextOverflow('resize');
411
+
412
+ if (!window.loadVideoExportModule) {
413
+ throw new Error(
414
+ 'Video export module loader is not defined in the client. Expected window.loadVideoExportModule().'
415
+ );
416
+ }
417
+
418
+ const { storeToVideo } = await window.loadVideoExportModule();
419
+
420
+ // Use exposed progress callback if available
421
+ const progressCallback = window.onProgress
422
+ ? (progress, frameTime) => {
423
+ // Check for asset-loading errors during render
424
+ window.__polotnoThrowAssetErrorIfAny(attrs);
425
+ return window.onProgress(progress, frameTime);
426
+ }
427
+ : undefined;
428
+
429
+ const videoBlob = await storeToVideo({
430
+ store,
431
+ fps: attrs.fps,
432
+ pixelRatio,
433
+ onProgress: progressCallback,
434
+ });
435
+
436
+ // Convert Blob to data URL
437
+ const dataUrl = await new Promise((resolve, reject) => {
438
+ const reader = new FileReader();
439
+ reader.onloadend = () => resolve(reader.result);
440
+ reader.onerror = reject;
441
+ reader.readAsDataURL(videoBlob);
442
+ });
443
+ return dataUrl;
444
+ },
445
+ json,
446
+ attrs || {}
447
+ );
448
+ };
449
+
450
+ const jsonToVideoBase64 = async (json, attrs) => {
451
+ const url = await jsonToVideoDataURL(json, attrs);
452
+ return url.split('base64,')[1];
453
+ };
454
+
302
455
  const instance = {
303
456
  close: async () => {
304
457
  createdInstances.splice(createdInstances.indexOf(instance), 1);
@@ -314,6 +467,8 @@ module.exports.createInstance = async ({
314
467
  jsonToBlob,
315
468
  jsonToGIFDataURL,
316
469
  jsonToGIFBase64,
470
+ jsonToVideoDataURL,
471
+ jsonToVideoBase64,
317
472
  createPage: async () =>
318
473
  await module.exports.createPage(browser, visitPage, requestInterceptor),
319
474
  };
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "polotno-node",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "Polotno workflow from NodeJS",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
8
- "test": "ava --timeout=30s --concurrency=2",
8
+ "test": "npm run build && vitest run test/static/static.test.mjs",
9
+ "test:video": "npm run build && vitest run test/video/video.test.mjs",
10
+ "test:all": "npm run build && vitest run test/static/static.test.mjs test/video/video.test.mjs",
9
11
  "build": "rm -rf ./dist && npx vite build ./client/ --base=./ --outDir ../dist",
10
12
  "dev": "vite ./client.html"
11
13
  },
@@ -19,7 +21,7 @@
19
21
  ],
20
22
  "browserslist": "> 0.5%, last 2 versions, not dead",
21
23
  "devDependencies": {
22
- "ava": "^6.4.1",
24
+ "@polotno/video-export": "^0.0.4",
23
25
  "axios": "^1.13.2",
24
26
  "dotenv": "^17.2.3",
25
27
  "fluent-ffmpeg": "^2.1.3",
@@ -29,15 +31,16 @@
29
31
  "polotno": "2.34.0",
30
32
  "react": "^18.3.1",
31
33
  "react-dom": "^18.3.1",
32
- "vite": "^7.2.7"
34
+ "vite": "^7.3.0",
35
+ "vitest": "^4.0.16",
36
+ "web-audio-api": "^0.2.2"
33
37
  },
34
38
  "author": "Anton Lavrenov",
35
39
  "license": "MIT",
36
40
  "dependencies": {
37
41
  "@sparticuz/chromium": "^143.0.0",
38
- "mediabunny": "^1.25.8",
39
- "puppeteer": "24.32.1",
40
- "puppeteer-core": "24.32.1",
42
+ "puppeteer": "24.33.0",
43
+ "puppeteer-core": "24.33.0",
41
44
  "tmp": "^0.2.5"
42
45
  },
43
46
  "bugs": {
package/video-parallel.js CHANGED
@@ -265,7 +265,7 @@ module.exports.jsonToVideo = async function jsonToVideo(
265
265
  const skipImageError = isImageError && attrs.skipImageError;
266
266
 
267
267
  if (!skipError && !skipImageError) {
268
- throw new Error(error);
268
+ throw new Error('Asset loading error: ' + error);
269
269
  }
270
270
  }
271
271
  // TODO: add error handling!!!!